1
0
mirror of https://github.com/janeczku/calibre-web synced 2024-06-26 15:13:17 +00:00

Added editing star rating graphically

Added ability to reload database connection (refresh problem)
Bugfix display hot books (no hot books, hot books are deleted books, no longer result in error 500)
This commit is contained in:
OzzieIsaacs 2017-03-07 19:10:17 +01:00
parent 789a1af68f
commit edadf84710
8 changed files with 81 additions and 47 deletions

View File

@ -11,10 +11,8 @@ from ub import config
import ub import ub
session = None session = None
cc_exceptions = None cc_exceptions = ['datetime', 'int', 'comments', 'float', 'composite', 'series']
cc_classes = None cc_classes = None
cc_ids = None
books_custom_column_links = None
engine = None engine = None
@ -283,12 +281,9 @@ class Custom_Columns(Base):
def setup_db(): def setup_db():
global session
global cc_exceptions
global cc_classes
global cc_ids
global books_custom_column_links
global engine global engine
global session
global cc_classes
if config.config_calibre_dir is None or config.config_calibre_dir == u'': if config.config_calibre_dir is None or config.config_calibre_dir == u'':
return False return False
@ -297,7 +292,6 @@ def setup_db():
engine = create_engine('sqlite:///{0}'.format(dbpath.encode('utf-8')), echo=False, isolation_level="SERIALIZABLE") engine = create_engine('sqlite:///{0}'.format(dbpath.encode('utf-8')), echo=False, isolation_level="SERIALIZABLE")
try: try:
conn = engine.connect() conn = engine.connect()
except: except:
content = ub.session.query(ub.Settings).first() content = ub.session.query(ub.Settings).first()
content.config_calibre_dir = None content.config_calibre_dir = None
@ -311,43 +305,43 @@ def setup_db():
config.loadSettings() config.loadSettings()
conn.connection.create_function('title_sort', 1, title_sort) conn.connection.create_function('title_sort', 1, title_sort)
cc = conn.execute("SELECT id, datatype FROM custom_columns") if not cc_classes:
cc = conn.execute("SELECT id, datatype FROM custom_columns")
cc_ids = [] cc_ids = []
cc_exceptions = ['datetime', 'int', 'comments', 'float', 'composite', 'series'] books_custom_column_links = {}
books_custom_column_links = {} cc_classes = {}
cc_classes = {} for row in cc:
for row in cc: if row.datatype not in cc_exceptions:
if row.datatype not in cc_exceptions: books_custom_column_links[row.id] = Table('books_custom_column_' + str(row.id) + '_link', Base.metadata,
books_custom_column_links[row.id] = Table('books_custom_column_' + str(row.id) + '_link', Base.metadata, Column('book', Integer, ForeignKey('books.id'),
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
primary_key=True), Column('value', Integer,
Column('value', Integer, ForeignKey('custom_column_' + str(row.id) + '.id'),
ForeignKey('custom_column_' + str(row.id) + '.id'), primary_key=True)
primary_key=True) )
) cc_ids.append([row.id, row.datatype])
cc_ids.append([row.id, row.datatype]) if row.datatype == 'bool':
if row.datatype == 'bool': ccdict = {'__tablename__': 'custom_column_' + str(row.id),
ccdict = {'__tablename__': 'custom_column_' + str(row.id), 'id': Column(Integer, primary_key=True),
'id': Column(Integer, primary_key=True), 'book': Column(Integer, ForeignKey('books.id')),
'book': Column(Integer, ForeignKey('books.id')), 'value': Column(Boolean)}
'value': Column(Boolean)} else:
ccdict = {'__tablename__': 'custom_column_' + str(row.id),
'id': Column(Integer, primary_key=True),
'value': Column(String)}
cc_classes[row.id] = type('Custom_Column_' + str(row.id), (Base,), ccdict)
for id in cc_ids:
if id[1] == 'bool':
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]],
primaryjoin=(
Books.id == cc_classes[id[0]].book),
backref='books'))
else: else:
ccdict = {'__tablename__': 'custom_column_' + str(row.id), setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]],
'id': Column(Integer, primary_key=True), secondary=books_custom_column_links[id[0]],
'value': Column(String)} backref='books'))
cc_classes[row.id] = type('Custom_Column_' + str(row.id), (Base,), ccdict)
for id in cc_ids:
if id[1] == 'bool':
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]],
primaryjoin=(
Books.id == cc_classes[id[0]].book),
backref='books'))
else:
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]],
secondary=books_custom_column_links[id[0]],
backref='books'))
# Base.metadata.create_all(engine) # Base.metadata.create_all(engine)
Session = sessionmaker() Session = sessionmaker()

View File

@ -0,0 +1 @@
!function(a){"use strict";function b(a){return"[data-value"+(a?"="+a:"")+"]"}function c(a,b,c){var d=c.activeIcon,e=c.inactiveIcon;a.removeClass(b?e:d).addClass(b?d:e)}function d(b,c){var d=a.extend({},i,b.data(),c);return d.inline=""===d.inline||d.inline,d.readonly=""===d.readonly||d.readonly,d.clearable===!1?d.clearableLabel="":d.clearableLabel=d.clearable,d.clearable=""===d.clearable||d.clearable,d}function e(b,c){if(c.inline)var d=a('<span class="rating-input"></span>');else var d=a('<div class="rating-input"></div>');d.addClass(b.attr("class")),d.removeClass("rating");for(var e=c.min;e<=c.max;e++)d.append('<i class="'+c.iconLib+'" data-value="'+e+'"></i>');return c.clearable&&!c.readonly&&d.append("&nbsp;").append('<a class="'+f+'"><i class="'+c.iconLib+" "+c.clearableIcon+'"/>'+c.clearableLabel+"</a>"),d}var f="rating-clear",g="."+f,h="hidden",i={min:1,max:5,"empty-value":0,iconLib:"glyphicon",activeIcon:"glyphicon-star",inactiveIcon:"glyphicon-star-empty",clearable:!1,clearableIcon:"glyphicon-remove",clearableRemain:!1,inline:!1,readonly:!1},j=function(a,b){var c=this.$input=a;this.options=d(c,b);var f=this.$el=e(c,this.options);c.addClass(h).before(f),c.attr("type","hidden"),this.highlight(c.val())};j.VERSION="0.4.0",j.DEFAULTS=i,j.prototype={clear:function(){this.setValue(this.options["empty-value"])},setValue:function(a){this.highlight(a),this.updateInput(a)},highlight:function(a,d){var e=this.options,f=this.$el;if(a>=this.options.min&&a<=this.options.max){var i=f.find(b(a));c(i.prevAll("i").andSelf(),!0,e),c(i.nextAll("i"),!1,e)}else c(f.find(b()),!1,e);d||(this.options.clearableRemain?f.find(g).removeClass(h):a&&a!=this.options["empty-value"]?f.find(g).removeClass(h):f.find(g).addClass(h))},updateInput:function(a){var b=this.$input;b.val()!=a&&b.val(a).change()}};var k=a.fn.rating=function(c){return this.filter("input[type=number]").each(function(){var d=a(this),e="object"==typeof c&&c||{},f=new j(d,e);f.options.readonly||f.$el.on("mouseenter",b(),function(){f.highlight(a(this).data("value"),!0)}).on("mouseleave",b(),function(){f.highlight(d.val(),!0)}).on("click",b(),function(){f.setValue(a(this).data("value"))}).on("click",g,function(){f.clear()})})};k.Constructor=j,a(function(){a("input.rating[type=number]").each(function(){a(this).rating()})})}(jQuery);

View File

@ -65,6 +65,13 @@ $(function() {
} }
}); });
}); });
$("#restart_database").click(function() {
$.ajax({
dataType: 'json',
url: window.location.pathname+"/../../shutdown",
data: {"parameter":2}
});
});
$("#perform_update").click(function() { $("#perform_update").click(function() {
$('#spinner2').show(); $('#spinner2').show();
$.ajax({ $.ajax({

View File

@ -80,6 +80,7 @@
<div>{{_('Current commit timestamp')}}: <span>{{commit}} </span></div> <div>{{_('Current commit timestamp')}}: <span>{{commit}} </span></div>
<div class="hidden" id="update_info">{{_('Newest commit timestamp')}}: <span></span></div> <div class="hidden" id="update_info">{{_('Newest commit timestamp')}}: <span></span></div>
<p></p> <p></p>
<div class="btn btn-default" id="restart_database">{{_('Reconnect to Calibre DB')}}</div>
<div class="btn btn-default" data-toggle="modal" data-target="#RestartDialog">{{_('Restart Calibre-web')}}</div> <div class="btn btn-default" data-toggle="modal" data-target="#RestartDialog">{{_('Restart Calibre-web')}}</div>
<div class="btn btn-default" data-toggle="modal" data-target="#ShutdownDialog">{{_('Stop Calibre-web')}}</div> <div class="btn btn-default" data-toggle="modal" data-target="#ShutdownDialog">{{_('Stop Calibre-web')}}</div>
<div class="btn btn-default" id="check_for_update">{{_('Check for update')}}</div> <div class="btn btn-default" id="check_for_update">{{_('Check for update')}}</div>

View File

@ -39,7 +39,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="rating">{{_('Rating')}}</label> <label for="rating">{{_('Rating')}}</label>
<input type="number" min="0" max="5" step="1" class="form-control" name="rating" id="rating" value="{% if book.ratings %}{{book.ratings[0].rating / 2}}{% endif %}"> <input type="number" name="rating" id="rating" class="rating input-lg" data-clearable="" value="{% if book.ratings %}{{(book.ratings[0].rating / 2)|int}}{% endif %}">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="cover_url">{{_('Cover URL (jpg)')}}</label> <label for="cover_url">{{_('Cover URL (jpg)')}}</label>
@ -114,6 +114,7 @@
{% block js %} {% block js %}
<script src="{{ url_for('static', filename='js/libs/typeahead.bundle.js') }}"></script> <script src="{{ url_for('static', filename='js/libs/typeahead.bundle.js') }}"></script>
<script src="{{ url_for('static', filename='js/edit_books.js') }}"></script> <script src="{{ url_for('static', filename='js/edit_books.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/bootstrap-rating-input.min.js') }}"></script>
{% endblock %} {% endblock %}
{% block header %} {% block header %}
<link href="{{ url_for('static', filename='css/libs/typeahead.css') }}" rel="stylesheet" media="screen"> <link href="{{ url_for('static', filename='css/libs/typeahead.css') }}" rel="stylesheet" media="screen">

View File

@ -35,6 +35,7 @@
<uri>https://github.com/janeczku/calibre-web</uri> <uri>https://github.com/janeczku/calibre-web</uri>
</author> </author>
{% if entries[0] %}
{% for entry in entries %} {% for entry in entries %}
<entry> <entry>
<title>{{entry.title}}</title> <title>{{entry.title}}</title>
@ -60,6 +61,7 @@
{% endfor %} {% endfor %}
</entry> </entry>
{% endfor %} {% endfor %}
{% endif %}
{% for entry in listelements %} {% for entry in listelements %}
<entry> <entry>
<title>{{entry.name}}</title> <title>{{entry.name}}</title>

View File

@ -40,6 +40,7 @@
<div class="discover load-more"> <div class="discover load-more">
<h2>{{title}}</h2> <h2>{{title}}</h2>
<div class="row"> <div class="row">
{% if entries[0] %}
{% for entry in entries %} {% for entry in entries %}
<div id="books" 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"> <div class="cover">
@ -76,6 +77,7 @@
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
{% endif %}
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -136,6 +136,15 @@ lm.anonymous_user = ub.Anonymous
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT' app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
db.setup_db() db.setup_db()
if config.config_log_level == logging.DEBUG :
logging.getLogger("sqlalchemy.engine").addHandler(file_handler)
logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO)
logging.getLogger("sqlalchemy.pool").addHandler(file_handler)
logging.getLogger("sqlalchemy.pool").setLevel(config.config_log_level)
logging.getLogger("sqlalchemy.orm").addHandler(file_handler)
logging.getLogger("sqlalchemy.orm").setLevel(config.config_log_level)
@babel.localeselector @babel.localeselector
def get_locale(): def get_locale():
# if a user is logged in, use the locale from the user settings # if a user is logged in, use the locale from the user settings
@ -550,7 +559,13 @@ def feed_hot():
hot_books = all_books.offset(off).limit(config.config_books_per_page) hot_books = all_books.offset(off).limit(config.config_books_per_page)
entries = list() entries = list()
for book in hot_books: for book in hot_books:
entries.append(db.session.query(db.Books).filter(filter).filter(db.Books.id == book.Downloads.book_id).first()) downloadBook = db.session.query(db.Books).filter(db.Books.id == book.Downloads.book_id).first()
if downloadBook:
entries.append(
db.session.query(db.Books).filter(filter).filter(db.Books.id == book.Downloads.book_id).first())
else:
ub.session.query(ub.Downloads).filter(book.Downloads.book_id == ub.Downloads.book_id).delete()
ub.session.commit()
numBooks = entries.__len__() numBooks = entries.__len__()
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, numBooks) pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, numBooks)
xml = render_title_template('feed.xml', entries=entries, pagination=pagination) xml = render_title_template('feed.xml', entries=entries, pagination=pagination)
@ -839,7 +854,13 @@ def hot_books(page):
hot_books = all_books.offset(off).limit(config.config_books_per_page) hot_books = all_books.offset(off).limit(config.config_books_per_page)
entries = list() entries = list()
for book in hot_books: for book in hot_books:
entries.append(db.session.query(db.Books).filter(filter).filter(db.Books.id == book.Downloads.book_id).first()) downloadBook = db.session.query(db.Books).filter(db.Books.id == book.Downloads.book_id).first()
if downloadBook:
entries.append(
db.session.query(db.Books).filter(filter).filter(db.Books.id == book.Downloads.book_id).first())
else:
ub.session.query(ub.Downloads).filter(book.Downloads.book_id == ub.Downloads.book_id).delete()
ub.session.commit()
numBooks = entries.__len__() numBooks = entries.__len__()
pagination = Pagination(page, config.config_books_per_page, numBooks) pagination = Pagination(page, config.config_books_per_page, numBooks)
return render_title_template('index.html', random=random, entries=entries, pagination=pagination, return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
@ -1085,6 +1106,11 @@ def shutdown():
showtext['text'] = _(u'Performing shutdown of server, please close window') showtext['text'] = _(u'Performing shutdown of server, please close window')
return json.dumps(showtext) return json.dumps(showtext)
else: else:
if task == 2:
db.session.close()
db.engine.dispose()
db.setup_db()
return json.dumps({})
abort(404) abort(404)
@app.route("/update") @app.route("/update")