my-account: owner/watched repos are now loaded only using DB queries.

- major speed-up for large number of entries
- permissions checks using IN generator
This commit is contained in:
Marcin Kuzminski 2019-12-19 17:49:40 +01:00
parent f3ee9bebe7
commit 116ffd25d2
5 changed files with 84 additions and 83 deletions

View file

@ -33,22 +33,21 @@ from rhodecode import forms
from rhodecode.lib import helpers as h
from rhodecode.lib import audit_logger
from rhodecode.lib.ext_json import json
from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired, \
HasRepoPermissionAny, HasRepoGroupPermissionAny
from rhodecode.lib.auth import (
LoginRequired, NotAnonymous, CSRFRequired,
HasRepoPermissionAny, HasRepoGroupPermissionAny, AuthUser)
from rhodecode.lib.channelstream import (
channelstream_request, ChannelstreamException)
from rhodecode.lib.utils2 import safe_int, md5, str2bool
from rhodecode.model.auth_token import AuthTokenModel
from rhodecode.model.comment import CommentsModel
from rhodecode.model.db import (
IntegrityError, joinedload,
IntegrityError, or_, in_filter_generator,
Repository, UserEmailMap, UserApiKeys, UserFollowing,
PullRequest, UserBookmark, RepoGroup)
from rhodecode.model.meta import Session
from rhodecode.model.pull_request import PullRequestModel
from rhodecode.model.scm import RepoList
from rhodecode.model.user import UserModel
from rhodecode.model.repo import RepoModel
from rhodecode.model.user_group import UserGroupModel
from rhodecode.model.validation_schema.schemas import user_schema
@ -345,23 +344,59 @@ class MyAccountView(BaseAppView, DataGridAppView):
'You should see a new live message now.'}
def _load_my_repos_data(self, watched=False):
if watched:
admin = False
follows_repos = Session().query(UserFollowing)\
.filter(UserFollowing.user_id == self._rhodecode_user.user_id)\
.options(joinedload(UserFollowing.follows_repository))\
.all()
repo_list = [x.follows_repository for x in follows_repos]
else:
admin = True
repo_list = Repository.get_all_repos(
user_id=self._rhodecode_user.user_id)
repo_list = RepoList(repo_list, perm_set=[
'repository.read', 'repository.write', 'repository.admin'],
extra_kwargs=dict(user=self._rhodecode_user))
repos_data = RepoModel().get_repos_as_dict(
repo_list=repo_list, admin=admin, short_name=False)
allowed_ids = [-1] + self._rhodecode_user.repo_acl_ids_from_stack(AuthUser.repo_read_perms)
if watched:
# repos user watch
repo_list = Session().query(
Repository
) \
.join(
(UserFollowing, UserFollowing.follows_repo_id == Repository.repo_id)
) \
.filter(
UserFollowing.user_id == self._rhodecode_user.user_id
) \
.filter(or_(
# generate multiple IN to fix limitation problems
*in_filter_generator(Repository.repo_id, allowed_ids))
) \
.order_by(Repository.repo_name) \
.all()
else:
# repos user is owner of
repo_list = Session().query(
Repository
) \
.filter(
Repository.user_id == self._rhodecode_user.user_id
) \
.filter(or_(
# generate multiple IN to fix limitation problems
*in_filter_generator(Repository.repo_id, allowed_ids))
) \
.order_by(Repository.repo_name) \
.all()
_render = self.request.get_partial_renderer(
'rhodecode:templates/data_table/_dt_elements.mako')
def repo_lnk(name, rtype, rstate, private, archived, fork_of):
return _render('repo_name', name, rtype, rstate, private, archived, fork_of,
short_name=False, admin=False)
repos_data = []
for repo in repo_list:
row = {
"name": repo_lnk(repo.repo_name, repo.repo_type, repo.repo_state,
repo.private, repo.archived, repo.fork),
"name_raw": repo.repo_name.lower(),
}
repos_data.append(row)
# json used to render the grid
return json.dumps(repos_data)

View file

@ -1051,6 +1051,8 @@ class AuthUser(object):
anonymous access is enabled and if so, it returns default user as logged in
"""
GLOBAL_PERMS = [x[0] for x in Permission.PERMS]
repo_read_perms = ['repository.read', 'repository.admin', 'repository.write']
repo_group_read_perms = ['group.read', 'group.write', 'group.admin']
def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None):

View file

@ -40,8 +40,8 @@
<li class="${h.is_active('external_identity', c.active)}"><a href="${my_account_external_url}">${_('External Identities')}</a></li>
% endif
<li class="${h.is_active('repos', c.active)}"><a href="${h.route_path('my_account_repos')}">${_('Repositories')}</a></li>
<li class="${h.is_active('watched', c.active)}"><a href="${h.route_path('my_account_watched')}">${_('Watched')}</a></li>
<li class="${h.is_active('repos', c.active)}"><a href="${h.route_path('my_account_repos')}">${_('Owned Repositories')}</a></li>
<li class="${h.is_active('watched', c.active)}"><a href="${h.route_path('my_account_watched')}">${_('Watched Repositories')}</a></li>
<li class="${h.is_active('pullrequests', c.active)}"><a href="${h.route_path('my_account_pullrequests')}">${_('Pull Requests')}</a></li>
<li class="${h.is_active('perms', c.active)}"><a href="${h.route_path('my_account_perms')}">${_('Permissions')}</a></li>
<li class="${h.is_active('my_notifications', c.active)}"><a href="${h.route_path('my_account_notifications')}">${_('Live Notifications')}</a></li>

View file

@ -15,13 +15,10 @@
<script>
$(document).ready(function() {
var get_datatable_count = function(){
var api = $('#repo_list_table').dataTable().api();
$('#repo_count').text(api.page.info().recordsDisplay);
};
// repo list
$('#repo_list_table').DataTable({
$repoListTable = $('#repo_list_table');
$repoListTable.DataTable({
data: ${c.data|n},
dom: 'rtp',
pageLength: ${c.visual.admin_grid_items},
@ -29,39 +26,23 @@ $(document).ready(function() {
columns: [
{ data: {"_": "name",
"sort": "name_raw"}, title: "${_('Name')}", className: "td-componentname" },
{ data: 'menu', className: "quick_repo_menu" },
{ data: {"_": "last_changeset",
"sort": "last_changeset_raw",
"type": Number}, title: "${_('Commit')}", className: "td-hash" },
{ data: {"_": "action",
"sort": "action"}, title: "${_('Action')}", className: "td-action" }
],
language: {
paginate: DEFAULT_GRID_PAGINATION,
emptyTable: _gettext("No repositories available yet.")
},
"initComplete": function( settings, json ) {
get_datatable_count();
quick_repo_menu();
}
});
// update the counter when doing search
$('#repo_list_table').on( 'search.dt', function (e,settings) {
get_datatable_count();
});
// filter
$('#q_filter').on('keyup',
$.debounce(250, function() {
$repoListTable.DataTable().search(
$('#q_filter').val()
).draw();
})
);
// filter, filter both grids
$('#q_filter').on( 'keyup', function () {
var repo_api = $('#repo_list_table').dataTable().api();
repo_api
.columns(0)
.search(this.value)
.draw();
});
// refilter table if page load via back button
$("#q_filter").trigger('keyup');
});

View file

@ -15,13 +15,10 @@
<script>
$(document).ready(function() {
var get_datatable_count = function(){
var api = $('#repo_list_table').dataTable().api();
$('#repo_count').text(api.page.info().recordsDisplay);
};
// repo list
$('#repo_list_table').DataTable({
$repoListTable = $('#repo_list_table');
$repoListTable.DataTable({
data: ${c.data|n},
dom: 'rtp',
pageLength: ${c.visual.admin_grid_items},
@ -29,37 +26,23 @@ $(document).ready(function() {
columns: [
{ data: {"_": "name",
"sort": "name_raw"}, title: "${_('Name')}", className: "td-componentname" },
{ data: 'menu', className: "quick_repo_menu" },
{ data: {"_": "last_changeset",
"sort": "last_changeset_raw",
"type": Number}, title: "${_('Commit')}", className: "td-hash" }
],
language: {
paginate: DEFAULT_GRID_PAGINATION,
emptyTable: _gettext("No repositories available yet.")
},
"initComplete": function( settings, json ) {
get_datatable_count();
quick_repo_menu();
}
});
// update the counter when doing search
$('#repo_list_table').on( 'search.dt', function (e,settings) {
get_datatable_count();
});
// filter
$('#q_filter').on('keyup',
$.debounce(250, function() {
$repoListTable.DataTable().search(
$('#q_filter').val()
).draw();
})
);
// filter, filter both grids
$('#q_filter').on( 'keyup', function () {
var repo_api = $('#repo_list_table').dataTable().api();
repo_api
.columns(0)
.search(this.value)
.draw();
});
// refilter table if page load via back button
$("#q_filter").trigger('keyup');
});