mirror of
				https://github.com/janeczku/calibre-web
				synced 2025-10-31 15:23:02 +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:
		
							
								
								
									
										82
									
								
								cps/db.py
									
									
									
									
									
								
							
							
						
						
									
										82
									
								
								cps/db.py
									
									
									
									
									
								
							| @@ -11,10 +11,8 @@ from ub import config | ||||
| import ub | ||||
|  | ||||
| session = None | ||||
| cc_exceptions = None | ||||
| cc_exceptions = ['datetime', 'int', 'comments', 'float', 'composite', 'series'] | ||||
| cc_classes = None | ||||
| cc_ids = None | ||||
| books_custom_column_links = None | ||||
| engine = None | ||||
|  | ||||
|  | ||||
| @@ -283,12 +281,9 @@ class Custom_Columns(Base): | ||||
|  | ||||
|  | ||||
| def setup_db(): | ||||
|     global session | ||||
|     global cc_exceptions | ||||
|     global cc_classes | ||||
|     global cc_ids | ||||
|     global books_custom_column_links | ||||
|     global engine | ||||
|     global session | ||||
|     global cc_classes | ||||
|  | ||||
|     if config.config_calibre_dir is None or config.config_calibre_dir ==  u'': | ||||
|         return False | ||||
| @@ -297,7 +292,6 @@ def setup_db(): | ||||
|     engine = create_engine('sqlite:///{0}'.format(dbpath.encode('utf-8')), echo=False, isolation_level="SERIALIZABLE") | ||||
|     try: | ||||
|         conn = engine.connect() | ||||
|  | ||||
|     except: | ||||
|         content = ub.session.query(ub.Settings).first() | ||||
|         content.config_calibre_dir = None | ||||
| @@ -311,43 +305,43 @@ def setup_db(): | ||||
|     config.loadSettings() | ||||
|     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_exceptions = ['datetime', 'int', 'comments', 'float', 'composite', 'series'] | ||||
|     books_custom_column_links = {} | ||||
|     cc_classes = {} | ||||
|     for row in cc: | ||||
|         if row.datatype not in cc_exceptions: | ||||
|             books_custom_column_links[row.id] = Table('books_custom_column_' + str(row.id) + '_link', Base.metadata, | ||||
|                                                       Column('book', Integer, ForeignKey('books.id'), | ||||
|                                                              primary_key=True), | ||||
|                                                       Column('value', Integer, | ||||
|                                                              ForeignKey('custom_column_' + str(row.id) + '.id'), | ||||
|                                                              primary_key=True) | ||||
|                                                       ) | ||||
|             cc_ids.append([row.id, row.datatype]) | ||||
|             if row.datatype == 'bool': | ||||
|                 ccdict = {'__tablename__': 'custom_column_' + str(row.id), | ||||
|                           'id': Column(Integer, primary_key=True), | ||||
|                           'book': Column(Integer, ForeignKey('books.id')), | ||||
|                           'value': Column(Boolean)} | ||||
|         cc_ids = [] | ||||
|         books_custom_column_links = {} | ||||
|         cc_classes = {} | ||||
|         for row in cc: | ||||
|             if row.datatype not in cc_exceptions: | ||||
|                 books_custom_column_links[row.id] = Table('books_custom_column_' + str(row.id) + '_link', Base.metadata, | ||||
|                                                           Column('book', Integer, ForeignKey('books.id'), | ||||
|                                                                  primary_key=True), | ||||
|                                                           Column('value', Integer, | ||||
|                                                                  ForeignKey('custom_column_' + str(row.id) + '.id'), | ||||
|                                                                  primary_key=True) | ||||
|                                                           ) | ||||
|                 cc_ids.append([row.id, row.datatype]) | ||||
|                 if row.datatype == 'bool': | ||||
|                     ccdict = {'__tablename__': 'custom_column_' + str(row.id), | ||||
|                               'id': Column(Integer, primary_key=True), | ||||
|                               'book': Column(Integer, ForeignKey('books.id')), | ||||
|                               '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: | ||||
|                 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: | ||||
|             setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]], | ||||
|                                                                        secondary=books_custom_column_links[id[0]], | ||||
|                                                                        backref='books')) | ||||
|                 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) | ||||
|     Session = sessionmaker() | ||||
|   | ||||
							
								
								
									
										1
									
								
								cps/static/js/libs/bootstrap-rating-input.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								cps/static/js/libs/bootstrap-rating-input.min.js
									
									
									
									
										vendored
									
									
										Normal 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(" ").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); | ||||
| @@ -65,6 +65,13 @@ $(function() { | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
|     $("#restart_database").click(function() { | ||||
|         $.ajax({ | ||||
|             dataType: 'json', | ||||
|             url: window.location.pathname+"/../../shutdown", | ||||
|             data: {"parameter":2} | ||||
|         }); | ||||
|     }); | ||||
|     $("#perform_update").click(function() { | ||||
|         $('#spinner2').show(); | ||||
|         $.ajax({ | ||||
|   | ||||
| @@ -80,6 +80,7 @@ | ||||
|         <div>{{_('Current commit timestamp')}}: <span>{{commit}} </span></div> | ||||
|         <div class="hidden" id="update_info">{{_('Newest commit timestamp')}}: <span></span></div> | ||||
|         <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="#ShutdownDialog">{{_('Stop Calibre-web')}}</div> | ||||
|         <div class="btn btn-default" id="check_for_update">{{_('Check for update')}}</div> | ||||
|   | ||||
| @@ -39,7 +39,7 @@ | ||||
|       </div> | ||||
|       <div class="form-group"> | ||||
|         <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 class="form-group"> | ||||
|         <label for="cover_url">{{_('Cover URL (jpg)')}}</label> | ||||
| @@ -114,6 +114,7 @@ | ||||
| {% block js %} | ||||
| <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/libs/bootstrap-rating-input.min.js') }}"></script> | ||||
| {% endblock %} | ||||
| {% block header %} | ||||
| <link href="{{ url_for('static', filename='css/libs/typeahead.css') }}" rel="stylesheet" media="screen"> | ||||
|   | ||||
| @@ -35,6 +35,7 @@ | ||||
|     <uri>https://github.com/janeczku/calibre-web</uri> | ||||
|   </author> | ||||
|  | ||||
|   {% if entries[0] %} | ||||
|   {% for entry in entries %} | ||||
|   <entry> | ||||
|     <title>{{entry.title}}</title> | ||||
| @@ -60,6 +61,7 @@ | ||||
|     {% endfor %} | ||||
|   </entry> | ||||
|   {% endfor %} | ||||
|   {% endif %} | ||||
|   {% for entry in listelements %} | ||||
|   <entry> | ||||
|     <title>{{entry.name}}</title> | ||||
|   | ||||
| @@ -40,6 +40,7 @@ | ||||
| <div class="discover load-more"> | ||||
|   <h2>{{title}}</h2> | ||||
|   <div class="row"> | ||||
|     {% if entries[0] %} | ||||
|     {% for entry in entries %} | ||||
|     <div id="books" class="col-sm-3 col-lg-2 col-xs-6 book"> | ||||
|       <div class="cover"> | ||||
| @@ -76,6 +77,7 @@ | ||||
|       </div> | ||||
|     </div> | ||||
|     {% endfor %} | ||||
|   {% endif %} | ||||
|   </div> | ||||
| </div> | ||||
| {% endblock %} | ||||
|   | ||||
							
								
								
									
										30
									
								
								cps/web.py
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								cps/web.py
									
									
									
									
									
								
							| @@ -136,6 +136,15 @@ lm.anonymous_user = ub.Anonymous | ||||
| app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT' | ||||
| 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 | ||||
| def get_locale(): | ||||
|     # 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) | ||||
|     entries = list() | ||||
|     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__() | ||||
|     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) | ||||
| @@ -839,7 +854,13 @@ def hot_books(page): | ||||
|     hot_books = all_books.offset(off).limit(config.config_books_per_page) | ||||
|     entries = list() | ||||
|     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__() | ||||
|     pagination = Pagination(page, config.config_books_per_page, numBooks) | ||||
|     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') | ||||
|         return json.dumps(showtext) | ||||
|     else: | ||||
|         if task == 2: | ||||
|             db.session.close() | ||||
|             db.engine.dispose() | ||||
|             db.setup_db() | ||||
|             return json.dumps({}) | ||||
|         abort(404) | ||||
|  | ||||
| @app.route("/update") | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 OzzieIsaacs
					OzzieIsaacs