From 7e1c504e09cd976a2c91209def21a74dfc0de8d8 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 23 May 2018 14:12:24 +0200 Subject: [PATCH] updated with covers and authors --- app/__init__.py | 1 + app/__pycache__/__init__.cpython-36.pyc | Bin 831 -> 867 bytes app/__pycache__/forms.cpython-36.pyc | Bin 559 -> 1480 bytes app/__pycache__/models.cpython-36.pyc | Bin 1245 -> 1899 bytes app/__pycache__/views.cpython-36.pyc | Bin 4488 -> 6207 bytes app/forms.py | 17 +++++- app/models.py | 26 +++++++-- app/static/css/style.css | 36 +++++++++++- app/static/js/app.js | 33 ++++++++++- app/templates/add_book.html | 19 ++++++- app/templates/base.html | 7 ++- app/templates/footer.html | 7 ++- app/templates/header.html | 1 - app/templates/home.html | 2 +- app/templates/show_book_detail.html | 14 ++++- app/templates/show_books.html | 10 +++- app/views.py | 72 +++++++++++++++++++++--- 17 files changed, 220 insertions(+), 25 deletions(-) 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 d71f35dc070e14e161fba24cf5349f12d53ecb66..5bdcb03a085bd5114551fbb8e48cfedbd67a2038 100644 GIT binary patch delta 296 zcmdnb_LxoCn3tE!+n6z$otc5*F#{4{2eKW2xcI?D<*a(nES@aERDl%sW~M0NRFM>p z6wVZ`6z&wB6y9{UX2vMdRK`>>AT6H4mnxnmk-~4okSYXb3D_{C2&TgH3pF!|Gl0c~ zfhw3&#esSxLHsN!kbXvn6owR$9PwP~C}|*@C73}|^d-;{6aOXgSMin>PGIa}l$rdRak6NXaA<&!zoSdMo4=2XYf!wif0%2~KVWNe*Z{452onbr7ZVpqjERR4 E0Pi9~-v9sr delta 300 zcmaFNwx3Pen3tF9n>|DHDJBMn#|%h-9msY7;^Ipam9y%FQ`l2DQaDq%Qn*ui(%G6B zqeM~}Q$>NaSPE~dSeAGSpAAE*5SYbp!;m77%9+KJC73FZBG}9%&Hxq{0;*t66$9## z0P(XVLHZdPQW#Q%bHs9`qNIRqmS6@=k(VH6Xfobnb<0UC&IU5LCQC7fOs-|@Vw9fD z!8CdD2BzRVJN?k&)S_bj#GKTMqWsL19DSGk^1Ph<#FS$FG>|^s;=-KFl2qN?#Nv|F zBK^dI0{!^-%)HE!_;|g7%3B;Zx%nxjIjMGxAWzBw2_8lsMhQj^Mjj>+CO$?HCJrVp LCN7W&6AvQ*5Z^~; diff --git a/app/__pycache__/forms.cpython-36.pyc b/app/__pycache__/forms.cpython-36.pyc index e1e93001af38ce6e0eae7ae6128a685befb30c2f..44774c30b1be5391a4ad7713b2e6ed75f342bafb 100644 GIT binary patch literal 1480 zcmb_cOK;Oa5Z<*N$MK^{+O(915Z4Hi9N>gdRVWl8P!2>~mV@Q6o7U<&PS-Y+N}S5I z|A8xiX|HhUU*N>dx@jA!94g_+lX>jCzM1voDDvO_wmyEd3He2?JPz>N@D@LSaKfo1 z8D*3rZ%He&nVmVzF|sWinakX)$(lxX!0s{6@D1Qw%s0F%1LGI6FpF4ZbWOREwOKps zuuj%xT}oaP?(x=l!dt>WvDqrfJ`X?+1O<5w3s~=gMi53hVV1Bt70wCS zque^RScBWplB50FA2S{YHUD6gWCCjPKPNKfNtvr+)OWQP$1^a*vG(IQ%XuY{599c- zN@Q&@L4+78JC|#^+0FHpNGQ_g;2#Xk>W_@DVM{ec{MTQkxVDUWIi8Gp_*ba z|EgBN&4;(JfOwXXms)Lrej5)w1@f;}g)5rE<2H9-qK#9FySxby;Oq$txCcPAw1;IO z47yRKr33&}8)7bHqoCNqY}jH+P6&9?5uA)bzU;B))BRyx~nddRU|eN>|NbL(nQiif`Dna#$MqbXlDv5 zd0lO41I&2dbmP$u-K0jh)ba(uPvGQD0X~N|T67%0;%RA0{x9gNO{fWBu7TZHN^=EW zbsNs8J3t`qUHBXI{Tm^w@FHD{;e9Zy!CN5Kh@nEwsK3ryQ~XH8U&^V%Qlt{Plkw0fwxUiDBtJm-({okC4XNq5sqMkZl5$(gx8Nj_1vQPmA2$7i0 k#3`H6n(D4=1QxZv(p$KI1uj_#-E?ROzaH(`9jDXy3sXclJpcdz delta 367 zcmYk2yH3L}6o&1_xwN#vh{V_d1qhK~q(UH}B9;zZmM~fP1R~rzwViTV7|O~}^(mNm z3Zy=RSDt}|37bk)ZTZ*HkOEejwV zqby>?vV0R=E0A3w`^MLW<`84k7*Sp@s)bZ0pq0KCvKQBC<@^d0`hry)j_i-lC!2PzS^EQWV^u@| diff --git a/app/__pycache__/models.cpython-36.pyc b/app/__pycache__/models.cpython-36.pyc index 99c9588a845e3a5f37bed00644b24d97a267e756..a37e9422ddb5aa0b9603f54be99d8084f6362813 100644 GIT binary patch literal 1899 zcmZ`)OK&4Z5bmCr$76ew7zoQt1OXD3mPCT5DYO-K(O`=*y!=(M3`;Z3| z;^ZBQr~@yyD5fs>HYL;p-=RLd8ra~=syegb7_@!@_j)svmzgD~#pjcx9AEg3>&%SO+PQm;X(`9>kvHrthJHrcL=WP}M@Y-5Hx%jthiM8~>O zIql-W%0SOK)#?vNLw?0HE45NKQ3_$17d-DP_3Jz>xU#QL@|le?S1X2{H?K3{S8l|Jb7?qGrUSxosCio~ z1G&Ba5-*No-|e^^JwM{eZRoiK`mf<9x)eY{iz080qJ)tFZ1k4c=u?cScTEr1rk&OW z27~EBaS=Og?B{g#8N`W8DJIN$xa4ucv@lo|J&@F1QCj{VJDR zE#B58dN>-GH~HLMCT}r$n+Y2??=WEywwX%4sf^B#r{C-Iv@-`_P$%X+UUrsUT3iZV z5%&i6oG-1}5l+TX?#gZ7MdVrve5^m@jZ9W4(Ee#alDwBP4KYX1(ZE`cR_f&Lk|#^v zBOf6TY{G@x_EPRXU7D9ORZWZY!%_dH*IX^uM`gCY`l!mbB;Uuvjkd87H-gNAS^pQB;74Pp3I)?|Crs@a>F>S<1z_E9k08{tNP ze}Zh|2^?d)Q_kx~;e;A%H7>I0**&Oh_DUe)<`ZyuZGE(|7L7eL;`*e_ilX|>aO4ed tc18@h3mg8x9nS&9rONr?F4{1@_TR?$+g9*^n~qC$U*7eGyTfEV{tq>Hg2ey; literal 1245 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 G>;C~8z{RNm delta 2221 zcmZuyS#J|p6ux(6JYM2GjtN;v$co7hftE!SmFO&*7no6xiRjKMr-zt^1uSk{n0eziUBwqRts8scwYYJ)FL_WUvJL^50pDlhmK5;aa zO8jt(-C4~u_JZyDi{kk#e!Q>w7ZaD;oB@Z3lc{IR*?O*=Q+LzJm-C26o!)w(T;NRf zK@8%MfF4LfYQyaCa#7?uth`U;APt!vUhao1)(YFaB@e-%$cjKbn5A>w#r9%7`x#KdC`^ik`@~8yY6O~Ai8?DBILE!d8DDBUVJ3+LSj4ac>?TUd8&Z*$JO=Tv<$SGPT1$l!@Fm?={I z3?z)lxEu|h8|5i7Cf||~yoN@_t&3qic^VR?%dz0+hI^q!NsL-?om(#(w(fjAqh=scCILaaVC851$ z5?;l9V69<>yt%hFvYMR5+oMeIEZ-k&#Zt!)%m{?DLxr2Wrq1|u#%Z? zBSs@IEK?{TO_DOZDJkdg+fEg1Us!I#@|tV)svkzEhddc4VMD$0+l>;IB}{X@ z(Acv5N@&#FYC}?U%PHa*o_$}05x?p?A~eu;+YU{;i4~CD+Uq1*B2gXd6`FV5I=Yoq zPdP+zl4h=A2`OFab$cUPjyG{cEqaJtCP|7XjIB2vhoX>Y2s=yUKMiz=1ksaf?9(XX zQMWM7)Dl_@CnUxbJfU~L(|9fr&SThGNxUJ|l6aRFf@JQ;v&T`BG9(<37u8vXxu;_# zHP#w_yaW=)3uwqdQ}SH!XYOjAX0K$vodh`(e3TzKp+@pO>)WrF3_2D%3TpDyr$#J%LMOPVd;N7 zcc-t3BHedkiqiNlToBh-@O$r*#l4E2Xn^I5hrZfNpOB*3OFHKB2Ht{PwD|O=g2`w0 zXeOv$6@e>FenwjAwIJFKIgB45dhQwxMPDES4sVU7OSjnu!ZC7R{Ua2>zS-Tzp_E Qmg+bAv-xPcCyz<}8?#UJdH?_b 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: