updated with covers and authors

master
Alex 7 years ago
parent 9461301d21
commit 7e1c504e09

@ -7,6 +7,7 @@ from werkzeug.utils import secure_filename
basedir = os.path.abspath(os.path.dirname(__file__)) basedir = os.path.abspath(os.path.dirname(__file__))
UPLOAD_FOLDER = os.path.join(basedir, 'uploads') 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']) ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])
app = Flask(__name__) app = Flask(__name__)

@ -1,8 +1,21 @@
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import StringField, FileField 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): class UserForm(FlaskForm):
title = StringField('title', validators=[InputRequired()]) title = StringField('title', validators=[InputRequired()])
author = StringField('author', validators=[InputRequired()]) author = FieldList(FormField(AuthorForm, default=lambda: Author()), min_entries=1)
file = FileField() file = FileField()
class UserForm_Edit(FlaskForm):
title = StringField('title', validators=[InputRequired()])
author = FieldList(FormField(AuthorForm, default=lambda: Author()), min_entries=1)

@ -2,26 +2,44 @@ from app import db
from marshmallow import Schema, fields, ValidationError, pre_load from marshmallow import Schema, fields, ValidationError, pre_load
class Book(db.Model): class Book(db.Model):
__tablename__ = 'books'
id = db.Column(db.Integer, primary_key = True) id = db.Column(db.Integer, primary_key = True)
title = db.Column(db.String(255)) title = db.Column(db.String(255))
author = db.Column(db.String(255))
file = 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, file, cover, fileformat):
def __init__(self, title, author, file):
self.title = title self.title = title
self.author = author
self.file = file self.file = file
self.cover = cover
self.fileformat = fileformat
def __repr__(self): def __repr__(self):
return '<Title %r>' % self.title return '<Title %r>' % 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): class BookSchema(Schema):
id = fields.Int(dump_only=True) id = fields.Int(dump_only=True)
title = fields.Str() title = fields.Str()
author = fields.Str() author = fields.Str()
file = fields.Str() file = fields.Str()
cover = fields.Str()
fileformat = fields.Str()
def must_not_be_blank(data): def must_not_be_blank(data):
if not data: if not data:

@ -31,8 +31,42 @@ font-style: italic;
display: table; 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';
} }

@ -1 +1,32 @@
/* Add your Application JavaScript */ /* 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
});
});

@ -17,7 +17,24 @@
<form method="POST" action="{{ url_for('add_book') }}" enctype=multipart/form-data> <form method="POST" action="{{ url_for('add_book') }}" enctype=multipart/form-data>
{{ form.csrf_token }} {{ form.csrf_token }}
<div class="form-group">{{ form.title.label }} {{ form.title(size=20, class="form-control") }}</div> <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 }} {{ form.file }}
<button type="submit" class="btn btn-primary">Upload</button> <button type="submit" class="btn btn-primary">Upload</button>
</form> </form>

@ -5,7 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1"> <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 --> <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>XPUB LIB</title> <title>XPPL</title>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
@ -14,12 +14,15 @@
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]--> <![endif]-->
<link rel="stylesheet" href="/static/css/style.css"> <link rel="stylesheet" href="/static/css/style.css">
{% block css %} {% endblock%} {% block css %} {% endblock%}
</head> </head>
<body> <body>
{% block header %}
<header> <header>
{% include "header.html" %} {% include "header.html" %}
</header> </header>
{% endblock %}
<main> <main>
<div class="container"> <div class="container">
{% block main %}{% endblock %} {% block main %}{% endblock %}
@ -32,5 +35,7 @@
</footer> </footer>
{% block js %} {% endblock%} {% block js %} {% endblock%}
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
<script src="{{ url_for("static", filename="js/app.js") }}"></script>
</body> </body>
</html> </html>

@ -1,7 +1,8 @@
<br> <br>
<pre style="font-family:'Courier New'; font-weight:100; font-size:12px;"> <div class="footer">
<pre>
, , , ,
/////| /////|
///// | ///// |
@ -9,7 +10,9 @@
|===| | |===| |
|x | | |x | |
| p | | | p | |
|u b| / |p l| /
|===|/ |===|/
'---' '---'
</pre> </pre>
<p>XPPL. MADE POSSIBLE BY EXPERIMENTAL PUBLISHING, PZI.</p>
</div>

@ -6,5 +6,4 @@
<li><a href="{{ url_for('about') }}">About</a></li> <li><a href="{{ url_for('about') }}">About</a></li>
</ul> </ul>
<div class="clearfix"></div> <div class="clearfix"></div>
</nav> </nav>

@ -1,7 +1,7 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block main %} {% block main %}
<h1 class="header">XPUB LIB</h1> <h1 class="header">XPPL</h1>
<p class="lead">This is the awesome library of Experimental Publishing. <br> <p class="lead">This is the awesome library of Experimental Publishing. <br>
This might only be one interface to this library: This might only be one interface to this library:

@ -4,9 +4,19 @@
<div class="container"> <div class="container">
<h1 class="header">{{ book.title }}</h1> <h1 class="header">{{ book.title }}</h1>
<p>Author: {{ book.author }}</p>
<a href="../uploads/{{ book.file }}">download file</a> <img src="../uploads/cover/{{ book.cover }}" width="200">
<p>Author(s): {% for author in book.author %}
<li> {{ author.author_name }}</li>
{% endfor %}</p>
<a href="../uploads/{{ book.file }}">download {{ book.fileformat }}</a>
<br>
<br>
<a href="{{ url_for('edit_book_by_id', id=book.id )}}">edit</a>
</div> </div>
{% endblock %} {% endblock %}

@ -17,13 +17,21 @@
<table style="width:100%"> <table style="width:100%">
<tr> <tr>
<th>Cover</th>
<th>Title</th> <th>Title</th>
<th>Author</th> <th>Author</th>
<th>Filetype</th>
</tr> </tr>
{% for book in books %} {% for book in books %}
<tr> <tr>
<td><img src="../uploads/cover/{{ book.cover }}" width="80"></td>
<td><a href="books/{{ book.id }}">{{ book.title }}</a></td> <td><a href="books/{{ book.id }}">{{ book.title }}</a></td>
<td>{{ book.author }}</td> <td> {% for author in book.author %}
<li> {{ author.author_name }}</li>
{% endfor %}</td>
<td>{{ book.fileformat }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>

@ -8,11 +8,13 @@ This file creates your application.
from app import app, db from app import app, db
from flask import Flask, render_template, request, redirect, url_for, flash, send_from_directory, jsonify, abort from flask import Flask, render_template, request, redirect, url_for, flash, send_from_directory, jsonify, abort
from app.forms import UserForm from app.forms import UserForm, UserForm_Edit
from app.models import Book, BookSchema from app.models import Book, BookSchema, Author
from app.cover import get_cover
import os import os
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
# import sqlite3 # import sqlite3
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif']) ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])
@ -31,6 +33,9 @@ def home():
"""Render website's home page.""" """Render website's home page."""
return render_template('home.html') return render_template('home.html')
@app.route('/hello/<name>')
def hello(name):
return "Hello " + name
@app.route('/about/') @app.route('/about/')
def about(): def about():
@ -42,20 +47,61 @@ def uploaded_file(filename):
return send_from_directory(app.config['UPLOAD_FOLDER'], return send_from_directory(app.config['UPLOAD_FOLDER'],
filename) filename)
@app.route('/uploads/cover/<filename>')
def uploaded_file_cover(filename):
return send_from_directory(app.config['UPLOAD_FOLDER_COVER'],
filename)
@app.route('/books') @app.route('/books')
def show_books(): def show_books():
books = db.session.query(Book).all() # or you could have used User.query.all() books = db.session.query(Book).all() # or you could have used User.query.all()
return render_template('show_books.html', books=books) return render_template('show_books.html', books=books)
@app.route('/books/<int:id>') @app.route('/books/<int:id>')
def show_book_by_id(id): def show_book_by_id(id):
book = Book.query.get(id) book = Book.query.get(id)
if not book: if not book:
abort(404) return render_template('red_link.html', id=id)
else: else:
return render_template('show_book_detail.html', book=book) return render_template('show_book_detail.html', book=book)
@app.route('/books/<int:id>/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/<int:id>/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']) @app.route('/add-book', methods=['POST', 'GET'])
def add_book(): def add_book():
@ -77,15 +123,25 @@ def add_book():
if file and allowed_file(file.filename): if file and allowed_file(file.filename):
filename = secure_filename(file.filename) filename = secure_filename(file.filename)
fullpath = os.path.join(app.config['UPLOAD_FOLDER'], filename) fullpath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
name, file_extension = os.path.splitext(filename)
file.save(fullpath) file.save(fullpath)
cover = get_cover(fullpath, name)
title = user_form.title.data # You could also have used request.form['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'] author = user_form.author.data # You could also have used request.form['email']
# save user to database print(author)
book = Book(title, author, filename) print(len(author))
book = Book(title, filename, cover, file_extension)
db.session.add(book) db.session.add(book)
db.session.commit() 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)) flash("%s added to the library" % (title))
return redirect(url_for('show_books')) return redirect(url_for('show_books'))
else: else:

Loading…
Cancel
Save