diff --git a/app/static/css/style.css b/app/static/css/style.css
index b72808f..de6ccad 100755
--- a/app/static/css/style.css
+++ b/app/static/css/style.css
@@ -301,9 +301,11 @@ box-sizing: border-box;
.widget {
resize: both;
overflow: hidden;
- width: 300px;
- height: 300px;
+ width: 800px;
+ height: 200px;
display: inline-block;
+ position: relative;
+ left: 400px;
}
@@ -348,4 +350,4 @@ box-sizing: border-box;
}
.gridbox:hover{
opacity: 0.5;
-}
\ No newline at end of file
+}
diff --git a/app/templates/show_stack_detail.html b/app/templates/show_stack_detail.html
index af144cd..fda0469 100644
--- a/app/templates/show_stack_detail.html
+++ b/app/templates/show_stack_detail.html
@@ -9,7 +9,7 @@
Books in this stack: {% for book in stack.books %}
{{book.title}}
-
+
diff --git a/app/views_2.py b/app/views_2.py
new file mode 100755
index 0000000..edf46ac
--- /dev/null
+++ b/app/views_2.py
@@ -0,0 +1,539 @@
+"""
+Flask Documentation: http://flask.pocoo.org/docs/
+Jinja2 Documentation: http://jinja.pocoo.org/2/documentation/
+Werkzeug Documentation: http://werkzeug.pocoo.org/documentation/
+This file creates your application.
+"""
+
+from app import app, db, socketio, DOMAIN
+from flask import Flask, Response, render_template, request, redirect, url_for, flash, send_from_directory, jsonify, abort
+import json
+from sqlalchemy.sql.expression import func, select
+from app.forms import UploadForm, EditForm, SearchForm, ChatForm, StackForm, AddtoStackForm, EditStackForm
+from app.models import Book, BookSchema, Author, AuthorSchema, Stack, StackSchema, UserIns, Chat, ChatSchema
+from app.cover import get_cover
+from os import environ
+from flask_socketio import SocketIO, emit
+import datetime
+import time
+import autocomplete
+import sys
+from csv import DictWriter
+import io
+
+import os
+from werkzeug.utils import secure_filename
+
+# import sqlite3
+ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'epub', 'chm', 'mobi'])
+
+author_schema = AuthorSchema()
+authors_schema = AuthorSchema(many=True)
+book_schema = BookSchema()
+books_schema = BookSchema(many=True)
+stack_schema = StackSchema()
+stacks_schema = StackSchema(many=True)
+chat_schema = ChatSchema()
+chats_schema = ChatSchema(many=True)
+
+def allowed_file(filename):
+ return '.' in filename and \
+ filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
+###
+# Routing for your application.
+###
+
+@app.route('/', methods= ['POST','GET'])
+def home():
+ chat_form = ChatForm()
+ chat_messages = db.session.query(Chat).all()
+
+ # if request.method == 'POST':
+ # if chat_form.validate_on_submit():
+ # message = chat_form.message.data
+ # msg = Chat(message)
+ # db.session.add(msg)
+ # db.session.commit()
+
+ return render_template('home.html',domain=DOMAIN,chat=chat_messages, channel = 1, username="librarian")
+
+@app.route('/hello/')
+def hello(name):
+ return "Hello " + name
+
+@app.route('/about/')
+def about():
+ """Render the website's about page."""
+ return render_template('about.html', name="Mary Jane")
+
+@app.route('/uploads/')
+def uploaded_file(filename):
+ return send_from_directory(app.config['UPLOAD_FOLDER'],
+ filename)
+
+@app.route('/uploads/cover/')
+def uploaded_file_cover(filename):
+ return send_from_directory(app.config['UPLOAD_FOLDER_COVER'],
+ filename)
+
+@app.route('/updates', methods=['POST', 'GET'])
+def get_updates():
+ userin = UserIns.query.filter_by(title="lastViewed").first()
+ allbooks = db.session.query(Book).all()
+ id = len(allbooks)
+ latest_upload = allbooks[-1]
+ return "This is the XPPL ~ Library XPUB ~ Updates / / / / / / / Last viewed: " + userin.info + " / / / / / / / " + str(len(allbooks)) + " Books online "+ " / / / / / / / " + "Latest upload: " + latest_upload.title
+
+@app.route('/scape', methods=['POST', 'GET'])
+def scape():
+ if request.method == 'POST':
+ data = request.form
+ book = Book.query.get(data['id'])
+ print(book.scapeX)
+ book.scapeX = data['x']
+ book.scapeY = data['y']
+ db.session.commit()
+ books = db.session.query(Book).all() # or you could have used User.query.all()
+ return render_template('scape.html', books=books)
+
+
+@app.route('/books_grid')
+def show_books_grid():
+ books = db.session.query(Book).all() # or you could have used User.query.all()
+ return render_template('show_books_grid.html', books=books)
+
+@app.route('/books/')
+def show_book_by_id(id):
+ book = Book.query.get(id)
+ userin = UserIns.query.filter_by(title="lastViewed").first()
+ if userin != None:
+ userin.info = book.title
+ db.session.commit()
+ else:
+ user_info = UserIns("lastViewed", book.title)
+ db.session.add(user_info)
+ db.session.commit()
+ if not book:
+ return render_template('red_link.html', id=id)
+ else:
+ return render_template('show_book_detail.html', book=book)
+
+
+@app.route('/books//delete', methods=['POST', 'GET'])
+def remove_book_by_id(id):
+ book_to_edit = Book.query.filter_by(id=id).first()
+ title = book_to_edit.title
+ Book.query.filter_by(id=id).delete()
+ #author_table = Author.query.filter_by(book_id=book_to_edit.id).delete()
+ db.session.commit()
+ flash("%s deleted from library" % (title))
+ return redirect(url_for('show_books'))
+
+@app.route('/books//edit', methods=['POST', 'GET'])
+def edit_book_by_id(id):
+ book_to_edit = Book.query.filter_by(id=id).first()
+ user_form = EditForm(title = book_to_edit.title, author =book_to_edit.authors, category = book_to_edit.category, year_published= book_to_edit.year_published)
+
+ if request.method == 'POST':
+ if user_form.validate_on_submit():
+ # on submit, check fields
+ title = user_form.title.data
+ input_authors = user_form.author.data
+ category = user_form.category.data
+ year_published = user_form.year_published.data
+ if year_published=="":
+ year_published = None
+ book = Book.query.filter_by(id=id).first()
+ book.title = title
+ book.category = category
+ book.year_published = year_published
+
+ #authors update
+ book.authors.clear()
+ for i, author in enumerate(input_authors):
+ author_name = author.get("author_name")
+ if author_name:
+ a = db.session.query(Author).filter_by(author_name=author_name).first()
+ if a == None:
+ a = Author(author_name=author_name)
+ db.session.add(a)
+ book.authors.append(a)
+
+ # editing / uploading new file
+ if user_form.file.data:
+ file = request.files['file']
+ if file.filename == '':
+ flash('No selected file')
+ return redirect(request.url)
+ if file and allowed_file(file.filename):
+ filename = secure_filename(file.filename)
+ allbooks = db.session.query(Book).all()
+ id = book.id
+ new_filename = str(id) +"_"+ filename
+ fullpath = os.path.join(app.config['UPLOAD_FOLDER'], new_filename)
+ name, file_extension = os.path.splitext(new_filename)
+ file.save(fullpath)
+ book.cover = get_cover(fullpath, name)
+ book.file = new_filename
+ else:
+ flash('allowed file formats: %s' % ALLOWED_EXTENSIONS)
+
+ db.session.commit()
+ flash("%s updated" % (title))
+ return redirect(url_for('show_book_by_id', id=id))
+
+ return render_template('edit_book_detail.html', book=book_to_edit, form=user_form)
+
+
+@app.route('/add-book', methods=['POST', 'GET'])
+def add_book():
+ upload_form = UploadForm()
+
+ if request.method == 'POST':
+ if upload_form.validate_on_submit():
+ #get data from form
+ title = upload_form.title.data
+ authors = upload_form.author.data
+ category = upload_form.category.data
+ year_published = upload_form.year_published.data
+ if year_published=="":
+ year_published = None
+
+ #if upload with file
+ if upload_form.upload.data:
+ # check if the post request has the file part
+ if 'file' not in request.files:
+ flash('No file part')
+ return redirect(request.url)
+ file = request.files['file']
+ # if user does not select file, browser also
+ # submit a empty part without filename
+ if file.filename == '':
+ flash('No selected file')
+ return redirect(request.url)
+ if file and allowed_file(file.filename):
+ filename = secure_filename(file.filename)
+ allbooks = db.session.query(Book).all()
+ id = len(allbooks)+1
+ new_filename = str(id) +"_"+ filename
+ fullpath = os.path.join(app.config['UPLOAD_FOLDER'], new_filename)
+ name, file_extension = os.path.splitext(new_filename)
+ file.save(fullpath)
+ cover = get_cover(fullpath, name)
+ else:
+ flash('allowed file formats: %s' % ALLOWED_EXTENSIONS)
+ #if upload without file -> wishform, with potential PDF
+ if upload_form.wish.data:
+ #TO DO: make pdf generator
+ #file = open('app/uploads/potential.pdf')
+ #filename = 'potential.pdf'
+ #file_extension = '.pdf'
+ filename = ''
+ file_extension = ''
+ cover = ''
+
+ book = Book(title, filename, cover, file_extension, category,year_published)
+ db.session.add(book)
+ for author in authors:
+ author_name = author.get("author_name")
+ if author_name:
+ a = db.session.query(Author).filter_by(author_name=author_name).first()
+ if a == None:
+ a = Author(author_name=author_name)
+ db.session.add(a)
+ book.authors.append(a)
+ db.session.commit()
+
+ flash("%s added to the library" % (title))
+ return redirect(url_for('show_books'))
+
+ flash_errors(upload_form)
+ return render_template('add_book.html', form=upload_form)
+
+
+# Flash errors from the form if validation fails
+def flash_errors(form):
+ for field, errors in form.errors.items():
+ for error in errors:
+ flash(u"Error in the %s field - %s" % (
+ getattr(form, field).label.text,
+ error
+ ))
+
+#Authors
+
+@app.route('/authors/')
+def show_author_by_id(id):
+ author = Author.query.get(id)
+ if not author:
+ abort (404)
+ else:
+ return render_template('show_author_detail.html', author=author)
+
+
+@app.route('/authors//edit', methods=['POST', 'GET'])
+def edit_author_by_id(id):
+ return "Ask the programmer."
+
+##stacks
+
+@app.route('/stacks')
+def show_stacks():
+ stacks = db.session.query(Stack).all()
+ return render_template('show_stacks.html', stacks=stacks)
+
+@app.route('/stacks/add_stack', methods=['POST', 'GET'])
+def add_stack():
+ form = StackForm()
+ stacks = db.session.query(Stack).all()
+
+ if form.validate_on_submit():
+ stack_name = form.stack_name.data
+ stack_description = form.stack_description.data
+ stack = Stack(stack_name, stack_description)
+ if form.stack_name.data:
+ stack = Stack(stack_name, stack_description)
+ db.session.add(stack)
+ stacks = db.session.query(Stack).all()
+ return redirect(url_for('show_stacks'))
+ flash("%s stack created" % (stack_name))
+ return render_template('add_stack.html', stacks=stacks, form=form)
+
+@app.route('/stacks/tab/', methods=['POST', 'GET'])
+def show_stack_in_tab(id):
+ return show_stack_by_id(id, is_tab=True)
+
+
+@app.route('/stacks/', methods=['POST', 'GET'])
+def show_stack_by_id(id, is_tab=False):
+
+ stack = Stack.query.get(id)
+ if not stack:
+ abort (404)
+ else:
+ if is_tab == False:
+ return render_template('show_stack_detail.html', stack=stack)
+ else:
+ return render_template('show_stack_detail_tab.html', stack=stack)
+
+@app.route('/stacks//delete', methods=['POST', 'GET'])
+def remove_stack_by_id(id):
+ Stack.query.filter_by(id=id).delete()
+ db.session.commit()
+ return redirect(url_for('show_stacks'))
+
+@app.route('/stacks//edit', methods=['POST', 'GET'])
+def edit_stack_by_id(id):
+ stack = Stack.query.filter_by(id=id).first()
+ form = EditStackForm(edit_stack_name = stack.stack_name, edit_stack_description = stack.stack_description)
+
+ if request.method == 'POST':
+ if form.validate_on_submit():
+ stack_name = form.edit_stack_name.data
+ stack_description = form.edit_stack_description.data
+ stack.stack_name = stack_name
+ stack.stack_description = stack_description
+ db.session.commit()
+
+ return redirect(url_for('show_stack_by_id', id=id))
+ return render_template('edit_stack_detail.html', stack=stack, form=form)
+
+#@app.route('/stacks//remove/', methods=['POST', 'GET'])
+#def remove_from_stack(bookid, stackid):
+# import ipdb; ipdb.set_trace()
+# book = Book.query.get(id)
+# stack = Stack.query.get(id)
+
+# stack = db.session.query(Stack).join(stack.books).filter_by(stackid=stackid)
+# stack.books.delete(book)
+# db.session.commit()
+# return render_template('show_book_by_id.html', stackid=stack.id, bookid=book.id)
+
+@app.route('/add_to_stack/', methods=['GET', 'POST'])
+def add_to_stack(id):
+ stacks = db.session.query(Stack).all()
+ add_form = AddtoStackForm(request.form)
+ add_form.select_stack.choices = [(stack.id, stack.stack_name) for stack in stacks]
+ if request.method == 'GET':
+ book = Book.query.get(id)
+ return render_template('add_to_stacks.html', id=id, stacks=stacks, book=book, add_form=add_form)
+ else:
+ stack = Stack.query.get(int(add_form.select_stack.data))
+ book = Book.query.get(id)
+ stack.books.append(book)
+ db.session.commit()
+ return render_template('show_stack_detail.html', stack=stack)
+
+## search
+
+@app.route('/books', methods= ['POST','GET'])
+def show_books():
+ books = db.session.query(Book).all()
+ search = SearchForm(request.form)
+ if request.method == 'POST':
+ return redirect((url_for('search_results', searchtype=search.select.data, query=search.search.data)))
+
+ return render_template('show_books.html', books=books, form=search)
+
+@app.route('/search///', methods=['POST', 'GET'])
+def search_results(searchtype, query):
+ search = SearchForm(request.form)
+ random_order=Book.query.order_by(func.random()).limit(10)
+ results=Book.query.filter(Book.title.contains(query))
+
+ if searchtype == 'Title':
+ results=Book.query.filter(Book.title.contains(query))
+
+ if searchtype == 'Category':
+ results=Book.query.filter(Book.category.contains(query))
+
+ if searchtype== 'Author':
+ results=db.session.query(Book).join(Book.authors).filter(Author.author_name.contains(query))
+
+ if searchtype== 'Stack':
+ results=db.session.query(Book).join(Book.stacks).filter(Stack.stack_name.contains(query))
+
+ if searchtype== 'All':
+ # results=Book.query.whoosh_search(query)
+ results=Book.query.filter(Book.title.contains(query))
+ results=results.union(Book.query.filter(Book.category.contains(query)))
+ results=results.union(db.session.query(Book).join(Book.authors).filter(Author.author_name.contains(query)))
+ results=results.union(db.session.query(Book).join(Book.stacks).filter(Stack.stack_name.contains(query)))
+
+ if results.count() == 0:
+ upload_form = UploadForm(title= query, author='')
+ return render_template('red_link.html', form=upload_form, title=query)
+
+ if request.method == 'POST':
+ query = search.search.data
+ results = []
+ return redirect((url_for('search_results', searchtype=search.select.data, query=search.search.data)))
+
+ count = results.count()
+ whole = Book.query.count()
+ percentage = float(count / whole * 100)
+ return render_template('results.html', form=search, books=results, books_all=random_order, searchtype=search.select.data, query=query, count = count, whole = whole, percentage = percentage)
+
+
+## Search - autocomplete
+autocomplete_suggestions = []
+
+@app.route('/autocomplete_suggestions', methods=['GET', 'POST'])
+def test1():
+ if request.method == 'POST':
+ autocomplete.load()
+ query = request.form['search']
+ query_tokenized = query.lower().split()
+ print(query_tokenized)
+ word_1 = query_tokenized[-2]
+ word_2 = query_tokenized[-1]
+ #print(word_1)
+ autocomplete_output = autocomplete.predict(word_1 , word_2)
+ autocomplete_suggestions.clear()
+ for suggestion, score in autocomplete_output:
+ autocomplete_suggestions.append(suggestion)
+
+ print(autocomplete_suggestions)
+
+ return Response(json.dumps(autocomplete_suggestions), mimetype='application/json')
+
+
+
+
+
+@app.route('/export/csv', methods=['GET'])
+def export_csv ():
+ output = io.StringIO()
+ fieldnames = ['title', 'authors']
+ csv = DictWriter(output,fieldnames)
+ csv.writeheader()
+ # for i in range(10):
+ # csv.writerow({'ID': i, 'fruit': "Tomato"})
+ for book in Book.query.order_by("title"):
+ authors = ", ".join([x.author_name for x in book.authors])
+ csv.writerow({"title": book.title, "authors": authors})
+ resp = Response(output.getvalue(), mimetype="text/plain")
+ # resp.headers["Content-Disposition"] = "attachment;filename=export.csv"
+ return resp
+###
+# The API
+###
+
+@app.route('/api/books', methods=['GET'])
+def get_books():
+ books = Book.query.all()
+ data = books_schema.dump(books)
+ #print(errors)
+ return jsonify({'books': data})
+
+@app.route('/api/books/', methods=['GET'])
+def get_book_by_id(id):
+ book = Book.query.get(id)
+ data = book_schema.dump(book)
+ if not data:
+ return jsonify({"message": "Book could not be found."}), 400
+ else:
+ return jsonify({'book': data })
+
+@app.route('/api/chats', methods=['GET'])
+def get_chat():
+ chats = Chat.query.all()
+ data = chats_schema.dump(chats)
+ #print(errors)
+ return jsonify({'chat': data})
+
+
+
+###
+# The functions below should be applicable to all Flask apps.
+###
+
+@app.route('/.txt')
+def send_text_file(file_name):
+ """Send your static text file."""
+ file_dot_text = file_name + '.txt'
+ return app.send_static_file(file_dot_text)
+
+
+@app.after_request
+def add_header(response):
+ """
+ Add headers to both force latest IE rendering engine or Chrome Frame,
+ and also to cache the rendered page for 10 minutes.
+ """
+ response.headers['X-UA-Compatible'] = 'IE=Edge,chrome=1'
+ response.headers['Cache-Control'] = 'public, max-age=600'
+ return response
+
+
+@app.errorhandler(404)
+def page_not_found(error):
+ """Custom 404 page."""
+ return render_template('404.html'), 404
+
+@socketio.on('new_message')
+def new_message(message):
+ # Send message to alls users
+ print("new message")
+ emit('channel-' + str(message['channel']), {
+ 'username': message['username'],
+ 'text': message['text'],
+ 'time': str(datetime.datetime.utcnow().strftime("%d.%m.%Y %H:%M"))
+ },
+ broadcast=True
+ )
+ # Save message
+ my_new_chat = Chat(
+ message=message['text']
+ )
+ db.session.add(my_new_chat)
+ try:
+ db.session.commit()
+ except:
+ db.session.rollback()
+
+
+
+if __name__ == '__main__':
+ socketio.run(app)
+ #app.run(debug=True,host="0.0.0.0",port="8080")