diff --git a/app/__init__.py b/app/__init__.py index e653e29..ea15099 100755 --- a/app/__init__.py +++ b/app/__init__.py @@ -7,6 +7,7 @@ from werkzeug.utils import secure_filename basedir = os.path.abspath(os.path.dirname(__file__)) UPLOAD_FOLDER = os.path.join(basedir, 'uploads') +UPLOAD_FOLDER_COVER = os.path.join(basedir, 'uploads/cover') ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif']) app = Flask(__name__) diff --git a/app/__pycache__/__init__.cpython-36.pyc b/app/__pycache__/__init__.cpython-36.pyc index d71f35d..5bdcb03 100644 Binary files a/app/__pycache__/__init__.cpython-36.pyc and b/app/__pycache__/__init__.cpython-36.pyc differ diff --git a/app/__pycache__/forms.cpython-36.pyc b/app/__pycache__/forms.cpython-36.pyc index e1e9300..44774c3 100644 Binary files a/app/__pycache__/forms.cpython-36.pyc and b/app/__pycache__/forms.cpython-36.pyc differ diff --git a/app/__pycache__/models.cpython-36.pyc b/app/__pycache__/models.cpython-36.pyc index 99c9588..a37e942 100644 Binary files a/app/__pycache__/models.cpython-36.pyc and b/app/__pycache__/models.cpython-36.pyc differ diff --git a/app/__pycache__/views.cpython-36.pyc b/app/__pycache__/views.cpython-36.pyc index bd54b0d..5215722 100644 Binary files a/app/__pycache__/views.cpython-36.pyc and b/app/__pycache__/views.cpython-36.pyc differ diff --git a/app/forms.py b/app/forms.py index a4b251f..fac45fc 100755 --- a/app/forms.py +++ b/app/forms.py @@ -1,8 +1,21 @@ from flask_wtf import FlaskForm from wtforms import StringField, FileField -from wtforms.validators import InputRequired +from wtforms.validators import InputRequired, DataRequired +from wtforms import FieldList +from wtforms import Form as NoCsrfForm +from wtforms.fields import StringField, FormField, SubmitField +from app.models import Book, BookSchema, Author + +# - - - Forms - - - +class AuthorForm(NoCsrfForm): + # this forms is never exposed so we can user the non CSRF version + author_name = StringField('Author Name', validators=[DataRequired()]) class UserForm(FlaskForm): title = StringField('title', validators=[InputRequired()]) - author = StringField('author', validators=[InputRequired()]) + author = FieldList(FormField(AuthorForm, default=lambda: Author()), min_entries=1) file = FileField() + +class UserForm_Edit(FlaskForm): + title = StringField('title', validators=[InputRequired()]) + author = FieldList(FormField(AuthorForm, default=lambda: Author()), min_entries=1) diff --git a/app/models.py b/app/models.py index ebe947a..76e354c 100755 --- a/app/models.py +++ b/app/models.py @@ -2,26 +2,44 @@ from app import db from marshmallow import Schema, fields, ValidationError, pre_load class Book(db.Model): + __tablename__ = 'books' id = db.Column(db.Integer, primary_key = True) title = db.Column(db.String(255)) - author = db.Column(db.String(255)) file = db.Column(db.String(255)) + cover = db.Column(db.String(255)) + fileformat = db.Column(db.String(255)) + author = db.relationship('Author') - - def __init__(self, title, author, file): + def __init__(self, title, file, cover, fileformat): self.title = title - self.author = author self.file = file + self.cover = cover + self.fileformat = fileformat def __repr__(self): return '' % self.title + def get_id(self): + return self.id + + +class Author(db.Model): + __tablename__ = 'authors' + id = db.Column(db.Integer(), primary_key=True) + user_id = db.Column(db.Integer(), db.ForeignKey('books.id')) + author_name = db.Column(db.String(50)) + + + def __init__(self, author_name): + self.author_name = author_name class BookSchema(Schema): id = fields.Int(dump_only=True) title = fields.Str() author = fields.Str() file = fields.Str() + cover = fields.Str() + fileformat = fields.Str() def must_not_be_blank(data): if not data: diff --git a/app/static/css/style.css b/app/static/css/style.css index 07d1335..8e1aa24 100644 --- a/app/static/css/style.css +++ b/app/static/css/style.css @@ -31,8 +31,42 @@ font-style: italic; display: table; } +.container{ +padding: 0px 8px; -.header{ +} + +.header input{ +height:40px; +width: 500px; +font-size: 30px; +font-weight: bold; +} + +.author input{ +height:20px; +width: 500px; +font-size: 16px; +} + + +.footer{ + width: 100%; + font-family:'Courier New'; + font-weight:100; + font-size:12px; +} + +.footer pre{ + width: 60px; + margin:0 auto; +font-family:'Courier New'; +} +.footer p{ + width: 30%; + margin:0 auto; + text-align: center; +font-family:'Courier New'; } diff --git a/app/static/js/app.js b/app/static/js/app.js index 9a13c1e..edc9d30 100755 --- a/app/static/js/app.js +++ b/app/static/js/app.js @@ -1 +1,32 @@ -/* Add your Application JavaScript */ \ No newline at end of file +/* Add your Application JavaScript */ +$(function() { + $("div[data-toggle=fieldset]").each(function() { + var $this = $(this); + + //Add new entry + $this.find("button[data-toggle=fieldset-add-row]").click(function() { + var target = $($(this).data("target")) + console.log(target); + var oldrow = target.find("[data-toggle=fieldset-entry]:last"); + var row = oldrow.clone(true, true); + console.log(row.find(":input")[0]); + var elem_id = row.find(":input")[0].id; + var elem_num = parseInt(elem_id.replace(/.*-(\d{1,4})-.*/m, '$1')) + 1; + row.attr('data-id', elem_num); + row.find(":input").each(function() { + console.log(this); + var id = $(this).attr('id').replace('-' + (elem_num - 1) + '-', '-' + (elem_num) + '-'); + $(this).attr('name', id).attr('id', id).val('').removeAttr("checked"); + }); + oldrow.after(row); + }); //End add new entry + + //Remove row + $this.find("button[data-toggle=fieldset-remove-row]").click(function() { + if($this.find("[data-toggle=fieldset-entry]").length > 1) { + var thisRow = $(this).closest("[data-toggle=fieldset-entry]"); + thisRow.remove(); + } + }); //End remove row + }); +}); diff --git a/app/templates/add_book.html b/app/templates/add_book.html index a27cccd..0dc2ba8 100755 --- a/app/templates/add_book.html +++ b/app/templates/add_book.html @@ -17,7 +17,24 @@ <form method="POST" action="{{ url_for('add_book') }}" enctype=multipart/form-data> {{ form.csrf_token }} <div class="form-group">{{ form.title.label }} {{ form.title(size=20, class="form-control") }}</div> - <div class="form-group">{{ form.author.label }} {{ form.author(size=20, class="form-control") }}</div> + <br> + <div data-toggle="fieldset" id="phone-fieldset"> + {{ form.author.label }} <button type="button" data-toggle="fieldset-add-row" + data-target="#phone-fieldset">+</button> + <table> + <tr> + <th></th> + <th></th> + </tr> + {% for author in form.author %} + <tr data-toggle="fieldset-entry"> + <td>{{ author.author_name }}</td> + <td><button type="button" data-toggle="fieldset-remove-row" id="phone-{{loop.index0}}-remove">-</button></td> + </tr> + {% endfor %} + </table> + </div> +<br> {{ form.file }} <button type="submit" class="btn btn-primary">Upload</button> </form> diff --git a/app/templates/base.html b/app/templates/base.html index 425a1f9..9299451 100755 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -5,7 +5,7 @@ <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> - <title>XPUB LIB + XPPL @@ -14,12 +14,15 @@ + {% block css %} {% endblock%} + {% block header %}
{% include "header.html" %}
+ {% endblock %}
{% block main %}{% endblock %} @@ -32,5 +35,7 @@ {% block js %} {% endblock%} + + diff --git a/app/templates/footer.html b/app/templates/footer.html index 9b84d6f..2f7499f 100755 --- a/app/templates/footer.html +++ b/app/templates/footer.html @@ -1,7 +1,8 @@
-
+
diff --git a/app/templates/header.html b/app/templates/header.html
index 9082586..9c59e99 100755
--- a/app/templates/header.html
+++ b/app/templates/header.html
@@ -6,5 +6,4 @@
             
  • About
  • - diff --git a/app/templates/home.html b/app/templates/home.html index 6b81747..197b107 100755 --- a/app/templates/home.html +++ b/app/templates/home.html @@ -1,7 +1,7 @@ {% extends "base.html" %} {% block main %} -

    XPUB LIB

    +

    XPPL

    This is the awesome library of Experimental Publishing.
    This might only be one interface to this library: … diff --git a/app/templates/show_book_detail.html b/app/templates/show_book_detail.html index af403ab..3716923 100644 --- a/app/templates/show_book_detail.html +++ b/app/templates/show_book_detail.html @@ -4,9 +4,19 @@

    {{ book.title }}

    -

    Author: {{ book.author }}

    - download file + + +

    Author(s): {% for author in book.author %} + +

  • {{ author.author_name }}
  • + + {% endfor %}

    + + download {{ book.fileformat }} +
    +
    + edit
    {% endblock %} diff --git a/app/templates/show_books.html b/app/templates/show_books.html index 1e592ee..c967889 100755 --- a/app/templates/show_books.html +++ b/app/templates/show_books.html @@ -17,13 +17,21 @@ + + {% for book in books %} + - + + {% endfor %}
    Cover Title AuthorFiletype
    {{ book.title }}{{ book.author }} {% for author in book.author %} + +
  • {{ author.author_name }}
  • + + {% endfor %}
    {{ book.fileformat }}
    diff --git a/app/views.py b/app/views.py index 7a100e9..d4359af 100755 --- a/app/views.py +++ b/app/views.py @@ -8,11 +8,13 @@ This file creates your application. from app import app, db from flask import Flask, render_template, request, redirect, url_for, flash, send_from_directory, jsonify, abort -from app.forms import UserForm -from app.models import Book, BookSchema +from app.forms import UserForm, UserForm_Edit +from app.models import Book, BookSchema, Author +from app.cover import get_cover import os from werkzeug.utils import secure_filename + # import sqlite3 ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif']) @@ -31,6 +33,9 @@ def home(): """Render website's home page.""" return render_template('home.html') +@app.route('/hello/') +def hello(name): + return "Hello " + name @app.route('/about/') def about(): @@ -42,20 +47,61 @@ 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('/books') def show_books(): books = db.session.query(Book).all() # or you could have used User.query.all() - return render_template('show_books.html', books=books) @app.route('/books/') def show_book_by_id(id): book = Book.query.get(id) if not book: - abort(404) + 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(user_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 = UserForm_Edit(title = book_to_edit.title, author =book_to_edit.author) + + if request.method == 'POST': + if user_form.validate_on_submit(): + # check if the post request has the file part + title = user_form.title.data # You could also have used request.form['name'] + author = user_form.author.data # You could also have used request.form['email'] + # save user to database + #book = Book(title, author, filename, cover, file_extension) + book_to_edit.title = title + db.session.commit() + + book = Book.query.filter_by(title=title).first() + author_table = Author.query.filter_by(user_id=book.id).delete() + for this_author in author: + this_author = Author(this_author.get('author_name')) + book.author.append(this_author) + db.session.commit() + + flash("%s updated" % (title)) + return redirect(url_for('show_books')) + + return render_template('edit_book_detail.html', book=book_to_edit, form=user_form) + @app.route('/add-book', methods=['POST', 'GET']) def add_book(): @@ -77,15 +123,25 @@ def add_book(): if file and allowed_file(file.filename): filename = secure_filename(file.filename) fullpath = os.path.join(app.config['UPLOAD_FOLDER'], filename) - + name, file_extension = os.path.splitext(filename) file.save(fullpath) - + cover = get_cover(fullpath, name) title = user_form.title.data # You could also have used request.form['name'] author = user_form.author.data # You could also have used request.form['email'] - # save user to database - book = Book(title, author, filename) + print(author) + print(len(author)) + book = Book(title, filename, cover, file_extension) db.session.add(book) db.session.commit() + book = Book.query.filter_by(title=title).first() + for this_author in author: + this_author = Author(this_author.get('author_name')) + book.author.append(this_author) + db.session.commit() + #author = "hallo" + # save user to database + + flash("%s added to the library" % (title)) return redirect(url_for('show_books')) else: