diff --git a/rhodecode/apps/my_account/views/my_account.py b/rhodecode/apps/my_account/views/my_account.py --- a/rhodecode/apps/my_account/views/my_account.py +++ b/rhodecode/apps/my_account/views/my_account.py @@ -400,14 +400,15 @@ class MyAccountView(BaseAppView, DataGri c.active = 'bookmarks' return self._get_template_context(c) - def _process_entry(self, entry, user_id): + def _process_bookmark_entry(self, entry, user_id): position = safe_int(entry.get('position')) - if position is None: + cur_position = safe_int(entry.get('cur_position')) + if position is None or cur_position is None: return # check if this is an existing entry is_new = False - db_entry = UserBookmark().get_by_position_for_user(position, user_id) + db_entry = UserBookmark().get_by_position_for_user(cur_position, user_id) if db_entry and str2bool(entry.get('remove')): log.debug('Marked bookmark %s for deletion', db_entry) @@ -446,12 +447,12 @@ class MyAccountView(BaseAppView, DataGri should_save = True if should_save: - log.debug('Saving bookmark %s, new:%s', db_entry, is_new) # mark user and position db_entry.user_id = user_id db_entry.position = position db_entry.title = entry.get('title') db_entry.redirect_url = entry.get('redirect_url') or default_redirect_url + log.debug('Saving bookmark %s, new:%s', db_entry, is_new) Session().add(db_entry) @@ -468,15 +469,31 @@ class MyAccountView(BaseAppView, DataGri controls = peppercorn.parse(self.request.POST.items()) user_id = c.user.user_id + # validate positions + positions = {} + for entry in controls.get('bookmarks', []): + position = safe_int(entry['position']) + if position is None: + continue + + if position in positions: + h.flash(_("Position {} is defined twice. " + "Please correct this error.").format(position), category='error') + return HTTPFound(h.route_path('my_account_bookmarks')) + + entry['position'] = position + entry['cur_position'] = safe_int(entry.get('cur_position')) + positions[position] = entry + try: - for entry in controls.get('bookmarks', []): - self._process_entry(entry, user_id) + for entry in positions.values(): + self._process_bookmark_entry(entry, user_id) Session().commit() h.flash(_("Update Bookmarks"), category='success') except IntegrityError: h.flash(_("Failed to update bookmarks. " - "Make sure an unique position is used"), category='error') + "Make sure an unique position is used."), category='error') return HTTPFound(h.route_path('my_account_bookmarks')) diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py --- a/rhodecode/model/db.py +++ b/rhodecode/model/db.py @@ -5085,7 +5085,7 @@ class UserBookmark(Base, BaseModel): .all() def __unicode__(self): - return u'' % (self.position, self.redirect_url) + return u'' % (self.position, self.redirect_url) class FileStore(Base, BaseModel): diff --git a/rhodecode/templates/admin/my_account/my_account_bookmarks.mako b/rhodecode/templates/admin/my_account/my_account_bookmarks.mako --- a/rhodecode/templates/admin/my_account/my_account_bookmarks.mako +++ b/rhodecode/templates/admin/my_account/my_account_bookmarks.mako @@ -1,13 +1,14 @@ <%namespace name="dt" file="/data_table/_dt_elements.mako"/> -<%def name="form_item(count, position=None, title=None, redirect_url=None, repo=None, repo_group=None)"> +<%def name="form_item(position=None, title=None, redirect_url=None, repo=None, repo_group=None)">
- + + ${h.hidden('cur_position', position)}
@@ -91,14 +92,14 @@ ## generate always 10 entries - % for cnt, item in enumerate((c.bookmark_items + [None for i in range(10)])[:10]): + % for item in (c.bookmark_items + [None for i in range(10)])[:10]: % if item is None: ## empty placehodlder - ${form_item(cnt)} + ${form_item()} % else: ## actual entry - ${form_item(cnt, position=item.position, title=item.title, redirect_url=item.redirect_url, repo=item.repository, repo_group=item.repository_group)} + ${form_item(position=item.position, title=item.title, redirect_url=item.redirect_url, repo=item.repository, repo_group=item.repository_group)} % endif % endfor