Commit 0307ab6f authored by Radosław Kierznowski's avatar Radosław Kierznowski

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

parents 437358d6 ed459ddb
......@@ -99,7 +99,7 @@ def pdf_preview(tmp_file_path, tmp_dir):
return None
else:
cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jpg"
with Image(filename=tmp_file_path +"[0]", resolution=150) as img:
with Image(filename=tmp_file_path + "[0]", resolution=150) as img:
img.compression_quality = 88
img.save(filename=os.path.join(tmp_dir, cover_file_name))
return cover_file_name
......
......@@ -32,29 +32,29 @@ def title_sort(title):
Base = declarative_base()
books_authors_link = Table('books_authors_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('author', Integer, ForeignKey('authors.id'), primary_key=True)
)
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('author', Integer, ForeignKey('authors.id'), primary_key=True)
)
books_tags_link = Table('books_tags_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('tag', Integer, ForeignKey('tags.id'), primary_key=True)
)
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('tag', Integer, ForeignKey('tags.id'), primary_key=True)
)
books_series_link = Table('books_series_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('series', Integer, ForeignKey('series.id'), primary_key=True)
)
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('series', Integer, ForeignKey('series.id'), primary_key=True)
)
books_ratings_link = Table('books_ratings_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('rating', Integer, ForeignKey('ratings.id'), primary_key=True)
)
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('rating', Integer, ForeignKey('ratings.id'), primary_key=True)
)
books_languages_link = Table('books_languages_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('lang_code', Integer, ForeignKey('languages.id'), primary_key=True)
)
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('lang_code', Integer, ForeignKey('languages.id'), primary_key=True)
)
class Identifiers(Base):
......@@ -227,7 +227,7 @@ class Books(Base):
identifiers = relationship('Identifiers', backref='books')
def __init__(self, title, sort, author_sort, timestamp, pubdate, series_index, last_modified, path, has_cover,
authors, tags): # ToDO check Authors and tags necessary
authors, tags):
self.title = title
self.sort = sort
self.author_sort = author_sort
......
......@@ -6,7 +6,7 @@ import os
import uploader
import StringIO
# ToDo: Check usage of original_file_name
def get_fb2_info(tmp_file_path, original_file_extension):
ns = {
......@@ -20,37 +20,35 @@ def get_fb2_info(tmp_file_path, original_file_extension):
authors = tree.xpath('/fb:FictionBook/fb:description/fb:title-info/fb:author', namespaces=ns)
def get_author(element):
last_name=element.xpath('fb:last-name/text()', namespaces=ns)
last_name = element.xpath('fb:last-name/text()', namespaces=ns)
if len(last_name):
last_name=last_name[0]
last_name = last_name[0]
else:
last_name=u''
middle_name=element.xpath('fb:middle-name/text()', namespaces=ns)
last_name = u''
middle_name = element.xpath('fb:middle-name/text()', namespaces=ns)
if len(middle_name):
middle_name=middle_name[0]
middle_name = middle_name[0]
else:
middle_name=u''
first_name=element.xpath('fb:first-name/text()', namespaces=ns)
middle_name = u''
first_name = element.xpath('fb:first-name/text()', namespaces=ns)
if len(first_name):
first_name=first_name[0]
first_name = first_name[0]
else:
first_name=u''
return first_name + ' ' + middle_name + ' ' + last_name
first_name = u''
return first_name + ' ' + middle_name + ' ' + last_name
author = unicode(", ".join(map(get_author, authors)))
title = tree.xpath('/fb:FictionBook/fb:description/fb:title-info/fb:book-title/text()', namespaces=ns)
if len(title):
title=unicode(title[0])
title = unicode(title[0])
else:
title=u''
title = u''
description = tree.xpath('/fb:FictionBook/fb:description/fb:publish-info/fb:book-name/text()', namespaces=ns)
if len(description):
description=unicode(description[0])
description = unicode(description[0])
else:
description=u''
description = u''
return uploader.BookMeta(
file_path=tmp_file_path,
......
......@@ -22,6 +22,11 @@ from email.generator import Generator
from flask_babel import gettext as _
import subprocess
import shutil
try:
import unidecode
use_unidecode=True
except:
use_unidecode=False
def update_download(book_id, user_id):
check = ub.session.query(ub.Downloads).filter(ub.Downloads.user_id == user_id).filter(ub.Downloads.book_id ==
......@@ -203,7 +208,7 @@ def get_attachment(file_path):
return attachment
except IOError:
traceback.print_exc()
message = (_('The requested file could not be read. Maybe wrong permissions?')) # ToDo: What is this?
app.logger.error = (u'The requested file could not be read. Maybe wrong permissions?')
return None
......@@ -212,47 +217,54 @@ def get_valid_filename(value, replace_whitespace=True):
Returns the given string converted to a string that can be used for a clean
filename. Limits num characters to 128 max.
"""
value = value[:128]
# re_slugify = re.compile('[^\w\s-]', re.UNICODE)
value = unicodedata.normalize('NFKD', value)
re_slugify = re.compile('[^\w\s-]', re.UNICODE)
value = unicode(re_slugify.sub('', value).strip())
if value[-1:] ==u'.':
value = value[:-1]+u'_'
if use_unidecode:
value=(unidecode.unidecode(value)).strip()
else:
value=value.replace('§','SS')
value=value.replace('ß','ss')
value = unicodedata.normalize('NFKD', value)
re_slugify = re.compile('[\W\s-]', re.UNICODE)
value = unicode(re_slugify.sub('', value).strip())
if replace_whitespace:
value = re.sub('[\s]+', '_', value, flags=re.U)
value = value.replace(u"\u00DF", "ss")
#*+:\"/<>? werden durch _ ersetzt
value = re.sub('[\*\+:\\\"/<>\?]+', '_', value, flags=re.U)
value = value[:128]
return value
def get_sorted_author(value):
regexes = ["^(JR|SR)\.?$","^I{1,3}\.?$","^IV\.?$"]
combined = "(" + ")|(".join(regexes) + ")"
value = value.split(" ")
if re.match(combined,value[-1].upper()):
value2 = value[-2] + ", " + " ".join(value[:-2]) + " " + value[-1]
else:
value2 = value[-1] + ", " + " ".join(value[:-1])
return value2
def get_normalized_author(value):
"""
Normalizes sorted author name
"""
value = unicodedata.normalize('NFKD', value)
value = re.sub('[^\w,\s]', '', value, flags=re.U)
value = " ".join(value.split(", ")[::-1])
return value
def update_dir_stucture(book_id, calibrepath):
db.session.connection().connection.connection.create_function("title_sort", 1, db.title_sort)
book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
path = os.path.join(calibrepath, book.path)
path = os.path.join(calibrepath, book.path)#.replace('/',os.path.sep)).replace('\\',os.path.sep)
authordir = book.path.split(os.sep)[0]
new_authordir = get_valid_filename(book.authors[0].name, False)
titledir = book.path.split(os.sep)[1]
new_titledir = get_valid_filename(book.title, False) + " (" + str(book_id) + ")"
authordir = book.path.split('/')[0]
new_authordir = get_valid_filename(book.authors[0].name)
titledir = book.path.split('/')[1]
new_titledir = get_valid_filename(book.title) + " (" + str(book_id) + ")"
if titledir != new_titledir:
new_title_path = os.path.join(os.path.dirname(path), new_titledir)
os.rename(path, new_title_path)
path = new_title_path
book.path = book.path.split(os.sep)[0] + os.sep + new_titledir
book.path = book.path.split('/')[0] + '/' + new_titledir
if authordir != new_authordir:
new_author_path = os.path.join(os.path.join(calibrepath, new_authordir), os.path.basename(path))
os.renames(path, new_author_path)
book.path = new_authordir + os.sep + book.path.split(os.sep)[1]
os.rename(path, new_author_path)
book.path = new_authordir + '/' + book.path.split('/')[1]
db.session.commit()
......
......@@ -2,7 +2,7 @@
{% block body %}
<div class="discover">
<h2>{{_('User list')}}</h2>
<table class="table table-striped">
<table class="table table-striped" id="table_user">
<tr>
<th>{{_('Nickname')}}</th>
<th>{{_('Email')}}</th>
......@@ -30,9 +30,9 @@
{% endif %}
{% endfor %}
</table>
<div class="btn btn-default"><a href="{{url_for('new_user')}}">{{_('Add new user')}}</a></div>
<div class="btn btn-default" id="admin_new_user"><a href="{{url_for('new_user')}}">{{_('Add new user')}}</a></div>
<h2>{{_('SMTP mail settings')}}</h2>
<table class="table table-striped">
<table class="table table-striped" id="table_email">
<tr>
<th>{{_('SMTP hostname')}}</th>
<th>{{_('SMTP port')}}</th>
......@@ -51,10 +51,10 @@
</table>
<div class="btn btn-default"><a href="{{url_for('edit_mailsettings')}}">{{_('Change SMTP settings')}}</a></div>
<div class="btn btn-default" id="admin_edit_email"><a href="{{url_for('edit_mailsettings')}}">{{_('Change SMTP settings')}}</a></div>
<h2>{{_('Configuration')}}</h2>
<table class="table table-striped">
<table class="table table-striped" id="table_configuration">
<tr>
<th>{{_('Calibre DB dir')}}</th>
<th>{{_('Log Level')}}</th>
......@@ -76,6 +76,7 @@
<div class="btn btn-default"><a href="{{url_for('configuration')}}">{{_('Configuration')}}</a></div>
<h2>{{_('Administration')}}</h2>
{% if not development %}
<p>{{_('Current commit timestamp')}}: {{commit}} </p>
<div class="btn btn-default" data-toggle="modal" data-target="#RestartDialog">{{_('Restart Calibre-web')}}</a></div>
<div class="btn btn-default" data-toggle="modal" data-target="#ShutdownDialog">{{_('Stop Calibre-web')}}</a></div>
<div class="btn btn-default" id="check_for_update">{{_('Check for update')}}</a></div>
......
{% extends "layout.html" %}
{% block body %}
<div class="discover">
<h1>{{title}}</h1>
<h2>{{title}}</h2>
<form role="form" method="POST" autocomplete="off">
<div class="form-group required">
<label for="config_calibre_dir">{{_('Location of Calibre database')}}</label>
......@@ -49,6 +49,27 @@
<input type="checkbox" id="config_public_reg" name="config_public_reg" {% if content.config_public_reg %}checked{% endif %}>
<label for="config_public_reg">{{_('Enable public registration')}}</label>
</div>
<h2>{{_('Default Settings for new users')}}</h2>
<div class="form-group">
<input type="checkbox" name="admin_role" id="admin_role" {% if content.role_admin() %}checked{% endif %}>
<label for="admin_role">{{_('Admin user')}}</label>
</div>
<div class="form-group">
<input type="checkbox" name="download_role" id="download_role" {% if content.role_download() %}checked{% endif %}>
<label for="download_role">{{_('Allow Downloads')}}</label>
</div>
<div class="form-group">
<input type="checkbox" name="upload_role" id="upload_role" {% if content.role_upload() %}checked{% endif %}>
<label for="upload_role">{{_('Allow Uploads')}}</label>
</div>
<div class="form-group">
<input type="checkbox" name="edit_role" id="edit_role" {% if content.role_edit() %}checked{% endif %}>
<label for="edit_role">{{_('Allow Edit')}}</label>
</div>
<div class="form-group">
<input type="checkbox" name="passwd_role" id="passwd_role" {% if content.role_passwd() %}checked{% endif %}>
<label for="passwd_role">{{_('Allow Changing Password')}}</label>
</div>
<button type="submit" class="btn btn-default">{{_('Submit')}}</button>
{% if not origin %}
<a href="{{ url_for('admin') }}" class="btn btn-default">{{_('Back')}}</a>
......
......@@ -70,8 +70,8 @@
</div>
</p>
{% endif %}
{% if entry.pubdate != '0101-01-01 00:00:00' %}
<p>{{_('Publishing date')}}: {{entry.pubdate[:10]}} </p>
{% if entry.pubdate[:10] != '0101-01-01' %}
<p>{{_('Publishing date')}}: {{entry.pubdate|formatdate}} </p>
{% endif %}
{% if cc|length > 0 %}
<p>
......
......@@ -6,7 +6,7 @@
<div class="row">
{% for entry in random %}
<div class="col-sm-3 col-lg-2 col-xs-6 book">
<div id="books_rand" class="col-sm-3 col-lg-2 col-xs-6 book">
<div class="cover">
<a href="{{ url_for('show_book', id=entry.id) }}">
{% if entry.has_cover %}
......@@ -41,7 +41,7 @@
<h2>{{title}}</h2>
<div class="row">
{% for entry in entries %}
<div class="col-sm-3 col-lg-2 col-xs-6 book">
<div id="books" class="col-sm-3 col-lg-2 col-xs-6 book">
<div class="cover">
<a href="{{ url_for('show_book', id=entry.id) }}">
{% if entry.has_cover %}
......
......@@ -5,7 +5,7 @@
{% for lang in languages %}
<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 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>
{% endfor %}
</div>
......
......@@ -80,16 +80,16 @@
{% endif %}
{% endif %}
{% if g.user.role_admin() %}
<li><a href="{{url_for('admin')}}"><span class="glyphicon glyphicon-dashboard"></span> {{_('Admin')}}</a></li>
<li><a id="top_admin" href="{{url_for('admin')}}"><span class="glyphicon glyphicon-dashboard"></span> {{_('Admin')}}</a></li>
{% endif %}
<li><a href="{{url_for('profile')}}"><span class="glyphicon glyphicon-user"></span> {{g.user.nickname}}</a></li>
<li><a id="top_user" href="{{url_for('profile')}}"><span class="glyphicon glyphicon-user"></span> {{g.user.nickname}}</a></li>
{% if not g.user.is_anonymous() %}
<li><a href="{{url_for('logout')}}"><span class="glyphicon glyphicon-log-out"></span> {{_('Logout')}}</a></li>
<li><a id="logout" href="{{url_for('logout')}}"><span class="glyphicon glyphicon-log-out"></span> {{_('Logout')}}</a></li>
{% endif %}
{% endif %}
{% if g.allow_registration and not g.user.is_authenticated %}
<li><a href="{{url_for('login')}}"><span class="glyphicon glyphicon-log-in"></span> {{_('Login')}}</a></li>
<li><a href="{{url_for('register')}}"><span class="glyphicon glyphicon-user"></span> {{_('Register')}}</a></li>
<li><a id="login" href="{{url_for('login')}}"><span class="glyphicon glyphicon-log-in"></span> {{_('Login')}}</a></li>
<li><a id="register" href="{{url_for('register')}}"><span class="glyphicon glyphicon-user"></span> {{_('Register')}}</a></li>
{% endif %}
</ul>
</div><!--/.nav-collapse -->
......@@ -98,17 +98,17 @@
{% for message in get_flashed_messages(with_categories=True) %}
{%if message[0] == "error" %}
<div class="row-fluid" style="margin-top: -20px; text-align: center;">
<div class="alert alert-danger">{{ message[1] }}</div>
<div id="flash_alert" class="alert alert-danger">{{ message[1] }}</div>
</div>
{%endif%}
{%if message[0] == "info" %}
<div class="row-fluid" style="margin-top: -20px; text-align: center;">
<div class="alert alert-info">{{ message[1] }}</div>
<div id="flash_info" class="alert alert-info">{{ message[1] }}</div>
</div>
{%endif%}
{%if message[0] == "success" %}
<div class="row-fluid" style="margin-top: -20px; text-align: center;">
<div class="alert alert-success">{{ message[1] }}</div>
<div id="flash_success" class="alert alert-success">{{ message[1] }}</div>
</div>
{%endif%}
{% endfor %}
......@@ -119,25 +119,25 @@
<nav class="navigation">
<ul class="list-unstyled" id="scnd-nav" intent in-standard-append="nav.navigation" in-mobile-after="#main-nav" in-mobile-class="nav navbar-nav">
<li class="nav-head hidden-xs">{{_('Browse')}}</li>
<li><a href="{{url_for('index')}}"><span class="glyphicon glyphicon-book"></span> {{_('New Books')}}</a></li>
<li id="nav_new"><a href="{{url_for('index')}}"><span class="glyphicon glyphicon-book"></span> {{_('New Books')}}</a></li>
{% if g.user.show_hot_books() %}
<li><a href="{{url_for('hot_books')}}"><span class="glyphicon glyphicon-fire"></span> {{_('Hot Books')}}</a></li>
<li id="nav_hot"><a href="{{url_for('hot_books')}}"><span class="glyphicon glyphicon-fire"></span> {{_('Hot Books')}}</a></li>
{%endif%}
{% if g.user.show_best_rated_books() %}
<li><a href="{{url_for('best_rated_books')}}"><span class="glyphicon glyphicon-star"></span> {{_('Best rated Books')}}</a></li>
{%endif%}
{% if g.user.show_random_books() %}
<li><a href="{{url_for('discover')}}"><span class="glyphicon glyphicon-random"></span> {{_('Discover')}}</a></li>
<li id="nav_rand"><a href="{{url_for('discover')}}"><span class="glyphicon glyphicon-random"></span> {{_('Discover')}}</a></li>
{%endif%}
{% if g.user.show_category() %}
<li><a href="{{url_for('category_list')}}"><span class="glyphicon glyphicon-inbox"></span> {{_('Categories')}}</a></li>
<li id="nav_cat"><a href="{{url_for('category_list')}}"><span class="glyphicon glyphicon-inbox"></span> {{_('Categories')}}</a></li>
{%endif%}
{% if g.user.show_series() %}
<li><a href="{{url_for('series_list')}}"><span class="glyphicon glyphicon-bookmark"></span> {{_('Series')}}</a></li>
<li id="nav_serie"><a href="{{url_for('series_list')}}"><span class="glyphicon glyphicon-bookmark"></span> {{_('Series')}}</a></li>
{%endif%}
<li><a href="{{url_for('author_list')}}"><span class="glyphicon glyphicon-user"></span> {{_('Authors')}}</a></li>
<li id="nav_author"><a href="{{url_for('author_list')}}"><span class="glyphicon glyphicon-user"></span> {{_('Authors')}}</a></li>
{% if g.user.filter_language() == 'all' and g.user.show_language() %}
<li><a href="{{url_for('language_overview')}}"><span class="glyphicon glyphicon-flag"></span> {{_('Languages')}} </a></li>
<li id="nav_lang"><a href="{{url_for('language_overview')}}"><span class="glyphicon glyphicon-flag"></span> {{_('Languages')}} </a></li>
{%endif%}
{% if g.user.is_authenticated or g.user.is_anonymous() %}
<li class="nav-head hidden-xs">{{_('Public Shelves')}}</li>
......@@ -160,9 +160,9 @@
{% endif %}
<div class="col-sm-10">
{% block body %}{% endblock %}
{% if pagination %}
{% if pagination and (pagination.has_next or pagination.has_prev) %}
<div class="pagination">
{%- for page in pagination.iter_pages() %}
{% for page in pagination.iter_pages() %}
{% if page %}
{% if page != pagination.page %}
<a href="{{ url_for_other_page(page) }}">{{ page }}</a>
......@@ -172,7 +172,7 @@
{% else %}
<span class="ellipsis"></span>
{% endif %}
{%- endfor %}
{% endfor %}
{% if pagination.has_next %}
<a class="next" href="{{ url_for_other_page(pagination.page + 1)
}}">Next &raquo;</a>
......
......@@ -5,7 +5,7 @@
{% for entry in entries %}
<div class="row">
<div class="col-xs-1" align="left"><span class="badge">{{entry.count}}</span></div>
<div class="col-xs-6"><a 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>
{% endfor %}
</div>
......
......@@ -16,7 +16,7 @@
<input type="checkbox" name="remember_me" checked> {{_('Remember me')}}
</label>
</div>
<button type="submit" class="btn btn-default">{{_('Submit')}}</button>
<button type="submit" name="submit" class="btn btn-default">{{_('Submit')}}</button>
</form>
</div>
{% if error %}
......
......@@ -2,7 +2,7 @@
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
<LongName>{{instance}}</LongName>
<ShortName>{{instance}}</ShortName>
<Description>{{_('instanceCalibre Web ebook catalog')}}</Description>
<Description>{{_('Calibre Web ebook catalog')}}</Description>
<Developer>Janeczku</Developer>
<Contact>https://github.com/janeczku/calibre-web</Contact>
<Url type="text/html"
......
......@@ -2,7 +2,7 @@
{% block body %}
<h3>{{_('Linked libraries')}}</h3>
<table class="table">
<table id="libs" class="table">
<thead>
<tr>
<th>{{_('Program library')}}</th>
......@@ -30,7 +30,7 @@
</table>
<h3>{{_('Calibre library statistics')}}</h3>
<table class="table">
<table id="stats" class="table">
<tbody>
<tr>
<th>{{bookcounter}}</th>
......
......@@ -27,7 +27,7 @@
<label for="locale">{{_('Language')}}</label>
<select name="locale" id="locale" class="form-control">
{% for translation in translations %}
<option value="{{translation}}" {% if translation.language == content.locale %}selected{% endif %} {% if new_user == 1 and loop.first %}selected{% endif %}>{{ translation.display_name }}</option>
<option value="{{translation}}" {% if translation|string == content.locale %}selected{% endif %} {% if new_user == 1 and loop.first %}selected{% endif %}>{{ translation.display_name }}</option>
{% endfor %}
</select>
</div>
......@@ -108,7 +108,7 @@
{% endif %}
<button type="submit" id="submit" class="btn btn-default">{{_('Submit')}}</button>
{% if not profile %}
<a href="{{ url_for('admin') }}" class="btn btn-default">{{_('Back')}}</a>
<a href="{{ url_for('admin') }}" id="back" class="btn btn-default">{{_('Back')}}</a>
{% endif %}
</form>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -144,7 +144,6 @@ class UserBase:
else:
return False
def __repr__(self):
return '<User %r>' % self.nickname
......@@ -164,10 +163,6 @@ class User(UserBase, Base):
downloads = relationship('Downloads', backref='user', lazy='dynamic')
locale = Column(String(2), default="en")
sidebar_view = Column(Integer, default=1)
#language_books = Column(Integer, default=1)
#series_books = Column(Integer, default=1)
#category_books = Column(Integer, default=1)
#hot_books = Column(Integer, default=1)
default_language = Column(String(3), default="all")
......@@ -184,10 +179,6 @@ class Anonymous(AnonymousUserMixin, UserBase):
self.role = data.role
self.sidebar_view = data.sidebar_view
self.default_language = data.default_language
#self.language_books = data.language_books
#self.series_books = data.series_books
#self.category_books = data.category_books
#self.hot_books = data.hot_books
self.default_language = data.default_language
self.locale = data.locale
self.anon_browse = settings.config_anonbrowse
......@@ -262,6 +253,7 @@ class Settings(Base):
config_uploading = Column(SmallInteger, default=0)
config_anonbrowse = Column(SmallInteger, default=0)
config_public_reg = Column(SmallInteger, default=0)
config_default_role = Column(SmallInteger, default=0)
def __repr__(self):
pass
......@@ -287,7 +279,8 @@ class Config:
self.config_uploading = data.config_uploading
self.config_anonbrowse = data.config_anonbrowse
self.config_public_reg = data.config_public_reg
if self.config_calibre_dir is not None: # and (self.db_configured is None or self.db_configured is True):
self.config_default_role = data.config_default_role
if self.config_calibre_dir is not None:
self.db_configured = True
else:
self.db_configured = False
......@@ -296,6 +289,36 @@ class Config:
def get_main_dir(self):
return self.config_main_dir
def role_admin(self):
if self.config_default_role is not None:
return True if self.config_default_role & ROLE_ADMIN == ROLE_ADMIN else False
else:
return False
def role_download(self):
if self.config_default_role is not None:
return True if self.config_default_role & ROLE_DOWNLOAD == ROLE_DOWNLOAD else False
else:
return False
def role_upload(self):
if self.config_default_role is not None:
return True if self.config_default_role & ROLE_UPLOAD == ROLE_UPLOAD else False
else:
return False
def role_edit(self):
if self.config_default_role is not None:
return True if self.config_default_role & ROLE_EDIT == ROLE_EDIT else False
else:
return False
def role_passwd(self):
if self.config_default_role is not None:
return True if self.config_default_role & ROLE_PASSWD == ROLE_PASSWD else False
else:
return False
def get_Log_Level(self):
ret_value=""
if self.config_log_level == logging.INFO:
......@@ -338,6 +361,13 @@ def migrate_Database():
conn.execute("ALTER TABLE Settings ADD column `config_anonbrowse` SmallInteger DEFAULT 0")
conn.execute("ALTER TABLE Settings ADD column `config_public_reg` SmallInteger DEFAULT 0")
session.commit()
try:
session.query(exists().where(Settings.config_default_role)).scalar()
session.commit()
except exc.OperationalError: # Database is not compatible, some rows are missing
conn = engine.connect()
conn.execute("ALTER TABLE Settings ADD column `config_default_role` SmallInteger DEFAULT 0")
session.commit()
try:
session.query(exists().where(BookShelf.order)).scalar()
session.commit()
......
......@@ -25,6 +25,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.dates import format_date
from functools import wraps
import base64
from sqlalchemy.sql import *
......@@ -279,6 +280,12 @@ def mimetype_filter(val):
s = 'application/octet-stream'
return s
@app.template_filter('formatdate')
def formatdate(val):
conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))", '', val)
formatdate = datetime.datetime.strptime(conformed_timestamp[:-5], "%Y%m%d %H%M%S")
return format_date(formatdate, format='medium',locale=get_locale())
def admin_required(f):
"""
......@@ -658,10 +665,9 @@ def get_opds_download_link(book_id, format):
data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == format.upper()).first()
if current_user.is_authenticated:
helper.update_download(book_id, int(current_user.id))
author = helper.get_normalized_author(book.author_sort)
file_name = book.title
if len(author) > 0:
file_name = author + '-' + file_name
if len(book.authors) > 0:
file_name = book.authors[0].name + '-' + file_name
file_name = helper.get_valid_filename(file_name)
response = make_response(send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + format))
response.headers["Content-Disposition"] = "attachment; filename=\"%s.%s\"" % (data.name, format)
......@@ -1228,10 +1234,9 @@ def get_download_link(book_id, format):
# collect downloaded books only for registered user and not for anonymous user
if current_user.is_authenticated:
helper.update_download(book_id, int(current_user.id))
author = helper.get_normalized_author(book.author_sort)
file_name = book.title
if len(author) > 0:
file_name = author + '-' + file_name
if len(book.authors) > 0:
file_name = book.authors[0].name + '-' + file_name
file_name = helper.get_valid_filename(file_name)
response = make_response(
send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + format))
......@@ -1239,13 +1244,7 @@ def get_download_link(book_id, format):
response.headers["Content-Type"] = mimetypes.types_map['.' + format]
except:
pass
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
)
response.headers["Content-Disposition"] = "attachment; filename=\"%s.%s\"" % (file_name.encode('utf-8'), format)
return response
else:
abort(404)
......@@ -1271,7 +1270,7 @@ def register():
content.password = generate_password_hash(to_save["password"])
content.nickname = to_save["nickname"]
content.email = to_save["email"]
content.role = 0
content.role = config.config_default_role
try:
ub.session.add(content)
ub.session.commit()
......@@ -1578,9 +1577,10 @@ def profile():
@login_required
@admin_required
def admin():
commit = '$Format:%cI$'
content = ub.session.query(ub.User).all()
settings = ub.session.query(ub.Settings).first()
return render_title_template("admin.html", content=content, email=settings, config=config,
return render_title_template("admin.html", content=content, email=settings, config=config, commit=commit,
development=ub.DEVELOPMENT, title=_(u"Admin page"))
......@@ -1635,6 +1635,18 @@ def configuration_helper(origin):
content.config_anonbrowse = 1
if "config_public_reg" in to_save and to_save["config_public_reg"] == "on":
content.config_public_reg = 1
content.config_default_role = 0
if "admin_role" in to_save:
content.config_default_role = content.config_default_role + ub.ROLE_ADMIN
if "download_role" in to_save:
content.config_default_role = content.config_default_role + ub.ROLE_DOWNLOAD
if "upload_role" in to_save:
content.config_default_role = content.config_default_role + ub.ROLE_UPLOAD
if "edit_role" in to_save:
content.config_default_role = content.config_default_role + ub.ROLE_EDIT
if "passwd_role" in to_save:
content.config_default_role = content.config_default_role + ub.ROLE_PASSWD
try:
if db_change:
if config.db_configured:
......@@ -1656,7 +1668,7 @@ def configuration_helper(origin):
return render_title_template("config_edit.html", content=config, origin=origin,
title=_(u"Basic Configuration"))
if reboot_required:
# db.engine.dispose() # ToDo verify correct
# db.engine.dispose() # ToDo verify correct
ub.session.close()
ub.engine.dispose()
# stop tornado server
......@@ -1731,6 +1743,8 @@ def new_user():
except IntegrityError:
ub.session.rollback()
flash(_(u"Found an existing account for this email address or nickname."), category="error")
else:
content.role=config.config_default_role
return render_title_template("user_edit.html", new_user=1, content=content, translations=translations,
languages=languages, title=_(u"Add new user"))
......@@ -1913,7 +1927,7 @@ def edit_book(book_id):
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)
book.author_sort=helper.get_normalized_author(input_authors[0]) # ToDo: wrong sorting
book.author_sort=helper.get_sorted_author(input_authors[0])
if to_save["cover_url"] and os.path.splitext(to_save["cover_url"])[1].lower() == ".jpg":
img = requests.get(to_save["cover_url"])
......@@ -2141,9 +2155,10 @@ def upload():
if is_author:
db_author = is_author
else:
db_author = db.Authors(author, helper.get_normalized_author(author), "") # TODO: WRONG Sorting Author function
db_author = db.Authors(author, helper.get_sorted_author(author), "")
db.session.add(db_author)
path = os.path.join(author_dir, title_dir)
# combine path and normalize path from windows systems
path = os.path.join(author_dir, title_dir).replace('\\','/')
db_book = db.Books(title, "", db_author.sort, datetime.datetime.now(), datetime.datetime(101, 01, 01), 1,
datetime.datetime.now(), path, has_cover, db_author, [])
db_book.authors.append(db_author)
......
This diff is collapsed.
......@@ -11,7 +11,7 @@ Calibre Web is a web app providing a clean interface for browsing, reading and d
- full graphical setup
- User management
- Admin interface
- User Interface in english, french, german, simplified chinese, spanish
- User Interface in english, french, german, polish, simplified chinese, spanish
- OPDS feed for eBook reader apps
- Filter and search by titles, authors, tags, series and language
- Create custom book collection (shelves)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment