diff --git a/app/models.py b/app/models.py index 75aa24b..dd80db8 100755 --- a/app/models.py +++ b/app/models.py @@ -97,6 +97,18 @@ class Stack(db.Model): def __repr__(self): return '' % self.stack_name + +class Potential(db.Model): + __tablename__ = 'potential' + id = db.Column(db.Integer, primary_key = True) + ptitle = db.Column(db.String(50)) + time = db.Column(DateTime, default=datetime.datetime.utcnow()) + + def __init__(self, ptitle): + self.ptitle = ptitle + self.time = datetime.datetime.utcnow() + + class AuthorSchema(Schema): id = fields.Int(dump_only=True) author_name = fields.Str() diff --git a/app/templates/add_book.html b/app/templates/add_book.html index 2400b1e..b9dff17 100755 --- a/app/templates/add_book.html +++ b/app/templates/add_book.html @@ -19,8 +19,7 @@
Title: {{ form.title (size=34, class="form-control") }}

- Author(s): + Author(s): @@ -34,14 +33,15 @@ {% endfor %}
-
Category: {{ form.category(size=27, class="form-control") }}

- + Year published: {{ form.year_published(size=8, class="form-control") }} +
+
{{ form.file }} {{ form.upload }} {{ form.wish }} diff --git a/app/templates/potential_pdf.html b/app/templates/potential_pdf.html new file mode 100644 index 0000000..4450325 --- /dev/null +++ b/app/templates/potential_pdf.html @@ -0,0 +1,50 @@ + + + + + + + + + + + XPPL + + + + + + +
+

A Potential Collection

+

Every book ever requested by XPPL librarians:

+
+

{% for pbook in pbooks %}{{ pbook.ptitle }} requested on: {{ pbook.time }} +

{% endfor %} +
+ + + +
+ + diff --git a/app/templates/red_link.html b/app/templates/red_link.html index 3c81566..a4d6c5c 100755 --- a/app/templates/red_link.html +++ b/app/templates/red_link.html @@ -59,10 +59,12 @@ {% endfor %}
-
+
+ Category: {{ form.category(size=27, class="form-control") }}
-
Category: {{ form.category(size=27, class="form-control") }}
+
+ Year published: {{ form.year_published(size=8, class="form-control") }}
{{ form.file }} {{ form.upload }} diff --git a/app/views.py b/app/views.py index c32106f..163a448 100755 --- a/app/views.py +++ b/app/views.py @@ -10,10 +10,11 @@ from flask import Flask, Response, render_template, request, redirect, url_for, 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.models import Book, BookSchema, Author, AuthorSchema, Stack, StackSchema, UserIns, Chat, ChatSchema, Potential from app.cover import get_cover from os import environ from flask_socketio import SocketIO, emit +from weasyprint import HTML import datetime import time import autocomplete @@ -128,6 +129,15 @@ def remove_book_by_id(id): flash("%s deleted from library" % (title)) return redirect(url_for('show_books')) +@app.route('/potential') +def htmlpdf(): + paragraphs= ['test title'] + template = 'app/templates/potential_pdf.html' + html_string = render_template('potential_pdf.html', paragraphs=paragraphs) + html = HTML(string=html_string) + html.write_pdf(target='app/uploads/potential2.pdf'); + return render_template('potential_pdf.html', paragraphs=paragraphs) + @app.route('/books//edit', methods=['POST', 'GET']) def edit_book_by_id(id): book_to_edit = Book.query.filter_by(id=id).first() @@ -223,13 +233,20 @@ def add_book(): 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 = '' + #pdf generator + filename = 'potential.pdf' + file_extension = '.pdf' + cover= '' + ptitle = upload_form.title.data + pbook = Potential(ptitle) + db.session.add(pbook) + db.session.commit() + pbooks = Potential.query.all() + template = 'app/templates/potential_pdf.html' + html_string = render_template('potential_pdf.html', pbooks = pbooks) + html = HTML(string=html_string) + html.write_pdf(target='app/uploads/potential.pdf'); + print ('potential_pdf') book = Book(title, filename, cover, file_extension, category,year_published) db.session.add(book) diff --git a/app/views_2.py b/app/views_2.py deleted file mode 100755 index edf46ac..0000000 --- a/app/views_2.py +++ /dev/null @@ -1,539 +0,0 @@ -""" -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")