2015-08-02 20:59:11 +02:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import mimetypes
2016-03-28 21:07:13 +02:00
import logging
2016-04-15 18:23:00 +02:00
from logging . handlers import RotatingFileHandler
2016-04-03 23:33:29 +02:00
import textwrap
2015-08-02 20:59:11 +02:00
mimetypes . add_type ( ' application/xhtml+xml ' , ' .xhtml ' )
2015-10-13 19:06:37 +02:00
from flask import Flask , render_template , session , request , Response , redirect , url_for , send_from_directory , make_response , g , flash , abort
2016-08-07 10:32:45 +02:00
import db , config , ub , helper
2015-08-02 20:59:11 +02:00
import os
2016-06-17 20:01:27 +02:00
import errno
2015-08-02 20:59:11 +02:00
from sqlalchemy . sql . expression import func
2016-03-26 17:12:29 +02:00
from sqlalchemy . sql . expression import false
2015-10-13 18:07:17 +02:00
from sqlalchemy . exc import IntegrityError
2015-08-02 20:59:11 +02:00
from math import ceil
2016-11-09 20:24:33 +02:00
from flask_login import LoginManager , login_user , logout_user , login_required , current_user , AnonymousUserMixin
from flask_principal import Principal , Identity , AnonymousIdentity , identity_changed
from flask_babel import Babel
from flask_babel import gettext as _
2015-08-02 20:59:11 +02:00
import requests , zipfile
from werkzeug . security import generate_password_hash , check_password_hash
2016-11-09 20:24:33 +02:00
from babel import Locale as LC
from babel import negotiate_locale
2015-10-13 18:07:17 +02:00
from functools import wraps
2015-10-13 19:06:37 +02:00
import base64
2016-03-26 17:12:29 +02:00
from sqlalchemy . sql import *
2016-03-29 00:09:11 +02:00
import json
2016-07-09 10:54:13 +02:00
import urllib
2016-04-03 23:52:32 +02:00
import datetime
2016-11-09 20:24:33 +02:00
from iso639 import languages as isoLanguages
2016-04-03 23:52:32 +02:00
from uuid import uuid4
2016-07-16 10:44:47 +02:00
import os . path
import shutil
import re
2016-04-08 22:57:16 +02:00
try :
from wand . image import Image
use_generic_pdf_cover = False
except ImportError , e :
use_generic_pdf_cover = True
2015-08-02 20:59:11 +02:00
2016-04-08 22:57:16 +02:00
from shutil import copyfile
2016-07-16 10:44:47 +02:00
from cgi import escape
2015-08-02 20:59:11 +02:00
2016-07-14 02:12:21 +02:00
class ReverseProxied ( object ) :
''' Wrap the application in this middleware and configure the
front - end server to add these headers , to let you quietly bind
this to a URL other than / and to an HTTP scheme that is
different than what is used locally .
Code courtesy of : http : / / flask . pocoo . org / snippets / 35 /
In nginx :
location / myprefix {
proxy_pass http : / / 127.0 .0 .1 : 8083 ;
proxy_set_header Host $ host ;
proxy_set_header X - Forwarded - For $ proxy_add_x_forwarded_for ;
proxy_set_header X - Scheme $ scheme ;
proxy_set_header X - Script - Name / myprefix ;
}
'''
def __init__ ( self , app ) :
self . app = app
def __call__ ( self , environ , start_response ) :
script_name = environ . get ( ' HTTP_X_SCRIPT_NAME ' , ' ' )
if script_name :
environ [ ' SCRIPT_NAME ' ] = script_name
2016-07-15 01:28:12 +02:00
path_info = environ . get ( ' PATH_INFO ' , ' ' )
if path_info and path_info . startswith ( script_name ) :
2016-07-14 02:12:21 +02:00
environ [ ' PATH_INFO ' ] = path_info [ len ( script_name ) : ]
scheme = environ . get ( ' HTTP_X_SCHEME ' , ' ' )
if scheme :
environ [ ' wsgi.url_scheme ' ] = scheme
server = environ . get ( ' HTTP_X_FORWARDED_SERVER ' , ' ' )
if server :
environ [ ' HTTP_HOST ' ] = server
return self . app ( environ , start_response )
2015-08-02 20:59:11 +02:00
app = ( Flask ( __name__ ) )
2016-07-14 02:12:21 +02:00
app . wsgi_app = ReverseProxied ( app . wsgi_app )
2015-08-02 20:59:11 +02:00
2016-04-15 18:23:00 +02:00
formatter = logging . Formatter (
" [ %(asctime)s ] { %(pathname)s : %(lineno)d } %(levelname)s - %(message)s " )
file_handler = RotatingFileHandler ( os . path . join ( config . LOG_DIR , " calibre-web.log " ) , maxBytes = 10000 , backupCount = 1 )
2016-03-28 21:07:13 +02:00
file_handler . setLevel ( logging . INFO )
2016-04-15 18:23:00 +02:00
file_handler . setFormatter ( formatter )
2016-03-28 21:07:13 +02:00
app . logger . addHandler ( file_handler )
app . logger . info ( ' Starting Calibre Web... ' )
2016-06-05 18:42:18 +02:00
logging . getLogger ( " book_formats " ) . addHandler ( file_handler )
logging . getLogger ( " book_formats " ) . setLevel ( logging . INFO )
2016-03-28 21:07:13 +02:00
2015-08-02 20:59:11 +02:00
Principal ( app )
2016-11-09 20:24:33 +02:00
babel = Babel ( app )
2016-04-27 10:35:23 +02:00
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
2016-11-09 20:24:33 +02:00
def filter_language ( self ) :
return ' all '
def show_random_books ( self ) :
return True
def show_hot_books ( self ) :
return True
def show_series ( self ) :
return True
def show_category ( self ) :
return True
def show_language ( self ) :
return True
def is_anonymous ( self ) :
return config . ANON_BROWSE
2016-04-27 10:35:23 +02:00
2015-08-02 20:59:11 +02:00
lm = LoginManager ( app )
lm . init_app ( app )
lm . login_view = ' login '
2016-04-27 10:35:23 +02:00
lm . anonymous_user = Anonymous
2015-08-02 20:59:11 +02:00
app . secret_key = ' A0Zr98j/3yX R~XHH!jmN]LWX/,?RT '
2016-11-09 20:24:33 +02:00
LANGUAGES = {
' en ' : ' English ' ,
' de ' : ' Deutsch '
}
@babel.localeselector
def get_locale ( ) :
# if a user is logged in, use the locale from the user settings
user = getattr ( g , ' user ' , None )
if user is not None and hasattr ( user , " locale " ) :
return user . locale
preferred = [ x . replace ( ' - ' , ' _ ' ) for x in request . accept_languages . values ( ) ]
return negotiate_locale ( preferred , LANGUAGES . keys ( ) )
@babel.timezoneselector
def get_timezone ( ) :
user = getattr ( g , ' user ' , None )
if user is not None :
return user . timezone
2015-08-02 20:59:11 +02:00
@lm.user_loader
def load_user ( id ) :
return ub . session . query ( ub . User ) . filter ( ub . User . id == int ( id ) ) . first ( )
@lm.header_loader
def load_user_from_header ( header_val ) :
if header_val . startswith ( ' Basic ' ) :
header_val = header_val . replace ( ' Basic ' , ' ' , 1 )
try :
header_val = base64 . b64decode ( header_val )
2015-10-13 19:06:37 +02:00
basic_username = header_val . split ( ' : ' ) [ 0 ]
basic_password = header_val . split ( ' : ' ) [ 1 ]
2015-08-02 20:59:11 +02:00
except TypeError :
pass
2015-10-13 19:06:37 +02:00
user = ub . session . query ( ub . User ) . filter ( ub . User . nickname == basic_username ) . first ( )
if user and check_password_hash ( user . password , basic_password ) :
return user
return
def check_auth ( username , password ) :
user = ub . session . query ( ub . User ) . filter ( ub . User . nickname == username ) . first ( )
if user and check_password_hash ( user . password , password ) :
return True
else :
return False
def authenticate ( ) :
return Response (
' Could not verify your access level for that URL. \n '
' You have to login with proper credentials ' , 401 ,
{ ' WWW-Authenticate ' : ' Basic realm= " Login Required " ' } )
2016-04-27 18:29:45 +02:00
def requires_basic_auth_if_no_ano ( f ) :
2015-10-13 19:06:37 +02:00
@wraps ( f )
def decorated ( * args , * * kwargs ) :
auth = request . authorization
2016-04-29 22:30:33 +02:00
if config . ANON_BROWSE != 1 :
2016-04-27 18:29:45 +02:00
if not auth or not check_auth ( auth . username , auth . password ) :
return authenticate ( )
2015-10-13 19:06:37 +02:00
return f ( * args , * * kwargs )
return decorated
2015-08-02 20:59:11 +02:00
#simple pagination for the feed
class Pagination ( object ) :
def __init__ ( self , page , per_page , total_count ) :
self . page = page
self . per_page = per_page
self . total_count = total_count
@property
def pages ( self ) :
return int ( ceil ( self . total_count / float ( self . per_page ) ) )
@property
def has_prev ( self ) :
return self . page > 1
@property
def has_next ( self ) :
return self . page < self . pages
def iter_pages ( self , left_edge = 2 , left_current = 2 ,
right_current = 5 , right_edge = 2 ) :
last = 0
for num in xrange ( 1 , self . pages + 1 ) :
if num < = left_edge or \
( num > self . page - left_current - 1 and \
num < self . page + right_current ) or \
num > self . pages - right_edge :
if last + 1 != num :
yield None
yield num
last = num
##pagination links in jinja
def url_for_other_page ( page ) :
args = request . view_args . copy ( )
args [ ' page ' ] = page
return url_for ( request . endpoint , * * args )
app . jinja_env . globals [ ' url_for_other_page ' ] = url_for_other_page
2016-04-27 10:35:23 +02:00
def login_required_if_no_ano ( func ) :
2016-04-29 22:30:33 +02:00
if config . ANON_BROWSE == 1 :
2016-04-27 10:35:23 +02:00
return func
return login_required ( func )
2016-04-03 23:33:29 +02:00
## custom jinja filters
@app.template_filter ( ' shortentitle ' )
def shortentitle_filter ( s ) :
if len ( s ) > 60 :
s = s . split ( ' : ' , 1 ) [ 0 ]
if len ( s ) > 60 :
s = textwrap . wrap ( s , 60 , break_long_words = False ) [ 0 ] + ' [...] '
return s
2015-10-13 19:06:37 +02:00
2015-10-13 18:07:17 +02:00
def admin_required ( f ) :
"""
Checks if current_user . role == 1
"""
@wraps ( f )
def inner ( * args , * * kwargs ) :
2016-04-27 10:35:23 +02:00
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 ( ) :
2015-10-13 18:07:17 +02:00
return f ( * args , * * kwargs )
abort ( 403 )
return inner
2016-11-09 20:24:33 +02:00
# Fill indexpage with all requested data from database
def fill_indexpage ( page , database , db_filter , order ) :
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
else :
filter = True
if current_user . show_random_books ( ) :
random = db . session . query ( db . Books ) . filter ( filter ) . order_by ( func . random ( ) ) . limit ( config . RANDOM_BOOKS )
else :
random = false
off = int ( int ( config . NEWEST_BOOKS ) * ( page - 1 ) )
pagination = Pagination ( page , config . NEWEST_BOOKS , len ( db . session . query ( database ) . filter ( db_filter ) . filter ( filter ) . all ( ) ) )
entries = db . session . query ( database ) . filter ( db_filter ) . filter ( filter ) . order_by ( order ) . offset ( off ) . limit ( config . NEWEST_BOOKS )
return entries , random , pagination
def modify_database_object ( input_elements , db_book_object , db_object , db_session , type ) :
input_elements = [ x for x in input_elements if x != ' ' ]
# we have all input element (authors, series, tags) names now
# 1. search for elements to remove
del_elements = [ ]
for c_elements in db_book_object :
found = False
for inp_element in input_elements :
if inp_element == c_elements . name :
found = True
break ;
# if the element was not found in the new list, add it to remove list
if not found :
del_elements . append ( c_elements )
# 2. search for elements that need to be added
add_elements = [ ]
for inp_element in input_elements :
found = False
for c_elements in db_book_object :
if inp_element == c_elements . name :
found = True
break ;
if not found :
add_elements . append ( inp_element )
# if there are elements to remove, we remove them now
if len ( del_elements ) > 0 :
for del_element in del_elements :
db_book_object . remove ( del_element )
if len ( del_element . books ) == 0 :
db_session . delete ( del_element )
# if there are elements to add, we add them now!
if len ( add_elements ) > 0 :
if type == ' languages ' :
db_filter = db_object . lang_code
else :
db_filter = db_object . name
for add_element in add_elements :
# check if a element with that name exists
new_element = db_session . query ( db_object ) . filter ( db_filter == add_element ) . first ( )
# if no element is found add it
if new_element == None :
if type == ' author ' :
new_element = db_object ( add_element , add_element , " " )
else :
if type == ' series ' :
new_element = db_object ( add_element , add_element )
else : # type should be tag, or languages
new_element = db_object ( add_element )
db_session . add ( new_element )
new_element = db . session . query ( db_object ) . filter ( db_filter == add_element ) . first ( )
# add element to book
db_book_object . append ( new_element )
2015-08-02 20:59:11 +02:00
@app.before_request
def before_request ( ) :
g . user = current_user
g . public_shelfes = ub . session . query ( ub . Shelf ) . filter ( ub . Shelf . is_public == 1 ) . all ( )
2015-10-13 02:30:55 +02:00
g . allow_registration = config . PUBLIC_REG
2016-04-15 19:39:25 +02:00
g . allow_upload = config . UPLOADING
2015-08-02 20:59:11 +02:00
@app.route ( " /feed " )
2016-04-27 18:29:45 +02:00
@requires_basic_auth_if_no_ano
2015-08-02 20:59:11 +02:00
def feed_index ( ) :
2016-11-09 20:24:33 +02:00
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
else :
filter = True
2015-08-02 20:59:11 +02:00
xml = render_template ( ' index.xml ' )
response = make_response ( xml )
response . headers [ " Content-Type " ] = " application/xml "
return response
@app.route ( " /feed/osd " )
2016-04-27 18:29:45 +02:00
@requires_basic_auth_if_no_ano
2015-08-02 20:59:11 +02:00
def feed_osd ( ) :
xml = render_template ( ' osd.xml ' )
response = make_response ( xml )
response . headers [ " Content-Type " ] = " application/xml "
return response
@app.route ( " /feed/search " , methods = [ " GET " ] )
2016-04-27 18:29:45 +02:00
@requires_basic_auth_if_no_ano
2015-08-02 20:59:11 +02:00
def feed_search ( ) :
2016-08-27 10:32:53 +02:00
term = request . args . get ( " query " ) . strip ( )
2016-11-09 20:24:33 +02:00
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
else :
filter = True
2015-08-02 20:59:11 +02:00
if term :
2016-11-09 20:24:33 +02:00
entries = db . session . query ( db . Books ) . filter ( db . or_ ( db . Books . tags . any ( db . Tags . name . like ( " % " + term + " % " ) ) , db . Books . authors . any ( db . Authors . name . like ( " % " + term + " % " ) ) , db . Books . title . like ( " % " + term + " % " ) ) ) . filter ( filter ) . all ( )
xml = render_template ( ' feed.xml ' , searchterm = term , entries = entries , Last_Updated = Last_Updated )
2015-08-02 20:59:11 +02:00
else :
xml = render_template ( ' feed.xml ' , searchterm = " " )
response = make_response ( xml )
response . headers [ " Content-Type " ] = " application/xml "
return response
@app.route ( " /feed/new " )
2016-04-27 18:29:45 +02:00
@requires_basic_auth_if_no_ano
2015-08-02 20:59:11 +02:00
def feed_new ( ) :
off = request . args . get ( " start_index " )
2016-11-09 20:24:33 +02:00
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
2015-08-02 20:59:11 +02:00
else :
2016-11-09 20:24:33 +02:00
filter = True
if not off :
off = 0
entries = db . session . query ( db . Books ) . filter ( filter ) . order_by ( db . Books . last_modified . desc ( ) ) . offset ( off ) . limit ( config . NEWEST_BOOKS )
2015-08-02 20:59:11 +02:00
xml = render_template ( ' feed.xml ' , entries = entries , next_url = " /feed/new?start_index= %d " % ( int ( config . NEWEST_BOOKS ) + int ( off ) ) )
response = make_response ( xml )
response . headers [ " Content-Type " ] = " application/xml "
return response
@app.route ( " /feed/discover " )
2016-04-27 18:29:45 +02:00
@requires_basic_auth_if_no_ano
2015-08-02 20:59:11 +02:00
def feed_discover ( ) :
off = request . args . get ( " start_index " )
2016-11-09 20:24:33 +02:00
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
2015-08-02 20:59:11 +02:00
else :
2016-11-09 20:24:33 +02:00
filter = True
if not off :
off = 0
entries = db . session . query ( db . Books ) . filter ( filter ) . order_by ( func . random ( ) ) . offset ( off ) . limit ( config . NEWEST_BOOKS )
2015-08-02 20:59:11 +02:00
xml = render_template ( ' feed.xml ' , entries = entries , next_url = " /feed/discover?start_index= %d " % ( int ( config . NEWEST_BOOKS ) + int ( off ) ) )
2016-03-26 17:12:29 +02:00
response = make_response ( xml )
2015-08-02 20:59:11 +02:00
response . headers [ " Content-Type " ] = " application/xml "
return response
@app.route ( " /feed/hot " )
2016-04-27 18:29:45 +02:00
@requires_basic_auth_if_no_ano
2015-08-02 20:59:11 +02:00
def feed_hot ( ) :
off = request . args . get ( " start_index " )
2016-11-09 20:24:33 +02:00
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
2015-08-02 20:59:11 +02:00
else :
2016-11-09 20:24:33 +02:00
filter = True
if not off :
off = 0
entries = db . session . query ( db . Books ) . filter ( filter ) . filter ( db . Books . ratings . any ( db . Ratings . rating > 9 ) ) . offset ( off ) . limit ( config . NEWEST_BOOKS )
2015-08-02 20:59:11 +02:00
xml = render_template ( ' feed.xml ' , entries = entries , next_url = " /feed/hot?start_index= %d " % ( int ( config . NEWEST_BOOKS ) + int ( off ) ) )
response = make_response ( xml )
response . headers [ " Content-Type " ] = " application/xml "
return response
2016-11-09 20:24:33 +02:00
@app.route ( " /feed/author " )
@requires_basic_auth_if_no_ano
def feed_authorindex ( ) :
off = request . args . get ( " start_index " )
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
else :
filter = True
if not off :
off = 0
authors = db . session . query ( db . Authors ) . order_by ( db . Authors . sort ) . offset ( off ) . limit ( config . NEWEST_BOOKS )
xml = render_template ( ' feed.xml ' , authors = authors , next_url = " /feed/author?start_index= %d " % ( int ( config . NEWEST_BOOKS ) + int ( off ) ) )
response = make_response ( xml )
response . headers [ " Content-Type " ] = " application/xml "
return response
@app.route ( " /feed/author/<name> " )
@requires_basic_auth_if_no_ano
def feed_author ( name ) :
off = request . args . get ( " start_index " )
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
else :
filter = True
if not off :
off = 0
entries = db . session . query ( db . Books ) . filter ( db . Books . authors . any ( db . Authors . name . like ( " % " + name + " % " ) ) ) . filter (
filter ) . offset ( off ) . limit ( config . NEWEST_BOOKS )
xml = render_template ( ' feed.xml ' , entries = entries , next_url = " /feed/author?start_index= %d " % ( int ( config . NEWEST_BOOKS ) + int ( off ) ) )
response = make_response ( xml )
response . headers [ " Content-Type " ] = " application/xml "
return response
@app.route ( " /feed/category " )
@requires_basic_auth_if_no_ano
def feed_categoryindex ( ) :
off = request . args . get ( " start_index " )
if not off :
off = 0
entries = db . session . query ( db . Tags ) . order_by ( db . Tags . name ) . offset ( off ) . limit ( config . NEWEST_BOOKS )
xml = render_template ( ' feed.xml ' , categorys = entries , next_url = " /feed/category?start_index= %d " % ( int ( config . NEWEST_BOOKS ) + int ( off ) ) )
response = make_response ( xml )
response . headers [ " Content-Type " ] = " application/xml "
return response
@app.route ( " /feed/category/<name> " )
@requires_basic_auth_if_no_ano
def feed_category ( name ) :
off = request . args . get ( " start_index " )
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
else :
filter = True
if not off :
off = 0
entries = db . session . query ( db . Books ) . filter ( db . Books . tags . any ( db . Tags . name . like ( " % " + name + " % " ) ) ) . order_by (
db . Books . last_modified . desc ( ) ) . filter ( filter ) . offset ( off ) . limit ( config . NEWEST_BOOKS )
xml = render_template ( ' feed.xml ' , entries = entries , next_url = " /feed/category?start_index= %d " % ( int ( config . NEWEST_BOOKS ) + int ( off ) ) )
response = make_response ( xml )
response . headers [ " Content-Type " ] = " application/xml "
return response
@app.route ( " /feed/series " )
@requires_basic_auth_if_no_ano
def feed_seriesindex ( ) :
off = request . args . get ( " start_index " )
if not off :
off = 0
entries = db . session . query ( db . Series ) . order_by ( db . Series . name ) . offset ( off ) . limit ( config . NEWEST_BOOKS )
xml = render_template ( ' feed.xml ' , series = entries , next_url = " /feed/series?start_index= %d " % ( int ( config . NEWEST_BOOKS ) + int ( off ) ) )
response = make_response ( xml )
response . headers [ " Content-Type " ] = " application/xml "
return response
@app.route ( " /feed/series/<name> " )
@requires_basic_auth_if_no_ano
def feed_series ( name ) :
off = request . args . get ( " start_index " )
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
else :
filter = True
if not off :
off = 0
entries = db . session . query ( db . Books ) . filter ( db . Books . series . any ( db . Series . name . like ( " % " + name + " % " ) ) ) . order_by (
db . Books . last_modified . desc ( ) ) . filter ( filter ) . offset ( off ) . limit ( config . NEWEST_BOOKS )
xml = render_template ( ' feed.xml ' , entries = entries , next_url = " /feed/series?start_index= %d " % ( int ( config . NEWEST_BOOKS ) + int ( off ) ) )
response = make_response ( xml )
response . headers [ " Content-Type " ] = " application/xml "
return response
2015-10-13 19:06:37 +02:00
@app.route ( " /feed/download/<int:book_id>/<format> " )
2016-04-27 18:29:45 +02:00
@requires_basic_auth_if_no_ano
2016-04-27 10:35:23 +02:00
@download_required
2015-10-13 19:06:37 +02:00
def get_opds_download_link ( book_id , format ) :
format = format . split ( " . " ) [ 0 ]
book = db . session . query ( db . Books ) . filter ( db . Books . id == book_id ) . first ( )
data = db . session . query ( db . Data ) . filter ( db . Data . book == book . id ) . filter ( db . Data . format == format . upper ( ) ) . first ( )
helper . update_download ( book_id , int ( current_user . id ) )
2016-03-26 17:12:29 +02:00
author = helper . get_normalized_author ( book . author_sort )
file_name = book . title
if len ( author ) > 0 :
file_name = author + ' - ' + file_name
file_name = helper . get_valid_filename ( file_name )
2015-10-13 19:06:37 +02:00
response = make_response ( send_from_directory ( os . path . join ( config . DB_ROOT , book . path ) , data . name + " . " + format ) )
2016-03-28 21:07:13 +02:00
response . headers [ " Content-Disposition " ] = " attachment; filename= %s . %s " % ( data . name , format )
2015-10-13 19:06:37 +02:00
return response
2016-03-29 00:09:11 +02:00
@app.route ( " /get_authors_json " , methods = [ ' GET ' , ' POST ' ] )
2016-04-27 10:35:23 +02:00
@login_required_if_no_ano
2016-04-03 23:52:32 +02:00
def get_authors_json ( ) :
2016-04-15 23:35:18 +02:00
if request . method == " GET " :
query = request . args . get ( ' q ' )
entries = db . session . execute ( " select name from authors where name like ' % " + query + " % ' " )
json_dumps = json . dumps ( [ dict ( r ) for r in entries ] )
return json_dumps
@app.route ( " /get_tags_json " , methods = [ ' GET ' , ' POST ' ] )
2016-04-27 10:35:23 +02:00
@login_required_if_no_ano
2016-04-15 23:35:18 +02:00
def get_tags_json ( ) :
if request . method == " GET " :
query = request . args . get ( ' q ' )
entries = db . session . execute ( " select name from tags where name like ' % " + query + " % ' " )
json_dumps = json . dumps ( [ dict ( r ) for r in entries ] )
return json_dumps
2016-11-09 20:24:33 +02:00
@app.route ( " /get_languages_json " , methods = [ ' GET ' , ' POST ' ] )
@login_required_if_no_ano
def get_languages_json ( ) :
if request . method == " GET " :
query = request . args . get ( ' q ' ) . lower ( )
# entries = db.session.execute("select lang_code from languages where lang_code like '%" + query + "%'")
languages = db . session . query ( db . Languages ) . all ( )
for lang in languages :
try :
cur_l = LC . parse ( lang . lang_code )
lang . name = cur_l . get_language_name ( get_locale ( ) )
except :
lang . name = _ ( isoLanguages . get ( part3 = lang . lang_code ) . name )
entries = [ s for s in languages if query in s . name . lower ( ) ]
json_dumps = json . dumps ( [ dict ( name = r . name ) for r in entries ] )
return json_dumps
2016-04-15 23:35:18 +02:00
@app.route ( " /get_series_json " , methods = [ ' GET ' , ' POST ' ] )
2016-04-27 10:35:23 +02:00
@login_required_if_no_ano
2016-04-15 23:35:18 +02:00
def get_series_json ( ) :
if request . method == " GET " :
query = request . args . get ( ' q ' )
entries = db . session . execute ( " select name from series where name like ' % " + query + " % ' " )
json_dumps = json . dumps ( [ dict ( r ) for r in entries ] )
return json_dumps
2016-05-02 22:43:50 +02:00
@app.route ( " /get_matching_tags " , methods = [ ' GET ' , ' POST ' ] )
@login_required_if_no_ano
def get_matching_tags ( ) :
tag_dict = { ' tags ' : [ ] }
if request . method == " GET " :
q = db . session . query ( db . Books )
author_input = request . args . get ( ' author_name ' )
title_input = request . args . get ( ' book_title ' )
2016-05-03 14:27:38 +02:00
include_tag_inputs = request . args . getlist ( ' include_tag ' )
exclude_tag_inputs = request . args . getlist ( ' exclude_tag ' )
2016-05-02 22:43:50 +02:00
q = q . filter ( db . Books . authors . any ( db . Authors . name . like ( " % " + author_input + " % " ) ) , db . Books . title . like ( " % " + title_input + " % " ) )
2016-05-03 14:27:38 +02:00
if len ( include_tag_inputs ) > 0 :
for tag in include_tag_inputs :
2016-05-02 22:43:50 +02:00
q = q . filter ( db . Books . tags . any ( db . Tags . id == tag ) )
2016-05-03 14:27:38 +02:00
if len ( exclude_tag_inputs ) > 0 :
for tag in exclude_tag_inputs :
q = q . filter ( not_ ( db . Books . tags . any ( db . Tags . id == tag ) ) )
2016-05-02 22:43:50 +02:00
for book in q :
for tag in book . tags :
if tag . id not in tag_dict [ ' tags ' ] :
tag_dict [ ' tags ' ] . append ( tag . id )
json_dumps = json . dumps ( tag_dict )
return json_dumps
2015-10-13 19:06:37 +02:00
2015-08-02 20:59:11 +02:00
@app.route ( " / " , defaults = { ' page ' : 1 } )
@app.route ( ' /page/<int:page> ' )
2016-04-27 10:35:23 +02:00
@login_required_if_no_ano
2015-08-02 20:59:11 +02:00
def index ( page ) :
2016-11-09 20:24:33 +02:00
entries , random , pagination = fill_indexpage ( page , db . Books , True , db . Books . last_modified . desc ( ) )
return render_template ( ' index.html ' , random = random , entries = entries , pagination = pagination , title = _ ( u " Latest Books " ) )
2015-08-02 20:59:11 +02:00
@app.route ( " /hot " , defaults = { ' page ' : 1 } )
@app.route ( ' /hot/page/<int:page> ' )
2016-04-27 10:35:23 +02:00
@login_required_if_no_ano
2015-08-02 20:59:11 +02:00
def hot_books ( page ) :
2016-11-09 20:24:33 +02:00
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
else :
filter = True
if current_user . show_random_books ( ) :
random = db . session . query ( db . Books ) . filter ( filter ) . order_by ( func . random ( ) ) . limit ( config . RANDOM_BOOKS )
else :
random = false
off = int ( int ( config . NEWEST_BOOKS ) * ( page - 1 ) )
2015-08-02 20:59:11 +02:00
all_books = ub . session . query ( ub . Downloads , ub . func . count ( ub . Downloads . book_id ) ) . order_by ( ub . func . count ( ub . Downloads . book_id ) . desc ( ) ) . group_by ( ub . Downloads . book_id )
hot_books = all_books . offset ( off ) . limit ( config . NEWEST_BOOKS )
entries = list ( )
for book in hot_books :
2016-11-09 20:24:33 +02:00
entries . append ( db . session . query ( db . Books ) . filter ( filter ) . filter ( db . Books . id == book . Downloads . book_id ) . first ( ) )
numBooks = entries . __len__ ( )
pagination = Pagination ( page , config . NEWEST_BOOKS , numBooks )
return render_template ( ' index.html ' , random = random , entries = entries , pagination = pagination , title = _ ( u " Hot Books (most downloaded) " ) )
2015-08-02 20:59:11 +02:00
@app.route ( " /discover " , defaults = { ' page ' : 1 } )
@app.route ( ' /discover/page/<int:page> ' )
2016-04-27 10:35:23 +02:00
@login_required_if_no_ano
2015-08-02 20:59:11 +02:00
def discover ( page ) :
2016-11-09 20:24:33 +02:00
entries , random , pagination = fill_indexpage ( page , db . Books , func . randomblob ( 2 ) , db . Books . last_modified . desc ( ) )
return render_template ( ' discover.html ' , entries = entries , pagination = pagination , title = _ ( u " Random Books " ) )
@app.route ( " /author " )
@login_required_if_no_ano
def author_list ( ) :
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
2015-08-02 20:59:11 +02:00
else :
2016-11-09 20:24:33 +02:00
filter = True
entries = db . session . query ( db . Authors , func . count ( ' books_authors_link.book ' ) . label ( ' count ' ) ) . join ( db . books_authors_link ) . join ( db . Books ) . filter (
filter ) . group_by ( ' books_authors_link.author ' ) . order_by ( db . Authors . sort ) . all ( )
return render_template ( ' list.html ' , entries = entries , folder = ' author ' , title = _ ( u " Author list " ) )
2015-08-02 20:59:11 +02:00
2016-11-09 20:24:33 +02:00
@app.route ( " /author/<name> " )
2016-04-27 10:35:23 +02:00
@login_required_if_no_ano
2016-11-09 20:24:33 +02:00
def author ( name ) :
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
else :
filter = True
if current_user . show_random_books ( ) :
random = db . session . query ( db . Books ) . filter ( filter ) . order_by ( func . random ( ) ) . limit ( config . RANDOM_BOOKS )
else :
random = false
2015-08-02 20:59:11 +02:00
2016-11-09 20:24:33 +02:00
entries = db . session . query ( db . Books ) . filter ( db . Books . authors . any ( db . Authors . name . like ( " % " + name + " % " ) ) ) . filter ( filter ) . all ( )
return render_template ( ' index.html ' , random = random , entries = entries , title = _ ( u " Author: %(nam)s " , nam = name ) )
@app.route ( " /series " )
2016-04-27 10:35:23 +02:00
@login_required_if_no_ano
2016-11-09 20:24:33 +02:00
def series_list ( ) :
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
else :
filter = True
entries = db . session . query ( db . Series , func . count ( ' books_series_link.book ' ) . label ( ' count ' ) ) . join ( db . books_series_link ) . join ( db . Books ) . filter (
filter ) . group_by ( ' books_series_link.series ' ) . order_by ( db . Series . sort ) . all ( )
return render_template ( ' list.html ' , entries = entries , folder = ' series ' , title = _ ( u " Series list " ) )
2015-08-02 20:59:11 +02:00
2016-11-09 20:24:33 +02:00
@app.route ( " /series/<name>/ " , defaults = { ' page ' : 1 } )
@app.route ( " /series/<name>/<int:page> ' " )
2016-04-27 10:35:23 +02:00
@login_required_if_no_ano
2016-11-09 20:24:33 +02:00
def series ( name , page ) :
entries , random , pagination = fill_indexpage ( page , db . Books , db . Books . series . any ( db . Series . name == name ) , db . Books . series_index )
if entries :
return render_template ( ' index.html ' , random = random , pagination = pagination , entries = entries , title = _ ( u " Series: %(serie)s " , serie = name ) )
else :
flash ( _ ( u " Error opening eBook. File does not exist or file is not accessible: " ) , category = " error " )
return redirect ( ' / ' or url_for ( " index " , _external = True ) )
@app.route ( " /language " )
@login_required_if_no_ano
def language_overview ( ) :
if current_user . filter_language ( ) == u " all " :
languages = db . session . query ( db . Languages ) . all ( )
for lang in languages :
try :
cur_l = LC . parse ( lang . lang_code )
lang . name = cur_l . get_language_name ( get_locale ( ) )
except :
lang . name = _ ( isoLanguages . get ( part3 = lang . lang_code ) . name )
else :
try :
langfound = 1
cur_l = LC . parse ( current_user . filter_language ( ) )
except :
langfound = 0
languages = db . session . query ( db . Languages ) . filter ( db . Languages . lang_code == current_user . filter_language ( ) ) . all ( )
if langfound :
languages [ 0 ] . name = cur_l . get_language_name ( get_locale ( ) )
else :
languages [ 0 ] . name = _ ( isoLanguages . get ( part3 = languages [ 0 ] . lang_code ) . name )
lang_counter = db . session . query ( db . books_languages_link , func . count ( ' books_languages_link.book ' ) . label ( ' bookcount ' ) ) . group_by ( ' books_languages_link.lang_code ' ) . all ( )
return render_template ( ' languages.html ' , languages = languages , lang_counter = lang_counter , title = _ ( u " Available languages " ) )
@app.route ( " /language/<name> " , defaults = { ' page ' : 1 } )
@app.route ( ' /language/<name>/page/<int:page> ' )
@login_required_if_no_ano
def language ( name , page ) :
entries , random , pagination = fill_indexpage ( page , db . Books , db . Books . languages . any ( db . Languages . lang_code == name ) , db . Books . last_modified . desc ( ) )
try :
cur_l = LC . parse ( name )
name = cur_l . get_language_name ( get_locale ( ) )
except :
name = _ ( isoLanguages . get ( part3 = name ) . name )
return render_template ( ' index.html ' , random = random , entries = entries , pagination = pagination , title = _ ( u " Language: %(name)s " , name = name ) )
@app.route ( " /category " )
@login_required_if_no_ano
def category_list ( ) :
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
2015-08-02 20:59:11 +02:00
else :
2016-11-09 20:24:33 +02:00
filter = True
entries = db . session . query ( db . Tags , func . count ( ' books_tags_link.book ' ) . label ( ' count ' ) ) . join ( db . books_tags_link ) . join ( db . Books ) . filter (
filter ) . group_by ( ' books_tags_link.tag ' ) . all ( )
return render_template ( ' list.html ' , entries = entries , folder = ' category ' , title = _ ( u " Category list " ) )
2015-08-02 20:59:11 +02:00
2016-11-09 20:24:33 +02:00
@app.route ( " /category/<name> " , defaults = { ' page ' : 1 } )
@app.route ( ' /category/<name>/<int:page> ' )
2016-04-27 10:35:23 +02:00
@login_required_if_no_ano
2016-11-09 20:24:33 +02:00
def category ( name , page ) :
entries , random , pagination = fill_indexpage ( page , db . Books , db . Books . tags . any ( db . Tags . name == name ) , db . Books . last_modified . desc ( ) )
return render_template ( ' index.html ' , random = random , entries = entries , pagination = pagination , title = _ ( u " Category: %(name)s " , name = name ) )
2015-08-02 20:59:11 +02:00
2016-11-09 20:24:33 +02:00
@app.route ( " /book/<int:id> " )
@login_required_if_no_ano
def show_book ( id ) :
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
else :
filter = True
entries = db . session . query ( db . Books ) . filter ( db . Books . id == id ) . filter ( filter ) . first ( )
if entries :
for index in range ( 0 , len ( entries . languages ) ) :
try :
entries . languages [ index ] . language_name = LC . parse ( entries . languages [ index ] . lang_code ) . get_language_name ( get_locale ( ) )
except :
entries . languages [ index ] . language_name = _ ( isoLanguages . get ( part3 = entries . languages [ index ] . lang_code ) . name )
cc = db . session . query ( db . Custom_Columns ) . filter ( db . Custom_Columns . datatype . notin_ ( db . cc_exceptions ) ) . all ( )
book_in_shelfs = [ ]
shelfs = ub . session . query ( ub . BookShelf ) . filter ( ub . BookShelf . book_id == id ) . all ( )
for entry in shelfs :
book_in_shelfs . append ( entry . shelf )
return render_template ( ' detail.html ' , entry = entries , cc = cc , title = entries . title , books_shelfs = book_in_shelfs )
else :
flash ( _ ( u " Error opening eBook. File does not exist or file is not accessible: " ) , category = " error " )
return redirect ( ' / ' or url_for ( " index " , _external = True ) )
2015-08-02 20:59:11 +02:00
@app.route ( " /admin/ " )
2016-04-27 10:35:23 +02:00
@login_required
2015-08-02 20:59:11 +02:00
def admin ( ) :
2015-10-13 18:07:17 +02:00
#return "Admin ONLY!"
abort ( 403 )
2015-08-02 20:59:11 +02:00
2016-11-09 20:24:33 +02:00
@app.route ( " /stats " )
@login_required
def stats ( ) :
counter = len ( db . session . query ( db . Books ) . all ( ) )
authors = len ( db . session . query ( db . Authors ) . all ( ) )
return render_template ( ' stats.html ' , bookcounter = counter , authorcounter = authors , title = _ ( u " Statistics " ) )
2015-08-02 20:59:11 +02:00
@app.route ( " /search " , methods = [ " GET " ] )
2016-04-27 10:35:23 +02:00
@login_required_if_no_ano
2015-08-02 20:59:11 +02:00
def search ( ) :
2016-11-09 20:24:33 +02:00
term = request . args . get ( " query " ) . strip ( )
2015-08-02 20:59:11 +02:00
if term :
2016-11-09 20:24:33 +02:00
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
else :
filter = True
entries = db . session . query ( db . Books ) . filter ( db . or_ ( db . Books . tags . any ( db . Tags . name . like ( " % " + term + " % " ) ) , db . Books . series . any ( db . Series . name . like ( " % " + term + " % " ) ) , db . Books . authors . any ( db . Authors . name . like ( " % " + term + " % " ) ) , db . Books . title . like ( " % " + term + " % " ) ) ) . filter ( filter ) . all ( )
2015-08-02 20:59:11 +02:00
return render_template ( ' search.html ' , searchterm = term , entries = entries )
else :
return render_template ( ' search.html ' , searchterm = " " )
2016-11-09 20:24:33 +02:00
2016-05-02 22:43:50 +02:00
@app.route ( " /advanced_search " , methods = [ " GET " ] )
@login_required_if_no_ano
def advanced_search ( ) :
if request . method == ' GET ' :
q = db . session . query ( db . Books )
2016-05-03 14:27:38 +02:00
include_tag_inputs = request . args . getlist ( ' include_tag ' )
exclude_tag_inputs = request . args . getlist ( ' exclude_tag ' )
2016-10-03 12:08:34 +02:00
author_name = request . args . get ( " author_name " )
book_title = request . args . get ( " book_title " )
if author_name : author_name = author_name . strip ( )
if book_title : book_title = book_title . strip ( )
2016-05-03 14:27:38 +02:00
if include_tag_inputs or exclude_tag_inputs or author_name or book_title :
2016-05-03 11:00:45 +02:00
searchterm = [ ]
searchterm . extend ( ( author_name , book_title ) )
2016-05-03 14:27:38 +02:00
tag_names = db . session . query ( db . Tags ) . filter ( db . Tags . id . in_ ( include_tag_inputs ) ) . all ( )
2016-05-03 11:00:45 +02:00
searchterm . extend ( tag . name for tag in tag_names )
searchterm = " + " . join ( filter ( None , searchterm ) )
2016-05-02 22:43:50 +02:00
q = q . filter ( db . Books . authors . any ( db . Authors . name . like ( " % " + author_name + " % " ) ) , db . Books . title . like ( " % " + book_title + " % " ) )
2016-11-09 20:24:33 +02:00
# random = db.session.query(db.Books).order_by(func.random()).limit(config.RANDOM_BOOKS)
2016-05-03 14:27:38 +02:00
for tag in include_tag_inputs :
2016-05-02 22:43:50 +02:00
q = q . filter ( db . Books . tags . any ( db . Tags . id == tag ) )
2016-05-03 14:27:38 +02:00
for tag in exclude_tag_inputs :
q = q . filter ( not_ ( db . Books . tags . any ( db . Tags . id == tag ) ) )
2016-11-09 20:24:33 +02:00
if current_user . filter_language ( ) != " all " :
q = q . filter ( db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) ) )
2016-05-02 22:43:50 +02:00
q = q . all ( )
2016-05-03 11:00:45 +02:00
return render_template ( ' search.html ' , searchterm = searchterm , entries = q )
2016-05-02 22:43:50 +02:00
tags = db . session . query ( db . Tags ) . order_by ( db . Tags . name ) . all ( )
return render_template ( ' search_form.html ' , tags = tags )
2015-08-02 20:59:11 +02:00
@app.route ( " /cover/<path:cover_path> " )
2016-04-27 10:35:23 +02:00
@login_required_if_no_ano
2015-08-02 20:59:11 +02:00
def get_cover ( cover_path ) :
return send_from_directory ( os . path . join ( config . DB_ROOT , cover_path ) , " cover.jpg " )
2016-11-09 20:24:33 +02:00
@app.route ( " /feed/cover/<path:cover_path> " )
@requires_basic_auth_if_no_ano
def feed_get_cover ( cover_path ) :
return send_from_directory ( os . path . join ( config . DB_ROOT , cover_path ) , " cover.jpg " )
2016-07-16 10:44:47 +02:00
@app.route ( " /read/<int:book_id>/<format> " )
2015-08-02 20:59:11 +02:00
@login_required
2016-07-16 10:44:47 +02:00
def read_book ( book_id , format ) :
2015-08-02 20:59:11 +02:00
book = db . session . query ( db . Books ) . filter ( db . Books . id == book_id ) . first ( )
2016-10-30 12:44:02 +02:00
if book :
book_dir = os . path . join ( config . MAIN_DIR , " cps " , " static " , str ( book_id ) )
if not os . path . exists ( book_dir ) :
os . mkdir ( book_dir )
2016-11-01 19:49:47 +02:00
if format . lower ( ) == " epub " :
#check if mimetype file is exists
mime_file = str ( book_id ) + " /mimetype "
if os . path . exists ( mime_file ) == False :
epub_file = os . path . join ( config . DB_ROOT , book . path , book . data [ 0 ] . name ) + " .epub "
if not os . path . isfile ( epub_file ) :
raise ValueError ( ' Error opening eBook. File does not exist: ' , epub_file )
zfile = zipfile . ZipFile ( epub_file )
for name in zfile . namelist ( ) :
( dirName , fileName ) = os . path . split ( name )
newDir = os . path . join ( book_dir , dirName )
if not os . path . exists ( newDir ) :
try :
os . makedirs ( newDir )
except OSError as exception :
if exception . errno == errno . EEXIST :
pass
else :
raise
if fileName :
fd = open ( os . path . join ( newDir , fileName ) , " wb " )
fd . write ( zfile . read ( name ) )
fd . close ( )
zfile . close ( )
2016-11-09 20:24:33 +02:00
return render_template ( ' read.html ' , bookid = book_id , title = _ ( u " Read a Book " ) )
2016-11-01 19:49:47 +02:00
elif format . lower ( ) == " pdf " :
all_name = str ( book_id ) + " / " + urllib . quote ( book . data [ 0 ] . name ) + " .pdf "
tmp_file = os . path . join ( book_dir , urllib . quote ( book . data [ 0 ] . name ) ) + " .pdf "
if os . path . exists ( tmp_file ) == False :
pdf_file = os . path . join ( config . DB_ROOT , book . path , book . data [ 0 ] . name ) + " .pdf "
copyfile ( pdf_file , tmp_file )
2016-11-09 20:24:33 +02:00
return render_template ( ' readpdf.html ' , pdffile = all_name , title = _ ( u " Read a Book " ) )
2016-11-01 19:49:47 +02:00
elif format . lower ( ) == " txt " :
all_name = str ( book_id ) + " / " + urllib . quote ( book . data [ 0 ] . name ) + " .txt "
tmp_file = os . path . join ( book_dir , urllib . quote ( book . data [ 0 ] . name ) ) + " .txt "
if os . path . exists ( all_name ) == False :
txt_file = os . path . join ( config . DB_ROOT , book . path , book . data [ 0 ] . name ) + " .txt "
copyfile ( txt_file , tmp_file )
2016-11-09 20:24:33 +02:00
return render_template ( ' readtxt.html ' , txtfile = all_name , title = _ ( u " Read a Book " ) )
2016-10-30 12:44:02 +02:00
else :
2016-11-09 20:24:33 +02:00
flash ( _ ( u " Error opening eBook. File does not exist or file is not accessible: " ) , category = " error " )
2016-10-30 12:44:02 +02:00
return redirect ( ' / ' or url_for ( " index " , _external = True ) )
2015-08-02 20:59:11 +02:00
@app.route ( " /download/<int:book_id>/<format> " )
@login_required
2016-04-27 10:35:23 +02:00
@download_required
2015-08-02 20:59:11 +02:00
def get_download_link ( book_id , format ) :
format = format . split ( " . " ) [ 0 ]
book = db . session . query ( db . Books ) . filter ( db . Books . id == book_id ) . first ( )
data = db . session . query ( db . Data ) . filter ( db . Data . book == book . id ) . filter ( db . Data . format == format . upper ( ) ) . first ( )
helper . update_download ( book_id , int ( current_user . id ) )
2016-03-26 17:12:29 +02:00
author = helper . get_normalized_author ( book . author_sort )
file_name = book . title
if len ( author ) > 0 :
file_name = author + ' - ' + file_name
file_name = helper . get_valid_filename ( file_name )
2015-08-02 20:59:11 +02:00
response = make_response ( send_from_directory ( os . path . join ( config . DB_ROOT , book . path ) , data . name + " . " + format ) )
2016-03-26 18:17:11 +02:00
response . headers [ " Content-Disposition " ] = \
" attachment; " \
" filename= {utf_filename} . {suffix} ; " \
" filename*=UTF-8 ' ' {utf_filename} . {suffix} " . format (
utf_filename = file_name . encode ( ' utf-8 ' ) ,
suffix = format
)
2015-08-02 20:59:11 +02:00
return response
2015-10-13 02:30:55 +02:00
@app.route ( ' /register ' , methods = [ ' GET ' , ' POST ' ] )
def register ( ) :
error = None
if not config . PUBLIC_REG :
abort ( 404 )
2016-11-09 20:24:33 +02:00
if current_user is not None and current_user . is_authenticated :
2016-07-15 01:28:12 +02:00
return redirect ( url_for ( ' index ' , _external = True ) )
2015-10-13 02:30:55 +02:00
if request . method == " POST " :
to_save = request . form . to_dict ( )
if not to_save [ " nickname " ] or not to_save [ " email " ] or not to_save [ " password " ] :
2016-11-09 20:24:33 +02:00
flash ( _ ( u " Please fill out all fields! " ) , category = " error " )
2015-10-13 02:30:55 +02:00
return render_template ( ' register.html ' , title = " register " )
existing_user = ub . session . query ( ub . User ) . filter ( ub . User . nickname == to_save [ " nickname " ] ) . first ( )
existing_email = ub . session . query ( ub . User ) . filter ( ub . User . email == to_save [ " email " ] ) . first ( )
if not existing_user and not existing_email :
content = ub . User ( )
content . password = generate_password_hash ( to_save [ " password " ] )
content . nickname = to_save [ " nickname " ]
content . email = to_save [ " email " ]
content . role = 0
try :
ub . session . add ( content )
ub . session . commit ( )
except :
ub . session . rollback ( )
2016-11-09 20:24:33 +02:00
flash ( _ ( u " An unknown error occured. Please try again later. " ) , category = " error " )
2015-10-13 02:30:55 +02:00
return render_template ( ' register.html ' , title = " register " )
flash ( " Your account has been created. Please login. " , category = " success " )
2016-07-15 01:28:12 +02:00
return redirect ( url_for ( ' login ' , _external = True ) )
2015-10-13 02:30:55 +02:00
else :
2016-11-09 20:24:33 +02:00
flash ( _ ( u " This username or email address is already in use. " ) , category = " error " )
2015-10-13 02:30:55 +02:00
return render_template ( ' register.html ' , title = " register " )
2016-11-09 20:24:33 +02:00
return render_template ( ' register.html ' , title = _ ( u " register " ) )
2015-10-13 02:30:55 +02:00
2015-08-02 20:59:11 +02:00
@app.route ( ' /login ' , methods = [ ' GET ' , ' POST ' ] )
def login ( ) :
error = None
2015-10-13 02:30:55 +02:00
2016-11-09 20:24:33 +02:00
if current_user is not None and current_user . is_authenticated :
2016-07-15 01:28:12 +02:00
return redirect ( url_for ( ' index ' , _external = True ) )
2015-08-02 20:59:11 +02:00
if request . method == " POST " :
form = request . form . to_dict ( )
2016-11-12 22:28:40 +02:00
user = ub . session . query ( ub . User ) . filter ( ub . User . nickname == form [ ' username ' ] . strip ( ) ) . first ( )
2015-08-02 20:59:11 +02:00
if user and check_password_hash ( user . password , form [ ' password ' ] ) :
login_user ( user , remember = True )
2016-11-09 20:24:33 +02:00
flash ( _ ( u " you are now logged in as: ' %(nickname)s ' " , nickname = user . nickname ) , category = " success " )
return redirect ( ' / ' or url_for ( " index " , _external = True ) )
2015-08-02 20:59:11 +02:00
else :
2016-11-09 20:24:33 +02:00
flash ( _ ( u " Wrong Username or Password " ) , category = " error " )
2015-08-02 20:59:11 +02:00
2016-11-09 20:24:33 +02:00
return render_template ( ' login.html ' , title = _ ( u " login " ) )
2015-08-02 20:59:11 +02:00
@app.route ( ' /logout ' )
@login_required
def logout ( ) :
2016-11-09 20:24:33 +02:00
if current_user is not None and current_user . is_authenticated :
2015-08-02 20:59:11 +02:00
logout_user ( )
2016-11-09 20:24:33 +02:00
return redirect ( url_for ( " index " , _external = True ) )
2015-08-02 20:59:11 +02:00
@app.route ( ' /send/<int:book_id> ' )
@login_required
2016-04-27 10:35:23 +02:00
@download_required
2015-08-02 20:59:11 +02:00
def send_to_kindle ( book_id ) :
2015-08-02 21:23:24 +02:00
settings = ub . get_mail_settings ( )
if settings . get ( " mail_server " , " mail.example.com " ) == " mail.example.com " :
2016-11-09 20:24:33 +02:00
flash ( _ ( u " Please configure the SMTP mail settings first... " ) , category = " error " )
2015-08-02 21:23:24 +02:00
elif current_user . kindle_mail :
2016-03-27 23:36:51 +02:00
result = helper . send_mail ( book_id , current_user . kindle_mail )
if result is None :
2016-11-09 20:24:33 +02:00
flash ( _ ( u " Book successfully send to %(kindlemail)s " , kindlemail = current_user . kindle_mail ) , category = " success " )
2015-08-02 20:59:11 +02:00
helper . update_download ( book_id , int ( current_user . id ) )
else :
2016-11-09 20:24:33 +02:00
flash ( _ ( u " There was an error sending this book: %(res)s " , res = result ) , category = " error " )
2015-08-02 20:59:11 +02:00
else :
2016-11-09 20:24:33 +02:00
flash ( _ ( u " Please configure your kindle email address first... " ) , category = " error " )
2015-08-02 20:59:11 +02:00
return redirect ( request . environ [ " HTTP_REFERER " ] )
@app.route ( " /shelf/add/<int:shelf_id>/<int:book_id> " )
@login_required
def add_to_shelf ( shelf_id , book_id ) :
shelf = ub . session . query ( ub . Shelf ) . filter ( ub . Shelf . id == shelf_id ) . first ( )
if not shelf . is_public and not shelf . user_id == int ( current_user . id ) :
flash ( " Sorry you are not allowed to add a book to the the shelf: %s " % shelf . name )
2016-07-15 01:28:12 +02:00
return redirect ( url_for ( ' index ' , _external = True ) )
2015-08-02 20:59:11 +02:00
ins = ub . BookShelf ( shelf = shelf . id , book_id = book_id )
ub . session . add ( ins )
ub . session . commit ( )
2016-11-09 20:24:33 +02:00
flash ( _ ( u " Book has been added to shelf: %(sname)s " , sname = shelf . name ) , category = " success " )
2015-10-12 03:09:56 +02:00
#return redirect(url_for('show_book', id=book_id))
return redirect ( request . environ [ " HTTP_REFERER " ] )
@app.route ( " /shelf/remove/<int:shelf_id>/<int:book_id> " )
@login_required
def remove_from_shelf ( shelf_id , book_id ) :
shelf = ub . session . query ( ub . Shelf ) . filter ( ub . Shelf . id == shelf_id ) . first ( )
if not shelf . is_public and not shelf . user_id == int ( current_user . id ) :
flash ( " Sorry you are not allowed to remove a book from this shelf: %s " % shelf . name )
2016-07-15 01:28:12 +02:00
return redirect ( url_for ( ' index ' , _external = True ) )
2015-10-12 03:09:56 +02:00
book_shelf = ub . session . query ( ub . BookShelf ) . filter ( ub . BookShelf . shelf == shelf_id , ub . BookShelf . book_id == book_id ) . first ( )
#rem = ub.BookShelf(shelf=shelf.id, book_id=book_id)
ub . session . delete ( book_shelf )
ub . session . commit ( )
2016-11-09 20:24:33 +02:00
flash ( _ ( u " Book has been removed from shelf: %(sname)s " , sname = shelf . name ) , category = " success " )
2015-10-12 03:09:56 +02:00
2015-08-02 20:59:11 +02:00
return redirect ( request . environ [ " HTTP_REFERER " ] )
@app.route ( " /shelf/create " , methods = [ " GET " , " POST " ] )
@login_required
def create_shelf ( ) :
shelf = ub . Shelf ( )
if request . method == " POST " :
to_save = request . form . to_dict ( )
if " is_public " in to_save :
shelf . is_public = 1
shelf . name = to_save [ " title " ]
shelf . user_id = int ( current_user . id )
2015-10-13 19:12:18 +02:00
existing_shelf = ub . session . query ( ub . Shelf ) . filter ( ub . Shelf . name == shelf . name ) . first ( )
if existing_shelf :
2016-11-09 20:24:33 +02:00
flash ( _ ( u " A shelf with the name ' %(title)s ' already exists. " , title = to_save [ " title " ] ) , category = " error " )
2015-10-13 19:12:18 +02:00
else :
try :
ub . session . add ( shelf )
ub . session . commit ( )
2016-11-09 20:24:33 +02:00
flash ( _ ( u " Shelf %(title)s created " , title = to_save [ " title " ] ) , category = " success " )
2015-10-13 19:12:18 +02:00
except :
2016-11-09 20:24:33 +02:00
flash ( _ ( u " There was an error " ) , category = " error " )
return render_template ( ' shelf_edit.html ' , title = _ ( u " create a shelf " ) )
2015-08-02 20:59:11 +02:00
else :
2016-11-09 20:24:33 +02:00
return render_template ( ' shelf_edit.html ' , title = _ ( u " create a shelf " ) )
2015-08-02 20:59:11 +02:00
2016-11-09 20:24:33 +02:00
@app.route ( " /shelf/delete/<int:shelf_id> " )
@login_required
def delete_shelf ( shelf_id ) :
cur_shelf = ub . session . query ( ub . Shelf ) . filter ( ub . Shelf . id == shelf_id ) . first ( )
deleted = 0
if current_user . role == ub . ROLE_ADMIN :
deleted = ub . session . query ( ub . Shelf ) . filter ( ub . Shelf . id == shelf_id ) . delete ( )
else :
deleted = ub . session . query ( ub . Shelf ) . filter ( ub . or_ ( ub . and_ ( ub . Shelf . user_id == int ( current_user . id ) , ub . Shelf . id == shelf_id ) , ub . and_ ( ub . Shelf . is_public == 1 , ub . Shelf . id == shelf_id ) ) ) . delete ( )
if deleted :
ub . session . query ( ub . BookShelf ) . filter ( ub . BookShelf . shelf == shelf_id ) . delete ( )
ub . session . commit ( )
flash ( _ ( " successfully deleted shelf %(name)s " , name = cur_shelf . name , category = " success " ) )
return redirect ( url_for ( ' index ' ) )
2015-08-02 20:59:11 +02:00
@app.route ( " /shelf/<int:shelf_id> " )
2016-11-09 20:24:33 +02:00
@login_required_if_no_ano
2015-08-02 20:59:11 +02:00
def show_shelf ( shelf_id ) :
2016-11-09 20:24:33 +02:00
if current_user . is_anonymous ( ) :
shelf = ub . session . query ( ub . Shelf ) . filter ( ub . Shelf . is_public == 1 , ub . Shelf . id == shelf_id ) . first ( )
else :
shelf = ub . session . query ( ub . Shelf ) . filter ( ub . or_ ( ub . and_ ( ub . Shelf . user_id == int ( current_user . id ) , ub . Shelf . id == shelf_id ) , ub . and_ ( ub . Shelf . is_public == 1 , ub . Shelf . id == shelf_id ) ) ) . first ( )
2015-08-02 20:59:11 +02:00
result = list ( )
if shelf :
books_in_shelf = ub . session . query ( ub . BookShelf ) . filter ( ub . BookShelf . shelf == shelf_id ) . all ( )
for book in books_in_shelf :
cur_book = db . session . query ( db . Books ) . filter ( db . Books . id == book . book_id ) . first ( )
result . append ( cur_book )
2016-11-09 20:24:33 +02:00
return render_template ( ' shelf.html ' , entries = result , title = _ ( u " Shelf: ' %(name)s ' " , name = shelf . name ) , shelf = shelf )
2015-08-02 20:59:11 +02:00
@app.route ( " /me " , methods = [ " GET " , " POST " ] )
@login_required
def profile ( ) :
content = ub . session . query ( ub . User ) . filter ( ub . User . id == int ( current_user . id ) ) . first ( )
downloads = list ( )
2016-11-09 20:24:33 +02:00
languages = db . session . query ( db . Languages ) . all ( )
for lang in languages :
try :
cur_l = LC . parse ( lang . lang_code )
lang . name = cur_l . get_language_name ( get_locale ( ) )
except :
lang . name = _ ( isoLanguages . get ( part3 = lang . lang_code ) . name )
translations = babel . list_translations ( ) + [ LC ( ' en ' ) ]
2015-08-02 20:59:11 +02:00
for book in content . downloads :
downloads . append ( db . session . query ( db . Books ) . filter ( db . Books . id == book . book_id ) . first ( ) )
if request . method == " POST " :
to_save = request . form . to_dict ( )
2016-11-09 20:24:33 +02:00
content . random_books = 0
2016-04-27 16:00:58 +02:00
if current_user . role_passwd ( ) or current_user . role_admin ( ) :
if to_save [ " password " ] :
content . password = generate_password_hash ( to_save [ " password " ] )
2016-08-08 21:01:38 +02:00
if " kindle_mail " in to_save and to_save [ " kindle_mail " ] != content . kindle_mail :
2015-08-02 20:59:11 +02:00
content . kindle_mail = to_save [ " kindle_mail " ]
2015-10-13 18:07:17 +02:00
if to_save [ " email " ] and to_save [ " email " ] != content . email :
content . email = to_save [ " email " ]
2016-11-09 20:24:33 +02:00
if " show_random " in to_save and to_save [ " show_random " ] == " on " :
content . random_books = 1
if " default_language " in to_save :
content . default_language = to_save [ " default_language " ]
if to_save [ " locale " ] :
content . locale = to_save [ " locale " ]
2015-10-13 18:07:17 +02:00
try :
ub . session . commit ( )
except IntegrityError :
ub . session . rollback ( )
2016-11-09 20:24:33 +02:00
flash ( _ ( u " Found an existing account for this email address. " ) , category = " error " )
return render_template ( " user_edit.html " , content = content , downloads = downloads , title = _ ( u " %(name)s ' s profile " , name = current_user . nickname ) )
flash ( _ ( u " Profile updated " ) , category = " success " )
return render_template ( " user_edit.html " , translations = translations , profile = 1 , languages = languages , content = content , downloads = downloads , title = _ ( u " %(name)s ' s profile " , name = current_user . nickname ) )
2015-08-02 20:59:11 +02:00
@app.route ( " /admin/user " )
@login_required
2015-10-13 18:07:17 +02:00
@admin_required
2015-08-02 20:59:11 +02:00
def user_list ( ) :
content = ub . session . query ( ub . User ) . all ( )
2015-08-02 21:23:24 +02:00
settings = ub . session . query ( ub . Settings ) . first ( )
2016-11-09 20:24:33 +02:00
return render_template ( " user_list.html " , content = content , email = settings , title = _ ( u " User list " ) )
2015-08-02 20:59:11 +02:00
@app.route ( " /admin/user/new " , methods = [ " GET " , " POST " ] )
@login_required
2015-10-13 18:07:17 +02:00
@admin_required
2015-08-02 20:59:11 +02:00
def new_user ( ) :
content = ub . User ( )
2016-11-09 20:24:33 +02:00
languages = db . session . query ( db . Languages ) . all ( )
for lang in languages :
try :
cur_l = LC . parse ( lang . lang_code )
lang . name = cur_l . get_language_name ( get_locale ( ) )
except :
lang . name = _ ( isoLanguages . get ( part3 = lang . lang_code ) . name )
translations = babel . list_translations ( ) + [ LC ( ' en ' ) ]
2015-08-02 20:59:11 +02:00
if request . method == " POST " :
to_save = request . form . to_dict ( )
2015-10-13 18:07:17 +02:00
if not to_save [ " nickname " ] or not to_save [ " email " ] or not to_save [ " password " ] :
2016-11-09 20:24:33 +02:00
flash ( _ ( u " Please fill out all fields! " ) , category = " error " )
return render_template ( " user_edit.html " , new_user = 1 , content = content , title = _ ( u " Add new user " ) )
2015-08-02 20:59:11 +02:00
content . password = generate_password_hash ( to_save [ " password " ] )
content . nickname = to_save [ " nickname " ]
content . email = to_save [ " email " ]
2016-11-09 20:24:33 +02:00
content . default_language = to_save [ " default_language " ]
content . locale = to_save [ " locale " ]
content . random_books = 0
content . language_books = 0
content . series_books = 0
content . category_books = 0
content . hot_books = 0
if " show_language " in to_save :
content . language_books = to_save [ " show_language " ]
if " show_series " in to_save :
content . series_books = to_save [ " show_series " ]
if " show_category " in to_save :
content . category_books = to_save [ " show_category " ]
if " show_hot " in to_save :
content . hot_books = to_save [ " show_hot " ]
2016-04-27 10:35:23 +02:00
content . role = 0
if " admin_role " in to_save :
content . role = content . role + ub . ROLE_ADMIN
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
2016-04-27 16:00:58 +02:00
if " passwd_role " in to_save :
content . role = content . role + ub . ROLE_PASSWD
2015-08-02 20:59:11 +02:00
try :
ub . session . add ( content )
ub . session . commit ( )
2016-11-09 20:24:33 +02:00
flash ( _ ( " User ' %(user)s ' created " , user = content . nickname ) , category = " success " )
2016-07-15 01:28:12 +02:00
return redirect ( url_for ( ' user_list ' , _external = True ) )
2015-10-13 18:07:17 +02:00
except IntegrityError :
ub . session . rollback ( )
2016-11-09 20:24:33 +02:00
flash ( _ ( u " Found an existing account for this email address or nickname. " ) , category = " error " )
return render_template ( " user_edit.html " , new_user = 1 , content = content , translations = translations , languages = languages , title = " Add new user " )
2015-08-02 20:59:11 +02:00
2015-08-02 21:23:24 +02:00
@app.route ( " /admin/user/mailsettings " , methods = [ " GET " , " POST " ] )
@login_required
2015-10-13 18:07:17 +02:00
@admin_required
2015-08-02 21:23:24 +02:00
def edit_mailsettings ( ) :
content = ub . session . query ( ub . Settings ) . first ( )
if request . method == " POST " :
to_save = request . form . to_dict ( )
content . mail_server = to_save [ " mail_server " ]
content . mail_port = int ( to_save [ " mail_port " ] )
content . mail_login = to_save [ " mail_login " ]
content . mail_password = to_save [ " mail_password " ]
content . mail_from = to_save [ " mail_from " ]
2016-03-27 23:36:51 +02:00
if " mail_use_ssl " in to_save :
content . mail_use_ssl = 1
else :
content . mail_use_ssl = 0
2015-08-02 21:23:24 +02:00
try :
ub . session . commit ( )
2016-11-09 20:24:33 +02:00
flash ( _ ( u " Mail settings updated " ) , category = " success " )
2015-08-02 21:23:24 +02:00
except ( e ) :
flash ( e , category = " error " )
2016-11-09 20:24:33 +02:00
return render_template ( " email_edit.html " , content = content , title = _ ( " Edit mail settings " ) )
2015-08-02 21:23:24 +02:00
2015-08-02 20:59:11 +02:00
@app.route ( " /admin/user/<int:user_id> " , methods = [ " GET " , " POST " ] )
@login_required
2015-10-13 18:07:17 +02:00
@admin_required
2015-08-02 20:59:11 +02:00
def edit_user ( user_id ) :
content = ub . session . query ( ub . User ) . filter ( ub . User . id == int ( user_id ) ) . first ( )
downloads = list ( )
2016-11-09 20:24:33 +02:00
languages = db . session . query ( db . Languages ) . all ( )
for lang in languages :
try :
cur_l = LC . parse ( lang . lang_code )
lang . name = cur_l . get_language_name ( get_locale ( ) )
except :
lang . name = _ ( isoLanguages . get ( part3 = lang . lang_code ) . name )
translations = babel . list_translations ( ) + [ LC ( ' en ' ) ]
2015-08-02 20:59:11 +02:00
for book in content . downloads :
downloads . append ( db . session . query ( db . Books ) . filter ( db . Books . id == book . book_id ) . first ( ) )
if request . method == " POST " :
to_save = request . form . to_dict ( )
if " delete " in to_save :
ub . session . delete ( content )
2016-11-09 20:24:33 +02:00
flash ( _ ( u " User ' %(nick)s ' deleted " , nick = content . nickname ) , category = " success " )
2016-07-15 01:28:12 +02:00
return redirect ( url_for ( ' user_list ' , _external = True ) )
2015-08-02 20:59:11 +02:00
else :
2015-10-13 18:07:17 +02:00
if to_save [ " password " ] :
2016-04-03 15:12:48 +02:00
content . password = generate_password_hash ( to_save [ " password " ] )
2016-04-27 10:35:23 +02:00
if " admin_role " in to_save and not content . role_admin ( ) :
content . role = content . role + ub . ROLE_ADMIN
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
2016-04-27 16:00:58 +02:00
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
2016-11-09 20:24:33 +02:00
content . random_books = 0
content . language_books = 0
content . series_books = 0
content . category_books = 0
content . hot_books = 0
if " show_random " in to_save and to_save [ " show_random " ] == " on " :
content . random_books = 1
if " show_language " in to_save and to_save [ " show_language " ] == " on " :
content . language_books = 1
if " show_series " in to_save and to_save [ " show_series " ] == " on " :
content . series_books = 1
if " show_category " in to_save and to_save [ " show_category " ] == " on " :
content . category_books = 1
if " show_hot " in to_save and to_save [ " show_hot " ] == " on " :
content . hot_books = 1
if " default_language " in to_save :
content . default_language = to_save [ " default_language " ]
if to_save [ " locale " ] :
content . locale = to_save [ " locale " ]
2015-10-13 18:07:17 +02:00
if to_save [ " email " ] and to_save [ " email " ] != content . email :
content . email = to_save [ " email " ]
2016-08-08 21:01:38 +02:00
if " kindle_mail " in to_save and to_save [ " kindle_mail " ] != content . kindle_mail :
2015-10-13 18:07:17 +02:00
content . kindle_mail = to_save [ " kindle_mail " ]
try :
ub . session . commit ( )
2016-11-09 20:24:33 +02:00
flash ( _ ( u " User ' %(nick)s ' updated " , nick = content . nickname ) , category = " success " )
2015-10-13 18:07:17 +02:00
except IntegrityError :
ub . session . rollback ( )
2016-11-09 20:24:33 +02:00
flash ( _ ( u " An unknown error occured. " ) , category = " error " )
return render_template ( " user_edit.html " , translations = translations , languages = languages , new_user = 0 , content = content , downloads = downloads , title = _ ( u " Edit User %(nick)s " , nick = content . nickname ) )
2015-08-02 20:59:11 +02:00
@app.route ( " /admin/book/<int:book_id> " , methods = [ ' GET ' , ' POST ' ] )
@login_required
2016-04-27 10:35:23 +02:00
@edit_required
2015-08-02 20:59:11 +02:00
def edit_book ( book_id ) :
## create the function for sorting...
db . session . connection ( ) . connection . connection . create_function ( " title_sort " , 1 , db . title_sort )
2016-04-20 18:56:03 +02:00
cc = db . session . query ( db . Custom_Columns ) . filter ( db . Custom_Columns . datatype . notin_ ( db . cc_exceptions ) ) . all ( )
2016-11-09 20:24:33 +02:00
if current_user . filter_language ( ) != " all " :
filter = db . Books . languages . any ( db . Languages . lang_code == current_user . filter_language ( ) )
else :
filter = True
book = db . session . query ( db . Books ) . filter ( db . Books . id == book_id ) . filter ( filter ) . first ( )
2016-04-15 23:35:18 +02:00
author_names = [ ]
2016-11-09 20:24:33 +02:00
if book :
for index in range ( 0 , len ( book . languages ) ) :
try :
book . languages [ index ] . language_name = LC . parse ( book . languages [ index ] . lang_code ) . get_language_name ( get_locale ( ) )
except :
book . languages [ index ] . language_name = _ ( isoLanguages . get ( part3 = book . languages [ index ] . lang_code ) . name )
for author in book . authors :
author_names . append ( author . name )
if request . method == ' POST ' :
edited_books_id = set ( )
to_save = request . form . to_dict ( )
if book . title != to_save [ " book_title " ] :
book . title = to_save [ " book_title " ]
edited_books_id . add ( book . id )
input_authors = to_save [ " author_name " ] . split ( ' & ' )
input_authors = map ( lambda it : it . strip ( ) , input_authors )
# we have all author names now
author0_before_edit = book . authors [ 0 ] . name
modify_database_object ( input_authors , book . authors , db . Authors , db . session , ' author ' )
if author0_before_edit != book . authors [ 0 ] . name :
edited_books_id . add ( book . id )
if to_save [ " cover_url " ] and os . path . splitext ( to_save [ " cover_url " ] ) [ 1 ] . lower ( ) == " .jpg " :
img = requests . get ( to_save [ " cover_url " ] )
f = open ( os . path . join ( config . DB_ROOT , book . path , " cover.jpg " ) , " wb " )
f . write ( img . content )
f . close ( )
if book . series_index != to_save [ " series_index " ] :
book . series_index = to_save [ " series_index " ]
if len ( book . comments ) :
book . comments [ 0 ] . text = to_save [ " description " ]
2015-08-02 20:59:11 +02:00
else :
2016-11-09 20:24:33 +02:00
book . comments . append ( db . Comments ( text = to_save [ " description " ] , book = book . id ) )
input_tags = to_save [ " tags " ] . split ( ' , ' )
input_tags = map ( lambda it : it . strip ( ) , input_tags )
modify_database_object ( input_tags , book . tags , db . Tags , db . session , ' tags ' )
input_series = [ to_save [ " series " ] . strip ( ) ]
input_series = [ x for x in input_series if x != ' ' ]
modify_database_object ( input_series , book . series , db . Series , db . session , ' series ' )
input_languages = to_save [ " languages " ] . split ( ' , ' )
input_languages = map ( lambda it : it . strip ( ) . lower ( ) , input_languages )
# retranslate displayed text to language codes
languages = db . session . query ( db . Languages ) . all ( )
input_l = [ ]
for lang in languages :
try :
lang . name = LC . parse ( lang . lang_code ) . get_language_name ( get_locale ( ) ) . lower ( )
except :
lang . name = _ ( isoLanguages . get ( part3 = lang . lang_code ) . name ) . lower ( )
for inp_lang in input_languages :
if inp_lang == lang . name :
input_l . append ( lang . lang_code )
modify_database_object ( input_l , book . languages , db . Languages , db . session , ' languages ' )
if to_save [ " rating " ] . strip ( ) :
old_rating = False
if len ( book . ratings ) > 0 :
old_rating = book . ratings [ 0 ] . rating
ratingx2 = int ( float ( to_save [ " rating " ] ) * 2 )
if ratingx2 != old_rating :
is_rating = db . session . query ( db . Ratings ) . filter ( db . Ratings . rating == ratingx2 ) . first ( )
if is_rating :
book . ratings . append ( is_rating )
else :
new_rating = db . Ratings ( rating = ratingx2 )
book . ratings . append ( new_rating )
if old_rating :
book . ratings . remove ( book . ratings [ 0 ] )
else :
if len ( book . ratings ) > 0 :
2016-04-21 09:04:08 +02:00
book . ratings . remove ( book . ratings [ 0 ] )
2016-11-09 20:24:33 +02:00
for c in cc :
cc_string = " custom_column_ " + str ( c . id )
if not c . is_multiple :
if len ( getattr ( book , cc_string ) ) > 0 :
cc_db_value = getattr ( book , cc_string ) [ 0 ] . value
else :
cc_db_value = None
if to_save [ cc_string ] . strip ( ) :
if c . datatype == ' bool ' :
if to_save [ cc_string ] == ' None ' :
to_save [ cc_string ] = None
else :
to_save [ cc_string ] = 1 if to_save [ cc_string ] == ' True ' else 0
if to_save [ cc_string ] != cc_db_value :
if cc_db_value is not None :
if to_save [ cc_string ] is not None :
setattr ( getattr ( book , cc_string ) [ 0 ] , ' value ' , to_save [ cc_string ] )
else :
del_cc = getattr ( book , cc_string ) [ 0 ]
getattr ( book , cc_string ) . remove ( del_cc )
db . session . delete ( del_cc )
else :
cc_class = db . cc_classes [ c . id ]
new_cc = cc_class ( value = to_save [ cc_string ] , book = book_id )
db . session . add ( new_cc )
else :
if c . datatype == ' rating ' :
to_save [ cc_string ] = str ( int ( float ( to_save [ cc_string ] ) * 2 ) )
if to_save [ cc_string ] . strip ( ) != cc_db_value :
if cc_db_value != None :
#remove old cc_val
del_cc = getattr ( book , cc_string ) [ 0 ]
getattr ( book , cc_string ) . remove ( del_cc )
if len ( del_cc . books ) == 0 :
db . session . delete ( del_cc )
cc_class = db . cc_classes [ c . id ]
new_cc = db . session . query ( cc_class ) . filter ( cc_class . value == to_save [ cc_string ] . strip ( ) ) . first ( )
# if no cc val is found add it
if new_cc == None :
new_cc = cc_class ( value = to_save [ cc_string ] . strip ( ) )
db . session . add ( new_cc )
new_cc = db . session . query ( cc_class ) . filter ( cc_class . value == to_save [ cc_string ] . strip ( ) ) . first ( )
# add cc value to book
getattr ( book , cc_string ) . append ( new_cc )
else :
2016-04-21 19:18:52 +02:00
if cc_db_value != None :
#remove old cc_val
del_cc = getattr ( book , cc_string ) [ 0 ]
getattr ( book , cc_string ) . remove ( del_cc )
if len ( del_cc . books ) == 0 :
db . session . delete ( del_cc )
else :
2016-11-09 20:24:33 +02:00
input_tags = to_save [ cc_string ] . split ( ' , ' )
input_tags = map ( lambda it : it . strip ( ) , input_tags )
input_tags = [ x for x in input_tags if x != ' ' ]
# we have all author names now
# 1. search for tags to remove
del_tags = [ ]
2016-04-21 19:18:52 +02:00
for c_tag in getattr ( book , cc_string ) :
2016-11-09 20:24:33 +02:00
found = False
for inp_tag in input_tags :
if inp_tag == c_tag . value :
found = True
break ;
# if the tag was not found in the new list, add him to remove list
if not found :
del_tags . append ( c_tag )
# 2. search for tags that need to be added
add_tags = [ ]
for inp_tag in input_tags :
found = False
for c_tag in getattr ( book , cc_string ) :
if inp_tag == c_tag . value :
found = True
break ;
if not found :
add_tags . append ( inp_tag )
# if there are tags to remove, we remove them now
if len ( del_tags ) > 0 :
for del_tag in del_tags :
getattr ( book , cc_string ) . remove ( del_tag )
if len ( del_tag . books ) == 0 :
db . session . delete ( del_tag )
# if there are tags to add, we add them now!
if len ( add_tags ) > 0 :
for add_tag in add_tags :
# check if a tag with that name exists
2016-04-21 19:18:52 +02:00
new_tag = db . session . query ( db . cc_classes [ c . id ] ) . filter ( db . cc_classes [ c . id ] . value == add_tag ) . first ( )
2016-11-09 20:24:33 +02:00
# if no tag is found add it
if new_tag == None :
new_tag = db . cc_classes [ c . id ] ( value = add_tag )
db . session . add ( new_tag )
new_tag = db . session . query ( db . cc_classes [ c . id ] ) . filter ( db . cc_classes [ c . id ] . value == add_tag ) . first ( )
# add tag to book
getattr ( book , cc_string ) . append ( new_tag )
db . session . commit ( )
author_names = [ ]
for author in book . authors :
author_names . append ( author . name )
for b in edited_books_id :
helper . update_dir_stucture ( b )
if " detail_view " in to_save :
return redirect ( url_for ( ' show_book ' , id = book . id , _external = True ) )
else :
return render_template ( ' edit_book.html ' , book = book , authors = author_names , cc = cc )
2015-08-02 20:59:11 +02:00
else :
2016-04-20 00:20:02 +02:00
return render_template ( ' edit_book.html ' , book = book , authors = author_names , cc = cc )
2015-08-02 20:59:11 +02:00
else :
2016-11-09 20:24:33 +02:00
flash ( _ ( u " Error opening eBook. File does not exist or file is not accessible: " ) , category = " error " )
return redirect ( ' / ' or url_for ( " index " , _external = True ) )
2016-04-03 23:52:32 +02:00
2016-06-05 17:41:47 +02:00
import uploader
2016-06-05 18:42:18 +02:00
from shutil import move
2016-06-05 17:41:47 +02:00
2016-04-03 23:52:32 +02:00
@app.route ( " /upload " , methods = [ " GET " , " POST " ] )
@login_required
2016-04-27 10:35:23 +02:00
@upload_required
2016-04-03 23:52:32 +02:00
def upload ( ) :
2016-04-15 19:39:25 +02:00
if not config . UPLOADING :
abort ( 404 )
2016-04-03 23:52:32 +02:00
## 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 ( ' uuid4 ' , 0 , lambda : str ( uuid4 ( ) ) )
if request . method == ' POST ' and ' btn-upload ' in request . files :
file = request . files [ ' btn-upload ' ]
2016-06-05 17:41:47 +02:00
meta = uploader . upload ( file )
2016-10-30 12:44:02 +02:00
title = meta . title . encode ( ' utf-8 ' )
author = meta . author . encode ( ' utf-8 ' )
2016-06-05 17:41:47 +02:00
2016-08-07 22:10:00 +02:00
title_dir = helper . get_valid_filename ( title . decode ( ' utf-8 ' ) , False )
2016-04-04 23:25:53 +02:00
author_dir = helper . get_valid_filename ( author . decode ( ' utf-8 ' ) , False )
data_name = title_dir
2016-10-30 12:44:02 +02:00
filepath = config . DB_ROOT + os . sep + author_dir + os . sep + title_dir
saved_filename = filepath + os . sep + data_name + meta . extension
2016-04-03 23:52:32 +02:00
if not os . path . exists ( filepath ) :
2016-04-17 17:42:22 +02:00
try :
os . makedirs ( filepath )
except OSError :
2016-11-09 20:24:33 +02:00
flash ( _ ( u " Failed to create path %s (Permission denied). " % filepath ) , category = " error " )
2016-07-15 01:28:12 +02:00
return redirect ( url_for ( ' index ' , _external = True ) )
2016-04-17 17:42:22 +02:00
try :
2016-10-30 12:44:02 +02:00
copyfile ( meta . file_path , saved_filename )
except OSError , e :
2016-11-09 20:24:33 +02:00
flash ( _ ( u " Failed to store file %s (Permission denied). " % saved_filename ) , category = " error " )
2016-07-15 01:28:12 +02:00
return redirect ( url_for ( ' index ' , _external = True ) )
2016-10-30 12:44:02 +02:00
try :
os . unlink ( meta . file_path )
except OSError , e :
2016-11-09 20:24:33 +02:00
flash ( _ ( u " Failed to delete file %s (Permission denied). " % meta . file_path ) , category = " warning " )
2016-06-05 17:41:47 +02:00
2016-04-04 23:25:53 +02:00
file_size = os . path . getsize ( saved_filename )
2016-06-05 17:41:47 +02:00
if meta . cover is None :
has_cover = 0
basedir = os . path . dirname ( __file__ )
copyfile ( os . path . join ( basedir , " static/generic_cover.jpg " ) , os . path . join ( filepath , " cover.jpg " ) )
else :
has_cover = 1
2016-06-05 18:42:18 +02:00
move ( meta . cover , os . path . join ( filepath , " cover.jpg " ) )
2016-06-05 17:41:47 +02:00
2016-04-04 23:25:53 +02:00
is_author = db . session . query ( db . Authors ) . filter ( db . Authors . name == author ) . first ( )
2016-04-03 23:52:32 +02:00
if is_author :
db_author = is_author
else :
2016-04-04 23:25:53 +02:00
db_author = db . Authors ( author , " " , " " )
2016-04-03 23:52:32 +02:00
db . session . add ( db_author )
2016-04-20 00:20:02 +02:00
path = os . path . join ( author_dir , title_dir )
db_book = db . Books ( title , " " , " " , datetime . datetime . now ( ) , datetime . datetime ( 101 , 01 , 01 ) , 1 , datetime . datetime . now ( ) , path , has_cover , db_author , [ ] )
2016-04-03 23:52:32 +02:00
db_book . authors . append ( db_author )
2016-06-05 17:41:47 +02:00
db_data = db . Data ( db_book , meta . extension . upper ( ) [ 1 : ] , file_size , data_name )
2016-04-04 23:25:53 +02:00
db_book . data . append ( db_data )
2016-04-03 23:52:32 +02:00
db . session . add ( db_book )
db . session . commit ( )
2016-04-20 00:23:14 +02:00
author_names = [ ]
for author in db_book . authors :
author_names . append ( author . name )
2016-04-20 18:56:03 +02:00
cc = db . session . query ( db . Custom_Columns ) . filter ( db . Custom_Columns . datatype . notin_ ( db . cc_exceptions ) ) . all ( )
2016-04-27 10:35:23 +02:00
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 = [ ]
2016-07-16 11:17:43 +02:00
return render_template ( ' detail.html ' , entry = db_book , cc = cc , title = db_book . title , books_shelfs = book_in_shelfs )