Merge branch 'master' into develop

# Conflicts:
#	cps/db.py
#	cps/web.py
This commit is contained in:
Jack Darlington 2017-02-26 19:49:49 +00:00
commit d9c48a6203
12 changed files with 170 additions and 64 deletions

View File

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

View File

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

View File

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

View File

@ -144,10 +144,10 @@
</div> </div>
{% endif %} {% endif %}
{% if g.user.is_authenticated %} {% if g.user.kindle_mail and g.user.is_authenticated %}
{% if g.user.kindle_mail %}
<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> <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 %} {% endif %}
{% if (g.user.role_download() and g.user.is_anonymous()) or g.user.is_authenticated %}
<div class="btn-group" role="group"> <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"> <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')}} <span class="glyphicon glyphicon-eye-open"></span> {{_('Read in browser')}}

View File

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

View File

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

View File

@ -1,7 +1,27 @@
{% extends "layout.html" %} {% extends "layout.html" %}
{% block body %} {% 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> <h3>{{_('Linked libraries')}}</h3>
<table id="libs" class="table"> <table id="libs" class="table">
<thead> <thead>
<tr> <tr>
@ -24,30 +44,51 @@
</tr> </tr>
<tr> <tr>
<th>PyPDF2</th> <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> </tr>
</tbody> </tbody>
</table> </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 %} {% endblock %}

View File

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

View File

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

View File

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

View File

@ -8,6 +8,7 @@ from logging.handlers import RotatingFileHandler
import textwrap import textwrap
from flask import Flask, render_template, session, request, Response, redirect, url_for, send_from_directory, \ from flask import Flask, render_template, session, request, Response, redirect, url_for, send_from_directory, \
make_response, g, flash, abort, send_file make_response, g, flash, abort, send_file
from flask import __version__ as flaskVersion
import ub import ub
from ub import config from ub import config
import helper import helper
@ -16,9 +17,12 @@ import errno
from sqlalchemy.sql.expression import func from sqlalchemy.sql.expression import func
from sqlalchemy.sql.expression import false from sqlalchemy.sql.expression import false
from sqlalchemy.exc import IntegrityError from sqlalchemy.exc import IntegrityError
from sqlalchemy import __version__ as sqlalchemyVersion
from math import ceil from math import ceil
from flask_login import LoginManager, login_user, logout_user, login_required, current_user 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_principal import Principal, Identity, AnonymousIdentity, identity_changed
from flask_login import __version__ as flask_principalVersion
from flask_babel import Babel from flask_babel import Babel
from flask_babel import gettext as _ from flask_babel import gettext as _
import requests import requests
@ -26,6 +30,7 @@ import zipfile
from werkzeug.security import generate_password_hash, check_password_hash from werkzeug.security import generate_password_hash, check_password_hash
from babel import Locale as LC from babel import Locale as LC
from babel import negotiate_locale from babel import negotiate_locale
from babel import __version__ as babelVersion
from babel.dates import format_date from babel.dates import format_date
from functools import wraps from functools import wraps
import base64 import base64
@ -34,13 +39,13 @@ import json
import urllib import urllib
import datetime import datetime
from iso639 import languages as isoLanguages from iso639 import languages as isoLanguages
from iso639 import __version__ as iso639Version
from uuid import uuid4 from uuid import uuid4
import os.path import os.path
import sys import sys
import subprocess import subprocess
import re import re
import db import db
import thread
from shutil import move, copyfile from shutil import move, copyfile
from tornado.ioloop import IOLoop from tornado.ioloop import IOLoop
import shutil import shutil
@ -50,6 +55,8 @@ import io
import hashlib import hashlib
import threading import threading
from tornado import version as tornadoVersion
import time import time
current_milli_time = lambda: int(round(time.time() * 1000)) current_milli_time = lambda: int(round(time.time() * 1000))
@ -66,6 +73,8 @@ from cgi import escape
gdrive_watch_callback_token='target=calibreweb-watch_files' gdrive_watch_callback_token='target=calibreweb-watch_files'
global_task = None global_task = None
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'djvu', 'prc', 'doc', 'docx', 'fb2'])
def md5(fname): def md5(fname):
hash_md5 = hashlib.md5() hash_md5 = hashlib.md5()
with open(fname, "rb") as f: with open(fname, "rb") as f:
@ -1162,6 +1171,17 @@ def stats():
if re.search('Amazon kindlegen\(', lines): if re.search('Amazon kindlegen\(', lines):
versions['KindlegenVersion'] = lines versions['KindlegenVersion'] = lines
versions['PythonVersion'] = sys.version 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, return render_title_template('stats.html', bookcounter=counter, authorcounter=authors, versions=versions,
categorycounter=categorys, seriecounter=series, title=_(u"Statistics")) categorycounter=categorys, seriecounter=series, title=_(u"Statistics"))
@ -1457,7 +1477,7 @@ def unread_books(page):
return render_read_books(page, False) return render_read_books(page, False)
@app.route("/read/<int:book_id>/<format>") @app.route("/read/<int:book_id>/<format>")
@login_required @login_required_if_no_ano
def read_book(book_id, format): def read_book(book_id, format):
book = db.session.query(db.Books).filter(db.Books.id == book_id).first() book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
if book: if book:
@ -2105,6 +2125,8 @@ def edit_mailsettings():
category="success") category="success")
else: else:
flash(_(u"There was an error sending the Test E-Mail: %(res)s", res=result), category="error") 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")) return render_title_template("email_edit.html", content=content, title=_(u"Edit mail settings"))
@ -2448,6 +2470,18 @@ def upload():
db.session.connection().connection.connection.create_function('uuid4', 0, lambda: str(uuid4())) db.session.connection().connection.connection.create_function('uuid4', 0, lambda: str(uuid4()))
if request.method == 'POST' and 'btn-upload' in request.files: if request.method == 'POST' and 'btn-upload' in request.files:
file = request.files['btn-upload'] 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) meta = uploader.upload(file)
title = meta.title title = meta.title