mirror of
				https://github.com/janeczku/calibre-web
				synced 2025-10-31 15:23:02 +00:00 
			
		
		
		
	Added config option for shelf sync behavior
This commit is contained in:
		
							
								
								
									
										10
									
								
								cps/admin.py
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								cps/admin.py
									
									
									
									
									
								
							| @@ -236,7 +236,7 @@ def edit_user_table(): | |||||||
|         custom_values = [] |         custom_values = [] | ||||||
|     if not config.config_anonbrowse: |     if not config.config_anonbrowse: | ||||||
|         allUser = allUser.filter(ub.User.role.op('&')(constants.ROLE_ANONYMOUS) != constants.ROLE_ANONYMOUS) |         allUser = allUser.filter(ub.User.role.op('&')(constants.ROLE_ANONYMOUS) != constants.ROLE_ANONYMOUS) | ||||||
|  |     kobo_support = feature_support['kobo'] and config.config_kobo_sync | ||||||
|     return render_title_template("user_table.html", |     return render_title_template("user_table.html", | ||||||
|                                  users=allUser.all(), |                                  users=allUser.all(), | ||||||
|                                  tags=tags, |                                  tags=tags, | ||||||
| @@ -245,6 +245,7 @@ def edit_user_table(): | |||||||
|                                  languages=languages, |                                  languages=languages, | ||||||
|                                  visiblility=visibility, |                                  visiblility=visibility, | ||||||
|                                  all_roles=constants.ALL_ROLES, |                                  all_roles=constants.ALL_ROLES, | ||||||
|  |                                  kobo_support=kobo_support, | ||||||
|                                  sidebar_settings=constants.sidebar_settings, |                                  sidebar_settings=constants.sidebar_settings, | ||||||
|                                  title=_(u"Edit Users"), |                                  title=_(u"Edit Users"), | ||||||
|                                  page="usertable") |                                  page="usertable") | ||||||
| @@ -391,6 +392,8 @@ def edit_list_user(param): | |||||||
|                     user.name = check_username(vals['value']) |                     user.name = check_username(vals['value']) | ||||||
|                 elif param =='email': |                 elif param =='email': | ||||||
|                     user.email = check_email(vals['value']) |                     user.email = check_email(vals['value']) | ||||||
|  |                 elif param =='kobo_only_shelves_sync': | ||||||
|  |                     user.kobo_only_shelves_sync = int(vals['value'] == 'true') | ||||||
|                 elif param == 'kindle_mail': |                 elif param == 'kindle_mail': | ||||||
|                     user.kindle_mail = valid_email(vals['value']) if vals['value'] else "" |                     user.kindle_mail = valid_email(vals['value']) if vals['value'] else "" | ||||||
|                 elif param.endswith('role'): |                 elif param.endswith('role'): | ||||||
| @@ -558,6 +561,8 @@ def load_dialogtexts(element_id): | |||||||
|         texts["main"] = _('Are you sure you want to change the selected restrictions for the selected user(s)?') |         texts["main"] = _('Are you sure you want to change the selected restrictions for the selected user(s)?') | ||||||
|     elif element_id == "sidebar_view": |     elif element_id == "sidebar_view": | ||||||
|         texts["main"] = _('Are you sure you want to change the selected visibility restrictions for the selected user(s)?') |         texts["main"] = _('Are you sure you want to change the selected visibility restrictions for the selected user(s)?') | ||||||
|  |     elif element_id == "kobo_only_shelves_sync": | ||||||
|  |         texts["main"] = _('Are you sure you want to change shelf sync behavior for the selected user(s)?') | ||||||
|     return json.dumps(texts) |     return json.dumps(texts) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1314,6 +1319,7 @@ def _handle_new_user(to_save, content, languages, translations, kobo_support): | |||||||
|         content.denied_tags = config.config_denied_tags |         content.denied_tags = config.config_denied_tags | ||||||
|         content.allowed_column_value = config.config_allowed_column_value |         content.allowed_column_value = config.config_allowed_column_value | ||||||
|         content.denied_column_value = config.config_denied_column_value |         content.denied_column_value = config.config_denied_column_value | ||||||
|  |         content.kobo_only_shelves_sync = 0  # No default value for kobo sync shelf setting | ||||||
|         ub.session.add(content) |         ub.session.add(content) | ||||||
|         ub.session.commit() |         ub.session.commit() | ||||||
|         flash(_(u"User '%(user)s' created", user=content.name), category="success") |         flash(_(u"User '%(user)s' created", user=content.name), category="success") | ||||||
| @@ -1381,6 +1387,8 @@ def _handle_edit_user(to_save, content, languages, translations, kobo_support): | |||||||
|         else: |         else: | ||||||
|             content.sidebar_view &= ~constants.DETAIL_RANDOM |             content.sidebar_view &= ~constants.DETAIL_RANDOM | ||||||
|  |  | ||||||
|  |         content.kobo_only_shelves_sync = int(to_save.get("kobo_only_shelves_sync") == "on") or 0 | ||||||
|  |  | ||||||
|         if to_save.get("default_language"): |         if to_save.get("default_language"): | ||||||
|             content.default_language = to_save["default_language"] |             content.default_language = to_save["default_language"] | ||||||
|         if to_save.get("locale"): |         if to_save.get("locale"): | ||||||
|   | |||||||
| @@ -152,8 +152,8 @@ def HandleSyncRequest(): | |||||||
|     # in case of external changes (e.g: adding a book through Calibre). |     # in case of external changes (e.g: adding a book through Calibre). | ||||||
|     calibre_db.reconnect_db(config, ub.app_DB_path) |     calibre_db.reconnect_db(config, ub.app_DB_path) | ||||||
|  |  | ||||||
|     only_kobo_shelves = calibre_db.session.query(ub.Shelf).filter(ub.Shelf.user_id == current_user.id)\ |     only_kobo_shelves = current_user.kobo_only_shelves_sync | ||||||
|         .filter(ub.Shelf.kobo_sync).count() > 0 |     # calibre_db.session.query(ub.Shelf).filter(ub.Shelf.user_id == current_user.id).filter(ub.Shelf.kobo_sync).count() > 0 | ||||||
|  |  | ||||||
|     if only_kobo_shelves: |     if only_kobo_shelves: | ||||||
|         changed_entries = ( |         changed_entries = ( | ||||||
|   | |||||||
| @@ -240,8 +240,8 @@ def edit_shelf(shelf_id): | |||||||
|  |  | ||||||
| # if shelf ID is set, we are editing a shelf | # if shelf ID is set, we are editing a shelf | ||||||
| def create_edit_shelf(shelf, title, page, shelf_id=False): | def create_edit_shelf(shelf, title, page, shelf_id=False): | ||||||
|     sync_all_books = calibre_db.session.query(ub.Shelf).filter(ub.Shelf.user_id == current_user.id)\ |     sync_only_selected_shelves = current_user.kobo_only_shelves_sync | ||||||
|                          .filter(ub.Shelf.kobo_sync).count() |     # calibre_db.session.query(ub.Shelf).filter(ub.Shelf.user_id == current_user.id).filter(ub.Shelf.kobo_sync).count() | ||||||
|     if request.method == "POST": |     if request.method == "POST": | ||||||
|         to_save = request.form.to_dict() |         to_save = request.form.to_dict() | ||||||
|         shelf.is_public = 1 if to_save.get("is_public") else 0 |         shelf.is_public = 1 if to_save.get("is_public") else 0 | ||||||
| @@ -277,7 +277,7 @@ def create_edit_shelf(shelf, title, page, shelf_id=False): | |||||||
|                                  title=title, |                                  title=title, | ||||||
|                                  page=page, |                                  page=page, | ||||||
|                                  kobo_sync_enabled=config.config_kobo_sync, |                                  kobo_sync_enabled=config.config_kobo_sync, | ||||||
|                                  sync_all_books=sync_all_books) |                                  sync_only_selected_shelves=sync_only_selected_shelves) | ||||||
|  |  | ||||||
|  |  | ||||||
| def check_shelf_is_unique(shelf, to_save, shelf_id=False): | def check_shelf_is_unique(shelf, to_save, shelf_id=False): | ||||||
|   | |||||||
| @@ -580,12 +580,19 @@ function singleUserFormatter(value, row) { | |||||||
|     return '<a class="btn btn-default" onclick="storeLocation()" href="' + window.location.pathname + '/../../admin/user/' + row.id + '">' + this.buttontext + '</a>' |     return '<a class="btn btn-default" onclick="storeLocation()" href="' + window.location.pathname + '/../../admin/user/' + row.id + '">' + this.buttontext + '</a>' | ||||||
| } | } | ||||||
|  |  | ||||||
| function checkboxFormatter(value, row, index){ | function checkboxFormatter(value, row){ | ||||||
|     if(value & this.column) |     if(value & this.column) | ||||||
|         return '<input type="checkbox" class="chk" data-pk="' + row.id + '" data-name="' + this.field + '" checked onchange="checkboxChange(this, ' + row.id + ', \'' + this.name + '\', ' + this.column + ')">'; |         return '<input type="checkbox" class="chk" data-pk="' + row.id + '" data-name="' + this.field + '" checked onchange="checkboxChange(this, ' + row.id + ', \'' + this.name + '\', ' + this.column + ')">'; | ||||||
|     else |     else | ||||||
|         return '<input type="checkbox" class="chk" data-pk="' + row.id + '" data-name="' + this.field + '" onchange="checkboxChange(this, ' + row.id + ', \'' + this.name + '\', ' + this.column + ')">'; |         return '<input type="checkbox" class="chk" data-pk="' + row.id + '" data-name="' + this.field + '" onchange="checkboxChange(this, ' + row.id + ', \'' + this.name + '\', ' + this.column + ')">'; | ||||||
| } | } | ||||||
|  | function singlecheckboxFormatter(value, row){ | ||||||
|  |     if(value) | ||||||
|  |         return '<input type="checkbox" class="chk" data-pk="' + row.id + '" data-name="' + this.field + '" checked onchange="checkboxChange(this, ' + row.id + ', \'' + this.name + '\', 0)">'; | ||||||
|  |     else | ||||||
|  |         return '<input type="checkbox" class="chk" data-pk="' + row.id + '" data-name="' + this.field + '" onchange="checkboxChange(this, ' + row.id + ', \'' + this.name + '\', 0)">'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /* Do some hiding disabling after user list is loaded */ | /* Do some hiding disabling after user list is loaded */ | ||||||
| function loadSuccess() { | function loadSuccess() { | ||||||
|   | |||||||
| @@ -14,14 +14,10 @@ | |||||||
|         </label> |         </label> | ||||||
|       </div> |       </div> | ||||||
|     {% endif %} |     {% endif %} | ||||||
|     {% if kobo_sync_enabled %} |     {% if kobo_sync_enabled and sync_only_selected_shelves %} | ||||||
|       <div class="checkbox"> |       <div class="checkbox"> | ||||||
|           <label> |           <label> <input type="checkbox" name="kobo_sync" {% if shelf.kobo_sync == 1 %}checked{% endif %}> | ||||||
|               <input type="checkbox" name="kobo_sync" |               {{ _('Sync this shelf with Kobo device') }} | ||||||
|                      {% if shelf.kobo_sync == 1 %}checked{% endif %}> |  | ||||||
|             {% if shelf.kobo_sync == 1 and sync_all_books == 1 %}{{ _('Sync with Kobo device - If this option is turned off, all books and shelves will be synced with Kobo') }} |  | ||||||
|             {% elif sync_all_books == 0 and shelf.kobo_sync == 0 %}{{ _('Only sync books from selected shelves to Kobo instead of all books and shelves') }} |  | ||||||
|             {% else %}{{ _('Sync with Kobo device') }}{% endif %} |  | ||||||
|           </label> |           </label> | ||||||
|       </div> |       </div> | ||||||
|     {% endif %} |     {% endif %} | ||||||
|   | |||||||
| @@ -66,7 +66,6 @@ | |||||||
|       <div class="btn btn-danger" id="config_delete_kobo_token" data-value="{{ content.id }}" data-remote="false" {% if not content.remote_auth_token.first() %} style="display: none;" {% endif %}>{{_('Delete')}}</div> |       <div class="btn btn-danger" id="config_delete_kobo_token" data-value="{{ content.id }}" data-remote="false" {% if not content.remote_auth_token.first() %} style="display: none;" {% endif %}>{{_('Delete')}}</div> | ||||||
|     </div> |     </div> | ||||||
|     {% endif %} |     {% endif %} | ||||||
|     </div> |  | ||||||
|     <div class="col-sm-6"> |     <div class="col-sm-6"> | ||||||
|         {% for element in sidebar %} |         {% for element in sidebar %} | ||||||
|           {% if element['config_show'] %} |           {% if element['config_show'] %} | ||||||
| @@ -125,6 +124,12 @@ | |||||||
|         </div> |         </div> | ||||||
|       {% endif %} |       {% endif %} | ||||||
|     {% endif %} |     {% endif %} | ||||||
|  |     {% if kobo_support and not content.role_anonymous() %} | ||||||
|  |     <div class="form-group"> | ||||||
|  |       <input type="checkbox" name="kobo_only_shelves_sync" id="kobo_only_shelves_sync" {% if content.kobo_only_shelves_sync %}checked{% endif %}> | ||||||
|  |       <label for="kobo_only_shelves_sync">{{_('Sync only books in selected shelves with Kobo')}}</label> | ||||||
|  |     </div> | ||||||
|  |     {% endif %} | ||||||
|     </div> |     </div> | ||||||
|       <div class="col-sm-12"> |       <div class="col-sm-12"> | ||||||
|     <div id="user_submit" class="btn btn-default">{{_('Save')}}</div> |     <div id="user_submit" class="btn btn-default">{{_('Save')}}</div> | ||||||
|   | |||||||
| @@ -32,6 +32,21 @@ | |||||||
| </th> | </th> | ||||||
| {%- endmacro %} | {%- endmacro %} | ||||||
|  |  | ||||||
|  | {% macro user_single_checkbox_row(parameter, show_text) -%} | ||||||
|  | <th data-name="{{parameter}}" data-field="{{parameter}}" | ||||||
|  |     data-formatter="singlecheckboxFormatter"> | ||||||
|  |     <div class="form-check"> | ||||||
|  |     <div> | ||||||
|  |         <input type="radio" class="check_head" data-set="false" data-val="0" name="{{parameter}}" id="false_{{parameter}}" data-name="{{parameter}}" disabled>{{_('Deny')}} | ||||||
|  |     </div> | ||||||
|  |     <div> | ||||||
|  |         <input type="radio" class="check_head" data-set="true" data-val="1" name="{{parameter}}" data-name="{{parameter}}" disabled>{{_('Allow')}} | ||||||
|  |     </div> | ||||||
|  |     </div> | ||||||
|  |     {{show_text}} | ||||||
|  | </th> | ||||||
|  | {%- endmacro %} | ||||||
|  |  | ||||||
| {% macro user_checkbox_row(parameter, array_field, show_text, element, value) -%} | {% macro user_checkbox_row(parameter, array_field, show_text, element, value) -%} | ||||||
| <th data-name="{{array_field}}" data-field="{{parameter}}" | <th data-name="{{array_field}}" data-field="{{parameter}}" | ||||||
|     data-visible="{{element.get(array_field)}}" |     data-visible="{{element.get(array_field)}}" | ||||||
| @@ -39,14 +54,10 @@ | |||||||
|     data-formatter="checkboxFormatter"> |     data-formatter="checkboxFormatter"> | ||||||
|     <div  class="form-check"> |     <div  class="form-check"> | ||||||
|     <div> |     <div> | ||||||
|  |         <input type="radio" class="check_head" data-set="false" data-val="{{value.get(array_field)}}" name="options_{{array_field}}" id="false_{{array_field}}" data-name="{{parameter}}" disabled>{{_('Deny')}} | ||||||
|         <input type="radio" class="check_head" data-set="false" data-val={{value.get(array_field)}} name="options_{{array_field}}" id="false_{{array_field}}" data-name="{{parameter}}" disabled>{{_('Deny')}} |  | ||||||
|  |  | ||||||
|     </div> |     </div> | ||||||
|     <div> |     <div> | ||||||
|  |         <input type="radio" class="check_head" data-set="true" data-val="{{value.get(array_field)}}" name="options_{{array_field}}" data-name="{{parameter}}" disabled>{{_('Allow')}} | ||||||
|         <input type="radio" class="check_head" data-set="true" data-val={{value.get(array_field)}} name="options_{{array_field}}" data-name="{{parameter}}" disabled>{{_('Allow')}} |  | ||||||
|  |  | ||||||
|     </div> |     </div> | ||||||
|     </div> |     </div> | ||||||
|     {{show_text}} |     {{show_text}} | ||||||
| @@ -134,7 +145,10 @@ | |||||||
|             {{ user_checkbox_row("role", "viewer_role", _('View'), visiblility, all_roles)}} |             {{ user_checkbox_row("role", "viewer_role", _('View'), visiblility, all_roles)}} | ||||||
|             {{ user_checkbox_row("role", "edit_role", _('Edit'), visiblility, all_roles)}} |             {{ user_checkbox_row("role", "edit_role", _('Edit'), visiblility, all_roles)}} | ||||||
|             {{ user_checkbox_row("role", "delete_role", _('Delete'), visiblility, all_roles)}} |             {{ user_checkbox_row("role", "delete_role", _('Delete'), visiblility, all_roles)}} | ||||||
|             {{ user_checkbox_row("role", "edit_shelf_role", _('Edit Public Shelfs'), visiblility, all_roles)}} |             {{ user_checkbox_row("role", "edit_shelf_role", _('Edit Public Shelves'), visiblility, all_roles)}} | ||||||
|  |             {%  if kobo_support %} | ||||||
|  |             {{ user_single_checkbox_row("kobo_only_shelves_sync", _('Sync Selected Shelves with Kobo'))}} | ||||||
|  |             {%  endif %} | ||||||
|             {{ user_checkbox_row("sidebar_view", "detail_random", _('Show Random Books in Detail View'), visiblility, sidebar_settings)}} |             {{ user_checkbox_row("sidebar_view", "detail_random", _('Show Random Books in Detail View'), visiblility, sidebar_settings)}} | ||||||
|             {{ user_checkbox_row("sidebar_view", "sidebar_language", _('Show language selection'), visiblility, sidebar_settings)}} |             {{ user_checkbox_row("sidebar_view", "sidebar_language", _('Show language selection'), visiblility, sidebar_settings)}} | ||||||
|             {{ user_checkbox_row("sidebar_view", "sidebar_read_and_unread", _('Show read/unread selection'), visiblility, sidebar_settings)}} |             {{ user_checkbox_row("sidebar_view", "sidebar_read_and_unread", _('Show read/unread selection'), visiblility, sidebar_settings)}} | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								cps/ub.py
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								cps/ub.py
									
									
									
									
									
								
							| @@ -188,7 +188,7 @@ class User(UserBase, Base): | |||||||
|     allowed_column_value = Column(String, default="") |     allowed_column_value = Column(String, default="") | ||||||
|     remote_auth_token = relationship('RemoteAuthToken', backref='user', lazy='dynamic') |     remote_auth_token = relationship('RemoteAuthToken', backref='user', lazy='dynamic') | ||||||
|     view_settings = Column(JSON, default={}) |     view_settings = Column(JSON, default={}) | ||||||
|  |     kobo_only_shelves_sync = Column(Integer, default=1) | ||||||
|  |  | ||||||
|  |  | ||||||
| if oauth_support: | if oauth_support: | ||||||
| @@ -229,6 +229,7 @@ class Anonymous(AnonymousUserMixin, UserBase): | |||||||
|         self.denied_column_value = data.denied_column_value |         self.denied_column_value = data.denied_column_value | ||||||
|         self.allowed_column_value = data.allowed_column_value |         self.allowed_column_value = data.allowed_column_value | ||||||
|         self.view_settings = data.view_settings |         self.view_settings = data.view_settings | ||||||
|  |         self.kobo_only_shelves_sync = data.kobo_only_shelves_sync | ||||||
|  |  | ||||||
|  |  | ||||||
|     def role_admin(self): |     def role_admin(self): | ||||||
| @@ -603,6 +604,13 @@ def migrate_Database(session): | |||||||
|         with engine.connect() as conn: |         with engine.connect() as conn: | ||||||
|             conn.execute("ALTER TABLE user ADD column `view_settings` VARCHAR(10) DEFAULT '{}'") |             conn.execute("ALTER TABLE user ADD column `view_settings` VARCHAR(10) DEFAULT '{}'") | ||||||
|         session.commit() |         session.commit() | ||||||
|  |     try: | ||||||
|  |         session.query(exists().where(User.kobo_only_shelves_sync)).scalar() | ||||||
|  |     except exc.OperationalError: | ||||||
|  |         with engine.connect() as conn: | ||||||
|  |             conn.execute("ALTER TABLE user ADD column `kobo_only_shelves_sync` SMALLINT DEFAULT 0") | ||||||
|  |         session.commit() | ||||||
|  |  | ||||||
|     try: |     try: | ||||||
|         # check if name is in User table instead of nickname |         # check if name is in User table instead of nickname | ||||||
|         session.query(exists().where(User.name)).scalar() |         session.query(exists().where(User.name)).scalar() | ||||||
| @@ -623,14 +631,15 @@ def migrate_Database(session): | |||||||
|                      "denied_column_value VARCHAR," |                      "denied_column_value VARCHAR," | ||||||
|                      "allowed_column_value VARCHAR," |                      "allowed_column_value VARCHAR," | ||||||
|                      "view_settings JSON," |                      "view_settings JSON," | ||||||
|  |                      "kobo_only_shelves_sync SMALLINT,"                               | ||||||
|                      "UNIQUE (name)," |                      "UNIQUE (name)," | ||||||
|                      "UNIQUE (email))")) |                      "UNIQUE (email))")) | ||||||
|             conn.execute(text("INSERT INTO user_id(id, name, email, role, password, kindle_mail,locale," |             conn.execute(text("INSERT INTO user_id(id, name, email, role, password, kindle_mail,locale," | ||||||
|                      "sidebar_view, default_language, denied_tags, allowed_tags, denied_column_value, " |                      "sidebar_view, default_language, denied_tags, allowed_tags, denied_column_value, " | ||||||
|                      "allowed_column_value, view_settings)" |                      "allowed_column_value, view_settings, kobo_only_shelves_sync)" | ||||||
|                      "SELECT id, nickname, email, role, password, kindle_mail, locale," |                      "SELECT id, nickname, email, role, password, kindle_mail, locale," | ||||||
|                      "sidebar_view, default_language, denied_tags, allowed_tags, denied_column_value, " |                      "sidebar_view, default_language, denied_tags, allowed_tags, denied_column_value, " | ||||||
|                      "allowed_column_value, view_settings FROM user")) |                      "allowed_column_value, view_settings, kobo_only_shelves_sync FROM user")) | ||||||
|             # delete old user table and rename new user_id table to user: |             # delete old user table and rename new user_id table to user: | ||||||
|             conn.execute(text("DROP TABLE user")) |             conn.execute(text("DROP TABLE user")) | ||||||
|             conn.execute(text("ALTER TABLE user_id RENAME TO user")) |             conn.execute(text("ALTER TABLE user_id RENAME TO user")) | ||||||
|   | |||||||
| @@ -1593,6 +1593,8 @@ def change_profile(kobo_support, local_oauth_check, oauth_status, translations, | |||||||
|             current_user.default_language = to_save["default_language"] |             current_user.default_language = to_save["default_language"] | ||||||
|         if to_save.get("locale"): |         if to_save.get("locale"): | ||||||
|             current_user.locale = to_save["locale"] |             current_user.locale = to_save["locale"] | ||||||
|  |         current_user.kobo_only_shelves_sync = int(to_save.get("kobo_only_shelves_sync") == "on") or 0 | ||||||
|  |  | ||||||
|     except Exception as ex: |     except Exception as ex: | ||||||
|         flash(str(ex), category="error") |         flash(str(ex), category="error") | ||||||
|         return render_title_template("user_edit.html", content=current_user, |         return render_title_template("user_edit.html", content=current_user, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Ozzie Isaacs
					Ozzie Isaacs