Merge remote-tracking branch 'refs/remotes/janeczku/master'

This commit is contained in:
Radosław Kierznowski 2017-02-27 22:40:42 +01:00
commit 76c907484b
14 changed files with 228 additions and 88 deletions

View File

@ -56,6 +56,10 @@ books_languages_link = Table('books_languages_link', Base.metadata,
Column('lang_code', Integer, ForeignKey('languages.id'), primary_key=True)
)
books_publishers_link = Table('books_publishers_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('publisher', Integer, ForeignKey('publishers.id'), primary_key=True)
)
class Identifiers(Base):
__tablename__ = 'identifiers'
@ -182,6 +186,21 @@ class Languages(Base):
def __repr__(self):
return u"<Languages('{0}')>".format(self.lang_code)
class Publishers(Base):
__tablename__ = 'publishers'
id = Column(Integer, primary_key=True)
name = Column(String)
sort = Column(String)
def __init__(self, name,sort):
self.name = name
self.sort = sort
def __repr__(self):
return u"<Publishers('{0},{1}')>".format(self.name, self.sort)
class Data(Base):
__tablename__ = 'data'
@ -224,6 +243,7 @@ class Books(Base):
series = relationship('Series', secondary=books_series_link, backref='books')
ratings = relationship('Ratings', secondary=books_ratings_link, backref='books')
languages = relationship('Languages', secondary=books_languages_link, backref='books')
publishers = relationship('Publishers', secondary=books_publishers_link, backref='books')
identifiers = relationship('Identifiers', backref='books')
def __init__(self, title, sort, author_sort, timestamp, pubdate, series_index, last_modified, path, has_cover,
@ -274,7 +294,7 @@ def setup_db():
return False
dbpath = os.path.join(config.config_calibre_dir, "metadata.db")
engine = create_engine('sqlite:///{0}'.format(dbpath.encode('utf-8')), echo=False)
engine = create_engine('sqlite:///{0}'.format(dbpath.encode('utf-8')), echo=False, isolation_level="SERIALIZABLE")
try:
conn = engine.connect()

View File

@ -7,13 +7,14 @@ import os
import uploader
def extractCover(zip, coverFile, tmp_file_name):
def extractCover(zip, coverFile, coverpath, tmp_file_name):
if coverFile is None:
return None
else:
cf = zip.read("OPS/" + coverFile)
zipCoverPath = os.path.join(coverpath , coverFile).replace('\\','/')
cf = zip.read(zipCoverPath)
prefix = os.path.splitext(tmp_file_name)[0]
tmp_cover_name = prefix + "." + coverFile
tmp_cover_name = prefix + '.' + os.path.basename(zipCoverPath)
image = open(tmp_cover_name, 'wb')
image.write(cf)
image.close()
@ -32,10 +33,11 @@ def get_epub_info(tmp_file_path, original_file_name, original_file_extension):
txt = zip.read('META-INF/container.xml')
tree = etree.fromstring(txt)
cfname = tree.xpath('n:rootfiles/n:rootfile/@full-path', namespaces=ns)[0]
cf = zip.read(cfname)
tree = etree.fromstring(cf)
coverpath=os.path.dirname(cfname)
p = tree.xpath('/pkg:package/pkg:metadata', namespaces=ns)[0]
epub_metadata = {}
@ -46,11 +48,16 @@ def get_epub_info(tmp_file_path, original_file_name, original_file_extension):
else:
epub_metadata[s] = "Unknown"
coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='cover']/@href", namespaces=ns)
coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='cover-image']/@href", namespaces=ns)
if len(coversection) > 0:
coverfile = extractCover(zip, coversection[0], tmp_file_path)
coverfile = extractCover(zip, coversection[0], coverpath, tmp_file_path)
else:
coverfile = None
coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='cover']/@href", namespaces=ns)
if len(coversection) > 0:
coverfile = extractCover(zip, coversection[0], coverpath, tmp_file_path)
else:
coverfile = None
if epub_metadata['title'] is None:
title = original_file_name
else:

View File

@ -19,6 +19,8 @@ from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.generator import Generator
from email.utils import formatdate
from email.utils import make_msgid
from flask_babel import gettext as _
import subprocess
import threading
@ -165,6 +167,8 @@ def send_mail(book_id, kindle_mail, calibrepath):
# create MIME message
msg = MIMEMultipart()
msg['Subject'] = _(u'Send to Kindle')
msg['Message-Id'] = make_msgid('calibre-web')
msg['Date'] = formatdate(localtime=True)
text = _(u'This email has been sent via calibre web.')
msg.attach(MIMEText(text.encode('UTF-8'), 'plain', 'UTF-8'))

View File

@ -36,7 +36,7 @@ $(function() {
success: function(data) {
$('#spinner').show();
displaytext=data.text;
window.setTimeout(restartTimer, 3000);}
setTimeout(restartTimer, 3000);}
});
});
$("#shutdown").click(function() {
@ -50,7 +50,7 @@ $(function() {
});
$("#check_for_update").click(function() {
var button_text = $("#check_for_update").html();
$("#check_for_update").html('Checking...');
$("#check_for_update").html('...');
$.ajax({
dataType: 'json',
url: window.location.pathname+"/../../get_update_status",
@ -110,7 +110,8 @@ function updateTimer() {
$('#UpdateprogressDialog #updateFinished').removeClass('hidden');
$("#check_for_update").removeClass('hidden');
$("#perform_update").addClass('hidden');
}
},
timeout:2000
});
}

View File

@ -50,6 +50,7 @@
{% if entry.identifiers|length > 0 %}
<div class="identifiers">
<p>
<span class="glyphicon glyphicon-link"></span>
{% for identifier in entry.identifiers %}
<a href="{{identifier}}" target="_blank" class="btn btn-xs btn-success" role="button">{{identifier.formatType()}}</a>
@ -66,10 +67,16 @@
{% for tag in entry.tags %}
<a href="{{ url_for('category', id=tag.id) }}" class="btn btn-xs btn-info" role="button">{{tag.name}}</a>
{%endfor%}
</div>
</p>
{% endif %}
{% if entry.publishers|length > 0 %}
<div class="publishers">
<p>
<span>{{_('Publisher')}}:{% for publisher in entry.publishers %} {{publisher.name}}{% if not loop.last %},{% endif %}{% endfor %}</span>
</p>
</div>
{% endif %}
{% if entry.pubdate[:10] != '0101-01-01' %}
<p>{{_('Publishing date')}}: {{entry.pubdate|formatdate}} </p>
{% endif %}
@ -125,10 +132,10 @@
</div>
{% endif %}
{% if g.user.is_authenticated %}
{% if g.user.kindle_mail %}
{% if g.user.kindle_mail and g.user.is_authenticated %}
<a href="{{url_for('send_to_kindle', book_id=entry.id)}}" id="sendbtn" class="btn btn-primary" role="button"><span class="glyphicon glyphicon-send"></span> {{_('Send to Kindle')}}</a>
{% endif %}
{% if (g.user.role_download() and g.user.is_anonymous()) or g.user.is_authenticated %}
<div class="btn-group" role="group">
<button id="btnGroupDrop2" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="glyphicon glyphicon-eye-open"></span> {{_('Read in browser')}}

View File

@ -2,11 +2,17 @@
{% block body %}
<h1>{{title}}</h1>
<div class="container">
<div class="col-sm-6">
{% for lang in languages %}
{% if loop.index0 == (loop.length/2)|int and loop.length > 20 %}
</div>
<div class="col-sm-6">
{% endif %}
<div class="row">
<div class="col-xs-1" align="left"><span class="badge">{{lang_counter[loop.index0].bookcount}}</span></div>
<div class="col-xs-6"><a id="list_{{loop.index0}}" href="{{url_for('language', name=lang.lang_code)}}">{{lang.name}}</a></div>
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock %}

View File

@ -2,11 +2,17 @@
{% block body %}
<h1>{{title}}</h1>
<div class="container">
<div class="col-sm-6">
{% for entry in entries %}
{% if loop.index0 == (loop.length/2)|int and loop.length > 20 %}
</div>
<div class="col-sm-6">
{% endif %}
<div class="row">
<div class="col-xs-1" align="left"><span class="badge">{{entry.count}}</span></div>
<div class="col-xs-6"><a id="list_{{loop.index0}}" href="{{url_for(folder, id=entry[0].id )}}">{{entry[0].name}}</a></div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}

View File

@ -10,63 +10,67 @@
<label for="bookAuthor">{{_('Author')}}</label>
<input type="text" class="form-control typeahead" name="author_name" id="bookAuthor" value="" autocomplete="off">
</div>
<label for="Tags">{{_('Tags')}}</label>
<div class="form-group">
<label for="Publisher">{{_('Publisher')}}</label>
<input type="text" class="form-control" name="publisher" id="publisher" value="">
</div>
<label for="include_tag">{{_('Tags')}}</label>
<div class="form-group" id="test">
<div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
{% for tag in tags %}
<label id="tag_{{tag.id}}" class="btn btn-primary tags_click">
<input type="checkbox" autocomplete="off" name="include_tag" value="{{tag.id}}">{{tag.name}}</input>
<input type="checkbox" autocomplete="off" name="include_tag" id="include_tag" value="{{tag.id}}">{{tag.name}}</input>
</label>
{% endfor %}
</div>
</div>
<label for="Tags">{{_('Exclude Tags')}}</label>
<label for="exclude_tag">{{_('Exclude Tags')}}</label>
<div class="form-group">
<div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
{% for tag in tags %}
<label id="tag_{{tag.id}}" class="btn btn-danger tags_click">
<input type="checkbox" autocomplete="off" name="exclude_tag" value="{{tag.id}}">{{tag.name}}</input>
<input type="checkbox" autocomplete="off" name="exclude_tag" id="exclude_tag" value="{{tag.id}}">{{tag.name}}</input>
</label>
{% endfor %}
</div>
</div>
<label for="Series">{{_('Series')}}</label>
<label for="include_serie">{{_('Series')}}</label>
<div class="form-group">
<div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
{% for serie in series %}
<label id="serie_{{serie.id}}" class="btn btn-primary serie_click">
<input type="checkbox" autocomplete="off" name="include_serie" value="{{serie.id}}">{{serie.name}}</input>
<input type="checkbox" autocomplete="off" name="include_serie" id="include_serie" value="{{serie.id}}">{{serie.name}}</input>
</label>
{% endfor %}
</div>
</div>
<label for="Series">{{_('Exclude Series')}}</label>
<label for="exclude_serie">{{_('Exclude Series')}}</label>
<div class="form-group">
<div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
{% for serie in series %}
<label id="serie_{{serie.id}}" class="btn btn-danger serie_click">
<input type="checkbox" autocomplete="off" name="exclude_serie" value="{{serie.id}}">{{serie.name}}</input>
<input type="checkbox" autocomplete="off" name="exclude_serie" id="exclude_serie" value="{{serie.id}}">{{serie.name}}</input>
</label>
{% endfor %}
</div>
</div>
{% if languages %}
<label for="Languages">{{_('Languages')}}</label>
<label for="include_language">{{_('Languages')}}</label>
<div class="form-group">
<div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
{% for language in languages %}
<label id="language_{{language.id}}" class="btn btn-primary serie_click">
<input type="checkbox" autocomplete="off" name="include_language" value="{{language.id}}">{{language.name}}</input>
<input type="checkbox" autocomplete="off" name="include_language" id="include_language" value="{{language.id}}">{{language.name}}</input>
</label>
{% endfor %}
</div>
</div>
<label for="Languages">{{_('Exclude Languages')}}</label>
<label for="exclude_language">{{_('Exclude Languages')}}</label>
<div class="form-group">
<div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
{% for language in languages %}
<label id="language_{{language.id}}" class="btn btn-danger language_click">
<input type="checkbox" autocomplete="off" name="exclude_language" value="{{language.id}}">{{language.name}}</input>
<input type="checkbox" autocomplete="off" name="exclude_language" id="exclude_language" value="{{language.id}}">{{language.name}}</input>
</label>
{% endfor %}
</div>

View File

@ -1,7 +1,27 @@
{% extends "layout.html" %}
{% block body %}
<h3>{{_('Calibre library statistics')}}</h3>
<table id="stats" class="table">
<tbody>
<tr>
<th>{{bookcounter}}</th>
<td>{{_('Books in this Library')}}</td>
</tr>
<tr>
<th>{{authorcounter}}</th>
<td>{{_('Authors in this Library')}}</td>
</tr>
<tr>
<th>{{categorycounter}}</th>
<td>{{_('Categories in this Library')}}</td>
</tr>
<tr>
<th>{{seriecounter}}</th>
<td>{{_('Series in this Library')}}</td>
</tr>
</tbody>
</table>
<h3>{{_('Linked libraries')}}</h3>
<table id="libs" class="table">
<thead>
<tr>
@ -24,30 +44,51 @@
</tr>
<tr>
<th>PyPDF2</th>
<td>{{versions['PyPdfVersion']}}</td>
<td>v{{versions['PyPdfVersion']}}</td>
</tr>
<tr>
<th>Babel</th>
<td>v{{versions['babel']}}</td>
</tr>
<tr>
<th>SqlAlchemy</th>
<td>v{{versions['sqlalchemy']}}</td>
</tr>
<tr>
<th>Flask</th>
<td>v{{versions['flask']}}</td>
</tr>
<tr>
<th>Flask Login</th>
<td>v{{versions['flasklogin']}}</td>
</tr>
<tr>
<th>Flask Principal</th>
<td>v{{versions['flask_principal']}}</td>
</tr>
<tr>
<th>Tornado web server</th>
<td>v{{versions['tornado']}}</td>
</tr>
<tr>
<th>ISO639 Languages</th>
<td>v{{versions['iso639']}}</td>
</tr>
<tr>
<th>Requests</th>
<td>v{{versions['requests']}}</td>
</tr>
<tr>
<th>SQlite</th>
<td>v{{versions['sqlite']}}</td>
</tr>
<tr>
<th>Pysqlite</th>
<td>v{{versions['pysqlite']}}</td>
</tr>
</tbody>
</table>
<h3>{{_('Calibre library statistics')}}</h3>
<table id="stats" class="table">
<tbody>
<tr>
<th>{{bookcounter}}</th>
<td>{{_('Books in this Library')}}</td>
</tr>
<tr>
<th>{{authorcounter}}</th>
<td>{{_('Authors in this Library')}}</td>
</tr>
<tr>
<th>{{categorycounter}}</th>
<td>{{_('Categories in this Library')}}</td>
</tr>
<tr>
<th>{{seriecounter}}</th>
<td>{{_('Series in this Library')}}</td>
</tr>
</tbody>
</table>
{% endblock %}

View File

@ -40,6 +40,8 @@
{% endfor %}
</select>
</div>
<div class="col-sm-6">
<div class="form-group">
<input type="checkbox" name="show_random" id="show_random" {% if content.show_random_books() %}checked{% endif %}>
<label for="show_random">{{_('Show random books')}}</label>
@ -72,7 +74,8 @@
<input type="checkbox" name="show_detail_random" id="show_detail_random" {% if content.show_detail_random() %}checked{% endif %}>
<label for="show_detail_random">{{_('Show random books in detail view')}}</label>
</div>
</div>
<div class="col-sm-6">
{% if g.user and g.user.role_admin() and not profile %}
{% if not content.role_anonymous() %}
<div class="form-group">
@ -106,13 +109,17 @@
</label>
</div>
{% endif %}
</div>
<div class="col-sm-12">
<button type="submit" id="submit" class="btn btn-default">{{_('Submit')}}</button>
{% if not profile %}
<a href="{{ url_for('admin') }}" id="back" class="btn btn-default">{{_('Back')}}</a>
</div>
{% endif %}
</form>
{% if downloads %}
<div class="col-sm-12">
<h2>{{_('Recent Downloads')}}</h2>
{% for entry in downloads %}
<div class="col-sm-2">
@ -121,6 +128,7 @@
</a>
</div>
{% endfor %}
</div>
{% endif %}
</div>
{% endblock %}

View File

@ -61,31 +61,31 @@ msgstr "游客"
#: cps/web.py:734
msgid "Requesting update package"
msgstr ""
msgstr "正在请求更新包"
#: cps/web.py:735
msgid "Downloading update package"
msgstr ""
msgstr "正在下载更新包"
#: cps/web.py:736
msgid "Unzipping update package"
msgstr ""
msgstr "正在解压更新包"
#: cps/web.py:737
msgid "Files are replaced"
msgstr ""
msgstr "文件已替换"
#: cps/web.py:738
msgid "Database connections are closed"
msgstr ""
msgstr "数据库连接已关闭"
#: cps/web.py:739
msgid "Server is stopped"
msgstr ""
msgstr "服务器已停止"
#: cps/web.py:740
msgid "Update finished, please press okay and reload page"
msgstr ""
msgstr "更新完成,请按确定并刷新页面"
#: cps/web.py:810
msgid "Latest Books"
@ -97,7 +97,7 @@ msgstr "热门书籍(最多下载)"
#: cps/web.py:845
msgid "Best rated books"
msgstr ""
msgstr "最高评分书籍"
#: cps/templates/index.xml:36 cps/web.py:854
msgid "Random Books"
@ -108,9 +108,9 @@ msgid "Author list"
msgstr "作者列表"
#: cps/web.py:878
#, python-format
#, python-forma
msgid "Author: %(name)s"
msgstr ""
msgstr "作者: %(name)s"
#: cps/web.py:880 cps/web.py:908 cps/web.py:1007 cps/web.py:1235
#: cps/web.py:2115
@ -150,7 +150,7 @@ msgstr "统计"
#: cps/web.py:1061
msgid "Server restarted, please reload page"
msgstr ""
msgstr "服务器已重启,请刷新页面"
#: cps/web.py:1063
msgid "Performing shutdown of server, please close window"
@ -158,7 +158,7 @@ msgstr "正在关闭服务器,请关闭窗口"
#: cps/web.py:1073
msgid "Update done"
msgstr ""
msgstr "更新完成"
#: cps/web.py:1147 cps/web.py:1160
msgid "search"
@ -475,11 +475,11 @@ msgstr "管理"
#: cps/templates/admin.html:80
msgid "Current commit timestamp"
msgstr ""
msgstr "当前提交时间戳"
#: cps/templates/admin.html:81
msgid "Newest commit timestamp"
msgstr ""
msgstr "最新提交时间戳"
#: cps/templates/admin.html:83
msgid "Restart Calibre-web"
@ -491,11 +491,11 @@ msgstr "停止 Calibre-web"
#: cps/templates/admin.html:85
msgid "Check for update"
msgstr ""
msgstr "检查更新"
#: cps/templates/admin.html:86
msgid "Perform Update"
msgstr ""
msgstr "执行更新"
#: cps/templates/admin.html:96
msgid "Do you really want to restart Calibre-web?"
@ -519,7 +519,7 @@ msgstr "您确定要关闭 Calibre-web 吗?"
#: cps/templates/admin.html:127
msgid "Updating, please do not reload page"
msgstr ""
msgstr "正在更新,请不要刷新页面"
#: cps/templates/book_edit.html:16 cps/templates/search_form.html:6
msgid "Book Title"
@ -610,7 +610,7 @@ msgstr "启用注册"
#: cps/templates/config_edit.html:52
msgid "Default Settings for new users"
msgstr ""
msgstr "新用户默认设置"
#: cps/templates/config_edit.html:55 cps/templates/user_edit.html:80
msgid "Admin user"
@ -651,7 +651,7 @@ msgstr "语言"
#: cps/templates/detail.html:74
msgid "Publishing date"
msgstr ""
msgstr "出版日期"
#: cps/templates/detail.html:106
msgid "Description:"
@ -723,11 +723,11 @@ msgstr "热门书籍"
#: cps/templates/index.xml:19
msgid "Popular publications from this catalog based on Downloads."
msgstr ""
msgstr "基于下载数的热门书籍"
#: cps/templates/index.xml:22 cps/templates/layout.html:129
msgid "Best rated Books"
msgstr ""
msgstr "最高评分书籍"
#: cps/templates/index.xml:26
msgid "Popular publications from this catalog based on Rating."
@ -933,11 +933,11 @@ msgstr "个作者在此书库"
#: cps/templates/stats.html:45
msgid "Categories in this Library"
msgstr ""
msgstr "个分类在此书库"
#: cps/templates/stats.html:49
msgid "Series in this Library"
msgstr ""
msgstr "个丛书在此书库"
#: cps/templates/user_edit.html:23
msgid "Kindle E-Mail"
@ -961,7 +961,7 @@ msgstr "显示热门书籍"
#: cps/templates/user_edit.html:53
msgid "Show best rated books"
msgstr ""
msgstr "显示最高评分书籍"
#: cps/templates/user_edit.html:57
msgid "Show language selection"

View File

@ -7,7 +7,6 @@ from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import *
from flask_login import AnonymousUserMixin
import os
import traceback
import logging
from werkzeug.security import generate_password_hash
from flask_babel import gettext as _

View File

@ -4,8 +4,9 @@ import mimetypes
import logging
from logging.handlers import RotatingFileHandler
import textwrap
from flask import Flask, render_template, session, request, Response, redirect, url_for, send_from_directory, \
from flask import Flask, render_template, request, Response, redirect, url_for, send_from_directory, \
make_response, g, flash, abort
from flask import __version__ as flaskVersion
import ub
from ub import config
import helper
@ -14,9 +15,12 @@ import errno
from sqlalchemy.sql.expression import func
from sqlalchemy.sql.expression import false
from sqlalchemy.exc import IntegrityError
from sqlalchemy import __version__ as sqlalchemyVersion
from math import ceil
from flask_login import LoginManager, login_user, logout_user, login_required, current_user
from flask_login import __version__ as flask_loginVersion
from flask_principal import Principal, Identity, AnonymousIdentity, identity_changed
from flask_login import __version__ as flask_principalVersion
from flask_babel import Babel
from flask_babel import gettext as _
import requests
@ -24,6 +28,7 @@ import zipfile
from werkzeug.security import generate_password_hash, check_password_hash
from babel import Locale as LC
from babel import negotiate_locale
from babel import __version__ as babelVersion
from babel.dates import format_date
from functools import wraps
import base64
@ -32,16 +37,16 @@ import json
import urllib
import datetime
from iso639 import languages as isoLanguages
from iso639 import __version__ as iso639Version
from uuid import uuid4
import os.path
import sys
import subprocess
import re
import db
import thread
from shutil import move, copyfile
from tornado.ioloop import IOLoop
from tornado import version as tornadoVersion
try:
from wand.image import Image
@ -51,6 +56,7 @@ except ImportError, e:
use_generic_pdf_cover = True
from cgi import escape
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'djvu', 'prc', 'doc', 'docx', 'fb2'])
# Proxy Helper class
class ReverseProxied(object):
@ -473,8 +479,10 @@ def feed_search(term):
filter = True
if term:
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()
db.Books.series.any(db.Series.name.like("%" + term + "%")),
db.Books.authors.any(db.Authors.name.like("%" + term + "%")),
db.Books.publishers.any(db.Publishers.name.like("%" + term + "%")),
db.Books.title.like("%" + term + "%"))).filter(filter).all()
entriescount = len(entries) if len(entries) > 0 else 1
pagination = Pagination(1, entriescount, entriescount)
xml = render_title_template('feed.xml', searchterm=term, entries=entries, pagination=pagination)
@ -1039,6 +1047,17 @@ def stats():
if re.search('Amazon kindlegen\(', lines):
versions['KindlegenVersion'] = lines
versions['PythonVersion'] = sys.version
versions['babel'] = babelVersion
versions['sqlalchemy'] = sqlalchemyVersion
versions['flask'] = flaskVersion
versions['flasklogin'] = flask_loginVersion
versions['flask_principal'] = flask_principalVersion
versions['tornado'] = tornadoVersion
versions['iso639'] = iso639Version
versions['requests'] = requests.__version__
versions['pysqlite'] = db.engine.dialect.dbapi.version
versions['sqlite'] = db.engine.dialect.dbapi.sqlite_version
return render_title_template('stats.html', bookcounter=counter, authorcounter=authors, versions=versions,
categorycounter=categorys, seriecounter=series, title=_(u"Statistics"))
@ -1087,9 +1106,10 @@ def search():
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()
db.Books.series.any(db.Series.name.like("%" + term + "%")),
db.Books.authors.any(db.Authors.name.like("%" + term + "%")),
db.Books.publishers.any(db.Publishers.name.like("%" + term + "%")),
db.Books.title.like("%" + term + "%"))).filter(filter).all()
return render_title_template('search.html', searchterm=term, entries=entries)
else:
return render_title_template('search.html', searchterm="")
@ -1109,12 +1129,14 @@ def advanced_search():
author_name = request.args.get("author_name")
book_title = request.args.get("book_title")
publisher = request.args.get("publisher")
if author_name: author_name = author_name.strip()
if book_title: book_title = book_title.strip()
if publisher: publisher = publisher.strip()
if include_tag_inputs or exclude_tag_inputs or include_series_inputs or exclude_series_inputs or \
include_languages_inputs or exclude_languages_inputs or author_name or book_title:
include_languages_inputs or exclude_languages_inputs or author_name or book_title or publisher:
searchterm = []
searchterm.extend((author_name, book_title))
searchterm.extend((author_name, book_title, publisher))
tag_names = db.session.query(db.Tags).filter(db.Tags.id.in_(include_tag_inputs)).all()
searchterm.extend(tag.name for tag in tag_names)
# searchterm = " + ".join(filter(None, searchterm))
@ -1130,7 +1152,8 @@ def advanced_search():
searchterm.extend(language.name for language in language_names)
searchterm = " + ".join(filter(None, searchterm))
q = q.filter(db.Books.authors.any(db.Authors.name.like("%" + author_name + "%")),
db.Books.title.like("%" + book_title + "%"))
db.Books.title.like("%" + book_title + "%"),
db.Books.publishers.any(db.Publishers.name.like("%" + publisher + "%")))
for tag in include_tag_inputs:
q = q.filter(db.Books.tags.any(db.Tags.id == tag))
for tag in exclude_tag_inputs:
@ -1180,7 +1203,7 @@ def feed_get_cover(book_id):
@app.route("/read/<int:book_id>/<format>")
@login_required
@login_required_if_no_ano
def read_book(book_id, format):
book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
if book:
@ -1789,6 +1812,8 @@ def edit_mailsettings():
category="success")
else:
flash(_(u"There was an error sending the Test E-Mail: %(res)s", res=result), category="error")
else:
flash(_(u"E-Mail settings updated"), category="success")
return render_title_template("email_edit.html", content=content, title=_(u"Edit mail settings"))
@ -2130,6 +2155,18 @@ def upload():
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']
if '.' in file.filename:
file_ext = file.filename.rsplit('.', 1)[-1].lower()
if file_ext not in ALLOWED_EXTENSIONS:
flash(
_('File extension "%s" is not allowed to be uploaded to this server' %
file_ext),
category="error"
)
return redirect(url_for('index'))
else:
flash(_('File to be uploaded must have an extension'), category="error")
return redirect(url_for('index'))
meta = uploader.upload(file)
title = meta.title