Merge pull request #17 from cervinko/feature-rights-management

add user-permission management
This commit is contained in:
Jan B 2016-04-29 22:17:30 +02:00
commit 554bc6aaf5
7 changed files with 288 additions and 127 deletions

View File

@ -60,6 +60,7 @@ TITLE_REGEX = check_setting_str(CFG, 'Advanced', 'TITLE_REGEX', '^(A|The|An|Der|
DEVELOPMENT = bool(check_setting_int(CFG, 'Advanced', 'DEVELOPMENT', 0)) DEVELOPMENT = bool(check_setting_int(CFG, 'Advanced', 'DEVELOPMENT', 0))
PUBLIC_REG = bool(check_setting_int(CFG, 'Advanced', 'PUBLIC_REG', 0)) PUBLIC_REG = bool(check_setting_int(CFG, 'Advanced', 'PUBLIC_REG', 0))
UPLOADING = bool(check_setting_int(CFG, 'Advanced', 'UPLOADING', 0)) UPLOADING = bool(check_setting_int(CFG, 'Advanced', 'UPLOADING', 0))
ANO_SHOW_BOOKS = bool(check_setting_int(CFG, 'Advanced', 'ANO_SHOW_BOOKS', 0))
SYS_ENCODING="UTF-8" SYS_ENCODING="UTF-8"
@ -78,6 +79,8 @@ configval["DEVELOPMENT"] = DEVELOPMENT
configval["TITLE_REGEX"] = TITLE_REGEX configval["TITLE_REGEX"] = TITLE_REGEX
configval["PUBLIC_REG"] = PUBLIC_REG configval["PUBLIC_REG"] = PUBLIC_REG
configval["UPLOADING"] = UPLOADING configval["UPLOADING"] = UPLOADING
configval["ANO_SHOW_BOOKS"] = ANO_SHOW_BOOKS
def save_config(configval): def save_config(configval):
new_config = ConfigObj() new_config = ConfigObj()
@ -94,6 +97,7 @@ def save_config(configval):
new_config['Advanced']['DEVELOPMENT'] = int(configval["DEVELOPMENT"]) new_config['Advanced']['DEVELOPMENT'] = int(configval["DEVELOPMENT"])
new_config['Advanced']['PUBLIC_REG'] = int(configval["PUBLIC_REG"]) new_config['Advanced']['PUBLIC_REG'] = int(configval["PUBLIC_REG"])
new_config['Advanced']['UPLOADING'] = int(configval["UPLOADING"]) new_config['Advanced']['UPLOADING'] = int(configval["UPLOADING"])
new_config['Advanced']['ANO_SHOW_BOOKS'] = int(configval["ANO_SHOW_BOOKS"])
new_config.write() new_config.write()
return "Saved" return "Saved"

View File

@ -154,7 +154,7 @@
</div> </div>
{% endif %} {% endif %}
{% if g.user.role %} {% if g.user.role_edit() %}
<div class="btn-toolbar" role="toolbar"> <div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group" aria-label="Edit/Delete book"> <div class="btn-group" role="group" aria-label="Edit/Delete book">
<a href="{{ url_for('edit_book', book_id=entry.id) }}" class="btn btn-sm btn-warning" role="button"><span class="glyphicon glyphicon-edit"></span> Edit metadata</a> <a href="{{ url_for('edit_book', book_id=entry.id) }}" class="btn btn-sm btn-warning" role="button"><span class="glyphicon glyphicon-edit"></span> Edit metadata</a>

View File

@ -63,7 +63,7 @@
</ul> </ul>
<ul class="nav navbar-nav navbar-right" id="main-nav"> <ul class="nav navbar-nav navbar-right" id="main-nav">
{% if g.user.is_authenticated() %} {% if g.user.is_authenticated() %}
{% if g.user.role %} {% if g.user.role_upload() or g.user.role_admin()%}
{% if g.allow_upload %} {% if g.allow_upload %}
<li> <li>
<form id="form-upload" class="navbar-form" action="{{ url_for('upload') }}" method="post" enctype="multipart/form-data"> <form id="form-upload" class="navbar-form" action="{{ url_for('upload') }}" method="post" enctype="multipart/form-data">
@ -74,7 +74,7 @@
</li> </li>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if g.user.role %} {% if g.user.role_admin() %}
<li><a href="{{url_for('user_list')}}"><span class="glyphicon glyphicon-dashboard"></span> Admin</a></li> <li><a href="{{url_for('user_list')}}"><span class="glyphicon glyphicon-dashboard"></span> Admin</a></li>
{% endif %} {% endif %}
<li><a href="{{url_for('profile')}}"><span class="glyphicon glyphicon-user"></span> {{g.user.nickname}}</a></li> <li><a href="{{url_for('profile')}}"><span class="glyphicon glyphicon-user"></span> {{g.user.nickname}}</a></li>

View File

@ -3,7 +3,7 @@
<div class="discover"> <div class="discover">
<h1>{{title}}</h1> <h1>{{title}}</h1>
<form role="form" method="POST"> <form role="form" method="POST">
{% if g.user and g.user.role and new_user %} {% if g.user and g.user.role_admin() and new_user %}
<div class="form-group required"> <div class="form-group required">
<label for="nickname">Username</label> <label for="nickname">Username</label>
<input type="text" class="form-control" name="nickname" id="nickname" value="{{ content.nickname if content.nickname != None }}"> <input type="text" class="form-control" name="nickname" id="nickname" value="{{ content.nickname if content.nickname != None }}">
@ -13,21 +13,39 @@
<label for="email">Email address</label> <label for="email">Email address</label>
<input type="email" class="form-control" name="email" id="email" value="{{ content.email if content.email != None }}" required> <input type="email" class="form-control" name="email" id="email" value="{{ content.email if content.email != None }}" required>
</div> </div>
{% if g.user and g.user.role_passwd() or g.user.role_admin()%}
<div class="form-group"> <div class="form-group">
<label for="password">Password</label> <label for="password">Password</label>
<input type="password" class="form-control" name="password" id="password" value=""> <input type="password" class="form-control" name="password" id="password" value="">
</div> </div>
{% endif %}
<div class="form-group"> <div class="form-group">
<label for="kindle_mail">Kindle E-Mail</label> <label for="kindle_mail">Kindle E-Mail</label>
<input type="text" class="form-control" name="kindle_mail" id="kindle_mail" value="{{ content.kindle_mail if content.kindle_mail != None }}"> <input type="text" class="form-control" name="kindle_mail" id="kindle_mail" value="{{ content.kindle_mail if content.kindle_mail != None }}">
</div> </div>
{% if g.user and g.user.role and not profile %} {% if g.user and g.user.role_admin() and not profile %}
<div class="form-group"> <div class="form-group">
<label for="user_role">Admin user</label> <label for="admin_role">Admin user</label>
<input type="checkbox" name="admin_user" id="admin_user" {% if content.role %}checked{% endif %}> <input type="checkbox" name="admin_role" id="admin_role" {% if content.role_admin() %}checked{% endif %}>
</div>
<div class="form-group">
<label for="download_role">Allow Downloads</label>
<input type="checkbox" name="download_role" id="download_role" {% if content.role_download() %}checked{% endif %}>
</div>
<div class="form-group">
<label for="upload_role">Allow Uploads</label>
<input type="checkbox" name="upload_role" id="upload_role" {% if content.role_upload() %}checked{% endif %}>
</div>
<div class="form-group">
<label for="edit_role">Allow Edit</label>
<input type="checkbox" name="edit_role" id="edit_role" {% if content.role_edit() %}checked{% endif %}>
</div>
<div class="form-group">
<label for="passwd_role">Allow Changing Password</label>
<input type="checkbox" name="passwd_role" id="passwd_role" {% if content.role_passwd() %}checked{% endif %}>
</div> </div>
{% endif %} {% endif %}
{% if g.user and g.user.role and not profile and not new_user %} {% if g.user and g.user.role_admin() and not profile and not new_user %}
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" name="delete"> Delete this user <input type="checkbox" name="delete"> Delete this user

View File

@ -9,6 +9,11 @@
<th>Kindle</th> <th>Kindle</th>
<th>DLS</th> <th>DLS</th>
<th>Admin</th> <th>Admin</th>
<th>Download</th>
<th>Upload</th>
<th>Edit</th>
<th>Passwd</th>
</tr> </tr>
{% for user in content %} {% for user in content %}
<tr> <tr>
@ -16,7 +21,12 @@
<td>{{user.email}}</td> <td>{{user.email}}</td>
<td>{{user.kindle_mail}}</td> <td>{{user.kindle_mail}}</td>
<td>{{user.downloads.count()}}</td> <td>{{user.downloads.count()}}</td>
<td>{% if user.role %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td> <td>{% if user.role_admin() %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
<td>{% if user.role_download() %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
<td>{% if user.role_upload() %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
<td>{% if user.role_edit() %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
<td>{% if user.role_passwd() %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
{% endfor %} {% endfor %}
</table> </table>
<div class="btn btn-default"><a href="{{url_for('new_user')}}">Add new user</a></div> <div class="btn btn-default"><a href="{{url_for('new_user')}}">Add new user</a></div>

227
cps/ub.py
View File

@ -14,157 +14,186 @@ Base = declarative_base()
ROLE_USER = 0 ROLE_USER = 0
ROLE_ADMIN = 1 ROLE_ADMIN = 1
ROLE_DOWNLOAD = 2
ROLE_UPLOAD = 4
ROLE_EDIT = 8
ROLE_PASSWD = 16
DEFAULT_PASS = "admin123" DEFAULT_PASS = "admin123"
class User(Base): class User(Base):
__tablename__ = 'user' __tablename__ = 'user'
id = Column(Integer, primary_key = True) id = Column(Integer, primary_key = True)
nickname = Column(String(64), unique = True) nickname = Column(String(64), unique = True)
email = Column(String(120), unique = True, default = "") email = Column(String(120), unique = True, default = "")
role = Column(SmallInteger, default = ROLE_USER) role = Column(SmallInteger, default = ROLE_USER)
password = Column(String) password = Column(String)
kindle_mail = Column(String(120), default="") kindle_mail = Column(String(120), default="")
shelf = relationship('Shelf', backref = 'user', lazy = 'dynamic') shelf = relationship('Shelf', backref = 'user', lazy = 'dynamic')
whislist = relationship('Whislist', backref = 'user', lazy = 'dynamic') whislist = relationship('Whislist', backref = 'user', lazy = 'dynamic')
downloads = relationship('Downloads', backref= 'user', lazy = 'dynamic') downloads = relationship('Downloads', backref= 'user', lazy = 'dynamic')
def is_authenticated(self): def is_authenticated(self):
return True return True
def role_admin(self):
if self.role is not None:
return True if self.role & ROLE_ADMIN == ROLE_ADMIN else False
else:
return False
def role_download(self):
if self.role is not None:
return True if self.role & ROLE_DOWNLOAD == ROLE_DOWNLOAD else False
else:
return False
def role_upload(self):
if self.role is not None:
return True if self.role & ROLE_UPLOAD == ROLE_UPLOAD else False
else:
return False
def role_edit(self):
if self.role is not None:
return True if self.role & ROLE_EDIT == ROLE_EDIT else False
else:
return False
def role_passwd(self):
if self.role is not None:
return True if self.role & ROLE_PASSWD == ROLE_PASSWD else False
else:
return False
def is_active(self): def is_active(self):
return True return True
def is_anonymous(self): def is_anonymous(self):
return False return False
def get_id(self): def get_id(self):
return unicode(self.id) return unicode(self.id)
def __repr__(self): def __repr__(self):
return '<User %r>' % (self.nickname) return '<User %r>' % (self.nickname)
class Shelf(Base): class Shelf(Base):
__tablename__ = 'shelf' __tablename__ = 'shelf'
id = Column(Integer, primary_key = True) id = Column(Integer, primary_key = True)
name = Column(String) name = Column(String)
is_public = Column(Integer, default=0) is_public = Column(Integer, default=0)
user_id = Column(Integer, ForeignKey('user.id')) user_id = Column(Integer, ForeignKey('user.id'))
def __repr__(self): def __repr__(self):
return '<Shelf %r>' % (self.name) return '<Shelf %r>' % (self.name)
class Whislist(Base): class Whislist(Base):
__tablename__ = "wishlist" __tablename__ = "wishlist"
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
name = Column(String) name = Column(String)
is_public = Column(String) is_public = Column(String)
user_id = Column(Integer, ForeignKey('user.id')) user_id = Column(Integer, ForeignKey('user.id'))
def __init__(self): def __init__(self):
pass pass
def __repr__(self): def __repr__(self):
return '<Whislist %r>' % (self.name) return '<Whislist %r>' % (self.name)
class BookShelf(Base): class BookShelf(Base):
__tablename__ = 'book_shelf_link' __tablename__ = 'book_shelf_link'
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
book_id = Column(Integer) book_id = Column(Integer)
shelf = Column(Integer, ForeignKey('shelf.id')) shelf = Column(Integer, ForeignKey('shelf.id'))
def __repr__(self): def __repr__(self):
return '<Book %r>' % (self.id) return '<Book %r>' % (self.id)
class Downloads(Base): class Downloads(Base):
__tablename__ = 'downloads' __tablename__ = 'downloads'
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
book_id = Column(Integer) book_id = Column(Integer)
user_id = Column(Integer, ForeignKey('user.id')) user_id = Column(Integer, ForeignKey('user.id'))
def __repr__(self): def __repr__(self):
return '<Download %r' % (self.book_id) return '<Download %r' % (self.book_id)
class Whish(Base): class Whish(Base):
__tablename__ = 'whish' __tablename__ = 'whish'
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
title = Column(String) title = Column(String)
url = Column(String) url = Column(String)
wishlist = Column(Integer, ForeignKey('wishlist.id')) wishlist = Column(Integer, ForeignKey('wishlist.id'))
def __repr__(self): def __repr__(self):
return '<Whish %r>' % (self.title) return '<Whish %r>' % (self.title)
class Settings(Base): class Settings(Base):
__tablename__ = 'settings' __tablename__ = 'settings'
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
mail_server = Column(String) mail_server = Column(String)
mail_port = Column(Integer, default = 25) mail_port = Column(Integer, default = 25)
mail_use_ssl = Column(SmallInteger, default = 0) mail_use_ssl = Column(SmallInteger, default = 0)
mail_login = Column(String) mail_login = Column(String)
mail_password = Column(String) mail_password = Column(String)
mail_from = Column(String) mail_from = Column(String)
def __repr__(self): def __repr__(self):
#return '<Smtp %r>' % (self.mail_server) #return '<Smtp %r>' % (self.mail_server)
pass pass
def create_default_config(): def create_default_config():
settings = Settings() settings = Settings()
settings.mail_server = "mail.example.com" settings.mail_server = "mail.example.com"
settings.mail_port = 25 settings.mail_port = 25
settings.mail_use_ssl = 0 settings.mail_use_ssl = 0
settings.mail_login = "mail@example.com" settings.mail_login = "mail@example.com"
settings.mail_password = "mypassword" settings.mail_password = "mypassword"
settings.mail_from = "automailer <mail@example.com>" settings.mail_from = "automailer <mail@example.com>"
session.add(settings) session.add(settings)
session.commit() session.commit()
def get_mail_settings(): def get_mail_settings():
settings = session.query(Settings).first() settings = session.query(Settings).first()
if not settings: if not settings:
return {} return {}
data = { data = {
'mail_server': settings.mail_server, 'mail_server': settings.mail_server,
'mail_port': settings.mail_port, 'mail_port': settings.mail_port,
'mail_use_ssl': settings.mail_use_ssl, 'mail_use_ssl': settings.mail_use_ssl,
'mail_login': settings.mail_login, 'mail_login': settings.mail_login,
'mail_password': settings.mail_password, 'mail_password': settings.mail_password,
'mail_from': settings.mail_from 'mail_from': settings.mail_from
} }
return data return data
def create_admin_user(): def create_admin_user():
user = User() user = User()
user.nickname = "admin" user.nickname = "admin"
user.role = 1 user.role = ROLE_USER + ROLE_ADMIN + ROLE_DOWNLOAD + ROLE_UPLOAD + ROLE_EDIT + ROLE_PASSWD
user.password = generate_password_hash(DEFAULT_PASS) user.password = generate_password_hash(DEFAULT_PASS)
session.add(user) session.add(user)
session.commit() session.commit()
Session = sessionmaker() Session = sessionmaker()
Session.configure(bind=engine) Session.configure(bind=engine)
session = Session() session = Session()
if not os.path.exists(dbpath): if not os.path.exists(dbpath):
try: try:
Base.metadata.create_all(engine) Base.metadata.create_all(engine)
create_default_config() create_default_config()
create_admin_user() create_admin_user()
except Exception: except Exception:
pass pass

View File

@ -14,7 +14,7 @@ from sqlalchemy.sql.expression import func
from sqlalchemy.sql.expression import false from sqlalchemy.sql.expression import false
from sqlalchemy.exc import IntegrityError from sqlalchemy.exc import IntegrityError
from math import ceil from math import ceil
from flask.ext.login import LoginManager, login_user, logout_user, login_required, current_user from flask.ext.login import LoginManager, login_user, logout_user, login_required, current_user, AnonymousUserMixin
from flask.ext.principal import Principal, Identity, AnonymousIdentity, identity_changed from flask.ext.principal import Principal, Identity, AnonymousIdentity, identity_changed
import requests, zipfile import requests, zipfile
from werkzeug.security import generate_password_hash, check_password_hash from werkzeug.security import generate_password_hash, check_password_hash
@ -43,9 +43,23 @@ app.logger.info('Starting Calibre Web...')
Principal(app) Principal(app)
class Anonymous(AnonymousUserMixin):
def __init__(self):
self.nickname = 'Guest'
self.role = -1
def role_admin(self):
return False
def role_download(self):
return False
def role_upload(self):
return False
def role_edit(self):
return False
lm = LoginManager(app) lm = LoginManager(app)
lm.init_app(app) lm.init_app(app)
lm.login_view = 'login' lm.login_view = 'login'
lm.anonymous_user = Anonymous
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT' app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
@ -82,12 +96,13 @@ def authenticate():
'You have to login with proper credentials', 401, 'You have to login with proper credentials', 401,
{'WWW-Authenticate': 'Basic realm="Login Required"'}) {'WWW-Authenticate': 'Basic realm="Login Required"'})
def requires_basic_auth(f): def requires_basic_auth_if_no_ano(f):
@wraps(f) @wraps(f)
def decorated(*args, **kwargs): def decorated(*args, **kwargs):
auth = request.authorization auth = request.authorization
if not auth or not check_auth(auth.username, auth.password): if config.ANO_SHOW_BOOKS != 1:
return authenticate() if not auth or not check_auth(auth.username, auth.password):
return authenticate()
return f(*args, **kwargs) return f(*args, **kwargs)
return decorated return decorated
@ -132,6 +147,11 @@ def url_for_other_page(page):
app.jinja_env.globals['url_for_other_page'] = url_for_other_page app.jinja_env.globals['url_for_other_page'] = url_for_other_page
def login_required_if_no_ano(func):
if config.ANO_SHOW_BOOKS == 1:
return func
return login_required(func)
## custom jinja filters ## custom jinja filters
@app.template_filter('shortentitle') @app.template_filter('shortentitle')
def shortentitle_filter(s): def shortentitle_filter(s):
@ -147,7 +167,29 @@ def admin_required(f):
""" """
@wraps(f) @wraps(f)
def inner(*args, **kwargs): def inner(*args, **kwargs):
if int(current_user.role) == 1: if current_user.role_admin():
return f(*args, **kwargs)
abort(403)
return inner
def download_required(f):
@wraps(f)
def inner(*args, **kwargs):
if current_user.role_download() or current_user.role_admin():
return f(*args, **kwargs)
abort(403)
return inner
def upload_required(f):
@wraps(f)
def inner(*args, **kwargs):
if current_user.role_upload() or current_user.role_admin():
return f(*args, **kwargs)
abort(403)
return inner
def edit_required(f):
@wraps(f)
def inner(*args, **kwargs):
if current_user.role_edit() or current_user.role_admin():
return f(*args, **kwargs) return f(*args, **kwargs)
abort(403) abort(403)
return inner return inner
@ -160,6 +202,7 @@ def before_request():
g.allow_upload = config.UPLOADING g.allow_upload = config.UPLOADING
@app.route("/feed") @app.route("/feed")
@requires_basic_auth_if_no_ano
def feed_index(): def feed_index():
xml = render_template('index.xml') xml = render_template('index.xml')
response= make_response(xml) response= make_response(xml)
@ -167,6 +210,7 @@ def feed_index():
return response return response
@app.route("/feed/osd") @app.route("/feed/osd")
@requires_basic_auth_if_no_ano
def feed_osd(): def feed_osd():
xml = render_template('osd.xml') xml = render_template('osd.xml')
response= make_response(xml) response= make_response(xml)
@ -174,6 +218,7 @@ def feed_osd():
return response return response
@app.route("/feed/search", methods=["GET"]) @app.route("/feed/search", methods=["GET"])
@requires_basic_auth_if_no_ano
def feed_search(): def feed_search():
term = request.args.get("query") term = request.args.get("query")
if term: if term:
@ -187,6 +232,7 @@ def feed_search():
return response return response
@app.route("/feed/new") @app.route("/feed/new")
@requires_basic_auth_if_no_ano
def feed_new(): def feed_new():
off = request.args.get("start_index") off = request.args.get("start_index")
if off: if off:
@ -201,6 +247,7 @@ def feed_new():
@app.route("/feed/discover") @app.route("/feed/discover")
@requires_basic_auth_if_no_ano
def feed_discover(): def feed_discover():
off = request.args.get("start_index") off = request.args.get("start_index")
if off: if off:
@ -214,6 +261,7 @@ def feed_discover():
return response return response
@app.route("/feed/hot") @app.route("/feed/hot")
@requires_basic_auth_if_no_ano
def feed_hot(): def feed_hot():
off = request.args.get("start_index") off = request.args.get("start_index")
if off: if off:
@ -228,7 +276,8 @@ def feed_hot():
return response return response
@app.route("/feed/download/<int:book_id>/<format>") @app.route("/feed/download/<int:book_id>/<format>")
@requires_basic_auth @requires_basic_auth_if_no_ano
@download_required
def get_opds_download_link(book_id, format): def get_opds_download_link(book_id, format):
format = format.split(".")[0] format = format.split(".")[0]
book = db.session.query(db.Books).filter(db.Books.id == book_id).first() book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
@ -244,6 +293,7 @@ def get_opds_download_link(book_id, format):
return response return response
@app.route("/get_authors_json", methods = ['GET', 'POST']) @app.route("/get_authors_json", methods = ['GET', 'POST'])
@login_required_if_no_ano
def get_authors_json(): def get_authors_json():
if request.method == "GET": if request.method == "GET":
query = request.args.get('q') query = request.args.get('q')
@ -252,6 +302,7 @@ def get_authors_json():
return json_dumps return json_dumps
@app.route("/get_tags_json", methods = ['GET', 'POST']) @app.route("/get_tags_json", methods = ['GET', 'POST'])
@login_required_if_no_ano
def get_tags_json(): def get_tags_json():
if request.method == "GET": if request.method == "GET":
query = request.args.get('q') query = request.args.get('q')
@ -260,6 +311,7 @@ def get_tags_json():
return json_dumps return json_dumps
@app.route("/get_series_json", methods = ['GET', 'POST']) @app.route("/get_series_json", methods = ['GET', 'POST'])
@login_required_if_no_ano
def get_series_json(): def get_series_json():
if request.method == "GET": if request.method == "GET":
query = request.args.get('q') query = request.args.get('q')
@ -269,6 +321,7 @@ def get_series_json():
@app.route("/", defaults={'page': 1}) @app.route("/", defaults={'page': 1})
@app.route('/page/<int:page>') @app.route('/page/<int:page>')
@login_required_if_no_ano
def index(page): def index(page):
random = db.session.query(db.Books).order_by(func.random()).limit(config.RANDOM_BOOKS) random = db.session.query(db.Books).order_by(func.random()).limit(config.RANDOM_BOOKS)
if page == 1: if page == 1:
@ -281,6 +334,7 @@ def index(page):
@app.route("/hot", defaults={'page': 1}) @app.route("/hot", defaults={'page': 1})
@app.route('/hot/page/<int:page>') @app.route('/hot/page/<int:page>')
@login_required_if_no_ano
def hot_books(page): def hot_books(page):
random = db.session.query(db.Books).filter(false()) random = db.session.query(db.Books).filter(false())
off = int(int(6) * (page - 1)) off = int(int(6) * (page - 1))
@ -298,12 +352,14 @@ def hot_books(page):
return render_template('index.html', random=random, entries=entries, title="Hot Books (most downloaded)") return render_template('index.html', random=random, entries=entries, title="Hot Books (most downloaded)")
@app.route("/stats") @app.route("/stats")
@login_required
def stats(): def stats():
counter = len(db.session.query(db.Books).all()) counter = len(db.session.query(db.Books).all())
return render_template('stats.html', counter=counter, title="Statistics") return render_template('stats.html', counter=counter, title="Statistics")
@app.route("/discover", defaults={'page': 1}) @app.route("/discover", defaults={'page': 1})
@app.route('/discover/page/<int:page>') @app.route('/discover/page/<int:page>')
@login_required_if_no_ano
def discover(page): def discover(page):
if page == 1: if page == 1:
entries = db.session.query(db.Books).order_by(func.randomblob(2)).limit(config.NEWEST_BOOKS) entries = db.session.query(db.Books).order_by(func.randomblob(2)).limit(config.NEWEST_BOOKS)
@ -314,6 +370,7 @@ def discover(page):
return render_template('discover.html', entries=entries, pagination=pagination, title="Random Books") return render_template('discover.html', entries=entries, pagination=pagination, title="Random Books")
@app.route("/book/<int:id>") @app.route("/book/<int:id>")
@login_required_if_no_ano
def show_book(id): def show_book(id):
entries = db.session.query(db.Books).filter(db.Books.id == id).first() entries = db.session.query(db.Books).filter(db.Books.id == id).first()
cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all() cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
@ -324,11 +381,13 @@ def show_book(id):
return render_template('detail.html', entry=entries, cc=cc, title=entries.title, books_shelfs=book_in_shelfs) return render_template('detail.html', entry=entries, cc=cc, title=entries.title, books_shelfs=book_in_shelfs)
@app.route("/category") @app.route("/category")
@login_required_if_no_ano
def category_list(): def category_list():
entries = db.session.query(db.Tags).order_by(db.Tags.name).all() entries = db.session.query(db.Tags).order_by(db.Tags.name).all()
return render_template('categories.html', entries=entries, title="Category list") return render_template('categories.html', entries=entries, title="Category list")
@app.route("/category/<name>") @app.route("/category/<name>")
@login_required_if_no_ano
def category(name): def category(name):
random = db.session.query(db.Books).filter(false()) random = db.session.query(db.Books).filter(false())
if name != "all": if name != "all":
@ -338,6 +397,7 @@ def category(name):
return render_template('index.html', random=random, entries=entries, title="Category: %s" % name) return render_template('index.html', random=random, entries=entries, title="Category: %s" % name)
@app.route("/series/<name>") @app.route("/series/<name>")
@login_required_if_no_ano
def series(name): def series(name):
random = db.session.query(db.Books).filter(false()) random = db.session.query(db.Books).filter(false())
entries = db.session.query(db.Books).filter(db.Books.series.any(db.Series.name.like("%" +name + "%" ))).order_by(db.Books.series_index).all() entries = db.session.query(db.Books).filter(db.Books.series.any(db.Series.name.like("%" +name + "%" ))).order_by(db.Books.series_index).all()
@ -345,12 +405,14 @@ def series(name):
@app.route("/admin/") @app.route("/admin/")
@login_required
def admin(): def admin():
#return "Admin ONLY!" #return "Admin ONLY!"
abort(403) abort(403)
@app.route("/search", methods=["GET"]) @app.route("/search", methods=["GET"])
@login_required_if_no_ano
def search(): def search():
term = request.args.get("query") term = request.args.get("query")
if term: if term:
@ -361,17 +423,20 @@ def search():
return render_template('search.html', searchterm="") return render_template('search.html', searchterm="")
@app.route("/author") @app.route("/author")
@login_required_if_no_ano
def author_list(): def author_list():
entries = db.session.query(db.Authors).order_by(db.Authors.sort).all() entries = db.session.query(db.Authors).order_by(db.Authors.sort).all()
return render_template('authors.html', entries=entries, title="Author list") return render_template('authors.html', entries=entries, title="Author list")
@app.route("/author/<name>") @app.route("/author/<name>")
@login_required_if_no_ano
def author(name): def author(name):
random = db.session.query(db.Books).filter(false()) random = db.session.query(db.Books).filter(false())
entries = db.session.query(db.Books).filter(db.Books.authors.any(db.Authors.name.like("%" + name + "%"))).all() entries = db.session.query(db.Books).filter(db.Books.authors.any(db.Authors.name.like("%" + name + "%"))).all()
return render_template('index.html', random=random, entries=entries, title="Author: %s" % name) return render_template('index.html', random=random, entries=entries, title="Author: %s" % name)
@app.route("/cover/<path:cover_path>") @app.route("/cover/<path:cover_path>")
@login_required_if_no_ano
def get_cover(cover_path): def get_cover(cover_path):
return send_from_directory(os.path.join(config.DB_ROOT, cover_path), "cover.jpg") return send_from_directory(os.path.join(config.DB_ROOT, cover_path), "cover.jpg")
@ -399,6 +464,7 @@ def read_book(book_id):
@app.route("/download/<int:book_id>/<format>") @app.route("/download/<int:book_id>/<format>")
@login_required @login_required
@download_required
def get_download_link(book_id, format): def get_download_link(book_id, format):
format = format.split(".")[0] format = format.split(".")[0]
book = db.session.query(db.Books).filter(db.Books.id == book_id).first() book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
@ -486,6 +552,7 @@ def logout():
@app.route('/send/<int:book_id>') @app.route('/send/<int:book_id>')
@login_required @login_required
@download_required
def send_to_kindle(book_id): def send_to_kindle(book_id):
settings = ub.get_mail_settings() settings = ub.get_mail_settings()
if settings.get("mail_server", "mail.example.com") == "mail.example.com": if settings.get("mail_server", "mail.example.com") == "mail.example.com":
@ -583,8 +650,9 @@ def profile():
downloads.append(db.session.query(db.Books).filter(db.Books.id == book.book_id).first()) downloads.append(db.session.query(db.Books).filter(db.Books.id == book.book_id).first())
if request.method == "POST": if request.method == "POST":
to_save = request.form.to_dict() to_save = request.form.to_dict()
if to_save["password"]: if current_user.role_passwd() or current_user.role_admin():
content.password = generate_password_hash(to_save["password"]) if to_save["password"]:
content.password = generate_password_hash(to_save["password"])
if to_save["kindle_mail"] and to_save["kindle_mail"] != content.kindle_mail: if to_save["kindle_mail"] and to_save["kindle_mail"] != content.kindle_mail:
content.kindle_mail = to_save["kindle_mail"] content.kindle_mail = to_save["kindle_mail"]
if to_save["email"] and to_save["email"] != content.email: if to_save["email"] and to_save["email"] != content.email:
@ -619,10 +687,17 @@ def new_user():
content.password = generate_password_hash(to_save["password"]) content.password = generate_password_hash(to_save["password"])
content.nickname = to_save["nickname"] content.nickname = to_save["nickname"]
content.email = to_save["email"] content.email = to_save["email"]
if "admin_user" in to_save: content.role = 0
content.role = 1 if "admin_role" in to_save:
else: content.role = content.role + ub.ROLE_ADMIN
content.role = 0 if "download_role" in to_save:
content.role = content.role + ub.ROLE_DOWNLOAD
if "upload_role" in to_save:
content.role = content.role + ub.ROLE_UPLOAD
if "edit_role" in to_save:
content.role = content.role + ub.ROLE_EDIT
if "passwd_role" in to_save:
content.role = content.role + ub.ROLE_PASSWD
try: try:
ub.session.add(content) ub.session.add(content)
ub.session.commit() ub.session.commit()
@ -673,10 +748,32 @@ def edit_user(user_id):
else: else:
if to_save["password"]: if to_save["password"]:
content.password = generate_password_hash(to_save["password"]) content.password = generate_password_hash(to_save["password"])
if "admin_user" in to_save and content.role != 1:
content.role = 1 if "admin_role" in to_save and not content.role_admin():
elif not "admin_user" in to_save and content.role == 1: content.role = content.role + ub.ROLE_ADMIN
content.role = 0 elif not "admin_role" in to_save and content.role_admin():
content.role = content.role - ub.ROLE_ADMIN
if "download_role" in to_save and not content.role_download():
content.role = content.role + ub.ROLE_DOWNLOAD
elif not "download_role" in to_save and content.role_download():
content.role = content.role - ub.ROLE_DOWNLOAD
if "upload_role" in to_save and not content.role_upload():
content.role = content.role + ub.ROLE_UPLOAD
elif not "upload_role" in to_save and content.role_upload():
content.role = content.role - ub.ROLE_UPLOAD
if "edit_role" in to_save and not content.role_edit():
content.role = content.role + ub.ROLE_EDIT
elif not "edit_role" in to_save and content.role_edit():
content.role = content.role - ub.ROLE_EDIT
if "passwd_role" in to_save and not content.role_passwd():
content.role = content.role + ub.ROLE_PASSWD
elif not "passwd_role" in to_save and content.role_passwd():
content.role = content.role - ub.ROLE_PASSWD
if to_save["email"] and to_save["email"] != content.email: if to_save["email"] and to_save["email"] != content.email:
content.email = to_save["email"] content.email = to_save["email"]
if to_save["kindle_mail"] and to_save["kindle_mail"] != content.kindle_mail: if to_save["kindle_mail"] and to_save["kindle_mail"] != content.kindle_mail:
@ -691,7 +788,7 @@ def edit_user(user_id):
@app.route("/admin/book/<int:book_id>", methods=['GET', 'POST']) @app.route("/admin/book/<int:book_id>", methods=['GET', 'POST'])
@login_required @login_required
@admin_required @edit_required
def edit_book(book_id): def edit_book(book_id):
## create the function for sorting... ## create the function for sorting...
db.session.connection().connection.connection.create_function("title_sort",1,db.title_sort) db.session.connection().connection.connection.create_function("title_sort",1,db.title_sort)
@ -933,7 +1030,7 @@ def edit_book(book_id):
@app.route("/upload", methods = ["GET", "POST"]) @app.route("/upload", methods = ["GET", "POST"])
@login_required @login_required
@admin_required @upload_required
def upload(): def upload():
if not config.UPLOADING: if not config.UPLOADING:
abort(404) abort(404)
@ -996,4 +1093,7 @@ def upload():
for author in db_book.authors: for author in db_book.authors:
author_names.append(author.name) author_names.append(author.name)
cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all() cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
return render_template('edit_book.html', book=db_book, authors=author_names, cc=cc) if current_user.role_edit() or current_user.role_admin():
return render_template('edit_book.html', book=db_book, authors=author_names, cc=cc)
book_in_shelfs = []
return render_template('detail.html', entry=db_book, cc=cc, title=db_book.title, books_shelfs=book_in_shelfs)