##// END OF EJS Templates
permissions: rename repository permissions to mention those are access permissions....
marcink -
r3985:95009b08 default
parent child Browse files
Show More
@@ -1,59 +1,59 b''
1 .. _keyboard-shortcuts:
1 .. _keyboard-shortcuts:
2
2
3 Keyboard Shortcuts
3 Keyboard Shortcuts
4 ==================
4 ==================
5
5
6 |RCE| has a number of user interface shortcut keys.
6 |RCE| has a number of user interface shortcut keys.
7
7
8 System Wide Shortcuts
8 System Wide Shortcuts
9 ---------------------
9 ---------------------
10
10
11 .. rst-class:: dl-horizontal
11 .. rst-class:: dl-horizontal
12
12
13 \--:kbd:`/`
13 \--:kbd:`/`
14 Open the |repo| search box.
14 Open the |repo| search box.
15
15
16 \--:kbd:`?`
16 \--:kbd:`?`
17 Open the |RCE| keyboard shortcuts page.
17 Open the |RCE| keyboard shortcuts page.
18
18
19 \--:kbd:`gh`
19 \--:kbd:`gh`
20 Go to the home page.
20 Go to the home page.
21
21
22 \--:kbd:`gg`
22 \--:kbd:`gg`
23 Go to my private gists page.
23 Go to my private gists page.
24
24
25 \--:kbd:`gG`
25 \--:kbd:`gG`
26 Go to my public gists page.
26 Go to my public gists page.
27
27
28 \--:kbd:`nr`
28 \--:kbd:`nr`
29 Go to the create new repository page.
29 Go to the create new repository page.
30
30
31 \--:kbd:`ng`
31 \--:kbd:`ng`
32 Go to the new gist page.
32 Go to the new gist page.
33
33
34 Repository Shortcuts
34 Repository Shortcuts
35 --------------------
35 --------------------
36
36
37 .. rst-class:: dl-horizontal
37 .. rst-class:: dl-horizontal
38
38
39
39
40 \--:kbd:`gs`
40 \--:kbd:`gs`
41 Go to the |repo| summary page.
41 Go to the |repo| summary page.
42
42
43 \--:kbd:`gc`
43 \--:kbd:`gc`
44 Go to the changelog page.
44 Go to the changelog page.
45
45
46 \--:kbd:`gf`
46 \--:kbd:`gf`
47 Go to the files page.
47 Go to the files page.
48
48
49 \--:kbd:`gF`
49 \--:kbd:`gF`
50 Go to the files page with file search activated.
50 Go to the files page with file search activated.
51
51
52 \--:kbd:`gp`
52 \--:kbd:`gp`
53 Go to the pull requests page.
53 Go to the pull requests page.
54
54
55 \--:kbd:`go`
55 \--:kbd:`go`
56 Go to the repository settings page.
56 Go to the repository settings page.
57
57
58 \--:kbd:`gO`
58 \--:kbd:`gO`
59 Go to the repository permissions settings.
59 Go to the repository access permissions settings.
@@ -1,77 +1,77 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import pytest
21 import pytest
22
22
23 from rhodecode.tests.utils import permission_update_data_generator
23 from rhodecode.tests.utils import permission_update_data_generator
24
24
25
25
26 def route_path(name, params=None, **kwargs):
26 def route_path(name, params=None, **kwargs):
27 import urllib
27 import urllib
28
28
29 base_url = {
29 base_url = {
30 'edit_repo_perms': '/{repo_name}/settings/permissions'
30 'edit_repo_perms': '/{repo_name}/settings/permissions'
31 # update is the same url
31 # update is the same url
32 }[name].format(**kwargs)
32 }[name].format(**kwargs)
33
33
34 if params:
34 if params:
35 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
35 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
36 return base_url
36 return base_url
37
37
38
38
39 @pytest.mark.usefixtures("app")
39 @pytest.mark.usefixtures("app")
40 class TestRepoPermissionsView(object):
40 class TestRepoPermissionsView(object):
41
41
42 def test_edit_perms_view(self, user_util, autologin_user):
42 def test_edit_perms_view(self, user_util, autologin_user):
43 repo = user_util.create_repo()
43 repo = user_util.create_repo()
44 self.app.get(
44 self.app.get(
45 route_path('edit_repo_perms',
45 route_path('edit_repo_perms',
46 repo_name=repo.repo_name), status=200)
46 repo_name=repo.repo_name), status=200)
47
47
48 def test_update_permissions(self, csrf_token, user_util):
48 def test_update_permissions(self, csrf_token, user_util):
49 repo = user_util.create_repo()
49 repo = user_util.create_repo()
50 repo_name = repo.repo_name
50 repo_name = repo.repo_name
51 user = user_util.create_user()
51 user = user_util.create_user()
52 user_id = user.user_id
52 user_id = user.user_id
53 username = user.username
53 username = user.username
54
54
55 # grant new
55 # grant new
56 form_data = permission_update_data_generator(
56 form_data = permission_update_data_generator(
57 csrf_token,
57 csrf_token,
58 default='repository.write',
58 default='repository.write',
59 grant=[(user_id, 'repository.write', username, 'user')])
59 grant=[(user_id, 'repository.write', username, 'user')])
60
60
61 response = self.app.post(
61 response = self.app.post(
62 route_path('edit_repo_perms',
62 route_path('edit_repo_perms',
63 repo_name=repo_name), form_data).follow()
63 repo_name=repo_name), form_data).follow()
64
64
65 assert 'Repository permissions updated' in response
65 assert 'Repository access permissions updated' in response
66
66
67 # revoke given
67 # revoke given
68 form_data = permission_update_data_generator(
68 form_data = permission_update_data_generator(
69 csrf_token,
69 csrf_token,
70 default='repository.read',
70 default='repository.read',
71 revoke=[(user_id, 'user')])
71 revoke=[(user_id, 'user')])
72
72
73 response = self.app.post(
73 response = self.app.post(
74 route_path('edit_repo_perms',
74 route_path('edit_repo_perms',
75 repo_name=repo_name), form_data).follow()
75 repo_name=repo_name), form_data).follow()
76
76
77 assert 'Repository permissions updated' in response
77 assert 'Repository access permissions updated' in response
@@ -1,122 +1,122 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2019 RhodeCode GmbH
3 # Copyright (C) 2011-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 from pyramid.httpexceptions import HTTPFound
23 from pyramid.httpexceptions import HTTPFound
24 from pyramid.view import view_config
24 from pyramid.view import view_config
25
25
26 from rhodecode.apps._base import RepoAppView
26 from rhodecode.apps._base import RepoAppView
27 from rhodecode.lib import helpers as h
27 from rhodecode.lib import helpers as h
28 from rhodecode.lib import audit_logger
28 from rhodecode.lib import audit_logger
29 from rhodecode.lib.auth import (
29 from rhodecode.lib.auth import (
30 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
30 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
31 from rhodecode.model.forms import RepoPermsForm
31 from rhodecode.model.forms import RepoPermsForm
32 from rhodecode.model.meta import Session
32 from rhodecode.model.meta import Session
33 from rhodecode.model.permission import PermissionModel
33 from rhodecode.model.permission import PermissionModel
34 from rhodecode.model.repo import RepoModel
34 from rhodecode.model.repo import RepoModel
35
35
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38
38
39 class RepoSettingsPermissionsView(RepoAppView):
39 class RepoSettingsPermissionsView(RepoAppView):
40
40
41 def load_default_context(self):
41 def load_default_context(self):
42 c = self._get_local_tmpl_context()
42 c = self._get_local_tmpl_context()
43 return c
43 return c
44
44
45 @LoginRequired()
45 @LoginRequired()
46 @HasRepoPermissionAnyDecorator('repository.admin')
46 @HasRepoPermissionAnyDecorator('repository.admin')
47 @view_config(
47 @view_config(
48 route_name='edit_repo_perms', request_method='GET',
48 route_name='edit_repo_perms', request_method='GET',
49 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
49 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
50 def edit_permissions(self):
50 def edit_permissions(self):
51 _ = self.request.translate
51 _ = self.request.translate
52 c = self.load_default_context()
52 c = self.load_default_context()
53 c.active = 'permissions'
53 c.active = 'permissions'
54 if self.request.GET.get('branch_permissions'):
54 if self.request.GET.get('branch_permissions'):
55 h.flash(_('Explicitly add user or user group with write+ '
55 h.flash(_('Explicitly add user or user group with write+ '
56 'permission to modify their branch permissions.'),
56 'permission to modify their branch permissions.'),
57 category='notice')
57 category='notice')
58 return self._get_template_context(c)
58 return self._get_template_context(c)
59
59
60 @LoginRequired()
60 @LoginRequired()
61 @HasRepoPermissionAnyDecorator('repository.admin')
61 @HasRepoPermissionAnyDecorator('repository.admin')
62 @CSRFRequired()
62 @CSRFRequired()
63 @view_config(
63 @view_config(
64 route_name='edit_repo_perms', request_method='POST',
64 route_name='edit_repo_perms', request_method='POST',
65 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
65 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
66 def edit_permissions_update(self):
66 def edit_permissions_update(self):
67 _ = self.request.translate
67 _ = self.request.translate
68 c = self.load_default_context()
68 c = self.load_default_context()
69 c.active = 'permissions'
69 c.active = 'permissions'
70 data = self.request.POST
70 data = self.request.POST
71 # store private flag outside of HTML to verify if we can modify
71 # store private flag outside of HTML to verify if we can modify
72 # default user permissions, prevents submission of FAKE post data
72 # default user permissions, prevents submission of FAKE post data
73 # into the form for private repos
73 # into the form for private repos
74 data['repo_private'] = self.db_repo.private
74 data['repo_private'] = self.db_repo.private
75 form = RepoPermsForm(self.request.translate)().to_python(data)
75 form = RepoPermsForm(self.request.translate)().to_python(data)
76 changes = RepoModel().update_permissions(
76 changes = RepoModel().update_permissions(
77 self.db_repo_name, form['perm_additions'], form['perm_updates'],
77 self.db_repo_name, form['perm_additions'], form['perm_updates'],
78 form['perm_deletions'])
78 form['perm_deletions'])
79
79
80 action_data = {
80 action_data = {
81 'added': changes['added'],
81 'added': changes['added'],
82 'updated': changes['updated'],
82 'updated': changes['updated'],
83 'deleted': changes['deleted'],
83 'deleted': changes['deleted'],
84 }
84 }
85 audit_logger.store_web(
85 audit_logger.store_web(
86 'repo.edit.permissions', action_data=action_data,
86 'repo.edit.permissions', action_data=action_data,
87 user=self._rhodecode_user, repo=self.db_repo)
87 user=self._rhodecode_user, repo=self.db_repo)
88
88
89 Session().commit()
89 Session().commit()
90 h.flash(_('Repository permissions updated'), category='success')
90 h.flash(_('Repository access permissions updated'), category='success')
91
91
92 PermissionModel().flush_user_permission_caches(changes)
92 PermissionModel().flush_user_permission_caches(changes)
93
93
94 raise HTTPFound(
94 raise HTTPFound(
95 h.route_path('edit_repo_perms', repo_name=self.db_repo_name))
95 h.route_path('edit_repo_perms', repo_name=self.db_repo_name))
96
96
97 @LoginRequired()
97 @LoginRequired()
98 @HasRepoPermissionAnyDecorator('repository.admin')
98 @HasRepoPermissionAnyDecorator('repository.admin')
99 @CSRFRequired()
99 @CSRFRequired()
100 @view_config(
100 @view_config(
101 route_name='edit_repo_perms_set_private', request_method='POST',
101 route_name='edit_repo_perms_set_private', request_method='POST',
102 renderer='json_ext')
102 renderer='json_ext')
103 def edit_permissions_set_private_repo(self):
103 def edit_permissions_set_private_repo(self):
104 _ = self.request.translate
104 _ = self.request.translate
105 self.load_default_context()
105 self.load_default_context()
106
106
107 try:
107 try:
108 RepoModel().update(
108 RepoModel().update(
109 self.db_repo, **{'repo_private': True, 'repo_name': self.db_repo_name})
109 self.db_repo, **{'repo_private': True, 'repo_name': self.db_repo_name})
110 Session().commit()
110 Session().commit()
111
111
112 h.flash(_('Repository `{}` private mode set successfully').format(self.db_repo_name),
112 h.flash(_('Repository `{}` private mode set successfully').format(self.db_repo_name),
113 category='success')
113 category='success')
114 except Exception:
114 except Exception:
115 log.exception("Exception during update of repository")
115 log.exception("Exception during update of repository")
116 h.flash(_('Error occurred during update of repository {}').format(
116 h.flash(_('Error occurred during update of repository {}').format(
117 self.db_repo_name), category='error')
117 self.db_repo_name), category='error')
118
118
119 return {
119 return {
120 'redirect_url': h.route_path('edit_repo_perms', repo_name=self.db_repo_name),
120 'redirect_url': h.route_path('edit_repo_perms', repo_name=self.db_repo_name),
121 'private': True
121 'private': True
122 }
122 }
@@ -1,2352 +1,2352 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 authentication and permission libraries
22 authentication and permission libraries
23 """
23 """
24
24
25 import os
25 import os
26 import time
26 import time
27 import inspect
27 import inspect
28 import collections
28 import collections
29 import fnmatch
29 import fnmatch
30 import hashlib
30 import hashlib
31 import itertools
31 import itertools
32 import logging
32 import logging
33 import random
33 import random
34 import traceback
34 import traceback
35 from functools import wraps
35 from functools import wraps
36
36
37 import ipaddress
37 import ipaddress
38
38
39 from pyramid.httpexceptions import HTTPForbidden, HTTPFound, HTTPNotFound
39 from pyramid.httpexceptions import HTTPForbidden, HTTPFound, HTTPNotFound
40 from sqlalchemy.orm.exc import ObjectDeletedError
40 from sqlalchemy.orm.exc import ObjectDeletedError
41 from sqlalchemy.orm import joinedload
41 from sqlalchemy.orm import joinedload
42 from zope.cachedescriptors.property import Lazy as LazyProperty
42 from zope.cachedescriptors.property import Lazy as LazyProperty
43
43
44 import rhodecode
44 import rhodecode
45 from rhodecode.model import meta
45 from rhodecode.model import meta
46 from rhodecode.model.meta import Session
46 from rhodecode.model.meta import Session
47 from rhodecode.model.user import UserModel
47 from rhodecode.model.user import UserModel
48 from rhodecode.model.db import (
48 from rhodecode.model.db import (
49 User, Repository, Permission, UserToPerm, UserGroupToPerm, UserGroupMember,
49 User, Repository, Permission, UserToPerm, UserGroupToPerm, UserGroupMember,
50 UserIpMap, UserApiKeys, RepoGroup, UserGroup)
50 UserIpMap, UserApiKeys, RepoGroup, UserGroup)
51 from rhodecode.lib import rc_cache
51 from rhodecode.lib import rc_cache
52 from rhodecode.lib.utils2 import safe_unicode, aslist, safe_str, md5, safe_int, sha1
52 from rhodecode.lib.utils2 import safe_unicode, aslist, safe_str, md5, safe_int, sha1
53 from rhodecode.lib.utils import (
53 from rhodecode.lib.utils import (
54 get_repo_slug, get_repo_group_slug, get_user_group_slug)
54 get_repo_slug, get_repo_group_slug, get_user_group_slug)
55 from rhodecode.lib.caching_query import FromCache
55 from rhodecode.lib.caching_query import FromCache
56
56
57
57
58 if rhodecode.is_unix:
58 if rhodecode.is_unix:
59 import bcrypt
59 import bcrypt
60
60
61 log = logging.getLogger(__name__)
61 log = logging.getLogger(__name__)
62
62
63 csrf_token_key = "csrf_token"
63 csrf_token_key = "csrf_token"
64
64
65
65
66 class PasswordGenerator(object):
66 class PasswordGenerator(object):
67 """
67 """
68 This is a simple class for generating password from different sets of
68 This is a simple class for generating password from different sets of
69 characters
69 characters
70 usage::
70 usage::
71 passwd_gen = PasswordGenerator()
71 passwd_gen = PasswordGenerator()
72 #print 8-letter password containing only big and small letters
72 #print 8-letter password containing only big and small letters
73 of alphabet
73 of alphabet
74 passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
74 passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
75 """
75 """
76 ALPHABETS_NUM = r'''1234567890'''
76 ALPHABETS_NUM = r'''1234567890'''
77 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
77 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
78 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
78 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
79 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
79 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
80 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
80 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
81 + ALPHABETS_NUM + ALPHABETS_SPECIAL
81 + ALPHABETS_NUM + ALPHABETS_SPECIAL
82 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
82 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
83 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
83 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
84 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
84 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
85 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
85 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
86
86
87 def __init__(self, passwd=''):
87 def __init__(self, passwd=''):
88 self.passwd = passwd
88 self.passwd = passwd
89
89
90 def gen_password(self, length, type_=None):
90 def gen_password(self, length, type_=None):
91 if type_ is None:
91 if type_ is None:
92 type_ = self.ALPHABETS_FULL
92 type_ = self.ALPHABETS_FULL
93 self.passwd = ''.join([random.choice(type_) for _ in range(length)])
93 self.passwd = ''.join([random.choice(type_) for _ in range(length)])
94 return self.passwd
94 return self.passwd
95
95
96
96
97 class _RhodeCodeCryptoBase(object):
97 class _RhodeCodeCryptoBase(object):
98 ENC_PREF = None
98 ENC_PREF = None
99
99
100 def hash_create(self, str_):
100 def hash_create(self, str_):
101 """
101 """
102 hash the string using
102 hash the string using
103
103
104 :param str_: password to hash
104 :param str_: password to hash
105 """
105 """
106 raise NotImplementedError
106 raise NotImplementedError
107
107
108 def hash_check_with_upgrade(self, password, hashed):
108 def hash_check_with_upgrade(self, password, hashed):
109 """
109 """
110 Returns tuple in which first element is boolean that states that
110 Returns tuple in which first element is boolean that states that
111 given password matches it's hashed version, and the second is new hash
111 given password matches it's hashed version, and the second is new hash
112 of the password, in case this password should be migrated to new
112 of the password, in case this password should be migrated to new
113 cipher.
113 cipher.
114 """
114 """
115 checked_hash = self.hash_check(password, hashed)
115 checked_hash = self.hash_check(password, hashed)
116 return checked_hash, None
116 return checked_hash, None
117
117
118 def hash_check(self, password, hashed):
118 def hash_check(self, password, hashed):
119 """
119 """
120 Checks matching password with it's hashed value.
120 Checks matching password with it's hashed value.
121
121
122 :param password: password
122 :param password: password
123 :param hashed: password in hashed form
123 :param hashed: password in hashed form
124 """
124 """
125 raise NotImplementedError
125 raise NotImplementedError
126
126
127 def _assert_bytes(self, value):
127 def _assert_bytes(self, value):
128 """
128 """
129 Passing in an `unicode` object can lead to hard to detect issues
129 Passing in an `unicode` object can lead to hard to detect issues
130 if passwords contain non-ascii characters. Doing a type check
130 if passwords contain non-ascii characters. Doing a type check
131 during runtime, so that such mistakes are detected early on.
131 during runtime, so that such mistakes are detected early on.
132 """
132 """
133 if not isinstance(value, str):
133 if not isinstance(value, str):
134 raise TypeError(
134 raise TypeError(
135 "Bytestring required as input, got %r." % (value, ))
135 "Bytestring required as input, got %r." % (value, ))
136
136
137
137
138 class _RhodeCodeCryptoBCrypt(_RhodeCodeCryptoBase):
138 class _RhodeCodeCryptoBCrypt(_RhodeCodeCryptoBase):
139 ENC_PREF = ('$2a$10', '$2b$10')
139 ENC_PREF = ('$2a$10', '$2b$10')
140
140
141 def hash_create(self, str_):
141 def hash_create(self, str_):
142 self._assert_bytes(str_)
142 self._assert_bytes(str_)
143 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
143 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
144
144
145 def hash_check_with_upgrade(self, password, hashed):
145 def hash_check_with_upgrade(self, password, hashed):
146 """
146 """
147 Returns tuple in which first element is boolean that states that
147 Returns tuple in which first element is boolean that states that
148 given password matches it's hashed version, and the second is new hash
148 given password matches it's hashed version, and the second is new hash
149 of the password, in case this password should be migrated to new
149 of the password, in case this password should be migrated to new
150 cipher.
150 cipher.
151
151
152 This implements special upgrade logic which works like that:
152 This implements special upgrade logic which works like that:
153 - check if the given password == bcrypted hash, if yes then we
153 - check if the given password == bcrypted hash, if yes then we
154 properly used password and it was already in bcrypt. Proceed
154 properly used password and it was already in bcrypt. Proceed
155 without any changes
155 without any changes
156 - if bcrypt hash check is not working try with sha256. If hash compare
156 - if bcrypt hash check is not working try with sha256. If hash compare
157 is ok, it means we using correct but old hashed password. indicate
157 is ok, it means we using correct but old hashed password. indicate
158 hash change and proceed
158 hash change and proceed
159 """
159 """
160
160
161 new_hash = None
161 new_hash = None
162
162
163 # regular pw check
163 # regular pw check
164 password_match_bcrypt = self.hash_check(password, hashed)
164 password_match_bcrypt = self.hash_check(password, hashed)
165
165
166 # now we want to know if the password was maybe from sha256
166 # now we want to know if the password was maybe from sha256
167 # basically calling _RhodeCodeCryptoSha256().hash_check()
167 # basically calling _RhodeCodeCryptoSha256().hash_check()
168 if not password_match_bcrypt:
168 if not password_match_bcrypt:
169 if _RhodeCodeCryptoSha256().hash_check(password, hashed):
169 if _RhodeCodeCryptoSha256().hash_check(password, hashed):
170 new_hash = self.hash_create(password) # make new bcrypt hash
170 new_hash = self.hash_create(password) # make new bcrypt hash
171 password_match_bcrypt = True
171 password_match_bcrypt = True
172
172
173 return password_match_bcrypt, new_hash
173 return password_match_bcrypt, new_hash
174
174
175 def hash_check(self, password, hashed):
175 def hash_check(self, password, hashed):
176 """
176 """
177 Checks matching password with it's hashed value.
177 Checks matching password with it's hashed value.
178
178
179 :param password: password
179 :param password: password
180 :param hashed: password in hashed form
180 :param hashed: password in hashed form
181 """
181 """
182 self._assert_bytes(password)
182 self._assert_bytes(password)
183 try:
183 try:
184 return bcrypt.hashpw(password, hashed) == hashed
184 return bcrypt.hashpw(password, hashed) == hashed
185 except ValueError as e:
185 except ValueError as e:
186 # we're having a invalid salt here probably, we should not crash
186 # we're having a invalid salt here probably, we should not crash
187 # just return with False as it would be a wrong password.
187 # just return with False as it would be a wrong password.
188 log.debug('Failed to check password hash using bcrypt %s',
188 log.debug('Failed to check password hash using bcrypt %s',
189 safe_str(e))
189 safe_str(e))
190
190
191 return False
191 return False
192
192
193
193
194 class _RhodeCodeCryptoSha256(_RhodeCodeCryptoBase):
194 class _RhodeCodeCryptoSha256(_RhodeCodeCryptoBase):
195 ENC_PREF = '_'
195 ENC_PREF = '_'
196
196
197 def hash_create(self, str_):
197 def hash_create(self, str_):
198 self._assert_bytes(str_)
198 self._assert_bytes(str_)
199 return hashlib.sha256(str_).hexdigest()
199 return hashlib.sha256(str_).hexdigest()
200
200
201 def hash_check(self, password, hashed):
201 def hash_check(self, password, hashed):
202 """
202 """
203 Checks matching password with it's hashed value.
203 Checks matching password with it's hashed value.
204
204
205 :param password: password
205 :param password: password
206 :param hashed: password in hashed form
206 :param hashed: password in hashed form
207 """
207 """
208 self._assert_bytes(password)
208 self._assert_bytes(password)
209 return hashlib.sha256(password).hexdigest() == hashed
209 return hashlib.sha256(password).hexdigest() == hashed
210
210
211
211
212 class _RhodeCodeCryptoTest(_RhodeCodeCryptoBase):
212 class _RhodeCodeCryptoTest(_RhodeCodeCryptoBase):
213 ENC_PREF = '_'
213 ENC_PREF = '_'
214
214
215 def hash_create(self, str_):
215 def hash_create(self, str_):
216 self._assert_bytes(str_)
216 self._assert_bytes(str_)
217 return sha1(str_)
217 return sha1(str_)
218
218
219 def hash_check(self, password, hashed):
219 def hash_check(self, password, hashed):
220 """
220 """
221 Checks matching password with it's hashed value.
221 Checks matching password with it's hashed value.
222
222
223 :param password: password
223 :param password: password
224 :param hashed: password in hashed form
224 :param hashed: password in hashed form
225 """
225 """
226 self._assert_bytes(password)
226 self._assert_bytes(password)
227 return sha1(password) == hashed
227 return sha1(password) == hashed
228
228
229
229
230 def crypto_backend():
230 def crypto_backend():
231 """
231 """
232 Return the matching crypto backend.
232 Return the matching crypto backend.
233
233
234 Selection is based on if we run tests or not, we pick sha1-test backend to run
234 Selection is based on if we run tests or not, we pick sha1-test backend to run
235 tests faster since BCRYPT is expensive to calculate
235 tests faster since BCRYPT is expensive to calculate
236 """
236 """
237 if rhodecode.is_test:
237 if rhodecode.is_test:
238 RhodeCodeCrypto = _RhodeCodeCryptoTest()
238 RhodeCodeCrypto = _RhodeCodeCryptoTest()
239 else:
239 else:
240 RhodeCodeCrypto = _RhodeCodeCryptoBCrypt()
240 RhodeCodeCrypto = _RhodeCodeCryptoBCrypt()
241
241
242 return RhodeCodeCrypto
242 return RhodeCodeCrypto
243
243
244
244
245 def get_crypt_password(password):
245 def get_crypt_password(password):
246 """
246 """
247 Create the hash of `password` with the active crypto backend.
247 Create the hash of `password` with the active crypto backend.
248
248
249 :param password: The cleartext password.
249 :param password: The cleartext password.
250 :type password: unicode
250 :type password: unicode
251 """
251 """
252 password = safe_str(password)
252 password = safe_str(password)
253 return crypto_backend().hash_create(password)
253 return crypto_backend().hash_create(password)
254
254
255
255
256 def check_password(password, hashed):
256 def check_password(password, hashed):
257 """
257 """
258 Check if the value in `password` matches the hash in `hashed`.
258 Check if the value in `password` matches the hash in `hashed`.
259
259
260 :param password: The cleartext password.
260 :param password: The cleartext password.
261 :type password: unicode
261 :type password: unicode
262
262
263 :param hashed: The expected hashed version of the password.
263 :param hashed: The expected hashed version of the password.
264 :type hashed: The hash has to be passed in in text representation.
264 :type hashed: The hash has to be passed in in text representation.
265 """
265 """
266 password = safe_str(password)
266 password = safe_str(password)
267 return crypto_backend().hash_check(password, hashed)
267 return crypto_backend().hash_check(password, hashed)
268
268
269
269
270 def generate_auth_token(data, salt=None):
270 def generate_auth_token(data, salt=None):
271 """
271 """
272 Generates API KEY from given string
272 Generates API KEY from given string
273 """
273 """
274
274
275 if salt is None:
275 if salt is None:
276 salt = os.urandom(16)
276 salt = os.urandom(16)
277 return hashlib.sha1(safe_str(data) + salt).hexdigest()
277 return hashlib.sha1(safe_str(data) + salt).hexdigest()
278
278
279
279
280 def get_came_from(request):
280 def get_came_from(request):
281 """
281 """
282 get query_string+path from request sanitized after removing auth_token
282 get query_string+path from request sanitized after removing auth_token
283 """
283 """
284 _req = request
284 _req = request
285
285
286 path = _req.path
286 path = _req.path
287 if 'auth_token' in _req.GET:
287 if 'auth_token' in _req.GET:
288 # sanitize the request and remove auth_token for redirection
288 # sanitize the request and remove auth_token for redirection
289 _req.GET.pop('auth_token')
289 _req.GET.pop('auth_token')
290 qs = _req.query_string
290 qs = _req.query_string
291 if qs:
291 if qs:
292 path += '?' + qs
292 path += '?' + qs
293
293
294 return path
294 return path
295
295
296
296
297 class CookieStoreWrapper(object):
297 class CookieStoreWrapper(object):
298
298
299 def __init__(self, cookie_store):
299 def __init__(self, cookie_store):
300 self.cookie_store = cookie_store
300 self.cookie_store = cookie_store
301
301
302 def __repr__(self):
302 def __repr__(self):
303 return 'CookieStore<%s>' % (self.cookie_store)
303 return 'CookieStore<%s>' % (self.cookie_store)
304
304
305 def get(self, key, other=None):
305 def get(self, key, other=None):
306 if isinstance(self.cookie_store, dict):
306 if isinstance(self.cookie_store, dict):
307 return self.cookie_store.get(key, other)
307 return self.cookie_store.get(key, other)
308 elif isinstance(self.cookie_store, AuthUser):
308 elif isinstance(self.cookie_store, AuthUser):
309 return self.cookie_store.__dict__.get(key, other)
309 return self.cookie_store.__dict__.get(key, other)
310
310
311
311
312 def _cached_perms_data(user_id, scope, user_is_admin,
312 def _cached_perms_data(user_id, scope, user_is_admin,
313 user_inherit_default_permissions, explicit, algo,
313 user_inherit_default_permissions, explicit, algo,
314 calculate_super_admin):
314 calculate_super_admin):
315
315
316 permissions = PermissionCalculator(
316 permissions = PermissionCalculator(
317 user_id, scope, user_is_admin, user_inherit_default_permissions,
317 user_id, scope, user_is_admin, user_inherit_default_permissions,
318 explicit, algo, calculate_super_admin)
318 explicit, algo, calculate_super_admin)
319 return permissions.calculate()
319 return permissions.calculate()
320
320
321
321
322 class PermOrigin(object):
322 class PermOrigin(object):
323 SUPER_ADMIN = 'superadmin'
323 SUPER_ADMIN = 'superadmin'
324 ARCHIVED = 'archived'
324 ARCHIVED = 'archived'
325
325
326 REPO_USER = 'user:%s'
326 REPO_USER = 'user:%s'
327 REPO_USERGROUP = 'usergroup:%s'
327 REPO_USERGROUP = 'usergroup:%s'
328 REPO_OWNER = 'repo.owner'
328 REPO_OWNER = 'repo.owner'
329 REPO_DEFAULT = 'repo.default'
329 REPO_DEFAULT = 'repo.default'
330 REPO_DEFAULT_NO_INHERIT = 'repo.default.no.inherit'
330 REPO_DEFAULT_NO_INHERIT = 'repo.default.no.inherit'
331 REPO_PRIVATE = 'repo.private'
331 REPO_PRIVATE = 'repo.private'
332
332
333 REPOGROUP_USER = 'user:%s'
333 REPOGROUP_USER = 'user:%s'
334 REPOGROUP_USERGROUP = 'usergroup:%s'
334 REPOGROUP_USERGROUP = 'usergroup:%s'
335 REPOGROUP_OWNER = 'group.owner'
335 REPOGROUP_OWNER = 'group.owner'
336 REPOGROUP_DEFAULT = 'group.default'
336 REPOGROUP_DEFAULT = 'group.default'
337 REPOGROUP_DEFAULT_NO_INHERIT = 'group.default.no.inherit'
337 REPOGROUP_DEFAULT_NO_INHERIT = 'group.default.no.inherit'
338
338
339 USERGROUP_USER = 'user:%s'
339 USERGROUP_USER = 'user:%s'
340 USERGROUP_USERGROUP = 'usergroup:%s'
340 USERGROUP_USERGROUP = 'usergroup:%s'
341 USERGROUP_OWNER = 'usergroup.owner'
341 USERGROUP_OWNER = 'usergroup.owner'
342 USERGROUP_DEFAULT = 'usergroup.default'
342 USERGROUP_DEFAULT = 'usergroup.default'
343 USERGROUP_DEFAULT_NO_INHERIT = 'usergroup.default.no.inherit'
343 USERGROUP_DEFAULT_NO_INHERIT = 'usergroup.default.no.inherit'
344
344
345
345
346 class PermOriginDict(dict):
346 class PermOriginDict(dict):
347 """
347 """
348 A special dict used for tracking permissions along with their origins.
348 A special dict used for tracking permissions along with their origins.
349
349
350 `__setitem__` has been overridden to expect a tuple(perm, origin)
350 `__setitem__` has been overridden to expect a tuple(perm, origin)
351 `__getitem__` will return only the perm
351 `__getitem__` will return only the perm
352 `.perm_origin_stack` will return the stack of (perm, origin) set per key
352 `.perm_origin_stack` will return the stack of (perm, origin) set per key
353
353
354 >>> perms = PermOriginDict()
354 >>> perms = PermOriginDict()
355 >>> perms['resource'] = 'read', 'default'
355 >>> perms['resource'] = 'read', 'default'
356 >>> perms['resource']
356 >>> perms['resource']
357 'read'
357 'read'
358 >>> perms['resource'] = 'write', 'admin'
358 >>> perms['resource'] = 'write', 'admin'
359 >>> perms['resource']
359 >>> perms['resource']
360 'write'
360 'write'
361 >>> perms.perm_origin_stack
361 >>> perms.perm_origin_stack
362 {'resource': [('read', 'default'), ('write', 'admin')]}
362 {'resource': [('read', 'default'), ('write', 'admin')]}
363 """
363 """
364
364
365 def __init__(self, *args, **kw):
365 def __init__(self, *args, **kw):
366 dict.__init__(self, *args, **kw)
366 dict.__init__(self, *args, **kw)
367 self.perm_origin_stack = collections.OrderedDict()
367 self.perm_origin_stack = collections.OrderedDict()
368
368
369 def __setitem__(self, key, (perm, origin)):
369 def __setitem__(self, key, (perm, origin)):
370 self.perm_origin_stack.setdefault(key, []).append(
370 self.perm_origin_stack.setdefault(key, []).append(
371 (perm, origin))
371 (perm, origin))
372 dict.__setitem__(self, key, perm)
372 dict.__setitem__(self, key, perm)
373
373
374
374
375 class BranchPermOriginDict(PermOriginDict):
375 class BranchPermOriginDict(PermOriginDict):
376 """
376 """
377 Dedicated branch permissions dict, with tracking of patterns and origins.
377 Dedicated branch permissions dict, with tracking of patterns and origins.
378
378
379 >>> perms = BranchPermOriginDict()
379 >>> perms = BranchPermOriginDict()
380 >>> perms['resource'] = '*pattern', 'read', 'default'
380 >>> perms['resource'] = '*pattern', 'read', 'default'
381 >>> perms['resource']
381 >>> perms['resource']
382 {'*pattern': 'read'}
382 {'*pattern': 'read'}
383 >>> perms['resource'] = '*pattern', 'write', 'admin'
383 >>> perms['resource'] = '*pattern', 'write', 'admin'
384 >>> perms['resource']
384 >>> perms['resource']
385 {'*pattern': 'write'}
385 {'*pattern': 'write'}
386 >>> perms.perm_origin_stack
386 >>> perms.perm_origin_stack
387 {'resource': {'*pattern': [('read', 'default'), ('write', 'admin')]}}
387 {'resource': {'*pattern': [('read', 'default'), ('write', 'admin')]}}
388 """
388 """
389 def __setitem__(self, key, (pattern, perm, origin)):
389 def __setitem__(self, key, (pattern, perm, origin)):
390
390
391 self.perm_origin_stack.setdefault(key, {}) \
391 self.perm_origin_stack.setdefault(key, {}) \
392 .setdefault(pattern, []).append((perm, origin))
392 .setdefault(pattern, []).append((perm, origin))
393
393
394 if key in self:
394 if key in self:
395 self[key].__setitem__(pattern, perm)
395 self[key].__setitem__(pattern, perm)
396 else:
396 else:
397 patterns = collections.OrderedDict()
397 patterns = collections.OrderedDict()
398 patterns[pattern] = perm
398 patterns[pattern] = perm
399 dict.__setitem__(self, key, patterns)
399 dict.__setitem__(self, key, patterns)
400
400
401
401
402 class PermissionCalculator(object):
402 class PermissionCalculator(object):
403
403
404 def __init__(
404 def __init__(
405 self, user_id, scope, user_is_admin,
405 self, user_id, scope, user_is_admin,
406 user_inherit_default_permissions, explicit, algo,
406 user_inherit_default_permissions, explicit, algo,
407 calculate_super_admin_as_user=False):
407 calculate_super_admin_as_user=False):
408
408
409 self.user_id = user_id
409 self.user_id = user_id
410 self.user_is_admin = user_is_admin
410 self.user_is_admin = user_is_admin
411 self.inherit_default_permissions = user_inherit_default_permissions
411 self.inherit_default_permissions = user_inherit_default_permissions
412 self.explicit = explicit
412 self.explicit = explicit
413 self.algo = algo
413 self.algo = algo
414 self.calculate_super_admin_as_user = calculate_super_admin_as_user
414 self.calculate_super_admin_as_user = calculate_super_admin_as_user
415
415
416 scope = scope or {}
416 scope = scope or {}
417 self.scope_repo_id = scope.get('repo_id')
417 self.scope_repo_id = scope.get('repo_id')
418 self.scope_repo_group_id = scope.get('repo_group_id')
418 self.scope_repo_group_id = scope.get('repo_group_id')
419 self.scope_user_group_id = scope.get('user_group_id')
419 self.scope_user_group_id = scope.get('user_group_id')
420
420
421 self.default_user_id = User.get_default_user(cache=True).user_id
421 self.default_user_id = User.get_default_user(cache=True).user_id
422
422
423 self.permissions_repositories = PermOriginDict()
423 self.permissions_repositories = PermOriginDict()
424 self.permissions_repository_groups = PermOriginDict()
424 self.permissions_repository_groups = PermOriginDict()
425 self.permissions_user_groups = PermOriginDict()
425 self.permissions_user_groups = PermOriginDict()
426 self.permissions_repository_branches = BranchPermOriginDict()
426 self.permissions_repository_branches = BranchPermOriginDict()
427 self.permissions_global = set()
427 self.permissions_global = set()
428
428
429 self.default_repo_perms = Permission.get_default_repo_perms(
429 self.default_repo_perms = Permission.get_default_repo_perms(
430 self.default_user_id, self.scope_repo_id)
430 self.default_user_id, self.scope_repo_id)
431 self.default_repo_groups_perms = Permission.get_default_group_perms(
431 self.default_repo_groups_perms = Permission.get_default_group_perms(
432 self.default_user_id, self.scope_repo_group_id)
432 self.default_user_id, self.scope_repo_group_id)
433 self.default_user_group_perms = \
433 self.default_user_group_perms = \
434 Permission.get_default_user_group_perms(
434 Permission.get_default_user_group_perms(
435 self.default_user_id, self.scope_user_group_id)
435 self.default_user_id, self.scope_user_group_id)
436
436
437 # default branch perms
437 # default branch perms
438 self.default_branch_repo_perms = \
438 self.default_branch_repo_perms = \
439 Permission.get_default_repo_branch_perms(
439 Permission.get_default_repo_branch_perms(
440 self.default_user_id, self.scope_repo_id)
440 self.default_user_id, self.scope_repo_id)
441
441
442 def calculate(self):
442 def calculate(self):
443 if self.user_is_admin and not self.calculate_super_admin_as_user:
443 if self.user_is_admin and not self.calculate_super_admin_as_user:
444 return self._calculate_admin_permissions()
444 return self._calculate_admin_permissions()
445
445
446 self._calculate_global_default_permissions()
446 self._calculate_global_default_permissions()
447 self._calculate_global_permissions()
447 self._calculate_global_permissions()
448 self._calculate_default_permissions()
448 self._calculate_default_permissions()
449 self._calculate_repository_permissions()
449 self._calculate_repository_permissions()
450 self._calculate_repository_branch_permissions()
450 self._calculate_repository_branch_permissions()
451 self._calculate_repository_group_permissions()
451 self._calculate_repository_group_permissions()
452 self._calculate_user_group_permissions()
452 self._calculate_user_group_permissions()
453 return self._permission_structure()
453 return self._permission_structure()
454
454
455 def _calculate_admin_permissions(self):
455 def _calculate_admin_permissions(self):
456 """
456 """
457 admin user have all default rights for repositories
457 admin user have all default rights for repositories
458 and groups set to admin
458 and groups set to admin
459 """
459 """
460 self.permissions_global.add('hg.admin')
460 self.permissions_global.add('hg.admin')
461 self.permissions_global.add('hg.create.write_on_repogroup.true')
461 self.permissions_global.add('hg.create.write_on_repogroup.true')
462
462
463 # repositories
463 # repositories
464 for perm in self.default_repo_perms:
464 for perm in self.default_repo_perms:
465 r_k = perm.UserRepoToPerm.repository.repo_name
465 r_k = perm.UserRepoToPerm.repository.repo_name
466 archived = perm.UserRepoToPerm.repository.archived
466 archived = perm.UserRepoToPerm.repository.archived
467 p = 'repository.admin'
467 p = 'repository.admin'
468 self.permissions_repositories[r_k] = p, PermOrigin.SUPER_ADMIN
468 self.permissions_repositories[r_k] = p, PermOrigin.SUPER_ADMIN
469 # special case for archived repositories, which we block still even for
469 # special case for archived repositories, which we block still even for
470 # super admins
470 # super admins
471 if archived:
471 if archived:
472 p = 'repository.read'
472 p = 'repository.read'
473 self.permissions_repositories[r_k] = p, PermOrigin.ARCHIVED
473 self.permissions_repositories[r_k] = p, PermOrigin.ARCHIVED
474
474
475 # repository groups
475 # repository groups
476 for perm in self.default_repo_groups_perms:
476 for perm in self.default_repo_groups_perms:
477 rg_k = perm.UserRepoGroupToPerm.group.group_name
477 rg_k = perm.UserRepoGroupToPerm.group.group_name
478 p = 'group.admin'
478 p = 'group.admin'
479 self.permissions_repository_groups[rg_k] = p, PermOrigin.SUPER_ADMIN
479 self.permissions_repository_groups[rg_k] = p, PermOrigin.SUPER_ADMIN
480
480
481 # user groups
481 # user groups
482 for perm in self.default_user_group_perms:
482 for perm in self.default_user_group_perms:
483 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
483 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
484 p = 'usergroup.admin'
484 p = 'usergroup.admin'
485 self.permissions_user_groups[u_k] = p, PermOrigin.SUPER_ADMIN
485 self.permissions_user_groups[u_k] = p, PermOrigin.SUPER_ADMIN
486
486
487 # branch permissions
487 # branch permissions
488 # since super-admin also can have custom rule permissions
488 # since super-admin also can have custom rule permissions
489 # we *always* need to calculate those inherited from default, and also explicit
489 # we *always* need to calculate those inherited from default, and also explicit
490 self._calculate_default_permissions_repository_branches(
490 self._calculate_default_permissions_repository_branches(
491 user_inherit_object_permissions=False)
491 user_inherit_object_permissions=False)
492 self._calculate_repository_branch_permissions()
492 self._calculate_repository_branch_permissions()
493
493
494 return self._permission_structure()
494 return self._permission_structure()
495
495
496 def _calculate_global_default_permissions(self):
496 def _calculate_global_default_permissions(self):
497 """
497 """
498 global permissions taken from the default user
498 global permissions taken from the default user
499 """
499 """
500 default_global_perms = UserToPerm.query()\
500 default_global_perms = UserToPerm.query()\
501 .filter(UserToPerm.user_id == self.default_user_id)\
501 .filter(UserToPerm.user_id == self.default_user_id)\
502 .options(joinedload(UserToPerm.permission))
502 .options(joinedload(UserToPerm.permission))
503
503
504 for perm in default_global_perms:
504 for perm in default_global_perms:
505 self.permissions_global.add(perm.permission.permission_name)
505 self.permissions_global.add(perm.permission.permission_name)
506
506
507 if self.user_is_admin:
507 if self.user_is_admin:
508 self.permissions_global.add('hg.admin')
508 self.permissions_global.add('hg.admin')
509 self.permissions_global.add('hg.create.write_on_repogroup.true')
509 self.permissions_global.add('hg.create.write_on_repogroup.true')
510
510
511 def _calculate_global_permissions(self):
511 def _calculate_global_permissions(self):
512 """
512 """
513 Set global system permissions with user permissions or permissions
513 Set global system permissions with user permissions or permissions
514 taken from the user groups of the current user.
514 taken from the user groups of the current user.
515
515
516 The permissions include repo creating, repo group creating, forking
516 The permissions include repo creating, repo group creating, forking
517 etc.
517 etc.
518 """
518 """
519
519
520 # now we read the defined permissions and overwrite what we have set
520 # now we read the defined permissions and overwrite what we have set
521 # before those can be configured from groups or users explicitly.
521 # before those can be configured from groups or users explicitly.
522
522
523 # In case we want to extend this list we should make sure
523 # In case we want to extend this list we should make sure
524 # this is in sync with User.DEFAULT_USER_PERMISSIONS definitions
524 # this is in sync with User.DEFAULT_USER_PERMISSIONS definitions
525 _configurable = frozenset([
525 _configurable = frozenset([
526 'hg.fork.none', 'hg.fork.repository',
526 'hg.fork.none', 'hg.fork.repository',
527 'hg.create.none', 'hg.create.repository',
527 'hg.create.none', 'hg.create.repository',
528 'hg.usergroup.create.false', 'hg.usergroup.create.true',
528 'hg.usergroup.create.false', 'hg.usergroup.create.true',
529 'hg.repogroup.create.false', 'hg.repogroup.create.true',
529 'hg.repogroup.create.false', 'hg.repogroup.create.true',
530 'hg.create.write_on_repogroup.false', 'hg.create.write_on_repogroup.true',
530 'hg.create.write_on_repogroup.false', 'hg.create.write_on_repogroup.true',
531 'hg.inherit_default_perms.false', 'hg.inherit_default_perms.true'
531 'hg.inherit_default_perms.false', 'hg.inherit_default_perms.true'
532 ])
532 ])
533
533
534 # USER GROUPS comes first user group global permissions
534 # USER GROUPS comes first user group global permissions
535 user_perms_from_users_groups = Session().query(UserGroupToPerm)\
535 user_perms_from_users_groups = Session().query(UserGroupToPerm)\
536 .options(joinedload(UserGroupToPerm.permission))\
536 .options(joinedload(UserGroupToPerm.permission))\
537 .join((UserGroupMember, UserGroupToPerm.users_group_id ==
537 .join((UserGroupMember, UserGroupToPerm.users_group_id ==
538 UserGroupMember.users_group_id))\
538 UserGroupMember.users_group_id))\
539 .filter(UserGroupMember.user_id == self.user_id)\
539 .filter(UserGroupMember.user_id == self.user_id)\
540 .order_by(UserGroupToPerm.users_group_id)\
540 .order_by(UserGroupToPerm.users_group_id)\
541 .all()
541 .all()
542
542
543 # need to group here by groups since user can be in more than
543 # need to group here by groups since user can be in more than
544 # one group, so we get all groups
544 # one group, so we get all groups
545 _explicit_grouped_perms = [
545 _explicit_grouped_perms = [
546 [x, list(y)] for x, y in
546 [x, list(y)] for x, y in
547 itertools.groupby(user_perms_from_users_groups,
547 itertools.groupby(user_perms_from_users_groups,
548 lambda _x: _x.users_group)]
548 lambda _x: _x.users_group)]
549
549
550 for gr, perms in _explicit_grouped_perms:
550 for gr, perms in _explicit_grouped_perms:
551 # since user can be in multiple groups iterate over them and
551 # since user can be in multiple groups iterate over them and
552 # select the lowest permissions first (more explicit)
552 # select the lowest permissions first (more explicit)
553 # TODO(marcink): do this^^
553 # TODO(marcink): do this^^
554
554
555 # group doesn't inherit default permissions so we actually set them
555 # group doesn't inherit default permissions so we actually set them
556 if not gr.inherit_default_permissions:
556 if not gr.inherit_default_permissions:
557 # NEED TO IGNORE all previously set configurable permissions
557 # NEED TO IGNORE all previously set configurable permissions
558 # and replace them with explicitly set from this user
558 # and replace them with explicitly set from this user
559 # group permissions
559 # group permissions
560 self.permissions_global = self.permissions_global.difference(
560 self.permissions_global = self.permissions_global.difference(
561 _configurable)
561 _configurable)
562 for perm in perms:
562 for perm in perms:
563 self.permissions_global.add(perm.permission.permission_name)
563 self.permissions_global.add(perm.permission.permission_name)
564
564
565 # user explicit global permissions
565 # user explicit global permissions
566 user_perms = Session().query(UserToPerm)\
566 user_perms = Session().query(UserToPerm)\
567 .options(joinedload(UserToPerm.permission))\
567 .options(joinedload(UserToPerm.permission))\
568 .filter(UserToPerm.user_id == self.user_id).all()
568 .filter(UserToPerm.user_id == self.user_id).all()
569
569
570 if not self.inherit_default_permissions:
570 if not self.inherit_default_permissions:
571 # NEED TO IGNORE all configurable permissions and
571 # NEED TO IGNORE all configurable permissions and
572 # replace them with explicitly set from this user permissions
572 # replace them with explicitly set from this user permissions
573 self.permissions_global = self.permissions_global.difference(
573 self.permissions_global = self.permissions_global.difference(
574 _configurable)
574 _configurable)
575 for perm in user_perms:
575 for perm in user_perms:
576 self.permissions_global.add(perm.permission.permission_name)
576 self.permissions_global.add(perm.permission.permission_name)
577
577
578 def _calculate_default_permissions_repositories(self, user_inherit_object_permissions):
578 def _calculate_default_permissions_repositories(self, user_inherit_object_permissions):
579 for perm in self.default_repo_perms:
579 for perm in self.default_repo_perms:
580 r_k = perm.UserRepoToPerm.repository.repo_name
580 r_k = perm.UserRepoToPerm.repository.repo_name
581 archived = perm.UserRepoToPerm.repository.archived
581 archived = perm.UserRepoToPerm.repository.archived
582 p = perm.Permission.permission_name
582 p = perm.Permission.permission_name
583 o = PermOrigin.REPO_DEFAULT
583 o = PermOrigin.REPO_DEFAULT
584 self.permissions_repositories[r_k] = p, o
584 self.permissions_repositories[r_k] = p, o
585
585
586 # if we decide this user isn't inheriting permissions from
586 # if we decide this user isn't inheriting permissions from
587 # default user we set him to .none so only explicit
587 # default user we set him to .none so only explicit
588 # permissions work
588 # permissions work
589 if not user_inherit_object_permissions:
589 if not user_inherit_object_permissions:
590 p = 'repository.none'
590 p = 'repository.none'
591 o = PermOrigin.REPO_DEFAULT_NO_INHERIT
591 o = PermOrigin.REPO_DEFAULT_NO_INHERIT
592 self.permissions_repositories[r_k] = p, o
592 self.permissions_repositories[r_k] = p, o
593
593
594 if perm.Repository.private and not (
594 if perm.Repository.private and not (
595 perm.Repository.user_id == self.user_id):
595 perm.Repository.user_id == self.user_id):
596 # disable defaults for private repos,
596 # disable defaults for private repos,
597 p = 'repository.none'
597 p = 'repository.none'
598 o = PermOrigin.REPO_PRIVATE
598 o = PermOrigin.REPO_PRIVATE
599 self.permissions_repositories[r_k] = p, o
599 self.permissions_repositories[r_k] = p, o
600
600
601 elif perm.Repository.user_id == self.user_id:
601 elif perm.Repository.user_id == self.user_id:
602 # set admin if owner
602 # set admin if owner
603 p = 'repository.admin'
603 p = 'repository.admin'
604 o = PermOrigin.REPO_OWNER
604 o = PermOrigin.REPO_OWNER
605 self.permissions_repositories[r_k] = p, o
605 self.permissions_repositories[r_k] = p, o
606
606
607 if self.user_is_admin:
607 if self.user_is_admin:
608 p = 'repository.admin'
608 p = 'repository.admin'
609 o = PermOrigin.SUPER_ADMIN
609 o = PermOrigin.SUPER_ADMIN
610 self.permissions_repositories[r_k] = p, o
610 self.permissions_repositories[r_k] = p, o
611
611
612 # finally in case of archived repositories, we downgrade higher
612 # finally in case of archived repositories, we downgrade higher
613 # permissions to read
613 # permissions to read
614 if archived:
614 if archived:
615 current_perm = self.permissions_repositories[r_k]
615 current_perm = self.permissions_repositories[r_k]
616 if current_perm in ['repository.write', 'repository.admin']:
616 if current_perm in ['repository.write', 'repository.admin']:
617 p = 'repository.read'
617 p = 'repository.read'
618 o = PermOrigin.ARCHIVED
618 o = PermOrigin.ARCHIVED
619 self.permissions_repositories[r_k] = p, o
619 self.permissions_repositories[r_k] = p, o
620
620
621 def _calculate_default_permissions_repository_branches(self, user_inherit_object_permissions):
621 def _calculate_default_permissions_repository_branches(self, user_inherit_object_permissions):
622 for perm in self.default_branch_repo_perms:
622 for perm in self.default_branch_repo_perms:
623
623
624 r_k = perm.UserRepoToPerm.repository.repo_name
624 r_k = perm.UserRepoToPerm.repository.repo_name
625 p = perm.Permission.permission_name
625 p = perm.Permission.permission_name
626 pattern = perm.UserToRepoBranchPermission.branch_pattern
626 pattern = perm.UserToRepoBranchPermission.branch_pattern
627 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
627 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
628
628
629 if not self.explicit:
629 if not self.explicit:
630 cur_perm = self.permissions_repository_branches.get(r_k)
630 cur_perm = self.permissions_repository_branches.get(r_k)
631 if cur_perm:
631 if cur_perm:
632 cur_perm = cur_perm[pattern]
632 cur_perm = cur_perm[pattern]
633 cur_perm = cur_perm or 'branch.none'
633 cur_perm = cur_perm or 'branch.none'
634
634
635 p = self._choose_permission(p, cur_perm)
635 p = self._choose_permission(p, cur_perm)
636
636
637 # NOTE(marcink): register all pattern/perm instances in this
637 # NOTE(marcink): register all pattern/perm instances in this
638 # special dict that aggregates entries
638 # special dict that aggregates entries
639 self.permissions_repository_branches[r_k] = pattern, p, o
639 self.permissions_repository_branches[r_k] = pattern, p, o
640
640
641 def _calculate_default_permissions_repository_groups(self, user_inherit_object_permissions):
641 def _calculate_default_permissions_repository_groups(self, user_inherit_object_permissions):
642 for perm in self.default_repo_groups_perms:
642 for perm in self.default_repo_groups_perms:
643 rg_k = perm.UserRepoGroupToPerm.group.group_name
643 rg_k = perm.UserRepoGroupToPerm.group.group_name
644 p = perm.Permission.permission_name
644 p = perm.Permission.permission_name
645 o = PermOrigin.REPOGROUP_DEFAULT
645 o = PermOrigin.REPOGROUP_DEFAULT
646 self.permissions_repository_groups[rg_k] = p, o
646 self.permissions_repository_groups[rg_k] = p, o
647
647
648 # if we decide this user isn't inheriting permissions from default
648 # if we decide this user isn't inheriting permissions from default
649 # user we set him to .none so only explicit permissions work
649 # user we set him to .none so only explicit permissions work
650 if not user_inherit_object_permissions:
650 if not user_inherit_object_permissions:
651 p = 'group.none'
651 p = 'group.none'
652 o = PermOrigin.REPOGROUP_DEFAULT_NO_INHERIT
652 o = PermOrigin.REPOGROUP_DEFAULT_NO_INHERIT
653 self.permissions_repository_groups[rg_k] = p, o
653 self.permissions_repository_groups[rg_k] = p, o
654
654
655 if perm.RepoGroup.user_id == self.user_id:
655 if perm.RepoGroup.user_id == self.user_id:
656 # set admin if owner
656 # set admin if owner
657 p = 'group.admin'
657 p = 'group.admin'
658 o = PermOrigin.REPOGROUP_OWNER
658 o = PermOrigin.REPOGROUP_OWNER
659 self.permissions_repository_groups[rg_k] = p, o
659 self.permissions_repository_groups[rg_k] = p, o
660
660
661 if self.user_is_admin:
661 if self.user_is_admin:
662 p = 'group.admin'
662 p = 'group.admin'
663 o = PermOrigin.SUPER_ADMIN
663 o = PermOrigin.SUPER_ADMIN
664 self.permissions_repository_groups[rg_k] = p, o
664 self.permissions_repository_groups[rg_k] = p, o
665
665
666 def _calculate_default_permissions_user_groups(self, user_inherit_object_permissions):
666 def _calculate_default_permissions_user_groups(self, user_inherit_object_permissions):
667 for perm in self.default_user_group_perms:
667 for perm in self.default_user_group_perms:
668 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
668 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
669 p = perm.Permission.permission_name
669 p = perm.Permission.permission_name
670 o = PermOrigin.USERGROUP_DEFAULT
670 o = PermOrigin.USERGROUP_DEFAULT
671 self.permissions_user_groups[u_k] = p, o
671 self.permissions_user_groups[u_k] = p, o
672
672
673 # if we decide this user isn't inheriting permissions from default
673 # if we decide this user isn't inheriting permissions from default
674 # user we set him to .none so only explicit permissions work
674 # user we set him to .none so only explicit permissions work
675 if not user_inherit_object_permissions:
675 if not user_inherit_object_permissions:
676 p = 'usergroup.none'
676 p = 'usergroup.none'
677 o = PermOrigin.USERGROUP_DEFAULT_NO_INHERIT
677 o = PermOrigin.USERGROUP_DEFAULT_NO_INHERIT
678 self.permissions_user_groups[u_k] = p, o
678 self.permissions_user_groups[u_k] = p, o
679
679
680 if perm.UserGroup.user_id == self.user_id:
680 if perm.UserGroup.user_id == self.user_id:
681 # set admin if owner
681 # set admin if owner
682 p = 'usergroup.admin'
682 p = 'usergroup.admin'
683 o = PermOrigin.USERGROUP_OWNER
683 o = PermOrigin.USERGROUP_OWNER
684 self.permissions_user_groups[u_k] = p, o
684 self.permissions_user_groups[u_k] = p, o
685
685
686 if self.user_is_admin:
686 if self.user_is_admin:
687 p = 'usergroup.admin'
687 p = 'usergroup.admin'
688 o = PermOrigin.SUPER_ADMIN
688 o = PermOrigin.SUPER_ADMIN
689 self.permissions_user_groups[u_k] = p, o
689 self.permissions_user_groups[u_k] = p, o
690
690
691 def _calculate_default_permissions(self):
691 def _calculate_default_permissions(self):
692 """
692 """
693 Set default user permissions for repositories, repository branches,
693 Set default user permissions for repositories, repository branches,
694 repository groups, user groups taken from the default user.
694 repository groups, user groups taken from the default user.
695
695
696 Calculate inheritance of object permissions based on what we have now
696 Calculate inheritance of object permissions based on what we have now
697 in GLOBAL permissions. We check if .false is in GLOBAL since this is
697 in GLOBAL permissions. We check if .false is in GLOBAL since this is
698 explicitly set. Inherit is the opposite of .false being there.
698 explicitly set. Inherit is the opposite of .false being there.
699
699
700 .. note::
700 .. note::
701
701
702 the syntax is little bit odd but what we need to check here is
702 the syntax is little bit odd but what we need to check here is
703 the opposite of .false permission being in the list so even for
703 the opposite of .false permission being in the list so even for
704 inconsistent state when both .true/.false is there
704 inconsistent state when both .true/.false is there
705 .false is more important
705 .false is more important
706
706
707 """
707 """
708 user_inherit_object_permissions = not ('hg.inherit_default_perms.false'
708 user_inherit_object_permissions = not ('hg.inherit_default_perms.false'
709 in self.permissions_global)
709 in self.permissions_global)
710
710
711 # default permissions inherited from `default` user permissions
711 # default permissions inherited from `default` user permissions
712 self._calculate_default_permissions_repositories(
712 self._calculate_default_permissions_repositories(
713 user_inherit_object_permissions)
713 user_inherit_object_permissions)
714
714
715 self._calculate_default_permissions_repository_branches(
715 self._calculate_default_permissions_repository_branches(
716 user_inherit_object_permissions)
716 user_inherit_object_permissions)
717
717
718 self._calculate_default_permissions_repository_groups(
718 self._calculate_default_permissions_repository_groups(
719 user_inherit_object_permissions)
719 user_inherit_object_permissions)
720
720
721 self._calculate_default_permissions_user_groups(
721 self._calculate_default_permissions_user_groups(
722 user_inherit_object_permissions)
722 user_inherit_object_permissions)
723
723
724 def _calculate_repository_permissions(self):
724 def _calculate_repository_permissions(self):
725 """
725 """
726 Repository permissions for the current user.
726 Repository access permissions for the current user.
727
727
728 Check if the user is part of user groups for this repository and
728 Check if the user is part of user groups for this repository and
729 fill in the permission from it. `_choose_permission` decides of which
729 fill in the permission from it. `_choose_permission` decides of which
730 permission should be selected based on selected method.
730 permission should be selected based on selected method.
731 """
731 """
732
732
733 # user group for repositories permissions
733 # user group for repositories permissions
734 user_repo_perms_from_user_group = Permission\
734 user_repo_perms_from_user_group = Permission\
735 .get_default_repo_perms_from_user_group(
735 .get_default_repo_perms_from_user_group(
736 self.user_id, self.scope_repo_id)
736 self.user_id, self.scope_repo_id)
737
737
738 multiple_counter = collections.defaultdict(int)
738 multiple_counter = collections.defaultdict(int)
739 for perm in user_repo_perms_from_user_group:
739 for perm in user_repo_perms_from_user_group:
740 r_k = perm.UserGroupRepoToPerm.repository.repo_name
740 r_k = perm.UserGroupRepoToPerm.repository.repo_name
741 multiple_counter[r_k] += 1
741 multiple_counter[r_k] += 1
742 p = perm.Permission.permission_name
742 p = perm.Permission.permission_name
743 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
743 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
744 .users_group.users_group_name
744 .users_group.users_group_name
745
745
746 if multiple_counter[r_k] > 1:
746 if multiple_counter[r_k] > 1:
747 cur_perm = self.permissions_repositories[r_k]
747 cur_perm = self.permissions_repositories[r_k]
748 p = self._choose_permission(p, cur_perm)
748 p = self._choose_permission(p, cur_perm)
749
749
750 self.permissions_repositories[r_k] = p, o
750 self.permissions_repositories[r_k] = p, o
751
751
752 if perm.Repository.user_id == self.user_id:
752 if perm.Repository.user_id == self.user_id:
753 # set admin if owner
753 # set admin if owner
754 p = 'repository.admin'
754 p = 'repository.admin'
755 o = PermOrigin.REPO_OWNER
755 o = PermOrigin.REPO_OWNER
756 self.permissions_repositories[r_k] = p, o
756 self.permissions_repositories[r_k] = p, o
757
757
758 if self.user_is_admin:
758 if self.user_is_admin:
759 p = 'repository.admin'
759 p = 'repository.admin'
760 o = PermOrigin.SUPER_ADMIN
760 o = PermOrigin.SUPER_ADMIN
761 self.permissions_repositories[r_k] = p, o
761 self.permissions_repositories[r_k] = p, o
762
762
763 # user explicit permissions for repositories, overrides any specified
763 # user explicit permissions for repositories, overrides any specified
764 # by the group permission
764 # by the group permission
765 user_repo_perms = Permission.get_default_repo_perms(
765 user_repo_perms = Permission.get_default_repo_perms(
766 self.user_id, self.scope_repo_id)
766 self.user_id, self.scope_repo_id)
767 for perm in user_repo_perms:
767 for perm in user_repo_perms:
768 r_k = perm.UserRepoToPerm.repository.repo_name
768 r_k = perm.UserRepoToPerm.repository.repo_name
769 p = perm.Permission.permission_name
769 p = perm.Permission.permission_name
770 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
770 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
771
771
772 if not self.explicit:
772 if not self.explicit:
773 cur_perm = self.permissions_repositories.get(
773 cur_perm = self.permissions_repositories.get(
774 r_k, 'repository.none')
774 r_k, 'repository.none')
775 p = self._choose_permission(p, cur_perm)
775 p = self._choose_permission(p, cur_perm)
776
776
777 self.permissions_repositories[r_k] = p, o
777 self.permissions_repositories[r_k] = p, o
778
778
779 if perm.Repository.user_id == self.user_id:
779 if perm.Repository.user_id == self.user_id:
780 # set admin if owner
780 # set admin if owner
781 p = 'repository.admin'
781 p = 'repository.admin'
782 o = PermOrigin.REPO_OWNER
782 o = PermOrigin.REPO_OWNER
783 self.permissions_repositories[r_k] = p, o
783 self.permissions_repositories[r_k] = p, o
784
784
785 if self.user_is_admin:
785 if self.user_is_admin:
786 p = 'repository.admin'
786 p = 'repository.admin'
787 o = PermOrigin.SUPER_ADMIN
787 o = PermOrigin.SUPER_ADMIN
788 self.permissions_repositories[r_k] = p, o
788 self.permissions_repositories[r_k] = p, o
789
789
790 def _calculate_repository_branch_permissions(self):
790 def _calculate_repository_branch_permissions(self):
791 # user group for repositories permissions
791 # user group for repositories permissions
792 user_repo_branch_perms_from_user_group = Permission\
792 user_repo_branch_perms_from_user_group = Permission\
793 .get_default_repo_branch_perms_from_user_group(
793 .get_default_repo_branch_perms_from_user_group(
794 self.user_id, self.scope_repo_id)
794 self.user_id, self.scope_repo_id)
795
795
796 multiple_counter = collections.defaultdict(int)
796 multiple_counter = collections.defaultdict(int)
797 for perm in user_repo_branch_perms_from_user_group:
797 for perm in user_repo_branch_perms_from_user_group:
798 r_k = perm.UserGroupRepoToPerm.repository.repo_name
798 r_k = perm.UserGroupRepoToPerm.repository.repo_name
799 p = perm.Permission.permission_name
799 p = perm.Permission.permission_name
800 pattern = perm.UserGroupToRepoBranchPermission.branch_pattern
800 pattern = perm.UserGroupToRepoBranchPermission.branch_pattern
801 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
801 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
802 .users_group.users_group_name
802 .users_group.users_group_name
803
803
804 multiple_counter[r_k] += 1
804 multiple_counter[r_k] += 1
805 if multiple_counter[r_k] > 1:
805 if multiple_counter[r_k] > 1:
806 cur_perm = self.permissions_repository_branches[r_k][pattern]
806 cur_perm = self.permissions_repository_branches[r_k][pattern]
807 p = self._choose_permission(p, cur_perm)
807 p = self._choose_permission(p, cur_perm)
808
808
809 self.permissions_repository_branches[r_k] = pattern, p, o
809 self.permissions_repository_branches[r_k] = pattern, p, o
810
810
811 # user explicit branch permissions for repositories, overrides
811 # user explicit branch permissions for repositories, overrides
812 # any specified by the group permission
812 # any specified by the group permission
813 user_repo_branch_perms = Permission.get_default_repo_branch_perms(
813 user_repo_branch_perms = Permission.get_default_repo_branch_perms(
814 self.user_id, self.scope_repo_id)
814 self.user_id, self.scope_repo_id)
815
815
816 for perm in user_repo_branch_perms:
816 for perm in user_repo_branch_perms:
817
817
818 r_k = perm.UserRepoToPerm.repository.repo_name
818 r_k = perm.UserRepoToPerm.repository.repo_name
819 p = perm.Permission.permission_name
819 p = perm.Permission.permission_name
820 pattern = perm.UserToRepoBranchPermission.branch_pattern
820 pattern = perm.UserToRepoBranchPermission.branch_pattern
821 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
821 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
822
822
823 if not self.explicit:
823 if not self.explicit:
824 cur_perm = self.permissions_repository_branches.get(r_k)
824 cur_perm = self.permissions_repository_branches.get(r_k)
825 if cur_perm:
825 if cur_perm:
826 cur_perm = cur_perm[pattern]
826 cur_perm = cur_perm[pattern]
827 cur_perm = cur_perm or 'branch.none'
827 cur_perm = cur_perm or 'branch.none'
828 p = self._choose_permission(p, cur_perm)
828 p = self._choose_permission(p, cur_perm)
829
829
830 # NOTE(marcink): register all pattern/perm instances in this
830 # NOTE(marcink): register all pattern/perm instances in this
831 # special dict that aggregates entries
831 # special dict that aggregates entries
832 self.permissions_repository_branches[r_k] = pattern, p, o
832 self.permissions_repository_branches[r_k] = pattern, p, o
833
833
834 def _calculate_repository_group_permissions(self):
834 def _calculate_repository_group_permissions(self):
835 """
835 """
836 Repository group permissions for the current user.
836 Repository group permissions for the current user.
837
837
838 Check if the user is part of user groups for repository groups and
838 Check if the user is part of user groups for repository groups and
839 fill in the permissions from it. `_choose_permission` decides of which
839 fill in the permissions from it. `_choose_permission` decides of which
840 permission should be selected based on selected method.
840 permission should be selected based on selected method.
841 """
841 """
842 # user group for repo groups permissions
842 # user group for repo groups permissions
843 user_repo_group_perms_from_user_group = Permission\
843 user_repo_group_perms_from_user_group = Permission\
844 .get_default_group_perms_from_user_group(
844 .get_default_group_perms_from_user_group(
845 self.user_id, self.scope_repo_group_id)
845 self.user_id, self.scope_repo_group_id)
846
846
847 multiple_counter = collections.defaultdict(int)
847 multiple_counter = collections.defaultdict(int)
848 for perm in user_repo_group_perms_from_user_group:
848 for perm in user_repo_group_perms_from_user_group:
849 rg_k = perm.UserGroupRepoGroupToPerm.group.group_name
849 rg_k = perm.UserGroupRepoGroupToPerm.group.group_name
850 multiple_counter[rg_k] += 1
850 multiple_counter[rg_k] += 1
851 o = PermOrigin.REPOGROUP_USERGROUP % perm.UserGroupRepoGroupToPerm\
851 o = PermOrigin.REPOGROUP_USERGROUP % perm.UserGroupRepoGroupToPerm\
852 .users_group.users_group_name
852 .users_group.users_group_name
853 p = perm.Permission.permission_name
853 p = perm.Permission.permission_name
854
854
855 if multiple_counter[rg_k] > 1:
855 if multiple_counter[rg_k] > 1:
856 cur_perm = self.permissions_repository_groups[rg_k]
856 cur_perm = self.permissions_repository_groups[rg_k]
857 p = self._choose_permission(p, cur_perm)
857 p = self._choose_permission(p, cur_perm)
858 self.permissions_repository_groups[rg_k] = p, o
858 self.permissions_repository_groups[rg_k] = p, o
859
859
860 if perm.RepoGroup.user_id == self.user_id:
860 if perm.RepoGroup.user_id == self.user_id:
861 # set admin if owner, even for member of other user group
861 # set admin if owner, even for member of other user group
862 p = 'group.admin'
862 p = 'group.admin'
863 o = PermOrigin.REPOGROUP_OWNER
863 o = PermOrigin.REPOGROUP_OWNER
864 self.permissions_repository_groups[rg_k] = p, o
864 self.permissions_repository_groups[rg_k] = p, o
865
865
866 if self.user_is_admin:
866 if self.user_is_admin:
867 p = 'group.admin'
867 p = 'group.admin'
868 o = PermOrigin.SUPER_ADMIN
868 o = PermOrigin.SUPER_ADMIN
869 self.permissions_repository_groups[rg_k] = p, o
869 self.permissions_repository_groups[rg_k] = p, o
870
870
871 # user explicit permissions for repository groups
871 # user explicit permissions for repository groups
872 user_repo_groups_perms = Permission.get_default_group_perms(
872 user_repo_groups_perms = Permission.get_default_group_perms(
873 self.user_id, self.scope_repo_group_id)
873 self.user_id, self.scope_repo_group_id)
874 for perm in user_repo_groups_perms:
874 for perm in user_repo_groups_perms:
875 rg_k = perm.UserRepoGroupToPerm.group.group_name
875 rg_k = perm.UserRepoGroupToPerm.group.group_name
876 o = PermOrigin.REPOGROUP_USER % perm.UserRepoGroupToPerm\
876 o = PermOrigin.REPOGROUP_USER % perm.UserRepoGroupToPerm\
877 .user.username
877 .user.username
878 p = perm.Permission.permission_name
878 p = perm.Permission.permission_name
879
879
880 if not self.explicit:
880 if not self.explicit:
881 cur_perm = self.permissions_repository_groups.get(rg_k, 'group.none')
881 cur_perm = self.permissions_repository_groups.get(rg_k, 'group.none')
882 p = self._choose_permission(p, cur_perm)
882 p = self._choose_permission(p, cur_perm)
883
883
884 self.permissions_repository_groups[rg_k] = p, o
884 self.permissions_repository_groups[rg_k] = p, o
885
885
886 if perm.RepoGroup.user_id == self.user_id:
886 if perm.RepoGroup.user_id == self.user_id:
887 # set admin if owner
887 # set admin if owner
888 p = 'group.admin'
888 p = 'group.admin'
889 o = PermOrigin.REPOGROUP_OWNER
889 o = PermOrigin.REPOGROUP_OWNER
890 self.permissions_repository_groups[rg_k] = p, o
890 self.permissions_repository_groups[rg_k] = p, o
891
891
892 if self.user_is_admin:
892 if self.user_is_admin:
893 p = 'group.admin'
893 p = 'group.admin'
894 o = PermOrigin.SUPER_ADMIN
894 o = PermOrigin.SUPER_ADMIN
895 self.permissions_repository_groups[rg_k] = p, o
895 self.permissions_repository_groups[rg_k] = p, o
896
896
897 def _calculate_user_group_permissions(self):
897 def _calculate_user_group_permissions(self):
898 """
898 """
899 User group permissions for the current user.
899 User group permissions for the current user.
900 """
900 """
901 # user group for user group permissions
901 # user group for user group permissions
902 user_group_from_user_group = Permission\
902 user_group_from_user_group = Permission\
903 .get_default_user_group_perms_from_user_group(
903 .get_default_user_group_perms_from_user_group(
904 self.user_id, self.scope_user_group_id)
904 self.user_id, self.scope_user_group_id)
905
905
906 multiple_counter = collections.defaultdict(int)
906 multiple_counter = collections.defaultdict(int)
907 for perm in user_group_from_user_group:
907 for perm in user_group_from_user_group:
908 ug_k = perm.UserGroupUserGroupToPerm\
908 ug_k = perm.UserGroupUserGroupToPerm\
909 .target_user_group.users_group_name
909 .target_user_group.users_group_name
910 multiple_counter[ug_k] += 1
910 multiple_counter[ug_k] += 1
911 o = PermOrigin.USERGROUP_USERGROUP % perm.UserGroupUserGroupToPerm\
911 o = PermOrigin.USERGROUP_USERGROUP % perm.UserGroupUserGroupToPerm\
912 .user_group.users_group_name
912 .user_group.users_group_name
913 p = perm.Permission.permission_name
913 p = perm.Permission.permission_name
914
914
915 if multiple_counter[ug_k] > 1:
915 if multiple_counter[ug_k] > 1:
916 cur_perm = self.permissions_user_groups[ug_k]
916 cur_perm = self.permissions_user_groups[ug_k]
917 p = self._choose_permission(p, cur_perm)
917 p = self._choose_permission(p, cur_perm)
918
918
919 self.permissions_user_groups[ug_k] = p, o
919 self.permissions_user_groups[ug_k] = p, o
920
920
921 if perm.UserGroup.user_id == self.user_id:
921 if perm.UserGroup.user_id == self.user_id:
922 # set admin if owner, even for member of other user group
922 # set admin if owner, even for member of other user group
923 p = 'usergroup.admin'
923 p = 'usergroup.admin'
924 o = PermOrigin.USERGROUP_OWNER
924 o = PermOrigin.USERGROUP_OWNER
925 self.permissions_user_groups[ug_k] = p, o
925 self.permissions_user_groups[ug_k] = p, o
926
926
927 if self.user_is_admin:
927 if self.user_is_admin:
928 p = 'usergroup.admin'
928 p = 'usergroup.admin'
929 o = PermOrigin.SUPER_ADMIN
929 o = PermOrigin.SUPER_ADMIN
930 self.permissions_user_groups[ug_k] = p, o
930 self.permissions_user_groups[ug_k] = p, o
931
931
932 # user explicit permission for user groups
932 # user explicit permission for user groups
933 user_user_groups_perms = Permission.get_default_user_group_perms(
933 user_user_groups_perms = Permission.get_default_user_group_perms(
934 self.user_id, self.scope_user_group_id)
934 self.user_id, self.scope_user_group_id)
935 for perm in user_user_groups_perms:
935 for perm in user_user_groups_perms:
936 ug_k = perm.UserUserGroupToPerm.user_group.users_group_name
936 ug_k = perm.UserUserGroupToPerm.user_group.users_group_name
937 o = PermOrigin.USERGROUP_USER % perm.UserUserGroupToPerm\
937 o = PermOrigin.USERGROUP_USER % perm.UserUserGroupToPerm\
938 .user.username
938 .user.username
939 p = perm.Permission.permission_name
939 p = perm.Permission.permission_name
940
940
941 if not self.explicit:
941 if not self.explicit:
942 cur_perm = self.permissions_user_groups.get(ug_k, 'usergroup.none')
942 cur_perm = self.permissions_user_groups.get(ug_k, 'usergroup.none')
943 p = self._choose_permission(p, cur_perm)
943 p = self._choose_permission(p, cur_perm)
944
944
945 self.permissions_user_groups[ug_k] = p, o
945 self.permissions_user_groups[ug_k] = p, o
946
946
947 if perm.UserGroup.user_id == self.user_id:
947 if perm.UserGroup.user_id == self.user_id:
948 # set admin if owner
948 # set admin if owner
949 p = 'usergroup.admin'
949 p = 'usergroup.admin'
950 o = PermOrigin.USERGROUP_OWNER
950 o = PermOrigin.USERGROUP_OWNER
951 self.permissions_user_groups[ug_k] = p, o
951 self.permissions_user_groups[ug_k] = p, o
952
952
953 if self.user_is_admin:
953 if self.user_is_admin:
954 p = 'usergroup.admin'
954 p = 'usergroup.admin'
955 o = PermOrigin.SUPER_ADMIN
955 o = PermOrigin.SUPER_ADMIN
956 self.permissions_user_groups[ug_k] = p, o
956 self.permissions_user_groups[ug_k] = p, o
957
957
958 def _choose_permission(self, new_perm, cur_perm):
958 def _choose_permission(self, new_perm, cur_perm):
959 new_perm_val = Permission.PERM_WEIGHTS[new_perm]
959 new_perm_val = Permission.PERM_WEIGHTS[new_perm]
960 cur_perm_val = Permission.PERM_WEIGHTS[cur_perm]
960 cur_perm_val = Permission.PERM_WEIGHTS[cur_perm]
961 if self.algo == 'higherwin':
961 if self.algo == 'higherwin':
962 if new_perm_val > cur_perm_val:
962 if new_perm_val > cur_perm_val:
963 return new_perm
963 return new_perm
964 return cur_perm
964 return cur_perm
965 elif self.algo == 'lowerwin':
965 elif self.algo == 'lowerwin':
966 if new_perm_val < cur_perm_val:
966 if new_perm_val < cur_perm_val:
967 return new_perm
967 return new_perm
968 return cur_perm
968 return cur_perm
969
969
970 def _permission_structure(self):
970 def _permission_structure(self):
971 return {
971 return {
972 'global': self.permissions_global,
972 'global': self.permissions_global,
973 'repositories': self.permissions_repositories,
973 'repositories': self.permissions_repositories,
974 'repository_branches': self.permissions_repository_branches,
974 'repository_branches': self.permissions_repository_branches,
975 'repositories_groups': self.permissions_repository_groups,
975 'repositories_groups': self.permissions_repository_groups,
976 'user_groups': self.permissions_user_groups,
976 'user_groups': self.permissions_user_groups,
977 }
977 }
978
978
979
979
980 def allowed_auth_token_access(view_name, auth_token, whitelist=None):
980 def allowed_auth_token_access(view_name, auth_token, whitelist=None):
981 """
981 """
982 Check if given controller_name is in whitelist of auth token access
982 Check if given controller_name is in whitelist of auth token access
983 """
983 """
984 if not whitelist:
984 if not whitelist:
985 from rhodecode import CONFIG
985 from rhodecode import CONFIG
986 whitelist = aslist(
986 whitelist = aslist(
987 CONFIG.get('api_access_controllers_whitelist'), sep=',')
987 CONFIG.get('api_access_controllers_whitelist'), sep=',')
988 # backward compat translation
988 # backward compat translation
989 compat = {
989 compat = {
990 # old controller, new VIEW
990 # old controller, new VIEW
991 'ChangesetController:*': 'RepoCommitsView:*',
991 'ChangesetController:*': 'RepoCommitsView:*',
992 'ChangesetController:changeset_patch': 'RepoCommitsView:repo_commit_patch',
992 'ChangesetController:changeset_patch': 'RepoCommitsView:repo_commit_patch',
993 'ChangesetController:changeset_raw': 'RepoCommitsView:repo_commit_raw',
993 'ChangesetController:changeset_raw': 'RepoCommitsView:repo_commit_raw',
994 'FilesController:raw': 'RepoCommitsView:repo_commit_raw',
994 'FilesController:raw': 'RepoCommitsView:repo_commit_raw',
995 'FilesController:archivefile': 'RepoFilesView:repo_archivefile',
995 'FilesController:archivefile': 'RepoFilesView:repo_archivefile',
996 'GistsController:*': 'GistView:*',
996 'GistsController:*': 'GistView:*',
997 }
997 }
998
998
999 log.debug(
999 log.debug(
1000 'Allowed views for AUTH TOKEN access: %s', whitelist)
1000 'Allowed views for AUTH TOKEN access: %s', whitelist)
1001 auth_token_access_valid = False
1001 auth_token_access_valid = False
1002
1002
1003 for entry in whitelist:
1003 for entry in whitelist:
1004 token_match = True
1004 token_match = True
1005 if entry in compat:
1005 if entry in compat:
1006 # translate from old Controllers to Pyramid Views
1006 # translate from old Controllers to Pyramid Views
1007 entry = compat[entry]
1007 entry = compat[entry]
1008
1008
1009 if '@' in entry:
1009 if '@' in entry:
1010 # specific AuthToken
1010 # specific AuthToken
1011 entry, allowed_token = entry.split('@', 1)
1011 entry, allowed_token = entry.split('@', 1)
1012 token_match = auth_token == allowed_token
1012 token_match = auth_token == allowed_token
1013
1013
1014 if fnmatch.fnmatch(view_name, entry) and token_match:
1014 if fnmatch.fnmatch(view_name, entry) and token_match:
1015 auth_token_access_valid = True
1015 auth_token_access_valid = True
1016 break
1016 break
1017
1017
1018 if auth_token_access_valid:
1018 if auth_token_access_valid:
1019 log.debug('view: `%s` matches entry in whitelist: %s',
1019 log.debug('view: `%s` matches entry in whitelist: %s',
1020 view_name, whitelist)
1020 view_name, whitelist)
1021
1021
1022 else:
1022 else:
1023 msg = ('view: `%s` does *NOT* match any entry in whitelist: %s'
1023 msg = ('view: `%s` does *NOT* match any entry in whitelist: %s'
1024 % (view_name, whitelist))
1024 % (view_name, whitelist))
1025 if auth_token:
1025 if auth_token:
1026 # if we use auth token key and don't have access it's a warning
1026 # if we use auth token key and don't have access it's a warning
1027 log.warning(msg)
1027 log.warning(msg)
1028 else:
1028 else:
1029 log.debug(msg)
1029 log.debug(msg)
1030
1030
1031 return auth_token_access_valid
1031 return auth_token_access_valid
1032
1032
1033
1033
1034 class AuthUser(object):
1034 class AuthUser(object):
1035 """
1035 """
1036 A simple object that handles all attributes of user in RhodeCode
1036 A simple object that handles all attributes of user in RhodeCode
1037
1037
1038 It does lookup based on API key,given user, or user present in session
1038 It does lookup based on API key,given user, or user present in session
1039 Then it fills all required information for such user. It also checks if
1039 Then it fills all required information for such user. It also checks if
1040 anonymous access is enabled and if so, it returns default user as logged in
1040 anonymous access is enabled and if so, it returns default user as logged in
1041 """
1041 """
1042 GLOBAL_PERMS = [x[0] for x in Permission.PERMS]
1042 GLOBAL_PERMS = [x[0] for x in Permission.PERMS]
1043
1043
1044 def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None):
1044 def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None):
1045
1045
1046 self.user_id = user_id
1046 self.user_id = user_id
1047 self._api_key = api_key
1047 self._api_key = api_key
1048
1048
1049 self.api_key = None
1049 self.api_key = None
1050 self.username = username
1050 self.username = username
1051 self.ip_addr = ip_addr
1051 self.ip_addr = ip_addr
1052 self.name = ''
1052 self.name = ''
1053 self.lastname = ''
1053 self.lastname = ''
1054 self.first_name = ''
1054 self.first_name = ''
1055 self.last_name = ''
1055 self.last_name = ''
1056 self.email = ''
1056 self.email = ''
1057 self.is_authenticated = False
1057 self.is_authenticated = False
1058 self.admin = False
1058 self.admin = False
1059 self.inherit_default_permissions = False
1059 self.inherit_default_permissions = False
1060 self.password = ''
1060 self.password = ''
1061
1061
1062 self.anonymous_user = None # propagated on propagate_data
1062 self.anonymous_user = None # propagated on propagate_data
1063 self.propagate_data()
1063 self.propagate_data()
1064 self._instance = None
1064 self._instance = None
1065 self._permissions_scoped_cache = {} # used to bind scoped calculation
1065 self._permissions_scoped_cache = {} # used to bind scoped calculation
1066
1066
1067 @LazyProperty
1067 @LazyProperty
1068 def permissions(self):
1068 def permissions(self):
1069 return self.get_perms(user=self, cache=None)
1069 return self.get_perms(user=self, cache=None)
1070
1070
1071 @LazyProperty
1071 @LazyProperty
1072 def permissions_safe(self):
1072 def permissions_safe(self):
1073 """
1073 """
1074 Filtered permissions excluding not allowed repositories
1074 Filtered permissions excluding not allowed repositories
1075 """
1075 """
1076 perms = self.get_perms(user=self, cache=None)
1076 perms = self.get_perms(user=self, cache=None)
1077
1077
1078 perms['repositories'] = {
1078 perms['repositories'] = {
1079 k: v for k, v in perms['repositories'].items()
1079 k: v for k, v in perms['repositories'].items()
1080 if v != 'repository.none'}
1080 if v != 'repository.none'}
1081 perms['repositories_groups'] = {
1081 perms['repositories_groups'] = {
1082 k: v for k, v in perms['repositories_groups'].items()
1082 k: v for k, v in perms['repositories_groups'].items()
1083 if v != 'group.none'}
1083 if v != 'group.none'}
1084 perms['user_groups'] = {
1084 perms['user_groups'] = {
1085 k: v for k, v in perms['user_groups'].items()
1085 k: v for k, v in perms['user_groups'].items()
1086 if v != 'usergroup.none'}
1086 if v != 'usergroup.none'}
1087 perms['repository_branches'] = {
1087 perms['repository_branches'] = {
1088 k: v for k, v in perms['repository_branches'].iteritems()
1088 k: v for k, v in perms['repository_branches'].iteritems()
1089 if v != 'branch.none'}
1089 if v != 'branch.none'}
1090 return perms
1090 return perms
1091
1091
1092 @LazyProperty
1092 @LazyProperty
1093 def permissions_full_details(self):
1093 def permissions_full_details(self):
1094 return self.get_perms(
1094 return self.get_perms(
1095 user=self, cache=None, calculate_super_admin=True)
1095 user=self, cache=None, calculate_super_admin=True)
1096
1096
1097 def permissions_with_scope(self, scope):
1097 def permissions_with_scope(self, scope):
1098 """
1098 """
1099 Call the get_perms function with scoped data. The scope in that function
1099 Call the get_perms function with scoped data. The scope in that function
1100 narrows the SQL calls to the given ID of objects resulting in fetching
1100 narrows the SQL calls to the given ID of objects resulting in fetching
1101 Just particular permission we want to obtain. If scope is an empty dict
1101 Just particular permission we want to obtain. If scope is an empty dict
1102 then it basically narrows the scope to GLOBAL permissions only.
1102 then it basically narrows the scope to GLOBAL permissions only.
1103
1103
1104 :param scope: dict
1104 :param scope: dict
1105 """
1105 """
1106 if 'repo_name' in scope:
1106 if 'repo_name' in scope:
1107 obj = Repository.get_by_repo_name(scope['repo_name'])
1107 obj = Repository.get_by_repo_name(scope['repo_name'])
1108 if obj:
1108 if obj:
1109 scope['repo_id'] = obj.repo_id
1109 scope['repo_id'] = obj.repo_id
1110 _scope = collections.OrderedDict()
1110 _scope = collections.OrderedDict()
1111 _scope['repo_id'] = -1
1111 _scope['repo_id'] = -1
1112 _scope['user_group_id'] = -1
1112 _scope['user_group_id'] = -1
1113 _scope['repo_group_id'] = -1
1113 _scope['repo_group_id'] = -1
1114
1114
1115 for k in sorted(scope.keys()):
1115 for k in sorted(scope.keys()):
1116 _scope[k] = scope[k]
1116 _scope[k] = scope[k]
1117
1117
1118 # store in cache to mimic how the @LazyProperty works,
1118 # store in cache to mimic how the @LazyProperty works,
1119 # the difference here is that we use the unique key calculated
1119 # the difference here is that we use the unique key calculated
1120 # from params and values
1120 # from params and values
1121 return self.get_perms(user=self, cache=None, scope=_scope)
1121 return self.get_perms(user=self, cache=None, scope=_scope)
1122
1122
1123 def get_instance(self):
1123 def get_instance(self):
1124 return User.get(self.user_id)
1124 return User.get(self.user_id)
1125
1125
1126 def propagate_data(self):
1126 def propagate_data(self):
1127 """
1127 """
1128 Fills in user data and propagates values to this instance. Maps fetched
1128 Fills in user data and propagates values to this instance. Maps fetched
1129 user attributes to this class instance attributes
1129 user attributes to this class instance attributes
1130 """
1130 """
1131 log.debug('AuthUser: starting data propagation for new potential user')
1131 log.debug('AuthUser: starting data propagation for new potential user')
1132 user_model = UserModel()
1132 user_model = UserModel()
1133 anon_user = self.anonymous_user = User.get_default_user(cache=True)
1133 anon_user = self.anonymous_user = User.get_default_user(cache=True)
1134 is_user_loaded = False
1134 is_user_loaded = False
1135
1135
1136 # lookup by userid
1136 # lookup by userid
1137 if self.user_id is not None and self.user_id != anon_user.user_id:
1137 if self.user_id is not None and self.user_id != anon_user.user_id:
1138 log.debug('Trying Auth User lookup by USER ID: `%s`', self.user_id)
1138 log.debug('Trying Auth User lookup by USER ID: `%s`', self.user_id)
1139 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
1139 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
1140
1140
1141 # try go get user by api key
1141 # try go get user by api key
1142 elif self._api_key and self._api_key != anon_user.api_key:
1142 elif self._api_key and self._api_key != anon_user.api_key:
1143 log.debug('Trying Auth User lookup by API KEY: `%s`', self._api_key)
1143 log.debug('Trying Auth User lookup by API KEY: `%s`', self._api_key)
1144 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
1144 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
1145
1145
1146 # lookup by username
1146 # lookup by username
1147 elif self.username:
1147 elif self.username:
1148 log.debug('Trying Auth User lookup by USER NAME: `%s`', self.username)
1148 log.debug('Trying Auth User lookup by USER NAME: `%s`', self.username)
1149 is_user_loaded = user_model.fill_data(self, username=self.username)
1149 is_user_loaded = user_model.fill_data(self, username=self.username)
1150 else:
1150 else:
1151 log.debug('No data in %s that could been used to log in', self)
1151 log.debug('No data in %s that could been used to log in', self)
1152
1152
1153 if not is_user_loaded:
1153 if not is_user_loaded:
1154 log.debug(
1154 log.debug(
1155 'Failed to load user. Fallback to default user %s', anon_user)
1155 'Failed to load user. Fallback to default user %s', anon_user)
1156 # if we cannot authenticate user try anonymous
1156 # if we cannot authenticate user try anonymous
1157 if anon_user.active:
1157 if anon_user.active:
1158 log.debug('default user is active, using it as a session user')
1158 log.debug('default user is active, using it as a session user')
1159 user_model.fill_data(self, user_id=anon_user.user_id)
1159 user_model.fill_data(self, user_id=anon_user.user_id)
1160 # then we set this user is logged in
1160 # then we set this user is logged in
1161 self.is_authenticated = True
1161 self.is_authenticated = True
1162 else:
1162 else:
1163 log.debug('default user is NOT active')
1163 log.debug('default user is NOT active')
1164 # in case of disabled anonymous user we reset some of the
1164 # in case of disabled anonymous user we reset some of the
1165 # parameters so such user is "corrupted", skipping the fill_data
1165 # parameters so such user is "corrupted", skipping the fill_data
1166 for attr in ['user_id', 'username', 'admin', 'active']:
1166 for attr in ['user_id', 'username', 'admin', 'active']:
1167 setattr(self, attr, None)
1167 setattr(self, attr, None)
1168 self.is_authenticated = False
1168 self.is_authenticated = False
1169
1169
1170 if not self.username:
1170 if not self.username:
1171 self.username = 'None'
1171 self.username = 'None'
1172
1172
1173 log.debug('AuthUser: propagated user is now %s', self)
1173 log.debug('AuthUser: propagated user is now %s', self)
1174
1174
1175 def get_perms(self, user, scope=None, explicit=True, algo='higherwin',
1175 def get_perms(self, user, scope=None, explicit=True, algo='higherwin',
1176 calculate_super_admin=False, cache=None):
1176 calculate_super_admin=False, cache=None):
1177 """
1177 """
1178 Fills user permission attribute with permissions taken from database
1178 Fills user permission attribute with permissions taken from database
1179 works for permissions given for repositories, and for permissions that
1179 works for permissions given for repositories, and for permissions that
1180 are granted to groups
1180 are granted to groups
1181
1181
1182 :param user: instance of User object from database
1182 :param user: instance of User object from database
1183 :param explicit: In case there are permissions both for user and a group
1183 :param explicit: In case there are permissions both for user and a group
1184 that user is part of, explicit flag will defiine if user will
1184 that user is part of, explicit flag will defiine if user will
1185 explicitly override permissions from group, if it's False it will
1185 explicitly override permissions from group, if it's False it will
1186 make decision based on the algo
1186 make decision based on the algo
1187 :param algo: algorithm to decide what permission should be choose if
1187 :param algo: algorithm to decide what permission should be choose if
1188 it's multiple defined, eg user in two different groups. It also
1188 it's multiple defined, eg user in two different groups. It also
1189 decides if explicit flag is turned off how to specify the permission
1189 decides if explicit flag is turned off how to specify the permission
1190 for case when user is in a group + have defined separate permission
1190 for case when user is in a group + have defined separate permission
1191 :param calculate_super_admin: calculate permissions for super-admin in the
1191 :param calculate_super_admin: calculate permissions for super-admin in the
1192 same way as for regular user without speedups
1192 same way as for regular user without speedups
1193 :param cache: Use caching for calculation, None = let the cache backend decide
1193 :param cache: Use caching for calculation, None = let the cache backend decide
1194 """
1194 """
1195 user_id = user.user_id
1195 user_id = user.user_id
1196 user_is_admin = user.is_admin
1196 user_is_admin = user.is_admin
1197
1197
1198 # inheritance of global permissions like create repo/fork repo etc
1198 # inheritance of global permissions like create repo/fork repo etc
1199 user_inherit_default_permissions = user.inherit_default_permissions
1199 user_inherit_default_permissions = user.inherit_default_permissions
1200
1200
1201 cache_seconds = safe_int(
1201 cache_seconds = safe_int(
1202 rhodecode.CONFIG.get('rc_cache.cache_perms.expiration_time'))
1202 rhodecode.CONFIG.get('rc_cache.cache_perms.expiration_time'))
1203
1203
1204 if cache is None:
1204 if cache is None:
1205 # let the backend cache decide
1205 # let the backend cache decide
1206 cache_on = cache_seconds > 0
1206 cache_on = cache_seconds > 0
1207 else:
1207 else:
1208 cache_on = cache
1208 cache_on = cache
1209
1209
1210 log.debug(
1210 log.debug(
1211 'Computing PERMISSION tree for user %s scope `%s` '
1211 'Computing PERMISSION tree for user %s scope `%s` '
1212 'with caching: %s[TTL: %ss]', user, scope, cache_on, cache_seconds or 0)
1212 'with caching: %s[TTL: %ss]', user, scope, cache_on, cache_seconds or 0)
1213
1213
1214 cache_namespace_uid = 'cache_user_auth.{}'.format(user_id)
1214 cache_namespace_uid = 'cache_user_auth.{}'.format(user_id)
1215 region = rc_cache.get_or_create_region('cache_perms', cache_namespace_uid)
1215 region = rc_cache.get_or_create_region('cache_perms', cache_namespace_uid)
1216
1216
1217 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
1217 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
1218 condition=cache_on)
1218 condition=cache_on)
1219 def compute_perm_tree(cache_name,
1219 def compute_perm_tree(cache_name,
1220 user_id, scope, user_is_admin,user_inherit_default_permissions,
1220 user_id, scope, user_is_admin,user_inherit_default_permissions,
1221 explicit, algo, calculate_super_admin):
1221 explicit, algo, calculate_super_admin):
1222 return _cached_perms_data(
1222 return _cached_perms_data(
1223 user_id, scope, user_is_admin, user_inherit_default_permissions,
1223 user_id, scope, user_is_admin, user_inherit_default_permissions,
1224 explicit, algo, calculate_super_admin)
1224 explicit, algo, calculate_super_admin)
1225
1225
1226 start = time.time()
1226 start = time.time()
1227 result = compute_perm_tree(
1227 result = compute_perm_tree(
1228 'permissions', user_id, scope, user_is_admin,
1228 'permissions', user_id, scope, user_is_admin,
1229 user_inherit_default_permissions, explicit, algo,
1229 user_inherit_default_permissions, explicit, algo,
1230 calculate_super_admin)
1230 calculate_super_admin)
1231
1231
1232 result_repr = []
1232 result_repr = []
1233 for k in result:
1233 for k in result:
1234 result_repr.append((k, len(result[k])))
1234 result_repr.append((k, len(result[k])))
1235 total = time.time() - start
1235 total = time.time() - start
1236 log.debug('PERMISSION tree for user %s computed in %.4fs: %s',
1236 log.debug('PERMISSION tree for user %s computed in %.4fs: %s',
1237 user, total, result_repr)
1237 user, total, result_repr)
1238
1238
1239 return result
1239 return result
1240
1240
1241 @property
1241 @property
1242 def is_default(self):
1242 def is_default(self):
1243 return self.username == User.DEFAULT_USER
1243 return self.username == User.DEFAULT_USER
1244
1244
1245 @property
1245 @property
1246 def is_admin(self):
1246 def is_admin(self):
1247 return self.admin
1247 return self.admin
1248
1248
1249 @property
1249 @property
1250 def is_user_object(self):
1250 def is_user_object(self):
1251 return self.user_id is not None
1251 return self.user_id is not None
1252
1252
1253 @property
1253 @property
1254 def repositories_admin(self):
1254 def repositories_admin(self):
1255 """
1255 """
1256 Returns list of repositories you're an admin of
1256 Returns list of repositories you're an admin of
1257 """
1257 """
1258 return [
1258 return [
1259 x[0] for x in self.permissions['repositories'].items()
1259 x[0] for x in self.permissions['repositories'].items()
1260 if x[1] == 'repository.admin']
1260 if x[1] == 'repository.admin']
1261
1261
1262 @property
1262 @property
1263 def repository_groups_admin(self):
1263 def repository_groups_admin(self):
1264 """
1264 """
1265 Returns list of repository groups you're an admin of
1265 Returns list of repository groups you're an admin of
1266 """
1266 """
1267 return [
1267 return [
1268 x[0] for x in self.permissions['repositories_groups'].items()
1268 x[0] for x in self.permissions['repositories_groups'].items()
1269 if x[1] == 'group.admin']
1269 if x[1] == 'group.admin']
1270
1270
1271 @property
1271 @property
1272 def user_groups_admin(self):
1272 def user_groups_admin(self):
1273 """
1273 """
1274 Returns list of user groups you're an admin of
1274 Returns list of user groups you're an admin of
1275 """
1275 """
1276 return [
1276 return [
1277 x[0] for x in self.permissions['user_groups'].items()
1277 x[0] for x in self.permissions['user_groups'].items()
1278 if x[1] == 'usergroup.admin']
1278 if x[1] == 'usergroup.admin']
1279
1279
1280 def repo_acl_ids(self, perms=None, name_filter=None, cache=False):
1280 def repo_acl_ids(self, perms=None, name_filter=None, cache=False):
1281 """
1281 """
1282 Returns list of repository ids that user have access to based on given
1282 Returns list of repository ids that user have access to based on given
1283 perms. The cache flag should be only used in cases that are used for
1283 perms. The cache flag should be only used in cases that are used for
1284 display purposes, NOT IN ANY CASE for permission checks.
1284 display purposes, NOT IN ANY CASE for permission checks.
1285 """
1285 """
1286 from rhodecode.model.scm import RepoList
1286 from rhodecode.model.scm import RepoList
1287 if not perms:
1287 if not perms:
1288 perms = [
1288 perms = [
1289 'repository.read', 'repository.write', 'repository.admin']
1289 'repository.read', 'repository.write', 'repository.admin']
1290
1290
1291 def _cached_repo_acl(user_id, perm_def, _name_filter):
1291 def _cached_repo_acl(user_id, perm_def, _name_filter):
1292 qry = Repository.query()
1292 qry = Repository.query()
1293 if _name_filter:
1293 if _name_filter:
1294 ilike_expression = u'%{}%'.format(safe_unicode(_name_filter))
1294 ilike_expression = u'%{}%'.format(safe_unicode(_name_filter))
1295 qry = qry.filter(
1295 qry = qry.filter(
1296 Repository.repo_name.ilike(ilike_expression))
1296 Repository.repo_name.ilike(ilike_expression))
1297
1297
1298 return [x.repo_id for x in
1298 return [x.repo_id for x in
1299 RepoList(qry, perm_set=perm_def)]
1299 RepoList(qry, perm_set=perm_def)]
1300
1300
1301 return _cached_repo_acl(self.user_id, perms, name_filter)
1301 return _cached_repo_acl(self.user_id, perms, name_filter)
1302
1302
1303 def repo_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1303 def repo_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1304 """
1304 """
1305 Returns list of repository group ids that user have access to based on given
1305 Returns list of repository group ids that user have access to based on given
1306 perms. The cache flag should be only used in cases that are used for
1306 perms. The cache flag should be only used in cases that are used for
1307 display purposes, NOT IN ANY CASE for permission checks.
1307 display purposes, NOT IN ANY CASE for permission checks.
1308 """
1308 """
1309 from rhodecode.model.scm import RepoGroupList
1309 from rhodecode.model.scm import RepoGroupList
1310 if not perms:
1310 if not perms:
1311 perms = [
1311 perms = [
1312 'group.read', 'group.write', 'group.admin']
1312 'group.read', 'group.write', 'group.admin']
1313
1313
1314 def _cached_repo_group_acl(user_id, perm_def, _name_filter):
1314 def _cached_repo_group_acl(user_id, perm_def, _name_filter):
1315 qry = RepoGroup.query()
1315 qry = RepoGroup.query()
1316 if _name_filter:
1316 if _name_filter:
1317 ilike_expression = u'%{}%'.format(safe_unicode(_name_filter))
1317 ilike_expression = u'%{}%'.format(safe_unicode(_name_filter))
1318 qry = qry.filter(
1318 qry = qry.filter(
1319 RepoGroup.group_name.ilike(ilike_expression))
1319 RepoGroup.group_name.ilike(ilike_expression))
1320
1320
1321 return [x.group_id for x in
1321 return [x.group_id for x in
1322 RepoGroupList(qry, perm_set=perm_def)]
1322 RepoGroupList(qry, perm_set=perm_def)]
1323
1323
1324 return _cached_repo_group_acl(self.user_id, perms, name_filter)
1324 return _cached_repo_group_acl(self.user_id, perms, name_filter)
1325
1325
1326 def user_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1326 def user_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1327 """
1327 """
1328 Returns list of user group ids that user have access to based on given
1328 Returns list of user group ids that user have access to based on given
1329 perms. The cache flag should be only used in cases that are used for
1329 perms. The cache flag should be only used in cases that are used for
1330 display purposes, NOT IN ANY CASE for permission checks.
1330 display purposes, NOT IN ANY CASE for permission checks.
1331 """
1331 """
1332 from rhodecode.model.scm import UserGroupList
1332 from rhodecode.model.scm import UserGroupList
1333 if not perms:
1333 if not perms:
1334 perms = [
1334 perms = [
1335 'usergroup.read', 'usergroup.write', 'usergroup.admin']
1335 'usergroup.read', 'usergroup.write', 'usergroup.admin']
1336
1336
1337 def _cached_user_group_acl(user_id, perm_def, name_filter):
1337 def _cached_user_group_acl(user_id, perm_def, name_filter):
1338 qry = UserGroup.query()
1338 qry = UserGroup.query()
1339 if name_filter:
1339 if name_filter:
1340 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1340 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1341 qry = qry.filter(
1341 qry = qry.filter(
1342 UserGroup.users_group_name.ilike(ilike_expression))
1342 UserGroup.users_group_name.ilike(ilike_expression))
1343
1343
1344 return [x.users_group_id for x in
1344 return [x.users_group_id for x in
1345 UserGroupList(qry, perm_set=perm_def)]
1345 UserGroupList(qry, perm_set=perm_def)]
1346
1346
1347 return _cached_user_group_acl(self.user_id, perms, name_filter)
1347 return _cached_user_group_acl(self.user_id, perms, name_filter)
1348
1348
1349 @property
1349 @property
1350 def ip_allowed(self):
1350 def ip_allowed(self):
1351 """
1351 """
1352 Checks if ip_addr used in constructor is allowed from defined list of
1352 Checks if ip_addr used in constructor is allowed from defined list of
1353 allowed ip_addresses for user
1353 allowed ip_addresses for user
1354
1354
1355 :returns: boolean, True if ip is in allowed ip range
1355 :returns: boolean, True if ip is in allowed ip range
1356 """
1356 """
1357 # check IP
1357 # check IP
1358 inherit = self.inherit_default_permissions
1358 inherit = self.inherit_default_permissions
1359 return AuthUser.check_ip_allowed(self.user_id, self.ip_addr,
1359 return AuthUser.check_ip_allowed(self.user_id, self.ip_addr,
1360 inherit_from_default=inherit)
1360 inherit_from_default=inherit)
1361 @property
1361 @property
1362 def personal_repo_group(self):
1362 def personal_repo_group(self):
1363 return RepoGroup.get_user_personal_repo_group(self.user_id)
1363 return RepoGroup.get_user_personal_repo_group(self.user_id)
1364
1364
1365 @LazyProperty
1365 @LazyProperty
1366 def feed_token(self):
1366 def feed_token(self):
1367 return self.get_instance().feed_token
1367 return self.get_instance().feed_token
1368
1368
1369 @classmethod
1369 @classmethod
1370 def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default):
1370 def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default):
1371 allowed_ips = AuthUser.get_allowed_ips(
1371 allowed_ips = AuthUser.get_allowed_ips(
1372 user_id, cache=True, inherit_from_default=inherit_from_default)
1372 user_id, cache=True, inherit_from_default=inherit_from_default)
1373 if check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips):
1373 if check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips):
1374 log.debug('IP:%s for user %s is in range of %s',
1374 log.debug('IP:%s for user %s is in range of %s',
1375 ip_addr, user_id, allowed_ips)
1375 ip_addr, user_id, allowed_ips)
1376 return True
1376 return True
1377 else:
1377 else:
1378 log.info('Access for IP:%s forbidden for user %s, '
1378 log.info('Access for IP:%s forbidden for user %s, '
1379 'not in %s', ip_addr, user_id, allowed_ips)
1379 'not in %s', ip_addr, user_id, allowed_ips)
1380 return False
1380 return False
1381
1381
1382 def get_branch_permissions(self, repo_name, perms=None):
1382 def get_branch_permissions(self, repo_name, perms=None):
1383 perms = perms or self.permissions_with_scope({'repo_name': repo_name})
1383 perms = perms or self.permissions_with_scope({'repo_name': repo_name})
1384 branch_perms = perms.get('repository_branches', {})
1384 branch_perms = perms.get('repository_branches', {})
1385 if not branch_perms:
1385 if not branch_perms:
1386 return {}
1386 return {}
1387 repo_branch_perms = branch_perms.get(repo_name)
1387 repo_branch_perms = branch_perms.get(repo_name)
1388 return repo_branch_perms or {}
1388 return repo_branch_perms or {}
1389
1389
1390 def get_rule_and_branch_permission(self, repo_name, branch_name):
1390 def get_rule_and_branch_permission(self, repo_name, branch_name):
1391 """
1391 """
1392 Check if this AuthUser has defined any permissions for branches. If any of
1392 Check if this AuthUser has defined any permissions for branches. If any of
1393 the rules match in order, we return the matching permissions
1393 the rules match in order, we return the matching permissions
1394 """
1394 """
1395
1395
1396 rule = default_perm = ''
1396 rule = default_perm = ''
1397
1397
1398 repo_branch_perms = self.get_branch_permissions(repo_name=repo_name)
1398 repo_branch_perms = self.get_branch_permissions(repo_name=repo_name)
1399 if not repo_branch_perms:
1399 if not repo_branch_perms:
1400 return rule, default_perm
1400 return rule, default_perm
1401
1401
1402 # now calculate the permissions
1402 # now calculate the permissions
1403 for pattern, branch_perm in repo_branch_perms.items():
1403 for pattern, branch_perm in repo_branch_perms.items():
1404 if fnmatch.fnmatch(branch_name, pattern):
1404 if fnmatch.fnmatch(branch_name, pattern):
1405 rule = '`{}`=>{}'.format(pattern, branch_perm)
1405 rule = '`{}`=>{}'.format(pattern, branch_perm)
1406 return rule, branch_perm
1406 return rule, branch_perm
1407
1407
1408 return rule, default_perm
1408 return rule, default_perm
1409
1409
1410 def __repr__(self):
1410 def __repr__(self):
1411 return "<AuthUser('id:%s[%s] ip:%s auth:%s')>"\
1411 return "<AuthUser('id:%s[%s] ip:%s auth:%s')>"\
1412 % (self.user_id, self.username, self.ip_addr, self.is_authenticated)
1412 % (self.user_id, self.username, self.ip_addr, self.is_authenticated)
1413
1413
1414 def set_authenticated(self, authenticated=True):
1414 def set_authenticated(self, authenticated=True):
1415 if self.user_id != self.anonymous_user.user_id:
1415 if self.user_id != self.anonymous_user.user_id:
1416 self.is_authenticated = authenticated
1416 self.is_authenticated = authenticated
1417
1417
1418 def get_cookie_store(self):
1418 def get_cookie_store(self):
1419 return {
1419 return {
1420 'username': self.username,
1420 'username': self.username,
1421 'password': md5(self.password or ''),
1421 'password': md5(self.password or ''),
1422 'user_id': self.user_id,
1422 'user_id': self.user_id,
1423 'is_authenticated': self.is_authenticated
1423 'is_authenticated': self.is_authenticated
1424 }
1424 }
1425
1425
1426 @classmethod
1426 @classmethod
1427 def from_cookie_store(cls, cookie_store):
1427 def from_cookie_store(cls, cookie_store):
1428 """
1428 """
1429 Creates AuthUser from a cookie store
1429 Creates AuthUser from a cookie store
1430
1430
1431 :param cls:
1431 :param cls:
1432 :param cookie_store:
1432 :param cookie_store:
1433 """
1433 """
1434 user_id = cookie_store.get('user_id')
1434 user_id = cookie_store.get('user_id')
1435 username = cookie_store.get('username')
1435 username = cookie_store.get('username')
1436 api_key = cookie_store.get('api_key')
1436 api_key = cookie_store.get('api_key')
1437 return AuthUser(user_id, api_key, username)
1437 return AuthUser(user_id, api_key, username)
1438
1438
1439 @classmethod
1439 @classmethod
1440 def get_allowed_ips(cls, user_id, cache=False, inherit_from_default=False):
1440 def get_allowed_ips(cls, user_id, cache=False, inherit_from_default=False):
1441 _set = set()
1441 _set = set()
1442
1442
1443 if inherit_from_default:
1443 if inherit_from_default:
1444 def_user_id = User.get_default_user(cache=True).user_id
1444 def_user_id = User.get_default_user(cache=True).user_id
1445 default_ips = UserIpMap.query().filter(UserIpMap.user_id == def_user_id)
1445 default_ips = UserIpMap.query().filter(UserIpMap.user_id == def_user_id)
1446 if cache:
1446 if cache:
1447 default_ips = default_ips.options(
1447 default_ips = default_ips.options(
1448 FromCache("sql_cache_short", "get_user_ips_default"))
1448 FromCache("sql_cache_short", "get_user_ips_default"))
1449
1449
1450 # populate from default user
1450 # populate from default user
1451 for ip in default_ips:
1451 for ip in default_ips:
1452 try:
1452 try:
1453 _set.add(ip.ip_addr)
1453 _set.add(ip.ip_addr)
1454 except ObjectDeletedError:
1454 except ObjectDeletedError:
1455 # since we use heavy caching sometimes it happens that
1455 # since we use heavy caching sometimes it happens that
1456 # we get deleted objects here, we just skip them
1456 # we get deleted objects here, we just skip them
1457 pass
1457 pass
1458
1458
1459 # NOTE:(marcink) we don't want to load any rules for empty
1459 # NOTE:(marcink) we don't want to load any rules for empty
1460 # user_id which is the case of access of non logged users when anonymous
1460 # user_id which is the case of access of non logged users when anonymous
1461 # access is disabled
1461 # access is disabled
1462 user_ips = []
1462 user_ips = []
1463 if user_id:
1463 if user_id:
1464 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
1464 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
1465 if cache:
1465 if cache:
1466 user_ips = user_ips.options(
1466 user_ips = user_ips.options(
1467 FromCache("sql_cache_short", "get_user_ips_%s" % user_id))
1467 FromCache("sql_cache_short", "get_user_ips_%s" % user_id))
1468
1468
1469 for ip in user_ips:
1469 for ip in user_ips:
1470 try:
1470 try:
1471 _set.add(ip.ip_addr)
1471 _set.add(ip.ip_addr)
1472 except ObjectDeletedError:
1472 except ObjectDeletedError:
1473 # since we use heavy caching sometimes it happens that we get
1473 # since we use heavy caching sometimes it happens that we get
1474 # deleted objects here, we just skip them
1474 # deleted objects here, we just skip them
1475 pass
1475 pass
1476 return _set or {ip for ip in ['0.0.0.0/0', '::/0']}
1476 return _set or {ip for ip in ['0.0.0.0/0', '::/0']}
1477
1477
1478
1478
1479 def set_available_permissions(settings):
1479 def set_available_permissions(settings):
1480 """
1480 """
1481 This function will propagate pyramid settings with all available defined
1481 This function will propagate pyramid settings with all available defined
1482 permission given in db. We don't want to check each time from db for new
1482 permission given in db. We don't want to check each time from db for new
1483 permissions since adding a new permission also requires application restart
1483 permissions since adding a new permission also requires application restart
1484 ie. to decorate new views with the newly created permission
1484 ie. to decorate new views with the newly created permission
1485
1485
1486 :param settings: current pyramid registry.settings
1486 :param settings: current pyramid registry.settings
1487
1487
1488 """
1488 """
1489 log.debug('auth: getting information about all available permissions')
1489 log.debug('auth: getting information about all available permissions')
1490 try:
1490 try:
1491 sa = meta.Session
1491 sa = meta.Session
1492 all_perms = sa.query(Permission).all()
1492 all_perms = sa.query(Permission).all()
1493 settings.setdefault('available_permissions',
1493 settings.setdefault('available_permissions',
1494 [x.permission_name for x in all_perms])
1494 [x.permission_name for x in all_perms])
1495 log.debug('auth: set available permissions')
1495 log.debug('auth: set available permissions')
1496 except Exception:
1496 except Exception:
1497 log.exception('Failed to fetch permissions from the database.')
1497 log.exception('Failed to fetch permissions from the database.')
1498 raise
1498 raise
1499
1499
1500
1500
1501 def get_csrf_token(session, force_new=False, save_if_missing=True):
1501 def get_csrf_token(session, force_new=False, save_if_missing=True):
1502 """
1502 """
1503 Return the current authentication token, creating one if one doesn't
1503 Return the current authentication token, creating one if one doesn't
1504 already exist and the save_if_missing flag is present.
1504 already exist and the save_if_missing flag is present.
1505
1505
1506 :param session: pass in the pyramid session, else we use the global ones
1506 :param session: pass in the pyramid session, else we use the global ones
1507 :param force_new: force to re-generate the token and store it in session
1507 :param force_new: force to re-generate the token and store it in session
1508 :param save_if_missing: save the newly generated token if it's missing in
1508 :param save_if_missing: save the newly generated token if it's missing in
1509 session
1509 session
1510 """
1510 """
1511 # NOTE(marcink): probably should be replaced with below one from pyramid 1.9
1511 # NOTE(marcink): probably should be replaced with below one from pyramid 1.9
1512 # from pyramid.csrf import get_csrf_token
1512 # from pyramid.csrf import get_csrf_token
1513
1513
1514 if (csrf_token_key not in session and save_if_missing) or force_new:
1514 if (csrf_token_key not in session and save_if_missing) or force_new:
1515 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
1515 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
1516 session[csrf_token_key] = token
1516 session[csrf_token_key] = token
1517 if hasattr(session, 'save'):
1517 if hasattr(session, 'save'):
1518 session.save()
1518 session.save()
1519 return session.get(csrf_token_key)
1519 return session.get(csrf_token_key)
1520
1520
1521
1521
1522 def get_request(perm_class_instance):
1522 def get_request(perm_class_instance):
1523 from pyramid.threadlocal import get_current_request
1523 from pyramid.threadlocal import get_current_request
1524 pyramid_request = get_current_request()
1524 pyramid_request = get_current_request()
1525 return pyramid_request
1525 return pyramid_request
1526
1526
1527
1527
1528 # CHECK DECORATORS
1528 # CHECK DECORATORS
1529 class CSRFRequired(object):
1529 class CSRFRequired(object):
1530 """
1530 """
1531 Decorator for authenticating a form
1531 Decorator for authenticating a form
1532
1532
1533 This decorator uses an authorization token stored in the client's
1533 This decorator uses an authorization token stored in the client's
1534 session for prevention of certain Cross-site request forgery (CSRF)
1534 session for prevention of certain Cross-site request forgery (CSRF)
1535 attacks (See
1535 attacks (See
1536 http://en.wikipedia.org/wiki/Cross-site_request_forgery for more
1536 http://en.wikipedia.org/wiki/Cross-site_request_forgery for more
1537 information).
1537 information).
1538
1538
1539 For use with the ``webhelpers.secure_form`` helper functions.
1539 For use with the ``webhelpers.secure_form`` helper functions.
1540
1540
1541 """
1541 """
1542 def __init__(self, token=csrf_token_key, header='X-CSRF-Token',
1542 def __init__(self, token=csrf_token_key, header='X-CSRF-Token',
1543 except_methods=None):
1543 except_methods=None):
1544 self.token = token
1544 self.token = token
1545 self.header = header
1545 self.header = header
1546 self.except_methods = except_methods or []
1546 self.except_methods = except_methods or []
1547
1547
1548 def __call__(self, func):
1548 def __call__(self, func):
1549 return get_cython_compat_decorator(self.__wrapper, func)
1549 return get_cython_compat_decorator(self.__wrapper, func)
1550
1550
1551 def _get_csrf(self, _request):
1551 def _get_csrf(self, _request):
1552 return _request.POST.get(self.token, _request.headers.get(self.header))
1552 return _request.POST.get(self.token, _request.headers.get(self.header))
1553
1553
1554 def check_csrf(self, _request, cur_token):
1554 def check_csrf(self, _request, cur_token):
1555 supplied_token = self._get_csrf(_request)
1555 supplied_token = self._get_csrf(_request)
1556 return supplied_token and supplied_token == cur_token
1556 return supplied_token and supplied_token == cur_token
1557
1557
1558 def _get_request(self):
1558 def _get_request(self):
1559 return get_request(self)
1559 return get_request(self)
1560
1560
1561 def __wrapper(self, func, *fargs, **fkwargs):
1561 def __wrapper(self, func, *fargs, **fkwargs):
1562 request = self._get_request()
1562 request = self._get_request()
1563
1563
1564 if request.method in self.except_methods:
1564 if request.method in self.except_methods:
1565 return func(*fargs, **fkwargs)
1565 return func(*fargs, **fkwargs)
1566
1566
1567 cur_token = get_csrf_token(request.session, save_if_missing=False)
1567 cur_token = get_csrf_token(request.session, save_if_missing=False)
1568 if self.check_csrf(request, cur_token):
1568 if self.check_csrf(request, cur_token):
1569 if request.POST.get(self.token):
1569 if request.POST.get(self.token):
1570 del request.POST[self.token]
1570 del request.POST[self.token]
1571 return func(*fargs, **fkwargs)
1571 return func(*fargs, **fkwargs)
1572 else:
1572 else:
1573 reason = 'token-missing'
1573 reason = 'token-missing'
1574 supplied_token = self._get_csrf(request)
1574 supplied_token = self._get_csrf(request)
1575 if supplied_token and cur_token != supplied_token:
1575 if supplied_token and cur_token != supplied_token:
1576 reason = 'token-mismatch [%s:%s]' % (
1576 reason = 'token-mismatch [%s:%s]' % (
1577 cur_token or ''[:6], supplied_token or ''[:6])
1577 cur_token or ''[:6], supplied_token or ''[:6])
1578
1578
1579 csrf_message = \
1579 csrf_message = \
1580 ("Cross-site request forgery detected, request denied. See "
1580 ("Cross-site request forgery detected, request denied. See "
1581 "http://en.wikipedia.org/wiki/Cross-site_request_forgery for "
1581 "http://en.wikipedia.org/wiki/Cross-site_request_forgery for "
1582 "more information.")
1582 "more information.")
1583 log.warn('Cross-site request forgery detected, request %r DENIED: %s '
1583 log.warn('Cross-site request forgery detected, request %r DENIED: %s '
1584 'REMOTE_ADDR:%s, HEADERS:%s' % (
1584 'REMOTE_ADDR:%s, HEADERS:%s' % (
1585 request, reason, request.remote_addr, request.headers))
1585 request, reason, request.remote_addr, request.headers))
1586
1586
1587 raise HTTPForbidden(explanation=csrf_message)
1587 raise HTTPForbidden(explanation=csrf_message)
1588
1588
1589
1589
1590 class LoginRequired(object):
1590 class LoginRequired(object):
1591 """
1591 """
1592 Must be logged in to execute this function else
1592 Must be logged in to execute this function else
1593 redirect to login page
1593 redirect to login page
1594
1594
1595 :param api_access: if enabled this checks only for valid auth token
1595 :param api_access: if enabled this checks only for valid auth token
1596 and grants access based on valid token
1596 and grants access based on valid token
1597 """
1597 """
1598 def __init__(self, auth_token_access=None):
1598 def __init__(self, auth_token_access=None):
1599 self.auth_token_access = auth_token_access
1599 self.auth_token_access = auth_token_access
1600
1600
1601 def __call__(self, func):
1601 def __call__(self, func):
1602 return get_cython_compat_decorator(self.__wrapper, func)
1602 return get_cython_compat_decorator(self.__wrapper, func)
1603
1603
1604 def _get_request(self):
1604 def _get_request(self):
1605 return get_request(self)
1605 return get_request(self)
1606
1606
1607 def __wrapper(self, func, *fargs, **fkwargs):
1607 def __wrapper(self, func, *fargs, **fkwargs):
1608 from rhodecode.lib import helpers as h
1608 from rhodecode.lib import helpers as h
1609 cls = fargs[0]
1609 cls = fargs[0]
1610 user = cls._rhodecode_user
1610 user = cls._rhodecode_user
1611 request = self._get_request()
1611 request = self._get_request()
1612 _ = request.translate
1612 _ = request.translate
1613
1613
1614 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
1614 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
1615 log.debug('Starting login restriction checks for user: %s', user)
1615 log.debug('Starting login restriction checks for user: %s', user)
1616 # check if our IP is allowed
1616 # check if our IP is allowed
1617 ip_access_valid = True
1617 ip_access_valid = True
1618 if not user.ip_allowed:
1618 if not user.ip_allowed:
1619 h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr,))),
1619 h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr,))),
1620 category='warning')
1620 category='warning')
1621 ip_access_valid = False
1621 ip_access_valid = False
1622
1622
1623 # check if we used an APIKEY and it's a valid one
1623 # check if we used an APIKEY and it's a valid one
1624 # defined white-list of controllers which API access will be enabled
1624 # defined white-list of controllers which API access will be enabled
1625 _auth_token = request.GET.get(
1625 _auth_token = request.GET.get(
1626 'auth_token', '') or request.GET.get('api_key', '')
1626 'auth_token', '') or request.GET.get('api_key', '')
1627 auth_token_access_valid = allowed_auth_token_access(
1627 auth_token_access_valid = allowed_auth_token_access(
1628 loc, auth_token=_auth_token)
1628 loc, auth_token=_auth_token)
1629
1629
1630 # explicit controller is enabled or API is in our whitelist
1630 # explicit controller is enabled or API is in our whitelist
1631 if self.auth_token_access or auth_token_access_valid:
1631 if self.auth_token_access or auth_token_access_valid:
1632 log.debug('Checking AUTH TOKEN access for %s', cls)
1632 log.debug('Checking AUTH TOKEN access for %s', cls)
1633 db_user = user.get_instance()
1633 db_user = user.get_instance()
1634
1634
1635 if db_user:
1635 if db_user:
1636 if self.auth_token_access:
1636 if self.auth_token_access:
1637 roles = self.auth_token_access
1637 roles = self.auth_token_access
1638 else:
1638 else:
1639 roles = [UserApiKeys.ROLE_HTTP]
1639 roles = [UserApiKeys.ROLE_HTTP]
1640 token_match = db_user.authenticate_by_token(
1640 token_match = db_user.authenticate_by_token(
1641 _auth_token, roles=roles)
1641 _auth_token, roles=roles)
1642 else:
1642 else:
1643 log.debug('Unable to fetch db instance for auth user: %s', user)
1643 log.debug('Unable to fetch db instance for auth user: %s', user)
1644 token_match = False
1644 token_match = False
1645
1645
1646 if _auth_token and token_match:
1646 if _auth_token and token_match:
1647 auth_token_access_valid = True
1647 auth_token_access_valid = True
1648 log.debug('AUTH TOKEN ****%s is VALID', _auth_token[-4:])
1648 log.debug('AUTH TOKEN ****%s is VALID', _auth_token[-4:])
1649 else:
1649 else:
1650 auth_token_access_valid = False
1650 auth_token_access_valid = False
1651 if not _auth_token:
1651 if not _auth_token:
1652 log.debug("AUTH TOKEN *NOT* present in request")
1652 log.debug("AUTH TOKEN *NOT* present in request")
1653 else:
1653 else:
1654 log.warning("AUTH TOKEN ****%s *NOT* valid", _auth_token[-4:])
1654 log.warning("AUTH TOKEN ****%s *NOT* valid", _auth_token[-4:])
1655
1655
1656 log.debug('Checking if %s is authenticated @ %s', user.username, loc)
1656 log.debug('Checking if %s is authenticated @ %s', user.username, loc)
1657 reason = 'RHODECODE_AUTH' if user.is_authenticated \
1657 reason = 'RHODECODE_AUTH' if user.is_authenticated \
1658 else 'AUTH_TOKEN_AUTH'
1658 else 'AUTH_TOKEN_AUTH'
1659
1659
1660 if ip_access_valid and (
1660 if ip_access_valid and (
1661 user.is_authenticated or auth_token_access_valid):
1661 user.is_authenticated or auth_token_access_valid):
1662 log.info('user %s authenticating with:%s IS authenticated on func %s',
1662 log.info('user %s authenticating with:%s IS authenticated on func %s',
1663 user, reason, loc)
1663 user, reason, loc)
1664
1664
1665 return func(*fargs, **fkwargs)
1665 return func(*fargs, **fkwargs)
1666 else:
1666 else:
1667 log.warning(
1667 log.warning(
1668 'user %s authenticating with:%s NOT authenticated on '
1668 'user %s authenticating with:%s NOT authenticated on '
1669 'func: %s: IP_ACCESS:%s AUTH_TOKEN_ACCESS:%s',
1669 'func: %s: IP_ACCESS:%s AUTH_TOKEN_ACCESS:%s',
1670 user, reason, loc, ip_access_valid, auth_token_access_valid)
1670 user, reason, loc, ip_access_valid, auth_token_access_valid)
1671 # we preserve the get PARAM
1671 # we preserve the get PARAM
1672 came_from = get_came_from(request)
1672 came_from = get_came_from(request)
1673
1673
1674 log.debug('redirecting to login page with %s', came_from)
1674 log.debug('redirecting to login page with %s', came_from)
1675 raise HTTPFound(
1675 raise HTTPFound(
1676 h.route_path('login', _query={'came_from': came_from}))
1676 h.route_path('login', _query={'came_from': came_from}))
1677
1677
1678
1678
1679 class NotAnonymous(object):
1679 class NotAnonymous(object):
1680 """
1680 """
1681 Must be logged in to execute this function else
1681 Must be logged in to execute this function else
1682 redirect to login page
1682 redirect to login page
1683 """
1683 """
1684
1684
1685 def __call__(self, func):
1685 def __call__(self, func):
1686 return get_cython_compat_decorator(self.__wrapper, func)
1686 return get_cython_compat_decorator(self.__wrapper, func)
1687
1687
1688 def _get_request(self):
1688 def _get_request(self):
1689 return get_request(self)
1689 return get_request(self)
1690
1690
1691 def __wrapper(self, func, *fargs, **fkwargs):
1691 def __wrapper(self, func, *fargs, **fkwargs):
1692 import rhodecode.lib.helpers as h
1692 import rhodecode.lib.helpers as h
1693 cls = fargs[0]
1693 cls = fargs[0]
1694 self.user = cls._rhodecode_user
1694 self.user = cls._rhodecode_user
1695 request = self._get_request()
1695 request = self._get_request()
1696 _ = request.translate
1696 _ = request.translate
1697 log.debug('Checking if user is not anonymous @%s', cls)
1697 log.debug('Checking if user is not anonymous @%s', cls)
1698
1698
1699 anonymous = self.user.username == User.DEFAULT_USER
1699 anonymous = self.user.username == User.DEFAULT_USER
1700
1700
1701 if anonymous:
1701 if anonymous:
1702 came_from = get_came_from(request)
1702 came_from = get_came_from(request)
1703 h.flash(_('You need to be a registered user to '
1703 h.flash(_('You need to be a registered user to '
1704 'perform this action'),
1704 'perform this action'),
1705 category='warning')
1705 category='warning')
1706 raise HTTPFound(
1706 raise HTTPFound(
1707 h.route_path('login', _query={'came_from': came_from}))
1707 h.route_path('login', _query={'came_from': came_from}))
1708 else:
1708 else:
1709 return func(*fargs, **fkwargs)
1709 return func(*fargs, **fkwargs)
1710
1710
1711
1711
1712 class PermsDecorator(object):
1712 class PermsDecorator(object):
1713 """
1713 """
1714 Base class for controller decorators, we extract the current user from
1714 Base class for controller decorators, we extract the current user from
1715 the class itself, which has it stored in base controllers
1715 the class itself, which has it stored in base controllers
1716 """
1716 """
1717
1717
1718 def __init__(self, *required_perms):
1718 def __init__(self, *required_perms):
1719 self.required_perms = set(required_perms)
1719 self.required_perms = set(required_perms)
1720
1720
1721 def __call__(self, func):
1721 def __call__(self, func):
1722 return get_cython_compat_decorator(self.__wrapper, func)
1722 return get_cython_compat_decorator(self.__wrapper, func)
1723
1723
1724 def _get_request(self):
1724 def _get_request(self):
1725 return get_request(self)
1725 return get_request(self)
1726
1726
1727 def __wrapper(self, func, *fargs, **fkwargs):
1727 def __wrapper(self, func, *fargs, **fkwargs):
1728 import rhodecode.lib.helpers as h
1728 import rhodecode.lib.helpers as h
1729 cls = fargs[0]
1729 cls = fargs[0]
1730 _user = cls._rhodecode_user
1730 _user = cls._rhodecode_user
1731 request = self._get_request()
1731 request = self._get_request()
1732 _ = request.translate
1732 _ = request.translate
1733
1733
1734 log.debug('checking %s permissions %s for %s %s',
1734 log.debug('checking %s permissions %s for %s %s',
1735 self.__class__.__name__, self.required_perms, cls, _user)
1735 self.__class__.__name__, self.required_perms, cls, _user)
1736
1736
1737 if self.check_permissions(_user):
1737 if self.check_permissions(_user):
1738 log.debug('Permission granted for %s %s', cls, _user)
1738 log.debug('Permission granted for %s %s', cls, _user)
1739 return func(*fargs, **fkwargs)
1739 return func(*fargs, **fkwargs)
1740
1740
1741 else:
1741 else:
1742 log.debug('Permission denied for %s %s', cls, _user)
1742 log.debug('Permission denied for %s %s', cls, _user)
1743 anonymous = _user.username == User.DEFAULT_USER
1743 anonymous = _user.username == User.DEFAULT_USER
1744
1744
1745 if anonymous:
1745 if anonymous:
1746 came_from = get_came_from(self._get_request())
1746 came_from = get_came_from(self._get_request())
1747 h.flash(_('You need to be signed in to view this page'),
1747 h.flash(_('You need to be signed in to view this page'),
1748 category='warning')
1748 category='warning')
1749 raise HTTPFound(
1749 raise HTTPFound(
1750 h.route_path('login', _query={'came_from': came_from}))
1750 h.route_path('login', _query={'came_from': came_from}))
1751
1751
1752 else:
1752 else:
1753 # redirect with 404 to prevent resource discovery
1753 # redirect with 404 to prevent resource discovery
1754 raise HTTPNotFound()
1754 raise HTTPNotFound()
1755
1755
1756 def check_permissions(self, user):
1756 def check_permissions(self, user):
1757 """Dummy function for overriding"""
1757 """Dummy function for overriding"""
1758 raise NotImplementedError(
1758 raise NotImplementedError(
1759 'You have to write this function in child class')
1759 'You have to write this function in child class')
1760
1760
1761
1761
1762 class HasPermissionAllDecorator(PermsDecorator):
1762 class HasPermissionAllDecorator(PermsDecorator):
1763 """
1763 """
1764 Checks for access permission for all given predicates. All of them
1764 Checks for access permission for all given predicates. All of them
1765 have to be meet in order to fulfill the request
1765 have to be meet in order to fulfill the request
1766 """
1766 """
1767
1767
1768 def check_permissions(self, user):
1768 def check_permissions(self, user):
1769 perms = user.permissions_with_scope({})
1769 perms = user.permissions_with_scope({})
1770 if self.required_perms.issubset(perms['global']):
1770 if self.required_perms.issubset(perms['global']):
1771 return True
1771 return True
1772 return False
1772 return False
1773
1773
1774
1774
1775 class HasPermissionAnyDecorator(PermsDecorator):
1775 class HasPermissionAnyDecorator(PermsDecorator):
1776 """
1776 """
1777 Checks for access permission for any of given predicates. In order to
1777 Checks for access permission for any of given predicates. In order to
1778 fulfill the request any of predicates must be meet
1778 fulfill the request any of predicates must be meet
1779 """
1779 """
1780
1780
1781 def check_permissions(self, user):
1781 def check_permissions(self, user):
1782 perms = user.permissions_with_scope({})
1782 perms = user.permissions_with_scope({})
1783 if self.required_perms.intersection(perms['global']):
1783 if self.required_perms.intersection(perms['global']):
1784 return True
1784 return True
1785 return False
1785 return False
1786
1786
1787
1787
1788 class HasRepoPermissionAllDecorator(PermsDecorator):
1788 class HasRepoPermissionAllDecorator(PermsDecorator):
1789 """
1789 """
1790 Checks for access permission for all given predicates for specific
1790 Checks for access permission for all given predicates for specific
1791 repository. All of them have to be meet in order to fulfill the request
1791 repository. All of them have to be meet in order to fulfill the request
1792 """
1792 """
1793 def _get_repo_name(self):
1793 def _get_repo_name(self):
1794 _request = self._get_request()
1794 _request = self._get_request()
1795 return get_repo_slug(_request)
1795 return get_repo_slug(_request)
1796
1796
1797 def check_permissions(self, user):
1797 def check_permissions(self, user):
1798 perms = user.permissions
1798 perms = user.permissions
1799 repo_name = self._get_repo_name()
1799 repo_name = self._get_repo_name()
1800
1800
1801 try:
1801 try:
1802 user_perms = {perms['repositories'][repo_name]}
1802 user_perms = {perms['repositories'][repo_name]}
1803 except KeyError:
1803 except KeyError:
1804 log.debug('cannot locate repo with name: `%s` in permissions defs',
1804 log.debug('cannot locate repo with name: `%s` in permissions defs',
1805 repo_name)
1805 repo_name)
1806 return False
1806 return False
1807
1807
1808 log.debug('checking `%s` permissions for repo `%s`',
1808 log.debug('checking `%s` permissions for repo `%s`',
1809 user_perms, repo_name)
1809 user_perms, repo_name)
1810 if self.required_perms.issubset(user_perms):
1810 if self.required_perms.issubset(user_perms):
1811 return True
1811 return True
1812 return False
1812 return False
1813
1813
1814
1814
1815 class HasRepoPermissionAnyDecorator(PermsDecorator):
1815 class HasRepoPermissionAnyDecorator(PermsDecorator):
1816 """
1816 """
1817 Checks for access permission for any of given predicates for specific
1817 Checks for access permission for any of given predicates for specific
1818 repository. In order to fulfill the request any of predicates must be meet
1818 repository. In order to fulfill the request any of predicates must be meet
1819 """
1819 """
1820 def _get_repo_name(self):
1820 def _get_repo_name(self):
1821 _request = self._get_request()
1821 _request = self._get_request()
1822 return get_repo_slug(_request)
1822 return get_repo_slug(_request)
1823
1823
1824 def check_permissions(self, user):
1824 def check_permissions(self, user):
1825 perms = user.permissions
1825 perms = user.permissions
1826 repo_name = self._get_repo_name()
1826 repo_name = self._get_repo_name()
1827
1827
1828 try:
1828 try:
1829 user_perms = {perms['repositories'][repo_name]}
1829 user_perms = {perms['repositories'][repo_name]}
1830 except KeyError:
1830 except KeyError:
1831 log.debug(
1831 log.debug(
1832 'cannot locate repo with name: `%s` in permissions defs',
1832 'cannot locate repo with name: `%s` in permissions defs',
1833 repo_name)
1833 repo_name)
1834 return False
1834 return False
1835
1835
1836 log.debug('checking `%s` permissions for repo `%s`',
1836 log.debug('checking `%s` permissions for repo `%s`',
1837 user_perms, repo_name)
1837 user_perms, repo_name)
1838 if self.required_perms.intersection(user_perms):
1838 if self.required_perms.intersection(user_perms):
1839 return True
1839 return True
1840 return False
1840 return False
1841
1841
1842
1842
1843 class HasRepoGroupPermissionAllDecorator(PermsDecorator):
1843 class HasRepoGroupPermissionAllDecorator(PermsDecorator):
1844 """
1844 """
1845 Checks for access permission for all given predicates for specific
1845 Checks for access permission for all given predicates for specific
1846 repository group. All of them have to be meet in order to
1846 repository group. All of them have to be meet in order to
1847 fulfill the request
1847 fulfill the request
1848 """
1848 """
1849 def _get_repo_group_name(self):
1849 def _get_repo_group_name(self):
1850 _request = self._get_request()
1850 _request = self._get_request()
1851 return get_repo_group_slug(_request)
1851 return get_repo_group_slug(_request)
1852
1852
1853 def check_permissions(self, user):
1853 def check_permissions(self, user):
1854 perms = user.permissions
1854 perms = user.permissions
1855 group_name = self._get_repo_group_name()
1855 group_name = self._get_repo_group_name()
1856 try:
1856 try:
1857 user_perms = {perms['repositories_groups'][group_name]}
1857 user_perms = {perms['repositories_groups'][group_name]}
1858 except KeyError:
1858 except KeyError:
1859 log.debug(
1859 log.debug(
1860 'cannot locate repo group with name: `%s` in permissions defs',
1860 'cannot locate repo group with name: `%s` in permissions defs',
1861 group_name)
1861 group_name)
1862 return False
1862 return False
1863
1863
1864 log.debug('checking `%s` permissions for repo group `%s`',
1864 log.debug('checking `%s` permissions for repo group `%s`',
1865 user_perms, group_name)
1865 user_perms, group_name)
1866 if self.required_perms.issubset(user_perms):
1866 if self.required_perms.issubset(user_perms):
1867 return True
1867 return True
1868 return False
1868 return False
1869
1869
1870
1870
1871 class HasRepoGroupPermissionAnyDecorator(PermsDecorator):
1871 class HasRepoGroupPermissionAnyDecorator(PermsDecorator):
1872 """
1872 """
1873 Checks for access permission for any of given predicates for specific
1873 Checks for access permission for any of given predicates for specific
1874 repository group. In order to fulfill the request any
1874 repository group. In order to fulfill the request any
1875 of predicates must be met
1875 of predicates must be met
1876 """
1876 """
1877 def _get_repo_group_name(self):
1877 def _get_repo_group_name(self):
1878 _request = self._get_request()
1878 _request = self._get_request()
1879 return get_repo_group_slug(_request)
1879 return get_repo_group_slug(_request)
1880
1880
1881 def check_permissions(self, user):
1881 def check_permissions(self, user):
1882 perms = user.permissions
1882 perms = user.permissions
1883 group_name = self._get_repo_group_name()
1883 group_name = self._get_repo_group_name()
1884
1884
1885 try:
1885 try:
1886 user_perms = {perms['repositories_groups'][group_name]}
1886 user_perms = {perms['repositories_groups'][group_name]}
1887 except KeyError:
1887 except KeyError:
1888 log.debug(
1888 log.debug(
1889 'cannot locate repo group with name: `%s` in permissions defs',
1889 'cannot locate repo group with name: `%s` in permissions defs',
1890 group_name)
1890 group_name)
1891 return False
1891 return False
1892
1892
1893 log.debug('checking `%s` permissions for repo group `%s`',
1893 log.debug('checking `%s` permissions for repo group `%s`',
1894 user_perms, group_name)
1894 user_perms, group_name)
1895 if self.required_perms.intersection(user_perms):
1895 if self.required_perms.intersection(user_perms):
1896 return True
1896 return True
1897 return False
1897 return False
1898
1898
1899
1899
1900 class HasUserGroupPermissionAllDecorator(PermsDecorator):
1900 class HasUserGroupPermissionAllDecorator(PermsDecorator):
1901 """
1901 """
1902 Checks for access permission for all given predicates for specific
1902 Checks for access permission for all given predicates for specific
1903 user group. All of them have to be meet in order to fulfill the request
1903 user group. All of them have to be meet in order to fulfill the request
1904 """
1904 """
1905 def _get_user_group_name(self):
1905 def _get_user_group_name(self):
1906 _request = self._get_request()
1906 _request = self._get_request()
1907 return get_user_group_slug(_request)
1907 return get_user_group_slug(_request)
1908
1908
1909 def check_permissions(self, user):
1909 def check_permissions(self, user):
1910 perms = user.permissions
1910 perms = user.permissions
1911 group_name = self._get_user_group_name()
1911 group_name = self._get_user_group_name()
1912 try:
1912 try:
1913 user_perms = {perms['user_groups'][group_name]}
1913 user_perms = {perms['user_groups'][group_name]}
1914 except KeyError:
1914 except KeyError:
1915 return False
1915 return False
1916
1916
1917 if self.required_perms.issubset(user_perms):
1917 if self.required_perms.issubset(user_perms):
1918 return True
1918 return True
1919 return False
1919 return False
1920
1920
1921
1921
1922 class HasUserGroupPermissionAnyDecorator(PermsDecorator):
1922 class HasUserGroupPermissionAnyDecorator(PermsDecorator):
1923 """
1923 """
1924 Checks for access permission for any of given predicates for specific
1924 Checks for access permission for any of given predicates for specific
1925 user group. In order to fulfill the request any of predicates must be meet
1925 user group. In order to fulfill the request any of predicates must be meet
1926 """
1926 """
1927 def _get_user_group_name(self):
1927 def _get_user_group_name(self):
1928 _request = self._get_request()
1928 _request = self._get_request()
1929 return get_user_group_slug(_request)
1929 return get_user_group_slug(_request)
1930
1930
1931 def check_permissions(self, user):
1931 def check_permissions(self, user):
1932 perms = user.permissions
1932 perms = user.permissions
1933 group_name = self._get_user_group_name()
1933 group_name = self._get_user_group_name()
1934 try:
1934 try:
1935 user_perms = {perms['user_groups'][group_name]}
1935 user_perms = {perms['user_groups'][group_name]}
1936 except KeyError:
1936 except KeyError:
1937 return False
1937 return False
1938
1938
1939 if self.required_perms.intersection(user_perms):
1939 if self.required_perms.intersection(user_perms):
1940 return True
1940 return True
1941 return False
1941 return False
1942
1942
1943
1943
1944 # CHECK FUNCTIONS
1944 # CHECK FUNCTIONS
1945 class PermsFunction(object):
1945 class PermsFunction(object):
1946 """Base function for other check functions"""
1946 """Base function for other check functions"""
1947
1947
1948 def __init__(self, *perms):
1948 def __init__(self, *perms):
1949 self.required_perms = set(perms)
1949 self.required_perms = set(perms)
1950 self.repo_name = None
1950 self.repo_name = None
1951 self.repo_group_name = None
1951 self.repo_group_name = None
1952 self.user_group_name = None
1952 self.user_group_name = None
1953
1953
1954 def __bool__(self):
1954 def __bool__(self):
1955 frame = inspect.currentframe()
1955 frame = inspect.currentframe()
1956 stack_trace = traceback.format_stack(frame)
1956 stack_trace = traceback.format_stack(frame)
1957 log.error('Checking bool value on a class instance of perm '
1957 log.error('Checking bool value on a class instance of perm '
1958 'function is not allowed: %s', ''.join(stack_trace))
1958 'function is not allowed: %s', ''.join(stack_trace))
1959 # rather than throwing errors, here we always return False so if by
1959 # rather than throwing errors, here we always return False so if by
1960 # accident someone checks truth for just an instance it will always end
1960 # accident someone checks truth for just an instance it will always end
1961 # up in returning False
1961 # up in returning False
1962 return False
1962 return False
1963 __nonzero__ = __bool__
1963 __nonzero__ = __bool__
1964
1964
1965 def __call__(self, check_location='', user=None):
1965 def __call__(self, check_location='', user=None):
1966 if not user:
1966 if not user:
1967 log.debug('Using user attribute from global request')
1967 log.debug('Using user attribute from global request')
1968 request = self._get_request()
1968 request = self._get_request()
1969 user = request.user
1969 user = request.user
1970
1970
1971 # init auth user if not already given
1971 # init auth user if not already given
1972 if not isinstance(user, AuthUser):
1972 if not isinstance(user, AuthUser):
1973 log.debug('Wrapping user %s into AuthUser', user)
1973 log.debug('Wrapping user %s into AuthUser', user)
1974 user = AuthUser(user.user_id)
1974 user = AuthUser(user.user_id)
1975
1975
1976 cls_name = self.__class__.__name__
1976 cls_name = self.__class__.__name__
1977 check_scope = self._get_check_scope(cls_name)
1977 check_scope = self._get_check_scope(cls_name)
1978 check_location = check_location or 'unspecified location'
1978 check_location = check_location or 'unspecified location'
1979
1979
1980 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
1980 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
1981 self.required_perms, user, check_scope, check_location)
1981 self.required_perms, user, check_scope, check_location)
1982 if not user:
1982 if not user:
1983 log.warning('Empty user given for permission check')
1983 log.warning('Empty user given for permission check')
1984 return False
1984 return False
1985
1985
1986 if self.check_permissions(user):
1986 if self.check_permissions(user):
1987 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
1987 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
1988 check_scope, user, check_location)
1988 check_scope, user, check_location)
1989 return True
1989 return True
1990
1990
1991 else:
1991 else:
1992 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
1992 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
1993 check_scope, user, check_location)
1993 check_scope, user, check_location)
1994 return False
1994 return False
1995
1995
1996 def _get_request(self):
1996 def _get_request(self):
1997 return get_request(self)
1997 return get_request(self)
1998
1998
1999 def _get_check_scope(self, cls_name):
1999 def _get_check_scope(self, cls_name):
2000 return {
2000 return {
2001 'HasPermissionAll': 'GLOBAL',
2001 'HasPermissionAll': 'GLOBAL',
2002 'HasPermissionAny': 'GLOBAL',
2002 'HasPermissionAny': 'GLOBAL',
2003 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
2003 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
2004 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
2004 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
2005 'HasRepoGroupPermissionAll': 'repo_group:%s' % self.repo_group_name,
2005 'HasRepoGroupPermissionAll': 'repo_group:%s' % self.repo_group_name,
2006 'HasRepoGroupPermissionAny': 'repo_group:%s' % self.repo_group_name,
2006 'HasRepoGroupPermissionAny': 'repo_group:%s' % self.repo_group_name,
2007 'HasUserGroupPermissionAll': 'user_group:%s' % self.user_group_name,
2007 'HasUserGroupPermissionAll': 'user_group:%s' % self.user_group_name,
2008 'HasUserGroupPermissionAny': 'user_group:%s' % self.user_group_name,
2008 'HasUserGroupPermissionAny': 'user_group:%s' % self.user_group_name,
2009 }.get(cls_name, '?:%s' % cls_name)
2009 }.get(cls_name, '?:%s' % cls_name)
2010
2010
2011 def check_permissions(self, user):
2011 def check_permissions(self, user):
2012 """Dummy function for overriding"""
2012 """Dummy function for overriding"""
2013 raise Exception('You have to write this function in child class')
2013 raise Exception('You have to write this function in child class')
2014
2014
2015
2015
2016 class HasPermissionAll(PermsFunction):
2016 class HasPermissionAll(PermsFunction):
2017 def check_permissions(self, user):
2017 def check_permissions(self, user):
2018 perms = user.permissions_with_scope({})
2018 perms = user.permissions_with_scope({})
2019 if self.required_perms.issubset(perms.get('global')):
2019 if self.required_perms.issubset(perms.get('global')):
2020 return True
2020 return True
2021 return False
2021 return False
2022
2022
2023
2023
2024 class HasPermissionAny(PermsFunction):
2024 class HasPermissionAny(PermsFunction):
2025 def check_permissions(self, user):
2025 def check_permissions(self, user):
2026 perms = user.permissions_with_scope({})
2026 perms = user.permissions_with_scope({})
2027 if self.required_perms.intersection(perms.get('global')):
2027 if self.required_perms.intersection(perms.get('global')):
2028 return True
2028 return True
2029 return False
2029 return False
2030
2030
2031
2031
2032 class HasRepoPermissionAll(PermsFunction):
2032 class HasRepoPermissionAll(PermsFunction):
2033 def __call__(self, repo_name=None, check_location='', user=None):
2033 def __call__(self, repo_name=None, check_location='', user=None):
2034 self.repo_name = repo_name
2034 self.repo_name = repo_name
2035 return super(HasRepoPermissionAll, self).__call__(check_location, user)
2035 return super(HasRepoPermissionAll, self).__call__(check_location, user)
2036
2036
2037 def _get_repo_name(self):
2037 def _get_repo_name(self):
2038 if not self.repo_name:
2038 if not self.repo_name:
2039 _request = self._get_request()
2039 _request = self._get_request()
2040 self.repo_name = get_repo_slug(_request)
2040 self.repo_name = get_repo_slug(_request)
2041 return self.repo_name
2041 return self.repo_name
2042
2042
2043 def check_permissions(self, user):
2043 def check_permissions(self, user):
2044 self.repo_name = self._get_repo_name()
2044 self.repo_name = self._get_repo_name()
2045 perms = user.permissions
2045 perms = user.permissions
2046 try:
2046 try:
2047 user_perms = {perms['repositories'][self.repo_name]}
2047 user_perms = {perms['repositories'][self.repo_name]}
2048 except KeyError:
2048 except KeyError:
2049 return False
2049 return False
2050 if self.required_perms.issubset(user_perms):
2050 if self.required_perms.issubset(user_perms):
2051 return True
2051 return True
2052 return False
2052 return False
2053
2053
2054
2054
2055 class HasRepoPermissionAny(PermsFunction):
2055 class HasRepoPermissionAny(PermsFunction):
2056 def __call__(self, repo_name=None, check_location='', user=None):
2056 def __call__(self, repo_name=None, check_location='', user=None):
2057 self.repo_name = repo_name
2057 self.repo_name = repo_name
2058 return super(HasRepoPermissionAny, self).__call__(check_location, user)
2058 return super(HasRepoPermissionAny, self).__call__(check_location, user)
2059
2059
2060 def _get_repo_name(self):
2060 def _get_repo_name(self):
2061 if not self.repo_name:
2061 if not self.repo_name:
2062 _request = self._get_request()
2062 _request = self._get_request()
2063 self.repo_name = get_repo_slug(_request)
2063 self.repo_name = get_repo_slug(_request)
2064 return self.repo_name
2064 return self.repo_name
2065
2065
2066 def check_permissions(self, user):
2066 def check_permissions(self, user):
2067 self.repo_name = self._get_repo_name()
2067 self.repo_name = self._get_repo_name()
2068 perms = user.permissions
2068 perms = user.permissions
2069 try:
2069 try:
2070 user_perms = {perms['repositories'][self.repo_name]}
2070 user_perms = {perms['repositories'][self.repo_name]}
2071 except KeyError:
2071 except KeyError:
2072 return False
2072 return False
2073 if self.required_perms.intersection(user_perms):
2073 if self.required_perms.intersection(user_perms):
2074 return True
2074 return True
2075 return False
2075 return False
2076
2076
2077
2077
2078 class HasRepoGroupPermissionAny(PermsFunction):
2078 class HasRepoGroupPermissionAny(PermsFunction):
2079 def __call__(self, group_name=None, check_location='', user=None):
2079 def __call__(self, group_name=None, check_location='', user=None):
2080 self.repo_group_name = group_name
2080 self.repo_group_name = group_name
2081 return super(HasRepoGroupPermissionAny, self).__call__(check_location, user)
2081 return super(HasRepoGroupPermissionAny, self).__call__(check_location, user)
2082
2082
2083 def check_permissions(self, user):
2083 def check_permissions(self, user):
2084 perms = user.permissions
2084 perms = user.permissions
2085 try:
2085 try:
2086 user_perms = {perms['repositories_groups'][self.repo_group_name]}
2086 user_perms = {perms['repositories_groups'][self.repo_group_name]}
2087 except KeyError:
2087 except KeyError:
2088 return False
2088 return False
2089 if self.required_perms.intersection(user_perms):
2089 if self.required_perms.intersection(user_perms):
2090 return True
2090 return True
2091 return False
2091 return False
2092
2092
2093
2093
2094 class HasRepoGroupPermissionAll(PermsFunction):
2094 class HasRepoGroupPermissionAll(PermsFunction):
2095 def __call__(self, group_name=None, check_location='', user=None):
2095 def __call__(self, group_name=None, check_location='', user=None):
2096 self.repo_group_name = group_name
2096 self.repo_group_name = group_name
2097 return super(HasRepoGroupPermissionAll, self).__call__(check_location, user)
2097 return super(HasRepoGroupPermissionAll, self).__call__(check_location, user)
2098
2098
2099 def check_permissions(self, user):
2099 def check_permissions(self, user):
2100 perms = user.permissions
2100 perms = user.permissions
2101 try:
2101 try:
2102 user_perms = {perms['repositories_groups'][self.repo_group_name]}
2102 user_perms = {perms['repositories_groups'][self.repo_group_name]}
2103 except KeyError:
2103 except KeyError:
2104 return False
2104 return False
2105 if self.required_perms.issubset(user_perms):
2105 if self.required_perms.issubset(user_perms):
2106 return True
2106 return True
2107 return False
2107 return False
2108
2108
2109
2109
2110 class HasUserGroupPermissionAny(PermsFunction):
2110 class HasUserGroupPermissionAny(PermsFunction):
2111 def __call__(self, user_group_name=None, check_location='', user=None):
2111 def __call__(self, user_group_name=None, check_location='', user=None):
2112 self.user_group_name = user_group_name
2112 self.user_group_name = user_group_name
2113 return super(HasUserGroupPermissionAny, self).__call__(check_location, user)
2113 return super(HasUserGroupPermissionAny, self).__call__(check_location, user)
2114
2114
2115 def check_permissions(self, user):
2115 def check_permissions(self, user):
2116 perms = user.permissions
2116 perms = user.permissions
2117 try:
2117 try:
2118 user_perms = {perms['user_groups'][self.user_group_name]}
2118 user_perms = {perms['user_groups'][self.user_group_name]}
2119 except KeyError:
2119 except KeyError:
2120 return False
2120 return False
2121 if self.required_perms.intersection(user_perms):
2121 if self.required_perms.intersection(user_perms):
2122 return True
2122 return True
2123 return False
2123 return False
2124
2124
2125
2125
2126 class HasUserGroupPermissionAll(PermsFunction):
2126 class HasUserGroupPermissionAll(PermsFunction):
2127 def __call__(self, user_group_name=None, check_location='', user=None):
2127 def __call__(self, user_group_name=None, check_location='', user=None):
2128 self.user_group_name = user_group_name
2128 self.user_group_name = user_group_name
2129 return super(HasUserGroupPermissionAll, self).__call__(check_location, user)
2129 return super(HasUserGroupPermissionAll, self).__call__(check_location, user)
2130
2130
2131 def check_permissions(self, user):
2131 def check_permissions(self, user):
2132 perms = user.permissions
2132 perms = user.permissions
2133 try:
2133 try:
2134 user_perms = {perms['user_groups'][self.user_group_name]}
2134 user_perms = {perms['user_groups'][self.user_group_name]}
2135 except KeyError:
2135 except KeyError:
2136 return False
2136 return False
2137 if self.required_perms.issubset(user_perms):
2137 if self.required_perms.issubset(user_perms):
2138 return True
2138 return True
2139 return False
2139 return False
2140
2140
2141
2141
2142 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
2142 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
2143 class HasPermissionAnyMiddleware(object):
2143 class HasPermissionAnyMiddleware(object):
2144 def __init__(self, *perms):
2144 def __init__(self, *perms):
2145 self.required_perms = set(perms)
2145 self.required_perms = set(perms)
2146
2146
2147 def __call__(self, auth_user, repo_name):
2147 def __call__(self, auth_user, repo_name):
2148 # repo_name MUST be unicode, since we handle keys in permission
2148 # repo_name MUST be unicode, since we handle keys in permission
2149 # dict by unicode
2149 # dict by unicode
2150 repo_name = safe_unicode(repo_name)
2150 repo_name = safe_unicode(repo_name)
2151 log.debug(
2151 log.debug(
2152 'Checking VCS protocol permissions %s for user:%s repo:`%s`',
2152 'Checking VCS protocol permissions %s for user:%s repo:`%s`',
2153 self.required_perms, auth_user, repo_name)
2153 self.required_perms, auth_user, repo_name)
2154
2154
2155 if self.check_permissions(auth_user, repo_name):
2155 if self.check_permissions(auth_user, repo_name):
2156 log.debug('Permission to repo:`%s` GRANTED for user:%s @ %s',
2156 log.debug('Permission to repo:`%s` GRANTED for user:%s @ %s',
2157 repo_name, auth_user, 'PermissionMiddleware')
2157 repo_name, auth_user, 'PermissionMiddleware')
2158 return True
2158 return True
2159
2159
2160 else:
2160 else:
2161 log.debug('Permission to repo:`%s` DENIED for user:%s @ %s',
2161 log.debug('Permission to repo:`%s` DENIED for user:%s @ %s',
2162 repo_name, auth_user, 'PermissionMiddleware')
2162 repo_name, auth_user, 'PermissionMiddleware')
2163 return False
2163 return False
2164
2164
2165 def check_permissions(self, user, repo_name):
2165 def check_permissions(self, user, repo_name):
2166 perms = user.permissions_with_scope({'repo_name': repo_name})
2166 perms = user.permissions_with_scope({'repo_name': repo_name})
2167
2167
2168 try:
2168 try:
2169 user_perms = {perms['repositories'][repo_name]}
2169 user_perms = {perms['repositories'][repo_name]}
2170 except Exception:
2170 except Exception:
2171 log.exception('Error while accessing user permissions')
2171 log.exception('Error while accessing user permissions')
2172 return False
2172 return False
2173
2173
2174 if self.required_perms.intersection(user_perms):
2174 if self.required_perms.intersection(user_perms):
2175 return True
2175 return True
2176 return False
2176 return False
2177
2177
2178
2178
2179 # SPECIAL VERSION TO HANDLE API AUTH
2179 # SPECIAL VERSION TO HANDLE API AUTH
2180 class _BaseApiPerm(object):
2180 class _BaseApiPerm(object):
2181 def __init__(self, *perms):
2181 def __init__(self, *perms):
2182 self.required_perms = set(perms)
2182 self.required_perms = set(perms)
2183
2183
2184 def __call__(self, check_location=None, user=None, repo_name=None,
2184 def __call__(self, check_location=None, user=None, repo_name=None,
2185 group_name=None, user_group_name=None):
2185 group_name=None, user_group_name=None):
2186 cls_name = self.__class__.__name__
2186 cls_name = self.__class__.__name__
2187 check_scope = 'global:%s' % (self.required_perms,)
2187 check_scope = 'global:%s' % (self.required_perms,)
2188 if repo_name:
2188 if repo_name:
2189 check_scope += ', repo_name:%s' % (repo_name,)
2189 check_scope += ', repo_name:%s' % (repo_name,)
2190
2190
2191 if group_name:
2191 if group_name:
2192 check_scope += ', repo_group_name:%s' % (group_name,)
2192 check_scope += ', repo_group_name:%s' % (group_name,)
2193
2193
2194 if user_group_name:
2194 if user_group_name:
2195 check_scope += ', user_group_name:%s' % (user_group_name,)
2195 check_scope += ', user_group_name:%s' % (user_group_name,)
2196
2196
2197 log.debug('checking cls:%s %s %s @ %s',
2197 log.debug('checking cls:%s %s %s @ %s',
2198 cls_name, self.required_perms, check_scope, check_location)
2198 cls_name, self.required_perms, check_scope, check_location)
2199 if not user:
2199 if not user:
2200 log.debug('Empty User passed into arguments')
2200 log.debug('Empty User passed into arguments')
2201 return False
2201 return False
2202
2202
2203 # process user
2203 # process user
2204 if not isinstance(user, AuthUser):
2204 if not isinstance(user, AuthUser):
2205 user = AuthUser(user.user_id)
2205 user = AuthUser(user.user_id)
2206 if not check_location:
2206 if not check_location:
2207 check_location = 'unspecified'
2207 check_location = 'unspecified'
2208 if self.check_permissions(user.permissions, repo_name, group_name,
2208 if self.check_permissions(user.permissions, repo_name, group_name,
2209 user_group_name):
2209 user_group_name):
2210 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
2210 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
2211 check_scope, user, check_location)
2211 check_scope, user, check_location)
2212 return True
2212 return True
2213
2213
2214 else:
2214 else:
2215 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
2215 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
2216 check_scope, user, check_location)
2216 check_scope, user, check_location)
2217 return False
2217 return False
2218
2218
2219 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2219 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2220 user_group_name=None):
2220 user_group_name=None):
2221 """
2221 """
2222 implement in child class should return True if permissions are ok,
2222 implement in child class should return True if permissions are ok,
2223 False otherwise
2223 False otherwise
2224
2224
2225 :param perm_defs: dict with permission definitions
2225 :param perm_defs: dict with permission definitions
2226 :param repo_name: repo name
2226 :param repo_name: repo name
2227 """
2227 """
2228 raise NotImplementedError()
2228 raise NotImplementedError()
2229
2229
2230
2230
2231 class HasPermissionAllApi(_BaseApiPerm):
2231 class HasPermissionAllApi(_BaseApiPerm):
2232 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2232 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2233 user_group_name=None):
2233 user_group_name=None):
2234 if self.required_perms.issubset(perm_defs.get('global')):
2234 if self.required_perms.issubset(perm_defs.get('global')):
2235 return True
2235 return True
2236 return False
2236 return False
2237
2237
2238
2238
2239 class HasPermissionAnyApi(_BaseApiPerm):
2239 class HasPermissionAnyApi(_BaseApiPerm):
2240 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2240 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2241 user_group_name=None):
2241 user_group_name=None):
2242 if self.required_perms.intersection(perm_defs.get('global')):
2242 if self.required_perms.intersection(perm_defs.get('global')):
2243 return True
2243 return True
2244 return False
2244 return False
2245
2245
2246
2246
2247 class HasRepoPermissionAllApi(_BaseApiPerm):
2247 class HasRepoPermissionAllApi(_BaseApiPerm):
2248 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2248 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2249 user_group_name=None):
2249 user_group_name=None):
2250 try:
2250 try:
2251 _user_perms = {perm_defs['repositories'][repo_name]}
2251 _user_perms = {perm_defs['repositories'][repo_name]}
2252 except KeyError:
2252 except KeyError:
2253 log.warning(traceback.format_exc())
2253 log.warning(traceback.format_exc())
2254 return False
2254 return False
2255 if self.required_perms.issubset(_user_perms):
2255 if self.required_perms.issubset(_user_perms):
2256 return True
2256 return True
2257 return False
2257 return False
2258
2258
2259
2259
2260 class HasRepoPermissionAnyApi(_BaseApiPerm):
2260 class HasRepoPermissionAnyApi(_BaseApiPerm):
2261 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2261 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2262 user_group_name=None):
2262 user_group_name=None):
2263 try:
2263 try:
2264 _user_perms = {perm_defs['repositories'][repo_name]}
2264 _user_perms = {perm_defs['repositories'][repo_name]}
2265 except KeyError:
2265 except KeyError:
2266 log.warning(traceback.format_exc())
2266 log.warning(traceback.format_exc())
2267 return False
2267 return False
2268 if self.required_perms.intersection(_user_perms):
2268 if self.required_perms.intersection(_user_perms):
2269 return True
2269 return True
2270 return False
2270 return False
2271
2271
2272
2272
2273 class HasRepoGroupPermissionAnyApi(_BaseApiPerm):
2273 class HasRepoGroupPermissionAnyApi(_BaseApiPerm):
2274 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2274 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2275 user_group_name=None):
2275 user_group_name=None):
2276 try:
2276 try:
2277 _user_perms = {perm_defs['repositories_groups'][group_name]}
2277 _user_perms = {perm_defs['repositories_groups'][group_name]}
2278 except KeyError:
2278 except KeyError:
2279 log.warning(traceback.format_exc())
2279 log.warning(traceback.format_exc())
2280 return False
2280 return False
2281 if self.required_perms.intersection(_user_perms):
2281 if self.required_perms.intersection(_user_perms):
2282 return True
2282 return True
2283 return False
2283 return False
2284
2284
2285
2285
2286 class HasRepoGroupPermissionAllApi(_BaseApiPerm):
2286 class HasRepoGroupPermissionAllApi(_BaseApiPerm):
2287 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2287 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2288 user_group_name=None):
2288 user_group_name=None):
2289 try:
2289 try:
2290 _user_perms = {perm_defs['repositories_groups'][group_name]}
2290 _user_perms = {perm_defs['repositories_groups'][group_name]}
2291 except KeyError:
2291 except KeyError:
2292 log.warning(traceback.format_exc())
2292 log.warning(traceback.format_exc())
2293 return False
2293 return False
2294 if self.required_perms.issubset(_user_perms):
2294 if self.required_perms.issubset(_user_perms):
2295 return True
2295 return True
2296 return False
2296 return False
2297
2297
2298
2298
2299 class HasUserGroupPermissionAnyApi(_BaseApiPerm):
2299 class HasUserGroupPermissionAnyApi(_BaseApiPerm):
2300 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2300 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2301 user_group_name=None):
2301 user_group_name=None):
2302 try:
2302 try:
2303 _user_perms = {perm_defs['user_groups'][user_group_name]}
2303 _user_perms = {perm_defs['user_groups'][user_group_name]}
2304 except KeyError:
2304 except KeyError:
2305 log.warning(traceback.format_exc())
2305 log.warning(traceback.format_exc())
2306 return False
2306 return False
2307 if self.required_perms.intersection(_user_perms):
2307 if self.required_perms.intersection(_user_perms):
2308 return True
2308 return True
2309 return False
2309 return False
2310
2310
2311
2311
2312 def check_ip_access(source_ip, allowed_ips=None):
2312 def check_ip_access(source_ip, allowed_ips=None):
2313 """
2313 """
2314 Checks if source_ip is a subnet of any of allowed_ips.
2314 Checks if source_ip is a subnet of any of allowed_ips.
2315
2315
2316 :param source_ip:
2316 :param source_ip:
2317 :param allowed_ips: list of allowed ips together with mask
2317 :param allowed_ips: list of allowed ips together with mask
2318 """
2318 """
2319 log.debug('checking if ip:%s is subnet of %s', source_ip, allowed_ips)
2319 log.debug('checking if ip:%s is subnet of %s', source_ip, allowed_ips)
2320 source_ip_address = ipaddress.ip_address(safe_unicode(source_ip))
2320 source_ip_address = ipaddress.ip_address(safe_unicode(source_ip))
2321 if isinstance(allowed_ips, (tuple, list, set)):
2321 if isinstance(allowed_ips, (tuple, list, set)):
2322 for ip in allowed_ips:
2322 for ip in allowed_ips:
2323 ip = safe_unicode(ip)
2323 ip = safe_unicode(ip)
2324 try:
2324 try:
2325 network_address = ipaddress.ip_network(ip, strict=False)
2325 network_address = ipaddress.ip_network(ip, strict=False)
2326 if source_ip_address in network_address:
2326 if source_ip_address in network_address:
2327 log.debug('IP %s is network %s', source_ip_address, network_address)
2327 log.debug('IP %s is network %s', source_ip_address, network_address)
2328 return True
2328 return True
2329 # for any case we cannot determine the IP, don't crash just
2329 # for any case we cannot determine the IP, don't crash just
2330 # skip it and log as error, we want to say forbidden still when
2330 # skip it and log as error, we want to say forbidden still when
2331 # sending bad IP
2331 # sending bad IP
2332 except Exception:
2332 except Exception:
2333 log.error(traceback.format_exc())
2333 log.error(traceback.format_exc())
2334 continue
2334 continue
2335 return False
2335 return False
2336
2336
2337
2337
2338 def get_cython_compat_decorator(wrapper, func):
2338 def get_cython_compat_decorator(wrapper, func):
2339 """
2339 """
2340 Creates a cython compatible decorator. The previously used
2340 Creates a cython compatible decorator. The previously used
2341 decorator.decorator() function seems to be incompatible with cython.
2341 decorator.decorator() function seems to be incompatible with cython.
2342
2342
2343 :param wrapper: __wrapper method of the decorator class
2343 :param wrapper: __wrapper method of the decorator class
2344 :param func: decorated function
2344 :param func: decorated function
2345 """
2345 """
2346 @wraps(func)
2346 @wraps(func)
2347 def local_wrapper(*args, **kwds):
2347 def local_wrapper(*args, **kwds):
2348 return wrapper(func, *args, **kwds)
2348 return wrapper(func, *args, **kwds)
2349 local_wrapper.__wrapped__ = func
2349 local_wrapper.__wrapped__ = func
2350 return local_wrapper
2350 return local_wrapper
2351
2351
2352
2352
@@ -1,222 +1,222 b''
1 <%namespace name="base" file="/base/base.mako"/>
1 <%namespace name="base" file="/base/base.mako"/>
2
2
3 <div class="panel panel-default">
3 <div class="panel panel-default">
4 <div class="panel-heading">
4 <div class="panel-heading">
5 <h3 class="panel-title">${_('Repository Permissions')}</h3>
5 <h3 class="panel-title">${_('Repository Access Permissions')}</h3>
6 </div>
6 </div>
7 <div class="panel-body">
7 <div class="panel-body">
8 ${h.secure_form(h.route_path('edit_repo_perms', repo_name=c.repo_name), request=request)}
8 ${h.secure_form(h.route_path('edit_repo_perms', repo_name=c.repo_name), request=request)}
9 <table id="permissions_manage" class="rctable permissions">
9 <table id="permissions_manage" class="rctable permissions">
10 <tr>
10 <tr>
11 <th class="td-radio">${_('None')}</th>
11 <th class="td-radio">${_('None')}</th>
12 <th class="td-radio">${_('Read')}</th>
12 <th class="td-radio">${_('Read')}</th>
13 <th class="td-radio">${_('Write')}</th>
13 <th class="td-radio">${_('Write')}</th>
14 <th class="td-radio">${_('Admin')}</th>
14 <th class="td-radio">${_('Admin')}</th>
15 <th class="td-owner">${_('User/User Group')}</th>
15 <th class="td-owner">${_('User/User Group')}</th>
16 <th class="td-action"></th>
16 <th class="td-action"></th>
17 <th class="td-action"></th>
17 <th class="td-action"></th>
18 </tr>
18 </tr>
19 ## USERS
19 ## USERS
20 %for _user in c.rhodecode_db_repo.permissions():
20 %for _user in c.rhodecode_db_repo.permissions():
21 %if getattr(_user, 'admin_row', None) or getattr(_user, 'owner_row', None):
21 %if getattr(_user, 'admin_row', None) or getattr(_user, 'owner_row', None):
22 <tr class="perm_admin_row">
22 <tr class="perm_admin_row">
23 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.none', disabled="disabled")}</td>
23 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.none', disabled="disabled")}</td>
24 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.read', disabled="disabled")}</td>
24 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.read', disabled="disabled")}</td>
25 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.write', disabled="disabled")}</td>
25 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.write', disabled="disabled")}</td>
26 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.admin', 'repository.admin', disabled="disabled")}</td>
26 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.admin', 'repository.admin', disabled="disabled")}</td>
27 <td class="td-user">
27 <td class="td-user">
28 ${base.gravatar(_user.email, 16)}
28 ${base.gravatar(_user.email, 16)}
29 ${h.link_to_user(_user.username)}
29 ${h.link_to_user(_user.username)}
30 %if getattr(_user, 'admin_row', None):
30 %if getattr(_user, 'admin_row', None):
31 (${_('super admin')})
31 (${_('super admin')})
32 %endif
32 %endif
33 %if getattr(_user, 'owner_row', None):
33 %if getattr(_user, 'owner_row', None):
34 (${_('owner')})
34 (${_('owner')})
35 %endif
35 %endif
36 </td>
36 </td>
37 <td></td>
37 <td></td>
38 <td class="quick_repo_menu">
38 <td class="quick_repo_menu">
39 % if c.rhodecode_user.is_admin:
39 % if c.rhodecode_user.is_admin:
40 <i class="icon-more"></i>
40 <i class="icon-more"></i>
41 <div class="menu_items_container" style="display: none;">
41 <div class="menu_items_container" style="display: none;">
42 <ul class="menu_items">
42 <ul class="menu_items">
43 <li>
43 <li>
44 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='repositories-permissions'))}
44 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='repositories-permissions'))}
45 </li>
45 </li>
46 </ul>
46 </ul>
47 </div>
47 </div>
48 % endif
48 % endif
49 </td>
49 </td>
50 </tr>
50 </tr>
51 %elif _user.username == h.DEFAULT_USER and c.rhodecode_db_repo.private:
51 %elif _user.username == h.DEFAULT_USER and c.rhodecode_db_repo.private:
52 <tr>
52 <tr>
53 <td colspan="4">
53 <td colspan="4">
54 <span class="private_repo_msg">
54 <span class="private_repo_msg">
55 <strong title="${h.tooltip(_user.permission)}">${_('private repository')}</strong>
55 <strong title="${h.tooltip(_user.permission)}">${_('private repository')}</strong>
56 </span>
56 </span>
57 </td>
57 </td>
58 <td class="private_repo_msg">
58 <td class="private_repo_msg">
59 ${base.gravatar(h.DEFAULT_USER_EMAIL, 16)}
59 ${base.gravatar(h.DEFAULT_USER_EMAIL, 16)}
60 ${h.DEFAULT_USER} - ${_('only users/user groups explicitly added here will have access')}</td>
60 ${h.DEFAULT_USER} - ${_('only users/user groups explicitly added here will have access')}</td>
61 <td></td>
61 <td></td>
62 <td class="quick_repo_menu">
62 <td class="quick_repo_menu">
63 % if c.rhodecode_user.is_admin:
63 % if c.rhodecode_user.is_admin:
64 <i class="icon-more"></i>
64 <i class="icon-more"></i>
65 <div class="menu_items_container" style="display: none;">
65 <div class="menu_items_container" style="display: none;">
66 <ul class="menu_items">
66 <ul class="menu_items">
67 <li>
67 <li>
68 ${h.link_to('show permissions', h.route_path('admin_permissions_overview', _anchor='repositories-permissions'))}
68 ${h.link_to('show permissions', h.route_path('admin_permissions_overview', _anchor='repositories-permissions'))}
69 </li>
69 </li>
70 </ul>
70 </ul>
71 </div>
71 </div>
72 % endif
72 % endif
73 </td>
73 </td>
74 </tr>
74 </tr>
75 %else:
75 %else:
76 <% used_by_n_rules = len(getattr(_user, 'branch_rules', None) or []) %>
76 <% used_by_n_rules = len(getattr(_user, 'branch_rules', None) or []) %>
77 <tr>
77 <tr>
78 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.none', checked=_user.permission=='repository.none', disabled="disabled" if (used_by_n_rules and _user.username != h.DEFAULT_USER) else None)}</td>
78 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.none', checked=_user.permission=='repository.none', disabled="disabled" if (used_by_n_rules and _user.username != h.DEFAULT_USER) else None)}</td>
79 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.read', checked=_user.permission=='repository.read', disabled="disabled" if (used_by_n_rules and _user.username != h.DEFAULT_USER) else None)}</td>
79 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.read', checked=_user.permission=='repository.read', disabled="disabled" if (used_by_n_rules and _user.username != h.DEFAULT_USER) else None)}</td>
80 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.write', checked=_user.permission=='repository.write')}</td>
80 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.write', checked=_user.permission=='repository.write')}</td>
81 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.admin', checked=_user.permission=='repository.admin')}</td>
81 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.admin', checked=_user.permission=='repository.admin')}</td>
82 <td class="td-user">
82 <td class="td-user">
83 ${base.gravatar(_user.email, 16)}
83 ${base.gravatar(_user.email, 16)}
84 <span class="user">
84 <span class="user">
85 % if _user.username == h.DEFAULT_USER:
85 % if _user.username == h.DEFAULT_USER:
86 ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
86 ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
87 % else:
87 % else:
88 ${h.link_to_user(_user.username)}
88 ${h.link_to_user(_user.username)}
89 %if getattr(_user, 'duplicate_perm', None):
89 %if getattr(_user, 'duplicate_perm', None):
90 (${_('inactive duplicate')})
90 (${_('inactive duplicate')})
91 %endif
91 %endif
92 %if getattr(_user, 'branch_rules', None):
92 %if getattr(_user, 'branch_rules', None):
93 % if used_by_n_rules == 1:
93 % if used_by_n_rules == 1:
94 (${_('used by {} branch rule, requires write+ permissions').format(used_by_n_rules)})
94 (${_('used by {} branch rule, requires write+ permissions').format(used_by_n_rules)})
95 % else:
95 % else:
96 (${_('used by {} branch rules, requires write+ permissions').format(used_by_n_rules)})
96 (${_('used by {} branch rules, requires write+ permissions').format(used_by_n_rules)})
97 % endif
97 % endif
98 %endif
98 %endif
99 % endif
99 % endif
100 </span>
100 </span>
101 </td>
101 </td>
102 <td class="td-action">
102 <td class="td-action">
103 %if _user.username != h.DEFAULT_USER and getattr(_user, 'branch_rules', None) is None:
103 %if _user.username != h.DEFAULT_USER and getattr(_user, 'branch_rules', None) is None:
104 <span class="btn btn-link btn-danger revoke_perm"
104 <span class="btn btn-link btn-danger revoke_perm"
105 member="${_user.user_id}" member_type="user">
105 member="${_user.user_id}" member_type="user">
106 ${_('Remove')}
106 ${_('Remove')}
107 </span>
107 </span>
108 %elif _user.username == h.DEFAULT_USER:
108 %elif _user.username == h.DEFAULT_USER:
109 <span class="tooltip btn btn-link btn-default" onclick="enablePrivateRepo(); return false" title="${_('Private repositories are only visible to people explicitly added as collaborators.')}">
109 <span class="tooltip btn btn-link btn-default" onclick="enablePrivateRepo(); return false" title="${_('Private repositories are only visible to people explicitly added as collaborators.')}">
110 ${_('set private mode')}
110 ${_('set private mode')}
111 </span>
111 </span>
112 %endif
112 %endif
113 </td>
113 </td>
114 <td class="quick_repo_menu">
114 <td class="quick_repo_menu">
115 % if c.rhodecode_user.is_admin:
115 % if c.rhodecode_user.is_admin:
116 <i class="icon-more"></i>
116 <i class="icon-more"></i>
117 <div class="menu_items_container" style="display: none;">
117 <div class="menu_items_container" style="display: none;">
118 <ul class="menu_items">
118 <ul class="menu_items">
119 <li>
119 <li>
120 % if _user.username == h.DEFAULT_USER:
120 % if _user.username == h.DEFAULT_USER:
121 ${h.link_to('show permissions', h.route_path('admin_permissions_overview', _anchor='repositories-permissions'))}
121 ${h.link_to('show permissions', h.route_path('admin_permissions_overview', _anchor='repositories-permissions'))}
122 % else:
122 % else:
123 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='repositories-permissions'))}
123 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='repositories-permissions'))}
124 % endif
124 % endif
125 </li>
125 </li>
126 </ul>
126 </ul>
127 </div>
127 </div>
128 % endif
128 % endif
129 </td>
129 </td>
130 </tr>
130 </tr>
131 %endif
131 %endif
132 %endfor
132 %endfor
133
133
134 ## USER GROUPS
134 ## USER GROUPS
135 %for _user_group in c.rhodecode_db_repo.permission_user_groups(with_members=True):
135 %for _user_group in c.rhodecode_db_repo.permission_user_groups(with_members=True):
136 <tr>
136 <tr>
137 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.none', checked=_user_group.permission=='repository.none')}</td>
137 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.none', checked=_user_group.permission=='repository.none')}</td>
138 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.read', checked=_user_group.permission=='repository.read')}</td>
138 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.read', checked=_user_group.permission=='repository.read')}</td>
139 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.write', checked=_user_group.permission=='repository.write')}</td>
139 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.write', checked=_user_group.permission=='repository.write')}</td>
140 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.admin', checked=_user_group.permission=='repository.admin')}</td>
140 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.admin', checked=_user_group.permission=='repository.admin')}</td>
141 <td class="td-componentname">
141 <td class="td-componentname">
142 <i class="icon-user-group"></i>
142 <i class="icon-user-group"></i>
143 %if c.is_super_admin:
143 %if c.is_super_admin:
144 <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}">
144 <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}">
145 ${_user_group.users_group_name}
145 ${_user_group.users_group_name}
146 </a>
146 </a>
147 %else:
147 %else:
148 ${h.link_to_group(_user_group.users_group_name)}
148 ${h.link_to_group(_user_group.users_group_name)}
149 %endif
149 %endif
150 (${_('members')}: ${len(_user_group.members)})
150 (${_('members')}: ${len(_user_group.members)})
151 </td>
151 </td>
152 <td class="td-action">
152 <td class="td-action">
153 <span class="btn btn-link btn-danger revoke_perm"
153 <span class="btn btn-link btn-danger revoke_perm"
154 member="${_user_group.users_group_id}" member_type="user_group">
154 member="${_user_group.users_group_id}" member_type="user_group">
155 ${_('Remove')}
155 ${_('Remove')}
156 </span>
156 </span>
157 </td>
157 </td>
158 <td class="quick_repo_menu">
158 <td class="quick_repo_menu">
159 % if c.rhodecode_user.is_admin:
159 % if c.rhodecode_user.is_admin:
160 <i class="icon-more"></i>
160 <i class="icon-more"></i>
161 <div class="menu_items_container" style="display: none;">
161 <div class="menu_items_container" style="display: none;">
162 <ul class="menu_items">
162 <ul class="menu_items">
163 <li>
163 <li>
164 ${h.link_to('show permissions', h.route_path('edit_user_group_perms_summary', user_group_id=_user_group.users_group_id, _anchor='repositories-permissions'))}
164 ${h.link_to('show permissions', h.route_path('edit_user_group_perms_summary', user_group_id=_user_group.users_group_id, _anchor='repositories-permissions'))}
165 </li>
165 </li>
166 </ul>
166 </ul>
167 </div>
167 </div>
168 % endif
168 % endif
169 </td>
169 </td>
170 </tr>
170 </tr>
171 %endfor
171 %endfor
172 <tr class="new_members" id="add_perm_input"></tr>
172 <tr class="new_members" id="add_perm_input"></tr>
173
173
174 <tr>
174 <tr>
175 <td></td>
175 <td></td>
176 <td></td>
176 <td></td>
177 <td></td>
177 <td></td>
178 <td></td>
178 <td></td>
179 <td></td>
179 <td></td>
180 <td>
180 <td>
181 <span id="add_perm" class="link">
181 <span id="add_perm" class="link">
182 ${_('Add user/user group')}
182 ${_('Add user/user group')}
183 </span>
183 </span>
184 </td>
184 </td>
185 <td></td>
185 <td></td>
186 </tr>
186 </tr>
187
187
188 </table>
188 </table>
189
189
190 <div class="buttons">
190 <div class="buttons">
191 ${h.submit('save',_('Save'),class_="btn btn-primary")}
191 ${h.submit('save',_('Save'),class_="btn btn-primary")}
192 ${h.reset('reset',_('Reset'),class_="btn btn-danger")}
192 ${h.reset('reset',_('Reset'),class_="btn btn-danger")}
193 </div>
193 </div>
194 ${h.end_form()}
194 ${h.end_form()}
195 </div>
195 </div>
196 </div>
196 </div>
197
197
198 <script type="text/javascript">
198 <script type="text/javascript">
199 $('#add_perm').on('click', function(e){
199 $('#add_perm').on('click', function(e){
200 addNewPermInput($(this), 'repository');
200 addNewPermInput($(this), 'repository');
201 });
201 });
202 $('.revoke_perm').on('click', function(e){
202 $('.revoke_perm').on('click', function(e){
203 markRevokePermInput($(this), 'repository');
203 markRevokePermInput($(this), 'repository');
204 });
204 });
205 quick_repo_menu();
205 quick_repo_menu();
206
206
207 var enablePrivateRepo = function () {
207 var enablePrivateRepo = function () {
208 var postData = {
208 var postData = {
209 'csrf_token': CSRF_TOKEN
209 'csrf_token': CSRF_TOKEN
210 };
210 };
211
211
212 var success = function(o) {
212 var success = function(o) {
213 var defaultUrl = pyroutes.url('edit_repo_perms', {"repo_name": templateContext.repo_name});
213 var defaultUrl = pyroutes.url('edit_repo_perms', {"repo_name": templateContext.repo_name});
214 window.location = o.redirect_url || defaultUrl;
214 window.location = o.redirect_url || defaultUrl;
215 };
215 };
216
216
217 ajaxPOST(
217 ajaxPOST(
218 pyroutes.url('edit_repo_perms_set_private', {"repo_name": templateContext.repo_name}),
218 pyroutes.url('edit_repo_perms_set_private', {"repo_name": templateContext.repo_name}),
219 postData,
219 postData,
220 success);
220 success);
221 }
221 }
222 </script>
222 </script>
@@ -1,1063 +1,1063 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="root.mako"/>
2 <%inherit file="root.mako"/>
3
3
4 <%include file="/ejs_templates/templates.html"/>
4 <%include file="/ejs_templates/templates.html"/>
5
5
6 <div class="outerwrapper">
6 <div class="outerwrapper">
7 <!-- HEADER -->
7 <!-- HEADER -->
8 <div class="header">
8 <div class="header">
9 <div id="header-inner" class="wrapper">
9 <div id="header-inner" class="wrapper">
10 <div id="logo">
10 <div id="logo">
11 <div class="logo-wrapper">
11 <div class="logo-wrapper">
12 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
12 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
13 </div>
13 </div>
14 % if c.rhodecode_name:
14 % if c.rhodecode_name:
15 <div class="branding">
15 <div class="branding">
16 <a href="${h.route_path('home')}">${h.branding(c.rhodecode_name)}</a>
16 <a href="${h.route_path('home')}">${h.branding(c.rhodecode_name)}</a>
17 </div>
17 </div>
18 % endif
18 % endif
19 </div>
19 </div>
20 <!-- MENU BAR NAV -->
20 <!-- MENU BAR NAV -->
21 ${self.menu_bar_nav()}
21 ${self.menu_bar_nav()}
22 <!-- END MENU BAR NAV -->
22 <!-- END MENU BAR NAV -->
23 </div>
23 </div>
24 </div>
24 </div>
25 ${self.menu_bar_subnav()}
25 ${self.menu_bar_subnav()}
26 <!-- END HEADER -->
26 <!-- END HEADER -->
27
27
28 <!-- CONTENT -->
28 <!-- CONTENT -->
29 <div id="content" class="wrapper">
29 <div id="content" class="wrapper">
30
30
31 <rhodecode-toast id="notifications"></rhodecode-toast>
31 <rhodecode-toast id="notifications"></rhodecode-toast>
32
32
33 <div class="main">
33 <div class="main">
34 ${next.main()}
34 ${next.main()}
35 </div>
35 </div>
36 </div>
36 </div>
37 <!-- END CONTENT -->
37 <!-- END CONTENT -->
38
38
39 </div>
39 </div>
40 <!-- FOOTER -->
40 <!-- FOOTER -->
41 <div id="footer">
41 <div id="footer">
42 <div id="footer-inner" class="title wrapper">
42 <div id="footer-inner" class="title wrapper">
43 <div>
43 <div>
44 <p class="footer-link-right">
44 <p class="footer-link-right">
45 % if c.visual.show_version:
45 % if c.visual.show_version:
46 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
46 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
47 % endif
47 % endif
48 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
48 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
49 % if c.visual.rhodecode_support_url:
49 % if c.visual.rhodecode_support_url:
50 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
50 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
51 % endif
51 % endif
52 </p>
52 </p>
53 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
53 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
54 <p class="server-instance" style="display:${sid}">
54 <p class="server-instance" style="display:${sid}">
55 ## display hidden instance ID if specially defined
55 ## display hidden instance ID if specially defined
56 % if c.rhodecode_instanceid:
56 % if c.rhodecode_instanceid:
57 ${_('RhodeCode instance id: {}').format(c.rhodecode_instanceid)}
57 ${_('RhodeCode instance id: {}').format(c.rhodecode_instanceid)}
58 % endif
58 % endif
59 </p>
59 </p>
60 </div>
60 </div>
61 </div>
61 </div>
62 </div>
62 </div>
63
63
64 <!-- END FOOTER -->
64 <!-- END FOOTER -->
65
65
66 ### MAKO DEFS ###
66 ### MAKO DEFS ###
67
67
68 <%def name="menu_bar_subnav()">
68 <%def name="menu_bar_subnav()">
69 </%def>
69 </%def>
70
70
71 <%def name="breadcrumbs(class_='breadcrumbs')">
71 <%def name="breadcrumbs(class_='breadcrumbs')">
72 <div class="${class_}">
72 <div class="${class_}">
73 ${self.breadcrumbs_links()}
73 ${self.breadcrumbs_links()}
74 </div>
74 </div>
75 </%def>
75 </%def>
76
76
77 <%def name="admin_menu(active=None)">
77 <%def name="admin_menu(active=None)">
78 <%
78 <%
79 def is_active(selected):
79 def is_active(selected):
80 if selected == active:
80 if selected == active:
81 return "active"
81 return "active"
82 %>
82 %>
83
83
84 <div id="context-bar">
84 <div id="context-bar">
85 <div class="wrapper">
85 <div class="wrapper">
86 <div class="title">
86 <div class="title">
87 <div class="title-content">
87 <div class="title-content">
88 <div class="title-main">
88 <div class="title-main">
89 % if c.is_super_admin:
89 % if c.is_super_admin:
90 ${_('Super Admin Panel')}
90 ${_('Super Admin Panel')}
91 % else:
91 % else:
92 ${_('Delegated Admin Panel')}
92 ${_('Delegated Admin Panel')}
93 % endif
93 % endif
94 </div>
94 </div>
95 </div>
95 </div>
96 </div>
96 </div>
97
97
98 <ul id="context-pages" class="navigation horizontal-list">
98 <ul id="context-pages" class="navigation horizontal-list">
99
99
100 ## super admin case
100 ## super admin case
101 % if c.is_super_admin:
101 % if c.is_super_admin:
102 <li class="${is_active('audit_logs')}"><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
102 <li class="${is_active('audit_logs')}"><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
103 <li class="${is_active('repositories')}"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
103 <li class="${is_active('repositories')}"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
104 <li class="${is_active('repository_groups')}"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
104 <li class="${is_active('repository_groups')}"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
105 <li class="${is_active('users')}"><a href="${h.route_path('users')}">${_('Users')}</a></li>
105 <li class="${is_active('users')}"><a href="${h.route_path('users')}">${_('Users')}</a></li>
106 <li class="${is_active('user_groups')}"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
106 <li class="${is_active('user_groups')}"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
107 <li class="${is_active('permissions')}"><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
107 <li class="${is_active('permissions')}"><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
108 <li class="${is_active('authentication')}"><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
108 <li class="${is_active('authentication')}"><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
109 <li class="${is_active('integrations')}"><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
109 <li class="${is_active('integrations')}"><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
110 <li class="${is_active('defaults')}"><a href="${h.route_path('admin_defaults_repositories')}">${_('Defaults')}</a></li>
110 <li class="${is_active('defaults')}"><a href="${h.route_path('admin_defaults_repositories')}">${_('Defaults')}</a></li>
111 <li class="${is_active('settings')}"><a href="${h.route_path('admin_settings')}">${_('Settings')}</a></li>
111 <li class="${is_active('settings')}"><a href="${h.route_path('admin_settings')}">${_('Settings')}</a></li>
112
112
113 ## delegated admin
113 ## delegated admin
114 % elif c.is_delegated_admin:
114 % elif c.is_delegated_admin:
115 <%
115 <%
116 repositories=c.auth_user.repositories_admin or c.can_create_repo
116 repositories=c.auth_user.repositories_admin or c.can_create_repo
117 repository_groups=c.auth_user.repository_groups_admin or c.can_create_repo_group
117 repository_groups=c.auth_user.repository_groups_admin or c.can_create_repo_group
118 user_groups=c.auth_user.user_groups_admin or c.can_create_user_group
118 user_groups=c.auth_user.user_groups_admin or c.can_create_user_group
119 %>
119 %>
120
120
121 %if repositories:
121 %if repositories:
122 <li class="${is_active('repositories')} local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
122 <li class="${is_active('repositories')} local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
123 %endif
123 %endif
124 %if repository_groups:
124 %if repository_groups:
125 <li class="${is_active('repository_groups')} local-admin-repo-groups"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
125 <li class="${is_active('repository_groups')} local-admin-repo-groups"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
126 %endif
126 %endif
127 %if user_groups:
127 %if user_groups:
128 <li class="${is_active('user_groups')} local-admin-user-groups"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
128 <li class="${is_active('user_groups')} local-admin-user-groups"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
129 %endif
129 %endif
130 % endif
130 % endif
131 </ul>
131 </ul>
132
132
133 </div>
133 </div>
134 <div class="clear"></div>
134 <div class="clear"></div>
135 </div>
135 </div>
136 </%def>
136 </%def>
137
137
138 <%def name="dt_info_panel(elements)">
138 <%def name="dt_info_panel(elements)">
139 <dl class="dl-horizontal">
139 <dl class="dl-horizontal">
140 %for dt, dd, title, show_items in elements:
140 %for dt, dd, title, show_items in elements:
141 <dt>${dt}:</dt>
141 <dt>${dt}:</dt>
142 <dd title="${h.tooltip(title)}">
142 <dd title="${h.tooltip(title)}">
143 %if callable(dd):
143 %if callable(dd):
144 ## allow lazy evaluation of elements
144 ## allow lazy evaluation of elements
145 ${dd()}
145 ${dd()}
146 %else:
146 %else:
147 ${dd}
147 ${dd}
148 %endif
148 %endif
149 %if show_items:
149 %if show_items:
150 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
150 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
151 %endif
151 %endif
152 </dd>
152 </dd>
153
153
154 %if show_items:
154 %if show_items:
155 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
155 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
156 %for item in show_items:
156 %for item in show_items:
157 <dt></dt>
157 <dt></dt>
158 <dd>${item}</dd>
158 <dd>${item}</dd>
159 %endfor
159 %endfor
160 </div>
160 </div>
161 %endif
161 %endif
162
162
163 %endfor
163 %endfor
164 </dl>
164 </dl>
165 </%def>
165 </%def>
166
166
167 <%def name="gravatar(email, size=16)">
167 <%def name="gravatar(email, size=16)">
168 <%
168 <%
169 if (size > 16):
169 if (size > 16):
170 gravatar_class = 'gravatar gravatar-large'
170 gravatar_class = 'gravatar gravatar-large'
171 else:
171 else:
172 gravatar_class = 'gravatar'
172 gravatar_class = 'gravatar'
173 %>
173 %>
174 <%doc>
174 <%doc>
175 TODO: johbo: For now we serve double size images to make it smooth
175 TODO: johbo: For now we serve double size images to make it smooth
176 for retina. This is how it worked until now. Should be replaced
176 for retina. This is how it worked until now. Should be replaced
177 with a better solution at some point.
177 with a better solution at some point.
178 </%doc>
178 </%doc>
179 <img class="${gravatar_class}" src="${h.gravatar_url(email, size * 2)}" height="${size}" width="${size}">
179 <img class="${gravatar_class}" src="${h.gravatar_url(email, size * 2)}" height="${size}" width="${size}">
180 </%def>
180 </%def>
181
181
182
182
183 <%def name="gravatar_with_user(contact, size=16, show_disabled=False)">
183 <%def name="gravatar_with_user(contact, size=16, show_disabled=False)">
184 <% email = h.email_or_none(contact) %>
184 <% email = h.email_or_none(contact) %>
185 <div class="rc-user tooltip" title="${h.tooltip(h.author_string(email))}">
185 <div class="rc-user tooltip" title="${h.tooltip(h.author_string(email))}">
186 ${self.gravatar(email, size)}
186 ${self.gravatar(email, size)}
187 <span class="${'user user-disabled' if show_disabled else 'user'}"> ${h.link_to_user(contact)}</span>
187 <span class="${'user user-disabled' if show_disabled else 'user'}"> ${h.link_to_user(contact)}</span>
188 </div>
188 </div>
189 </%def>
189 </%def>
190
190
191
191
192 <%def name="repo_page_title(repo_instance)">
192 <%def name="repo_page_title(repo_instance)">
193 <div class="title-content repo-title">
193 <div class="title-content repo-title">
194
194
195 <div class="title-main">
195 <div class="title-main">
196 ## SVN/HG/GIT icons
196 ## SVN/HG/GIT icons
197 %if h.is_hg(repo_instance):
197 %if h.is_hg(repo_instance):
198 <i class="icon-hg"></i>
198 <i class="icon-hg"></i>
199 %endif
199 %endif
200 %if h.is_git(repo_instance):
200 %if h.is_git(repo_instance):
201 <i class="icon-git"></i>
201 <i class="icon-git"></i>
202 %endif
202 %endif
203 %if h.is_svn(repo_instance):
203 %if h.is_svn(repo_instance):
204 <i class="icon-svn"></i>
204 <i class="icon-svn"></i>
205 %endif
205 %endif
206
206
207 ## public/private
207 ## public/private
208 %if repo_instance.private:
208 %if repo_instance.private:
209 <i class="icon-repo-private"></i>
209 <i class="icon-repo-private"></i>
210 %else:
210 %else:
211 <i class="icon-repo-public"></i>
211 <i class="icon-repo-public"></i>
212 %endif
212 %endif
213
213
214 ## repo name with group name
214 ## repo name with group name
215 ${h.breadcrumb_repo_link(repo_instance)}
215 ${h.breadcrumb_repo_link(repo_instance)}
216
216
217 ## Context Actions
217 ## Context Actions
218 <div class="pull-right">
218 <div class="pull-right">
219 %if c.rhodecode_user.username != h.DEFAULT_USER:
219 %if c.rhodecode_user.username != h.DEFAULT_USER:
220 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid, _query=dict(auth_token=c.rhodecode_user.feed_token))}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
220 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid, _query=dict(auth_token=c.rhodecode_user.feed_token))}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
221
221
222 <a href="#WatchRepo" onclick="toggleFollowingRepo(this, templateContext.repo_id); return false" title="${_('Watch this Repository and actions on it in your personalized journal')}" class="btn btn-sm ${('watching' if c.repository_is_user_following else '')}">
222 <a href="#WatchRepo" onclick="toggleFollowingRepo(this, templateContext.repo_id); return false" title="${_('Watch this Repository and actions on it in your personalized journal')}" class="btn btn-sm ${('watching' if c.repository_is_user_following else '')}">
223 % if c.repository_is_user_following:
223 % if c.repository_is_user_following:
224 <i class="icon-eye-off"></i>${_('Unwatch')}
224 <i class="icon-eye-off"></i>${_('Unwatch')}
225 % else:
225 % else:
226 <i class="icon-eye"></i>${_('Watch')}
226 <i class="icon-eye"></i>${_('Watch')}
227 % endif
227 % endif
228
228
229 </a>
229 </a>
230 %else:
230 %else:
231 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid)}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
231 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid)}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
232 %endif
232 %endif
233 </div>
233 </div>
234
234
235 </div>
235 </div>
236
236
237 ## FORKED
237 ## FORKED
238 %if repo_instance.fork:
238 %if repo_instance.fork:
239 <p class="discreet">
239 <p class="discreet">
240 <i class="icon-code-fork"></i> ${_('Fork of')}
240 <i class="icon-code-fork"></i> ${_('Fork of')}
241 ${h.link_to_if(c.has_origin_repo_read_perm,repo_instance.fork.repo_name, h.route_path('repo_summary', repo_name=repo_instance.fork.repo_name))}
241 ${h.link_to_if(c.has_origin_repo_read_perm,repo_instance.fork.repo_name, h.route_path('repo_summary', repo_name=repo_instance.fork.repo_name))}
242 </p>
242 </p>
243 %endif
243 %endif
244
244
245 ## IMPORTED FROM REMOTE
245 ## IMPORTED FROM REMOTE
246 %if repo_instance.clone_uri:
246 %if repo_instance.clone_uri:
247 <p class="discreet">
247 <p class="discreet">
248 <i class="icon-code-fork"></i> ${_('Clone from')}
248 <i class="icon-code-fork"></i> ${_('Clone from')}
249 <a href="${h.safe_str(h.hide_credentials(repo_instance.clone_uri))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
249 <a href="${h.safe_str(h.hide_credentials(repo_instance.clone_uri))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
250 </p>
250 </p>
251 %endif
251 %endif
252
252
253 ## LOCKING STATUS
253 ## LOCKING STATUS
254 %if repo_instance.locked[0]:
254 %if repo_instance.locked[0]:
255 <p class="locking_locked discreet">
255 <p class="locking_locked discreet">
256 <i class="icon-repo-lock"></i>
256 <i class="icon-repo-lock"></i>
257 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
257 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
258 </p>
258 </p>
259 %elif repo_instance.enable_locking:
259 %elif repo_instance.enable_locking:
260 <p class="locking_unlocked discreet">
260 <p class="locking_unlocked discreet">
261 <i class="icon-repo-unlock"></i>
261 <i class="icon-repo-unlock"></i>
262 ${_('Repository not locked. Pull repository to lock it.')}
262 ${_('Repository not locked. Pull repository to lock it.')}
263 </p>
263 </p>
264 %endif
264 %endif
265
265
266 </div>
266 </div>
267 </%def>
267 </%def>
268
268
269 <%def name="repo_menu(active=None)">
269 <%def name="repo_menu(active=None)">
270 <%
270 <%
271 def is_active(selected):
271 def is_active(selected):
272 if selected == active:
272 if selected == active:
273 return "active"
273 return "active"
274 ## determine if we have "any" option available
274 ## determine if we have "any" option available
275 can_lock = h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking
275 can_lock = h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking
276 has_actions = can_lock
276 has_actions = can_lock
277
277
278 %>
278 %>
279 % if c.rhodecode_db_repo.archived:
279 % if c.rhodecode_db_repo.archived:
280 <div class="alert alert-warning text-center">
280 <div class="alert alert-warning text-center">
281 <strong>${_('This repository has been archived. It is now read-only.')}</strong>
281 <strong>${_('This repository has been archived. It is now read-only.')}</strong>
282 </div>
282 </div>
283 % endif
283 % endif
284
284
285 <!--- REPO CONTEXT BAR -->
285 <!--- REPO CONTEXT BAR -->
286 <div id="context-bar">
286 <div id="context-bar">
287 <div class="wrapper">
287 <div class="wrapper">
288
288
289 <div class="title">
289 <div class="title">
290 ${self.repo_page_title(c.rhodecode_db_repo)}
290 ${self.repo_page_title(c.rhodecode_db_repo)}
291 </div>
291 </div>
292
292
293 <ul id="context-pages" class="navigation horizontal-list">
293 <ul id="context-pages" class="navigation horizontal-list">
294 <li class="${is_active('summary')}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
294 <li class="${is_active('summary')}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
295 <li class="${is_active('commits')}"><a class="menulink" href="${h.route_path('repo_commits', repo_name=c.repo_name)}"><div class="menulabel">${_('Commits')}</div></a></li>
295 <li class="${is_active('commits')}"><a class="menulink" href="${h.route_path('repo_commits', repo_name=c.repo_name)}"><div class="menulabel">${_('Commits')}</div></a></li>
296 <li class="${is_active('files')}"><a class="menulink" href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.rhodecode_db_repo.landing_rev[1], f_path='')}"><div class="menulabel">${_('Files')}</div></a></li>
296 <li class="${is_active('files')}"><a class="menulink" href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.rhodecode_db_repo.landing_rev[1], f_path='')}"><div class="menulabel">${_('Files')}</div></a></li>
297 <li class="${is_active('compare')}"><a class="menulink" href="${h.route_path('repo_compare_select',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a></li>
297 <li class="${is_active('compare')}"><a class="menulink" href="${h.route_path('repo_compare_select',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a></li>
298
298
299 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
299 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
300 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
300 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
301 <li class="${is_active('showpullrequest')}">
301 <li class="${is_active('showpullrequest')}">
302 <a class="menulink" href="${h.route_path('pullrequest_show_all', repo_name=c.repo_name)}" title="${h.tooltip(_('Show Pull Requests for %s') % c.repo_name)}">
302 <a class="menulink" href="${h.route_path('pullrequest_show_all', repo_name=c.repo_name)}" title="${h.tooltip(_('Show Pull Requests for %s') % c.repo_name)}">
303 <div class="menulabel">
303 <div class="menulabel">
304 ${_('Pull Requests')} <span class="menulink-counter">${c.repository_pull_requests}</span>
304 ${_('Pull Requests')} <span class="menulink-counter">${c.repository_pull_requests}</span>
305 </div>
305 </div>
306 </a>
306 </a>
307 </li>
307 </li>
308 %endif
308 %endif
309
309
310 <li class="${is_active('artifacts')}">
310 <li class="${is_active('artifacts')}">
311 <a class="menulink" href="${h.route_path('repo_artifacts_list',repo_name=c.repo_name)}">
311 <a class="menulink" href="${h.route_path('repo_artifacts_list',repo_name=c.repo_name)}">
312 <div class="menulabel">
312 <div class="menulabel">
313 ${_('Artifacts')} <span class="menulink-counter">${c.repository_artifacts}</span>
313 ${_('Artifacts')} <span class="menulink-counter">${c.repository_artifacts}</span>
314 </div>
314 </div>
315 </a>
315 </a>
316 </li>
316 </li>
317
317
318 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
318 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
319 <li class="${is_active('settings')}"><a class="menulink" href="${h.route_path('edit_repo',repo_name=c.repo_name)}"><div class="menulabel">${_('Repository Settings')}</div></a></li>
319 <li class="${is_active('settings')}"><a class="menulink" href="${h.route_path('edit_repo',repo_name=c.repo_name)}"><div class="menulabel">${_('Repository Settings')}</div></a></li>
320 %endif
320 %endif
321
321
322 <li class="${is_active('options')}">
322 <li class="${is_active('options')}">
323 % if has_actions:
323 % if has_actions:
324 <a class="menulink dropdown">
324 <a class="menulink dropdown">
325 <div class="menulabel">${_('Options')}<div class="show_more"></div></div>
325 <div class="menulabel">${_('Options')}<div class="show_more"></div></div>
326 </a>
326 </a>
327 <ul class="submenu">
327 <ul class="submenu">
328 %if can_lock:
328 %if can_lock:
329 %if c.rhodecode_db_repo.locked[0]:
329 %if c.rhodecode_db_repo.locked[0]:
330 <li><a class="locking_del" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Unlock Repository')}</a></li>
330 <li><a class="locking_del" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Unlock Repository')}</a></li>
331 %else:
331 %else:
332 <li><a class="locking_add" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Lock Repository')}</a></li>
332 <li><a class="locking_add" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Lock Repository')}</a></li>
333 %endif
333 %endif
334 %endif
334 %endif
335 </ul>
335 </ul>
336 % else:
336 % else:
337 <a class="menulink disabled">
337 <a class="menulink disabled">
338 <div class="menulabel">${_('Options')}<div class="show_more"></div></div>
338 <div class="menulabel">${_('Options')}<div class="show_more"></div></div>
339 </a>
339 </a>
340 % endif
340 % endif
341 </li>
341 </li>
342
342
343 </ul>
343 </ul>
344 </div>
344 </div>
345 <div class="clear"></div>
345 <div class="clear"></div>
346 </div>
346 </div>
347
347
348 <!--- REPO END CONTEXT BAR -->
348 <!--- REPO END CONTEXT BAR -->
349
349
350 </%def>
350 </%def>
351
351
352 <%def name="repo_group_page_title(repo_group_instance)">
352 <%def name="repo_group_page_title(repo_group_instance)">
353 <div class="title-content">
353 <div class="title-content">
354 <div class="title-main">
354 <div class="title-main">
355 ## Repository Group icon
355 ## Repository Group icon
356 <i class="icon-repo-group"></i>
356 <i class="icon-repo-group"></i>
357
357
358 ## repo name with group name
358 ## repo name with group name
359 ${h.breadcrumb_repo_group_link(repo_group_instance)}
359 ${h.breadcrumb_repo_group_link(repo_group_instance)}
360 </div>
360 </div>
361
361
362 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
362 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
363 <div class="repo-group-desc discreet">
363 <div class="repo-group-desc discreet">
364 ${dt.repo_group_desc(repo_group_instance.description_safe, repo_group_instance.personal, c.visual.stylify_metatags)}
364 ${dt.repo_group_desc(repo_group_instance.description_safe, repo_group_instance.personal, c.visual.stylify_metatags)}
365 </div>
365 </div>
366
366
367 </div>
367 </div>
368 </%def>
368 </%def>
369
369
370
370
371 <%def name="repo_group_menu(active=None)">
371 <%def name="repo_group_menu(active=None)">
372 <%
372 <%
373 def is_active(selected):
373 def is_active(selected):
374 if selected == active:
374 if selected == active:
375 return "active"
375 return "active"
376
376
377 gr_name = c.repo_group.group_name if c.repo_group else None
377 gr_name = c.repo_group.group_name if c.repo_group else None
378 # create repositories with write permission on group is set to true
378 # create repositories with write permission on group is set to true
379 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
379 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
380
380
381 %>
381 %>
382
382
383
383
384 <!--- REPO GROUP CONTEXT BAR -->
384 <!--- REPO GROUP CONTEXT BAR -->
385 <div id="context-bar">
385 <div id="context-bar">
386 <div class="wrapper">
386 <div class="wrapper">
387 <div class="title">
387 <div class="title">
388 ${self.repo_group_page_title(c.repo_group)}
388 ${self.repo_group_page_title(c.repo_group)}
389 </div>
389 </div>
390
390
391 <ul id="context-pages" class="navigation horizontal-list">
391 <ul id="context-pages" class="navigation horizontal-list">
392 <li class="${is_active('home')}">
392 <li class="${is_active('home')}">
393 <a class="menulink" href="${h.route_path('repo_group_home', repo_group_name=c.repo_group.group_name)}"><div class="menulabel">${_('Group Home')}</div></a>
393 <a class="menulink" href="${h.route_path('repo_group_home', repo_group_name=c.repo_group.group_name)}"><div class="menulabel">${_('Group Home')}</div></a>
394 </li>
394 </li>
395 % if c.is_super_admin or group_admin:
395 % if c.is_super_admin or group_admin:
396 <li class="${is_active('settings')}">
396 <li class="${is_active('settings')}">
397 <a class="menulink" href="${h.route_path('edit_repo_group',repo_group_name=c.repo_group.group_name)}" title="${_('You have admin right to this group, and can edit it')}"><div class="menulabel">${_('Group Settings')}</div></a>
397 <a class="menulink" href="${h.route_path('edit_repo_group',repo_group_name=c.repo_group.group_name)}" title="${_('You have admin right to this group, and can edit it')}"><div class="menulabel">${_('Group Settings')}</div></a>
398 </li>
398 </li>
399 % endif
399 % endif
400
400
401 </ul>
401 </ul>
402 </div>
402 </div>
403 <div class="clear"></div>
403 <div class="clear"></div>
404 </div>
404 </div>
405
405
406 <!--- REPO GROUP CONTEXT BAR -->
406 <!--- REPO GROUP CONTEXT BAR -->
407
407
408 </%def>
408 </%def>
409
409
410
410
411 <%def name="usermenu(active=False)">
411 <%def name="usermenu(active=False)">
412 <%
412 <%
413 not_anonymous = c.rhodecode_user.username != h.DEFAULT_USER
413 not_anonymous = c.rhodecode_user.username != h.DEFAULT_USER
414
414
415 gr_name = c.repo_group.group_name if (hasattr(c, 'repo_group') and c.repo_group) else None
415 gr_name = c.repo_group.group_name if (hasattr(c, 'repo_group') and c.repo_group) else None
416 # create repositories with write permission on group is set to true
416 # create repositories with write permission on group is set to true
417
417
418 can_fork = c.is_super_admin or h.HasPermissionAny('hg.fork.repository')()
418 can_fork = c.is_super_admin or h.HasPermissionAny('hg.fork.repository')()
419 create_on_write = h.HasPermissionAny('hg.create.write_on_repogroup.true')()
419 create_on_write = h.HasPermissionAny('hg.create.write_on_repogroup.true')()
420 group_write = h.HasRepoGroupPermissionAny('group.write')(gr_name, 'can write into group index page')
420 group_write = h.HasRepoGroupPermissionAny('group.write')(gr_name, 'can write into group index page')
421 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
421 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
422
422
423 can_create_repos = c.is_super_admin or c.can_create_repo
423 can_create_repos = c.is_super_admin or c.can_create_repo
424 can_create_repo_groups = c.is_super_admin or c.can_create_repo_group
424 can_create_repo_groups = c.is_super_admin or c.can_create_repo_group
425
425
426 can_create_repos_in_group = c.is_super_admin or group_admin or (group_write and create_on_write)
426 can_create_repos_in_group = c.is_super_admin or group_admin or (group_write and create_on_write)
427 can_create_repo_groups_in_group = c.is_super_admin or group_admin
427 can_create_repo_groups_in_group = c.is_super_admin or group_admin
428 %>
428 %>
429
429
430 % if not_anonymous:
430 % if not_anonymous:
431 <%
431 <%
432 default_target_group = dict()
432 default_target_group = dict()
433 if c.rhodecode_user.personal_repo_group:
433 if c.rhodecode_user.personal_repo_group:
434 default_target_group = dict(parent_group=c.rhodecode_user.personal_repo_group.group_id)
434 default_target_group = dict(parent_group=c.rhodecode_user.personal_repo_group.group_id)
435 %>
435 %>
436
436
437 ## create action
437 ## create action
438 <li>
438 <li>
439 <a href="#create-actions" onclick="return false;" class="menulink childs">
439 <a href="#create-actions" onclick="return false;" class="menulink childs">
440 <i class="icon-plus-circled"></i>
440 <i class="icon-plus-circled"></i>
441 </a>
441 </a>
442
442
443 <div class="action-menu submenu">
443 <div class="action-menu submenu">
444
444
445 <ol>
445 <ol>
446 ## scope of within a repository
446 ## scope of within a repository
447 % if hasattr(c, 'rhodecode_db_repo') and c.rhodecode_db_repo:
447 % if hasattr(c, 'rhodecode_db_repo') and c.rhodecode_db_repo:
448 <li class="submenu-title">${_('This Repository')}</li>
448 <li class="submenu-title">${_('This Repository')}</li>
449 <li>
449 <li>
450 <a href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">${_('Create Pull Request')}</a>
450 <a href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">${_('Create Pull Request')}</a>
451 </li>
451 </li>
452 % if can_fork:
452 % if can_fork:
453 <li>
453 <li>
454 <a href="${h.route_path('repo_fork_new',repo_name=c.repo_name,_query=default_target_group)}">${_('Fork this repository')}</a>
454 <a href="${h.route_path('repo_fork_new',repo_name=c.repo_name,_query=default_target_group)}">${_('Fork this repository')}</a>
455 </li>
455 </li>
456 % endif
456 % endif
457 % endif
457 % endif
458
458
459 ## scope of within repository groups
459 ## scope of within repository groups
460 % if hasattr(c, 'repo_group') and c.repo_group and (can_create_repos_in_group or can_create_repo_groups_in_group):
460 % if hasattr(c, 'repo_group') and c.repo_group and (can_create_repos_in_group or can_create_repo_groups_in_group):
461 <li class="submenu-title">${_('This Repository Group')}</li>
461 <li class="submenu-title">${_('This Repository Group')}</li>
462
462
463 % if can_create_repos_in_group:
463 % if can_create_repos_in_group:
464 <li>
464 <li>
465 <a href="${h.route_path('repo_new',_query=default_target_group)}">${_('New Repository')}</a>
465 <a href="${h.route_path('repo_new',_query=default_target_group)}">${_('New Repository')}</a>
466 </li>
466 </li>
467 % endif
467 % endif
468
468
469 % if can_create_repo_groups_in_group:
469 % if can_create_repo_groups_in_group:
470 <li>
470 <li>
471 <a href="${h.route_path('repo_group_new',_query=default_target_group)}">${_(u'New Repository Group')}</a>
471 <a href="${h.route_path('repo_group_new',_query=default_target_group)}">${_(u'New Repository Group')}</a>
472 </li>
472 </li>
473 % endif
473 % endif
474 % endif
474 % endif
475
475
476 ## personal group
476 ## personal group
477 % if c.rhodecode_user.personal_repo_group:
477 % if c.rhodecode_user.personal_repo_group:
478 <li class="submenu-title">Personal Group</li>
478 <li class="submenu-title">Personal Group</li>
479
479
480 <li>
480 <li>
481 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}" >${_('New Repository')} </a>
481 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}" >${_('New Repository')} </a>
482 </li>
482 </li>
483
483
484 <li>
484 <li>
485 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}">${_('New Repository Group')} </a>
485 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}">${_('New Repository Group')} </a>
486 </li>
486 </li>
487 % endif
487 % endif
488
488
489 ## Global actions
489 ## Global actions
490 <li class="submenu-title">RhodeCode</li>
490 <li class="submenu-title">RhodeCode</li>
491 % if can_create_repos:
491 % if can_create_repos:
492 <li>
492 <li>
493 <a href="${h.route_path('repo_new')}" >${_('New Repository')}</a>
493 <a href="${h.route_path('repo_new')}" >${_('New Repository')}</a>
494 </li>
494 </li>
495 % endif
495 % endif
496
496
497 % if can_create_repo_groups:
497 % if can_create_repo_groups:
498 <li>
498 <li>
499 <a href="${h.route_path('repo_group_new')}" >${_(u'New Repository Group')}</a>
499 <a href="${h.route_path('repo_group_new')}" >${_(u'New Repository Group')}</a>
500 </li>
500 </li>
501 % endif
501 % endif
502
502
503 <li>
503 <li>
504 <a href="${h.route_path('gists_new')}">${_(u'New Gist')}</a>
504 <a href="${h.route_path('gists_new')}">${_(u'New Gist')}</a>
505 </li>
505 </li>
506
506
507 </ol>
507 </ol>
508
508
509 </div>
509 </div>
510 </li>
510 </li>
511
511
512 ## notifications
512 ## notifications
513 <li>
513 <li>
514 <a class="${('empty' if c.unread_notifications == 0 else '')}" href="${h.route_path('notifications_show_all')}">
514 <a class="${('empty' if c.unread_notifications == 0 else '')}" href="${h.route_path('notifications_show_all')}">
515 ${c.unread_notifications}
515 ${c.unread_notifications}
516 </a>
516 </a>
517 </li>
517 </li>
518 % endif
518 % endif
519
519
520 ## USER MENU
520 ## USER MENU
521 <li id="quick_login_li" class="${'active' if active else ''}">
521 <li id="quick_login_li" class="${'active' if active else ''}">
522 % if c.rhodecode_user.username == h.DEFAULT_USER:
522 % if c.rhodecode_user.username == h.DEFAULT_USER:
523 <a id="quick_login_link" class="menulink childs" href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">
523 <a id="quick_login_link" class="menulink childs" href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">
524 ${gravatar(c.rhodecode_user.email, 20)}
524 ${gravatar(c.rhodecode_user.email, 20)}
525 <span class="user">
525 <span class="user">
526 <span>${_('Sign in')}</span>
526 <span>${_('Sign in')}</span>
527 </span>
527 </span>
528 </a>
528 </a>
529 % else:
529 % else:
530 ## logged in user
530 ## logged in user
531 <a id="quick_login_link" class="menulink childs">
531 <a id="quick_login_link" class="menulink childs">
532 ${gravatar(c.rhodecode_user.email, 20)}
532 ${gravatar(c.rhodecode_user.email, 20)}
533 <span class="user">
533 <span class="user">
534 <span class="menu_link_user">${c.rhodecode_user.username}</span>
534 <span class="menu_link_user">${c.rhodecode_user.username}</span>
535 <div class="show_more"></div>
535 <div class="show_more"></div>
536 </span>
536 </span>
537 </a>
537 </a>
538 ## subnav with menu for logged in user
538 ## subnav with menu for logged in user
539 <div class="user-menu submenu">
539 <div class="user-menu submenu">
540 <div id="quick_login">
540 <div id="quick_login">
541 %if c.rhodecode_user.username != h.DEFAULT_USER:
541 %if c.rhodecode_user.username != h.DEFAULT_USER:
542 <div class="">
542 <div class="">
543 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
543 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
544 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
544 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
545 <div class="email">${c.rhodecode_user.email}</div>
545 <div class="email">${c.rhodecode_user.email}</div>
546 </div>
546 </div>
547 <div class="">
547 <div class="">
548 <ol class="links">
548 <ol class="links">
549 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
549 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
550 % if c.rhodecode_user.personal_repo_group:
550 % if c.rhodecode_user.personal_repo_group:
551 <li>${h.link_to(_(u'My personal group'), h.route_path('repo_group_home', repo_group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
551 <li>${h.link_to(_(u'My personal group'), h.route_path('repo_group_home', repo_group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
552 % endif
552 % endif
553 <li>${h.link_to(_(u'Pull Requests'), h.route_path('my_account_pullrequests'))}</li>
553 <li>${h.link_to(_(u'Pull Requests'), h.route_path('my_account_pullrequests'))}</li>
554
554
555 % if c.debug_style:
555 % if c.debug_style:
556 <li>
556 <li>
557 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
557 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
558 <div class="menulabel">${_('[Style]')}</div>
558 <div class="menulabel">${_('[Style]')}</div>
559 </a>
559 </a>
560 </li>
560 </li>
561 % endif
561 % endif
562
562
563 ## bookmark-items
563 ## bookmark-items
564 <li class="bookmark-items">
564 <li class="bookmark-items">
565 ${_('Bookmarks')}
565 ${_('Bookmarks')}
566 <div class="pull-right">
566 <div class="pull-right">
567 <a href="${h.route_path('my_account_bookmarks')}">
567 <a href="${h.route_path('my_account_bookmarks')}">
568
568
569 <i class="icon-cog"></i>
569 <i class="icon-cog"></i>
570 </a>
570 </a>
571 </div>
571 </div>
572 </li>
572 </li>
573 % if not c.bookmark_items:
573 % if not c.bookmark_items:
574 <li>
574 <li>
575 <a href="${h.route_path('my_account_bookmarks')}">${_('No Bookmarks yet.')}</a>
575 <a href="${h.route_path('my_account_bookmarks')}">${_('No Bookmarks yet.')}</a>
576 </li>
576 </li>
577 % endif
577 % endif
578 % for item in c.bookmark_items:
578 % for item in c.bookmark_items:
579 <li>
579 <li>
580 % if item.repository:
580 % if item.repository:
581 <div>
581 <div>
582 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
582 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
583 <code>${item.position}</code>
583 <code>${item.position}</code>
584 % if item.repository.repo_type == 'hg':
584 % if item.repository.repo_type == 'hg':
585 <i class="icon-hg" title="${_('Repository')}" style="font-size: 16px"></i>
585 <i class="icon-hg" title="${_('Repository')}" style="font-size: 16px"></i>
586 % elif item.repository.repo_type == 'git':
586 % elif item.repository.repo_type == 'git':
587 <i class="icon-git" title="${_('Repository')}" style="font-size: 16px"></i>
587 <i class="icon-git" title="${_('Repository')}" style="font-size: 16px"></i>
588 % elif item.repository.repo_type == 'svn':
588 % elif item.repository.repo_type == 'svn':
589 <i class="icon-svn" title="${_('Repository')}" style="font-size: 16px"></i>
589 <i class="icon-svn" title="${_('Repository')}" style="font-size: 16px"></i>
590 % endif
590 % endif
591 ${(item.title or h.shorter(item.repository.repo_name, 30))}
591 ${(item.title or h.shorter(item.repository.repo_name, 30))}
592 </a>
592 </a>
593 </div>
593 </div>
594 % elif item.repository_group:
594 % elif item.repository_group:
595 <div>
595 <div>
596 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
596 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
597 <code>${item.position}</code>
597 <code>${item.position}</code>
598 <i class="icon-repo-group" title="${_('Repository group')}" style="font-size: 14px"></i>
598 <i class="icon-repo-group" title="${_('Repository group')}" style="font-size: 14px"></i>
599 ${(item.title or h.shorter(item.repository_group.group_name, 30))}
599 ${(item.title or h.shorter(item.repository_group.group_name, 30))}
600 </a>
600 </a>
601 </div>
601 </div>
602 % else:
602 % else:
603 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
603 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
604 <code>${item.position}</code>
604 <code>${item.position}</code>
605 ${item.title}
605 ${item.title}
606 </a>
606 </a>
607 % endif
607 % endif
608 </li>
608 </li>
609 % endfor
609 % endfor
610
610
611 <li class="logout">
611 <li class="logout">
612 ${h.secure_form(h.route_path('logout'), request=request)}
612 ${h.secure_form(h.route_path('logout'), request=request)}
613 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
613 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
614 ${h.end_form()}
614 ${h.end_form()}
615 </li>
615 </li>
616 </ol>
616 </ol>
617 </div>
617 </div>
618 %endif
618 %endif
619 </div>
619 </div>
620 </div>
620 </div>
621
621
622 % endif
622 % endif
623 </li>
623 </li>
624 </%def>
624 </%def>
625
625
626 <%def name="menu_items(active=None)">
626 <%def name="menu_items(active=None)">
627 <%
627 <%
628 def is_active(selected):
628 def is_active(selected):
629 if selected == active:
629 if selected == active:
630 return "active"
630 return "active"
631 return ""
631 return ""
632 %>
632 %>
633
633
634 <ul id="quick" class="main_nav navigation horizontal-list">
634 <ul id="quick" class="main_nav navigation horizontal-list">
635 ## notice box for important system messages
635 ## notice box for important system messages
636 <li style="display: none">
636 <li style="display: none">
637 <a class="notice-box" href="#openNotice" onclick="return false">
637 <a class="notice-box" href="#openNotice" onclick="return false">
638 <div class="menulabel-notice" >
638 <div class="menulabel-notice" >
639 0
639 0
640 </div>
640 </div>
641 </a>
641 </a>
642 </li>
642 </li>
643
643
644 ## Main filter
644 ## Main filter
645 <li>
645 <li>
646 <div class="menulabel main_filter_box">
646 <div class="menulabel main_filter_box">
647 <div class="main_filter_input_box">
647 <div class="main_filter_input_box">
648 <ul class="searchItems">
648 <ul class="searchItems">
649
649
650 % if c.template_context['search_context']['repo_id']:
650 % if c.template_context['search_context']['repo_id']:
651 <li class="searchTag searchTagFilter searchTagHidable" >
651 <li class="searchTag searchTagFilter searchTagHidable" >
652 ##<a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">
652 ##<a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">
653 <span class="tag">
653 <span class="tag">
654 This repo
654 This repo
655 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
655 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
656 </span>
656 </span>
657 ##</a>
657 ##</a>
658 </li>
658 </li>
659 % elif c.template_context['search_context']['repo_group_id']:
659 % elif c.template_context['search_context']['repo_group_id']:
660 <li class="searchTag searchTagFilter searchTagHidable">
660 <li class="searchTag searchTagFilter searchTagHidable">
661 ##<a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">
661 ##<a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">
662 <span class="tag">
662 <span class="tag">
663 This group
663 This group
664 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
664 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
665 </span>
665 </span>
666 ##</a>
666 ##</a>
667 </li>
667 </li>
668 % endif
668 % endif
669
669
670 <li class="searchTagInput">
670 <li class="searchTagInput">
671 <input class="main_filter_input" id="main_filter" size="25" type="text" name="main_filter" placeholder="${_('search / go to...')}" value="" />
671 <input class="main_filter_input" id="main_filter" size="25" type="text" name="main_filter" placeholder="${_('search / go to...')}" value="" />
672 </li>
672 </li>
673 <li class="searchTag searchTagHelp">
673 <li class="searchTag searchTagHelp">
674 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
674 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
675 </li>
675 </li>
676 </ul>
676 </ul>
677 </div>
677 </div>
678 </div>
678 </div>
679
679
680 <div id="main_filter_help" style="display: none">
680 <div id="main_filter_help" style="display: none">
681 - Use '/' key to quickly access this field.
681 - Use '/' key to quickly access this field.
682
682
683 - Enter a name of repository, or repository group for quick search.
683 - Enter a name of repository, or repository group for quick search.
684
684
685 - Prefix query to allow special search:
685 - Prefix query to allow special search:
686
686
687 user:admin, to search for usernames, always global
687 user:admin, to search for usernames, always global
688
688
689 user_group:devops, to search for user groups, always global
689 user_group:devops, to search for user groups, always global
690
690
691 commit:efced4, to search for commits, scoped to repositories or groups
691 commit:efced4, to search for commits, scoped to repositories or groups
692
692
693 file:models.py, to search for file paths, scoped to repositories or groups
693 file:models.py, to search for file paths, scoped to repositories or groups
694
694
695 % if c.template_context['search_context']['repo_id']:
695 % if c.template_context['search_context']['repo_id']:
696 For advanced full text search visit: <a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">repository search</a>
696 For advanced full text search visit: <a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">repository search</a>
697 % elif c.template_context['search_context']['repo_group_id']:
697 % elif c.template_context['search_context']['repo_group_id']:
698 For advanced full text search visit: <a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">repository group search</a>
698 For advanced full text search visit: <a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">repository group search</a>
699 % else:
699 % else:
700 For advanced full text search visit: <a href="${h.route_path('search')}">global search</a>
700 For advanced full text search visit: <a href="${h.route_path('search')}">global search</a>
701 % endif
701 % endif
702 </div>
702 </div>
703 </li>
703 </li>
704
704
705 ## ROOT MENU
705 ## ROOT MENU
706 <li class="${is_active('home')}">
706 <li class="${is_active('home')}">
707 <a class="menulink" title="${_('Home')}" href="${h.route_path('home')}">
707 <a class="menulink" title="${_('Home')}" href="${h.route_path('home')}">
708 <div class="menulabel">${_('Home')}</div>
708 <div class="menulabel">${_('Home')}</div>
709 </a>
709 </a>
710 </li>
710 </li>
711
711
712 %if c.rhodecode_user.username != h.DEFAULT_USER:
712 %if c.rhodecode_user.username != h.DEFAULT_USER:
713 <li class="${is_active('journal')}">
713 <li class="${is_active('journal')}">
714 <a class="menulink" title="${_('Show activity journal')}" href="${h.route_path('journal')}">
714 <a class="menulink" title="${_('Show activity journal')}" href="${h.route_path('journal')}">
715 <div class="menulabel">${_('Journal')}</div>
715 <div class="menulabel">${_('Journal')}</div>
716 </a>
716 </a>
717 </li>
717 </li>
718 %else:
718 %else:
719 <li class="${is_active('journal')}">
719 <li class="${is_active('journal')}">
720 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.route_path('journal_public')}">
720 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.route_path('journal_public')}">
721 <div class="menulabel">${_('Public journal')}</div>
721 <div class="menulabel">${_('Public journal')}</div>
722 </a>
722 </a>
723 </li>
723 </li>
724 %endif
724 %endif
725
725
726 <li class="${is_active('gists')}">
726 <li class="${is_active('gists')}">
727 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
727 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
728 <div class="menulabel">${_('Gists')}</div>
728 <div class="menulabel">${_('Gists')}</div>
729 </a>
729 </a>
730 </li>
730 </li>
731
731
732 % if c.is_super_admin or c.is_delegated_admin:
732 % if c.is_super_admin or c.is_delegated_admin:
733 <li class="${is_active('admin')}">
733 <li class="${is_active('admin')}">
734 <a class="menulink childs" title="${_('Admin settings')}" href="${h.route_path('admin_home')}">
734 <a class="menulink childs" title="${_('Admin settings')}" href="${h.route_path('admin_home')}">
735 <div class="menulabel">${_('Admin')} </div>
735 <div class="menulabel">${_('Admin')} </div>
736 </a>
736 </a>
737 </li>
737 </li>
738 % endif
738 % endif
739
739
740 ## render extra user menu
740 ## render extra user menu
741 ${usermenu(active=(active=='my_account'))}
741 ${usermenu(active=(active=='my_account'))}
742
742
743 </ul>
743 </ul>
744
744
745 <script type="text/javascript">
745 <script type="text/javascript">
746 var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True";
746 var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True";
747
747
748 var formatRepoResult = function(result, container, query, escapeMarkup) {
748 var formatRepoResult = function(result, container, query, escapeMarkup) {
749 return function(data, escapeMarkup) {
749 return function(data, escapeMarkup) {
750 if (!data.repo_id){
750 if (!data.repo_id){
751 return data.text; // optgroup text Repositories
751 return data.text; // optgroup text Repositories
752 }
752 }
753
753
754 var tmpl = '';
754 var tmpl = '';
755 var repoType = data['repo_type'];
755 var repoType = data['repo_type'];
756 var repoName = data['text'];
756 var repoName = data['text'];
757
757
758 if(data && data.type == 'repo'){
758 if(data && data.type == 'repo'){
759 if(repoType === 'hg'){
759 if(repoType === 'hg'){
760 tmpl += '<i class="icon-hg"></i> ';
760 tmpl += '<i class="icon-hg"></i> ';
761 }
761 }
762 else if(repoType === 'git'){
762 else if(repoType === 'git'){
763 tmpl += '<i class="icon-git"></i> ';
763 tmpl += '<i class="icon-git"></i> ';
764 }
764 }
765 else if(repoType === 'svn'){
765 else if(repoType === 'svn'){
766 tmpl += '<i class="icon-svn"></i> ';
766 tmpl += '<i class="icon-svn"></i> ';
767 }
767 }
768 if(data['private']){
768 if(data['private']){
769 tmpl += '<i class="icon-lock" ></i> ';
769 tmpl += '<i class="icon-lock" ></i> ';
770 }
770 }
771 else if(visualShowPublicIcon){
771 else if(visualShowPublicIcon){
772 tmpl += '<i class="icon-unlock-alt"></i> ';
772 tmpl += '<i class="icon-unlock-alt"></i> ';
773 }
773 }
774 }
774 }
775 tmpl += escapeMarkup(repoName);
775 tmpl += escapeMarkup(repoName);
776 return tmpl;
776 return tmpl;
777
777
778 }(result, escapeMarkup);
778 }(result, escapeMarkup);
779 };
779 };
780
780
781 var formatRepoGroupResult = function(result, container, query, escapeMarkup) {
781 var formatRepoGroupResult = function(result, container, query, escapeMarkup) {
782 return function(data, escapeMarkup) {
782 return function(data, escapeMarkup) {
783 if (!data.repo_group_id){
783 if (!data.repo_group_id){
784 return data.text; // optgroup text Repositories
784 return data.text; // optgroup text Repositories
785 }
785 }
786
786
787 var tmpl = '';
787 var tmpl = '';
788 var repoGroupName = data['text'];
788 var repoGroupName = data['text'];
789
789
790 if(data){
790 if(data){
791
791
792 tmpl += '<i class="icon-repo-group"></i> ';
792 tmpl += '<i class="icon-repo-group"></i> ';
793
793
794 }
794 }
795 tmpl += escapeMarkup(repoGroupName);
795 tmpl += escapeMarkup(repoGroupName);
796 return tmpl;
796 return tmpl;
797
797
798 }(result, escapeMarkup);
798 }(result, escapeMarkup);
799 };
799 };
800
800
801 var escapeRegExChars = function (value) {
801 var escapeRegExChars = function (value) {
802 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
802 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
803 };
803 };
804
804
805 var getRepoIcon = function(repo_type) {
805 var getRepoIcon = function(repo_type) {
806 if (repo_type === 'hg') {
806 if (repo_type === 'hg') {
807 return '<i class="icon-hg"></i> ';
807 return '<i class="icon-hg"></i> ';
808 }
808 }
809 else if (repo_type === 'git') {
809 else if (repo_type === 'git') {
810 return '<i class="icon-git"></i> ';
810 return '<i class="icon-git"></i> ';
811 }
811 }
812 else if (repo_type === 'svn') {
812 else if (repo_type === 'svn') {
813 return '<i class="icon-svn"></i> ';
813 return '<i class="icon-svn"></i> ';
814 }
814 }
815 return ''
815 return ''
816 };
816 };
817
817
818 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
818 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
819
819
820 if (value.split(':').length === 2) {
820 if (value.split(':').length === 2) {
821 value = value.split(':')[1]
821 value = value.split(':')[1]
822 }
822 }
823
823
824 var searchType = data['type'];
824 var searchType = data['type'];
825 var searchSubType = data['subtype'];
825 var searchSubType = data['subtype'];
826 var valueDisplay = data['value_display'];
826 var valueDisplay = data['value_display'];
827
827
828 var pattern = '(' + escapeRegExChars(value) + ')';
828 var pattern = '(' + escapeRegExChars(value) + ')';
829
829
830 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
830 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
831
831
832 // highlight match
832 // highlight match
833 if (searchType != 'text') {
833 if (searchType != 'text') {
834 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
834 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
835 }
835 }
836
836
837 var icon = '';
837 var icon = '';
838
838
839 if (searchType === 'hint') {
839 if (searchType === 'hint') {
840 icon += '<i class="icon-repo-group"></i> ';
840 icon += '<i class="icon-repo-group"></i> ';
841 }
841 }
842 // full text search/hints
842 // full text search/hints
843 else if (searchType === 'search') {
843 else if (searchType === 'search') {
844 icon += '<i class="icon-more"></i> ';
844 icon += '<i class="icon-more"></i> ';
845 if (searchSubType !== undefined && searchSubType == 'repo') {
845 if (searchSubType !== undefined && searchSubType == 'repo') {
846 valueDisplay += '<div class="pull-right tag">repository</div>';
846 valueDisplay += '<div class="pull-right tag">repository</div>';
847 }
847 }
848 else if (searchSubType !== undefined && searchSubType == 'repo_group') {
848 else if (searchSubType !== undefined && searchSubType == 'repo_group') {
849 valueDisplay += '<div class="pull-right tag">repo group</div>';
849 valueDisplay += '<div class="pull-right tag">repo group</div>';
850 }
850 }
851 }
851 }
852 // repository
852 // repository
853 else if (searchType === 'repo') {
853 else if (searchType === 'repo') {
854
854
855 var repoIcon = getRepoIcon(data['repo_type']);
855 var repoIcon = getRepoIcon(data['repo_type']);
856 icon += repoIcon;
856 icon += repoIcon;
857
857
858 if (data['private']) {
858 if (data['private']) {
859 icon += '<i class="icon-lock" ></i> ';
859 icon += '<i class="icon-lock" ></i> ';
860 }
860 }
861 else if (visualShowPublicIcon) {
861 else if (visualShowPublicIcon) {
862 icon += '<i class="icon-unlock-alt"></i> ';
862 icon += '<i class="icon-unlock-alt"></i> ';
863 }
863 }
864 }
864 }
865 // repository groups
865 // repository groups
866 else if (searchType === 'repo_group') {
866 else if (searchType === 'repo_group') {
867 icon += '<i class="icon-repo-group"></i> ';
867 icon += '<i class="icon-repo-group"></i> ';
868 }
868 }
869 // user group
869 // user group
870 else if (searchType === 'user_group') {
870 else if (searchType === 'user_group') {
871 icon += '<i class="icon-group"></i> ';
871 icon += '<i class="icon-group"></i> ';
872 }
872 }
873 // user
873 // user
874 else if (searchType === 'user') {
874 else if (searchType === 'user') {
875 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
875 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
876 }
876 }
877 // commit
877 // commit
878 else if (searchType === 'commit') {
878 else if (searchType === 'commit') {
879 var repo_data = data['repo_data'];
879 var repo_data = data['repo_data'];
880 var repoIcon = getRepoIcon(repo_data['repository_type']);
880 var repoIcon = getRepoIcon(repo_data['repository_type']);
881 if (repoIcon) {
881 if (repoIcon) {
882 icon += repoIcon;
882 icon += repoIcon;
883 } else {
883 } else {
884 icon += '<i class="icon-tag"></i>';
884 icon += '<i class="icon-tag"></i>';
885 }
885 }
886 }
886 }
887 // file
887 // file
888 else if (searchType === 'file') {
888 else if (searchType === 'file') {
889 var repo_data = data['repo_data'];
889 var repo_data = data['repo_data'];
890 var repoIcon = getRepoIcon(repo_data['repository_type']);
890 var repoIcon = getRepoIcon(repo_data['repository_type']);
891 if (repoIcon) {
891 if (repoIcon) {
892 icon += repoIcon;
892 icon += repoIcon;
893 } else {
893 } else {
894 icon += '<i class="icon-tag"></i>';
894 icon += '<i class="icon-tag"></i>';
895 }
895 }
896 }
896 }
897 // generic text
897 // generic text
898 else if (searchType === 'text') {
898 else if (searchType === 'text') {
899 icon = '';
899 icon = '';
900 }
900 }
901
901
902 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
902 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
903 return tmpl.format(icon, valueDisplay);
903 return tmpl.format(icon, valueDisplay);
904 };
904 };
905
905
906 var handleSelect = function(element, suggestion) {
906 var handleSelect = function(element, suggestion) {
907 if (suggestion.type === "hint") {
907 if (suggestion.type === "hint") {
908 // we skip action
908 // we skip action
909 $('#main_filter').focus();
909 $('#main_filter').focus();
910 }
910 }
911 else if (suggestion.type === "text") {
911 else if (suggestion.type === "text") {
912 // we skip action
912 // we skip action
913 $('#main_filter').focus();
913 $('#main_filter').focus();
914
914
915 } else {
915 } else {
916 window.location = suggestion['url'];
916 window.location = suggestion['url'];
917 }
917 }
918 };
918 };
919
919
920 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
920 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
921 if (queryLowerCase.split(':').length === 2) {
921 if (queryLowerCase.split(':').length === 2) {
922 queryLowerCase = queryLowerCase.split(':')[1]
922 queryLowerCase = queryLowerCase.split(':')[1]
923 }
923 }
924 if (suggestion.type === "text") {
924 if (suggestion.type === "text") {
925 // special case we don't want to "skip" display for
925 // special case we don't want to "skip" display for
926 return true
926 return true
927 }
927 }
928 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
928 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
929 };
929 };
930
930
931 var cleanContext = {
931 var cleanContext = {
932 repo_view_type: null,
932 repo_view_type: null,
933
933
934 repo_id: null,
934 repo_id: null,
935 repo_name: "",
935 repo_name: "",
936
936
937 repo_group_id: null,
937 repo_group_id: null,
938 repo_group_name: null
938 repo_group_name: null
939 };
939 };
940 var removeGoToFilter = function () {
940 var removeGoToFilter = function () {
941 $('.searchTagHidable').hide();
941 $('.searchTagHidable').hide();
942 $('#main_filter').autocomplete(
942 $('#main_filter').autocomplete(
943 'setOptions', {params:{search_context: cleanContext}});
943 'setOptions', {params:{search_context: cleanContext}});
944 };
944 };
945
945
946 $('#main_filter').autocomplete({
946 $('#main_filter').autocomplete({
947 serviceUrl: pyroutes.url('goto_switcher_data'),
947 serviceUrl: pyroutes.url('goto_switcher_data'),
948 params: {
948 params: {
949 "search_context": templateContext.search_context
949 "search_context": templateContext.search_context
950 },
950 },
951 minChars:2,
951 minChars:2,
952 maxHeight:400,
952 maxHeight:400,
953 deferRequestBy: 300, //miliseconds
953 deferRequestBy: 300, //miliseconds
954 tabDisabled: true,
954 tabDisabled: true,
955 autoSelectFirst: false,
955 autoSelectFirst: false,
956 containerClass: 'autocomplete-qfilter-suggestions',
956 containerClass: 'autocomplete-qfilter-suggestions',
957 formatResult: autocompleteMainFilterFormatResult,
957 formatResult: autocompleteMainFilterFormatResult,
958 lookupFilter: autocompleteMainFilterResult,
958 lookupFilter: autocompleteMainFilterResult,
959 onSelect: function (element, suggestion) {
959 onSelect: function (element, suggestion) {
960 handleSelect(element, suggestion);
960 handleSelect(element, suggestion);
961 return false;
961 return false;
962 },
962 },
963 onSearchError: function (element, query, jqXHR, textStatus, errorThrown) {
963 onSearchError: function (element, query, jqXHR, textStatus, errorThrown) {
964 if (jqXHR !== 'abort') {
964 if (jqXHR !== 'abort') {
965 alert("Error during search.\nError code: {0}".format(textStatus));
965 alert("Error during search.\nError code: {0}".format(textStatus));
966 window.location = '';
966 window.location = '';
967 }
967 }
968 }
968 }
969 });
969 });
970
970
971 showMainFilterBox = function () {
971 showMainFilterBox = function () {
972 $('#main_filter_help').toggle();
972 $('#main_filter_help').toggle();
973 };
973 };
974
974
975 $('#main_filter').on('keydown.autocomplete', function (e) {
975 $('#main_filter').on('keydown.autocomplete', function (e) {
976
976
977 var BACKSPACE = 8;
977 var BACKSPACE = 8;
978 var el = $(e.currentTarget);
978 var el = $(e.currentTarget);
979 if(e.which === BACKSPACE){
979 if(e.which === BACKSPACE){
980 var inputVal = el.val();
980 var inputVal = el.val();
981 if (inputVal === ""){
981 if (inputVal === ""){
982 removeGoToFilter()
982 removeGoToFilter()
983 }
983 }
984 }
984 }
985 });
985 });
986
986
987 </script>
987 </script>
988 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
988 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
989 </%def>
989 </%def>
990
990
991 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
991 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
992 <div class="modal-dialog">
992 <div class="modal-dialog">
993 <div class="modal-content">
993 <div class="modal-content">
994 <div class="modal-header">
994 <div class="modal-header">
995 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
995 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
996 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
996 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
997 </div>
997 </div>
998 <div class="modal-body">
998 <div class="modal-body">
999 <div class="block-left">
999 <div class="block-left">
1000 <table class="keyboard-mappings">
1000 <table class="keyboard-mappings">
1001 <tbody>
1001 <tbody>
1002 <tr>
1002 <tr>
1003 <th></th>
1003 <th></th>
1004 <th>${_('Site-wide shortcuts')}</th>
1004 <th>${_('Site-wide shortcuts')}</th>
1005 </tr>
1005 </tr>
1006 <%
1006 <%
1007 elems = [
1007 elems = [
1008 ('/', 'Use quick search box'),
1008 ('/', 'Use quick search box'),
1009 ('g h', 'Goto home page'),
1009 ('g h', 'Goto home page'),
1010 ('g g', 'Goto my private gists page'),
1010 ('g g', 'Goto my private gists page'),
1011 ('g G', 'Goto my public gists page'),
1011 ('g G', 'Goto my public gists page'),
1012 ('g 0-9', 'Goto bookmarked items from 0-9'),
1012 ('g 0-9', 'Goto bookmarked items from 0-9'),
1013 ('n r', 'New repository page'),
1013 ('n r', 'New repository page'),
1014 ('n g', 'New gist page'),
1014 ('n g', 'New gist page'),
1015 ]
1015 ]
1016 %>
1016 %>
1017 %for key, desc in elems:
1017 %for key, desc in elems:
1018 <tr>
1018 <tr>
1019 <td class="keys">
1019 <td class="keys">
1020 <span class="key tag">${key}</span>
1020 <span class="key tag">${key}</span>
1021 </td>
1021 </td>
1022 <td>${desc}</td>
1022 <td>${desc}</td>
1023 </tr>
1023 </tr>
1024 %endfor
1024 %endfor
1025 </tbody>
1025 </tbody>
1026 </table>
1026 </table>
1027 </div>
1027 </div>
1028 <div class="block-left">
1028 <div class="block-left">
1029 <table class="keyboard-mappings">
1029 <table class="keyboard-mappings">
1030 <tbody>
1030 <tbody>
1031 <tr>
1031 <tr>
1032 <th></th>
1032 <th></th>
1033 <th>${_('Repositories')}</th>
1033 <th>${_('Repositories')}</th>
1034 </tr>
1034 </tr>
1035 <%
1035 <%
1036 elems = [
1036 elems = [
1037 ('g s', 'Goto summary page'),
1037 ('g s', 'Goto summary page'),
1038 ('g c', 'Goto changelog page'),
1038 ('g c', 'Goto changelog page'),
1039 ('g f', 'Goto files page'),
1039 ('g f', 'Goto files page'),
1040 ('g F', 'Goto files page with file search activated'),
1040 ('g F', 'Goto files page with file search activated'),
1041 ('g p', 'Goto pull requests page'),
1041 ('g p', 'Goto pull requests page'),
1042 ('g o', 'Goto repository settings'),
1042 ('g o', 'Goto repository settings'),
1043 ('g O', 'Goto repository permissions settings'),
1043 ('g O', 'Goto repository access permissions settings'),
1044 ]
1044 ]
1045 %>
1045 %>
1046 %for key, desc in elems:
1046 %for key, desc in elems:
1047 <tr>
1047 <tr>
1048 <td class="keys">
1048 <td class="keys">
1049 <span class="key tag">${key}</span>
1049 <span class="key tag">${key}</span>
1050 </td>
1050 </td>
1051 <td>${desc}</td>
1051 <td>${desc}</td>
1052 </tr>
1052 </tr>
1053 %endfor
1053 %endfor
1054 </tbody>
1054 </tbody>
1055 </table>
1055 </table>
1056 </div>
1056 </div>
1057 </div>
1057 </div>
1058 <div class="modal-footer">
1058 <div class="modal-footer">
1059 </div>
1059 </div>
1060 </div><!-- /.modal-content -->
1060 </div><!-- /.modal-content -->
1061 </div><!-- /.modal-dialog -->
1061 </div><!-- /.modal-dialog -->
1062 </div><!-- /.modal -->
1062 </div><!-- /.modal -->
1063
1063
@@ -1,372 +1,372 b''
1 ## snippet for displaying permissions overview for users
1 ## snippet for displaying permissions overview for users
2 ## usage:
2 ## usage:
3 ## <%namespace name="p" file="/base/perms_summary.mako"/>
3 ## <%namespace name="p" file="/base/perms_summary.mako"/>
4 ## ${p.perms_summary(c.perm_user.permissions)}
4 ## ${p.perms_summary(c.perm_user.permissions)}
5
5
6 <%def name="perms_summary(permissions, show_all=False, actions=True, side_link=None)">
6 <%def name="perms_summary(permissions, show_all=False, actions=True, side_link=None)">
7 <% section_to_label = {
7 <% section_to_label = {
8 'global': 'Global Permissions',
8 'global': 'Global Permissions',
9 'repository_branches': 'Repository Branch Rules',
9 'repository_branches': 'Repository Branch Rules',
10 'repositories': 'Repository Permissions',
10 'repositories': 'Repository Access Permissions',
11 'user_groups': 'User Group Permissions',
11 'user_groups': 'User Group Permissions',
12 'repositories_groups': 'Repository Group Permissions',
12 'repositories_groups': 'Repository Group Permissions',
13 } %>
13 } %>
14
14
15 <div id="perms" class="table fields">
15 <div id="perms" class="table fields">
16 %for section in sorted(permissions.keys(), key=lambda item: {'global': 0, 'repository_branches': 1}.get(item, 1000)):
16 %for section in sorted(permissions.keys(), key=lambda item: {'global': 0, 'repository_branches': 1}.get(item, 1000)):
17 <% total_counter = 0 %>
17 <% total_counter = 0 %>
18
18
19 <div class="panel panel-default">
19 <div class="panel panel-default">
20 <div class="panel-heading" id="${section.replace("_","-")}-permissions">
20 <div class="panel-heading" id="${section.replace("_","-")}-permissions">
21 <h3 class="panel-title">${section_to_label.get(section, section)} - <span id="total_count_${section}"></span>
21 <h3 class="panel-title">${section_to_label.get(section, section)} - <span id="total_count_${section}"></span>
22 <a class="permalink" href="#${section.replace("_","-")}-permissions"> ΒΆ</a>
22 <a class="permalink" href="#${section.replace("_","-")}-permissions"> ΒΆ</a>
23 </h3>
23 </h3>
24 % if side_link:
24 % if side_link:
25 <div class="pull-right">
25 <div class="pull-right">
26 <a href="${side_link}">${_('in JSON format')}</a>
26 <a href="${side_link}">${_('in JSON format')}</a>
27 </div>
27 </div>
28 % endif
28 % endif
29 </div>
29 </div>
30 <div class="panel-body">
30 <div class="panel-body">
31 <div class="perms_section_head field">
31 <div class="perms_section_head field">
32 <div class="radios">
32 <div class="radios">
33 % if section == 'repository_branches':
33 % if section == 'repository_branches':
34 <span class="permissions_boxes">
34 <span class="permissions_boxes">
35 <span class="desc">${_('show')}: </span>
35 <span class="desc">${_('show')}: </span>
36 ${h.checkbox('perms_filter_none_%s' % section, 'none', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='none')} <label for="${'perms_filter_none_{}'.format(section)}"><span class="perm_tag none">${_('none')}</span></label>
36 ${h.checkbox('perms_filter_none_%s' % section, 'none', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='none')} <label for="${'perms_filter_none_{}'.format(section)}"><span class="perm_tag none">${_('none')}</span></label>
37 ${h.checkbox('perms_filter_merge_%s' % section, 'merge', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='merge')} <label for="${'perms_filter_merge_{}'.format(section)}"><span class="perm_tag merge">${_('merge')}</span></label>
37 ${h.checkbox('perms_filter_merge_%s' % section, 'merge', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='merge')} <label for="${'perms_filter_merge_{}'.format(section)}"><span class="perm_tag merge">${_('merge')}</span></label>
38 ${h.checkbox('perms_filter_push_%s' % section, 'push', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='push')} <label for="${'perms_filter_push_{}'.format(section)}"> <span class="perm_tag push">${_('push')}</span></label>
38 ${h.checkbox('perms_filter_push_%s' % section, 'push', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='push')} <label for="${'perms_filter_push_{}'.format(section)}"> <span class="perm_tag push">${_('push')}</span></label>
39 ${h.checkbox('perms_filter_push_force_%s' % section, 'push_force', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='push_force')} <label for="${'perms_filter_push_force_{}'.format(section)}"><span class="perm_tag push_force">${_('push force')}</span></label>
39 ${h.checkbox('perms_filter_push_force_%s' % section, 'push_force', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='push_force')} <label for="${'perms_filter_push_force_{}'.format(section)}"><span class="perm_tag push_force">${_('push force')}</span></label>
40 </span>
40 </span>
41 % elif section != 'global':
41 % elif section != 'global':
42 <span class="permissions_boxes">
42 <span class="permissions_boxes">
43 <span class="desc">${_('show')}: </span>
43 <span class="desc">${_('show')}: </span>
44 ${h.checkbox('perms_filter_none_%s' % section, 'none', '', class_='perm_filter filter_%s' % section, section=section, perm_type='none')} <label for="${'perms_filter_none_{}'.format(section)}"><span class="perm_tag none">${_('none')}</span></label>
44 ${h.checkbox('perms_filter_none_%s' % section, 'none', '', class_='perm_filter filter_%s' % section, section=section, perm_type='none')} <label for="${'perms_filter_none_{}'.format(section)}"><span class="perm_tag none">${_('none')}</span></label>
45 ${h.checkbox('perms_filter_read_%s' % section, 'read', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='read')} <label for="${'perms_filter_read_{}'.format(section)}"><span class="perm_tag read">${_('read')}</span></label>
45 ${h.checkbox('perms_filter_read_%s' % section, 'read', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='read')} <label for="${'perms_filter_read_{}'.format(section)}"><span class="perm_tag read">${_('read')}</span></label>
46 ${h.checkbox('perms_filter_write_%s' % section, 'write', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='write')} <label for="${'perms_filter_write_{}'.format(section)}"> <span class="perm_tag write">${_('write')}</span></label>
46 ${h.checkbox('perms_filter_write_%s' % section, 'write', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='write')} <label for="${'perms_filter_write_{}'.format(section)}"> <span class="perm_tag write">${_('write')}</span></label>
47 ${h.checkbox('perms_filter_admin_%s' % section, 'admin', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='admin')} <label for="${'perms_filter_admin_{}'.format(section)}"><span class="perm_tag admin">${_('admin')}</span></label>
47 ${h.checkbox('perms_filter_admin_%s' % section, 'admin', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='admin')} <label for="${'perms_filter_admin_{}'.format(section)}"><span class="perm_tag admin">${_('admin')}</span></label>
48 </span>
48 </span>
49 % endif
49 % endif
50
50
51 </div>
51 </div>
52 </div>
52 </div>
53 <div class="field">
53 <div class="field">
54 %if not permissions[section]:
54 %if not permissions[section]:
55 <p class="empty_data help-block">${_('No permissions defined')}</p>
55 <p class="empty_data help-block">${_('No permissions defined')}</p>
56 %else:
56 %else:
57 <div id='tbl_list_wrap_${section}'>
57 <div id='tbl_list_wrap_${section}'>
58 <table id="tbl_list_${section}" class="rctable">
58 <table id="tbl_list_${section}" class="rctable">
59 ## global permission box
59 ## global permission box
60 %if section == 'global':
60 %if section == 'global':
61 <thead>
61 <thead>
62 <tr>
62 <tr>
63 <th colspan="2" class="left">${_('Permission')}</th>
63 <th colspan="2" class="left">${_('Permission')}</th>
64 %if actions:
64 %if actions:
65 <th colspan="2">${_('Edit Permission')}</th>
65 <th colspan="2">${_('Edit Permission')}</th>
66 %endif
66 %endif
67 </thead>
67 </thead>
68 <tbody>
68 <tbody>
69
69
70 <%
70 <%
71 def get_section_perms(prefix, opts):
71 def get_section_perms(prefix, opts):
72 _selected = []
72 _selected = []
73 for op in opts:
73 for op in opts:
74 if op.startswith(prefix) and not op.startswith('hg.create.write_on_repogroup'):
74 if op.startswith(prefix) and not op.startswith('hg.create.write_on_repogroup'):
75 _selected.append(op)
75 _selected.append(op)
76 admin = 'hg.admin' in opts
76 admin = 'hg.admin' in opts
77 _selected_vals = [x.partition(prefix)[-1] for x in _selected]
77 _selected_vals = [x.partition(prefix)[-1] for x in _selected]
78 return admin, _selected_vals, _selected
78 return admin, _selected_vals, _selected
79 %>
79 %>
80
80
81 <%def name="glob(lbl, val, val_lbl=None, edit_url=None, edit_global_url=None)">
81 <%def name="glob(lbl, val, val_lbl=None, edit_url=None, edit_global_url=None)">
82 <tr>
82 <tr>
83 <td class="td-tags">
83 <td class="td-tags">
84 ${lbl}
84 ${lbl}
85 </td>
85 </td>
86 <td class="td-tags">
86 <td class="td-tags">
87 %if val[0]:
87 %if val[0]:
88 %if not val_lbl:
88 %if not val_lbl:
89 ## super admin case
89 ## super admin case
90 True
90 True
91 %else:
91 %else:
92 <span class="perm_tag admin">${val_lbl}.admin</span>
92 <span class="perm_tag admin">${val_lbl}.admin</span>
93 %endif
93 %endif
94 %else:
94 %else:
95 %if not val_lbl:
95 %if not val_lbl:
96 ${{'false': False,
96 ${{'false': False,
97 'true': True,
97 'true': True,
98 'none': False,
98 'none': False,
99 'repository': True}.get(val[1][0] if 0 < len(val[1]) else 'false')}
99 'repository': True}.get(val[1][0] if 0 < len(val[1]) else 'false')}
100 %else:
100 %else:
101 <span class="perm_tag ${val[1][0]}">${val_lbl}.${val[1][0]}</span>
101 <span class="perm_tag ${val[1][0]}">${val_lbl}.${val[1][0]}</span>
102 %endif
102 %endif
103 %endif
103 %endif
104 </td>
104 </td>
105 %if actions:
105 %if actions:
106
106
107 % if edit_url or edit_global_url:
107 % if edit_url or edit_global_url:
108
108
109 <td class="td-action">
109 <td class="td-action">
110 % if edit_url:
110 % if edit_url:
111 <a href="${edit_url}">${_('edit')}</a>
111 <a href="${edit_url}">${_('edit')}</a>
112 % else:
112 % else:
113 -
113 -
114 % endif
114 % endif
115 </td>
115 </td>
116
116
117 <td class="td-action">
117 <td class="td-action">
118 % if edit_global_url:
118 % if edit_global_url:
119 <a href="${edit_global_url}">${_('edit global')}</a>
119 <a href="${edit_global_url}">${_('edit global')}</a>
120 % else:
120 % else:
121 -
121 -
122 % endif
122 % endif
123 </td>
123 </td>
124
124
125 % else:
125 % else:
126 <td class="td-action"></td>
126 <td class="td-action"></td>
127 <td class="td-action">
127 <td class="td-action">
128 <a href="${h.route_path('admin_permissions_global')}">${_('edit global')}</a>
128 <a href="${h.route_path('admin_permissions_global')}">${_('edit global')}</a>
129 <td class="td-action">
129 <td class="td-action">
130 % endif
130 % endif
131
131
132 %endif
132 %endif
133 </tr>
133 </tr>
134 </%def>
134 </%def>
135
135
136 ${glob(_('Repository default permission'), get_section_perms('repository.', permissions[section]), 'repository',
136 ${glob(_('Repository default permission'), get_section_perms('repository.', permissions[section]), 'repository',
137 edit_url=None, edit_global_url=h.route_path('admin_permissions_object'))}
137 edit_url=None, edit_global_url=h.route_path('admin_permissions_object'))}
138
138
139 ${glob(_('Repository group default permission'), get_section_perms('group.', permissions[section]), 'group',
139 ${glob(_('Repository group default permission'), get_section_perms('group.', permissions[section]), 'group',
140 edit_url=None, edit_global_url=h.route_path('admin_permissions_object'))}
140 edit_url=None, edit_global_url=h.route_path('admin_permissions_object'))}
141
141
142 ${glob(_('User group default permission'), get_section_perms('usergroup.', permissions[section]), 'usergroup',
142 ${glob(_('User group default permission'), get_section_perms('usergroup.', permissions[section]), 'usergroup',
143 edit_url=None, edit_global_url=h.route_path('admin_permissions_object'))}
143 edit_url=None, edit_global_url=h.route_path('admin_permissions_object'))}
144
144
145 ${glob(_('Super admin'), get_section_perms('hg.admin', permissions[section]),
145 ${glob(_('Super admin'), get_section_perms('hg.admin', permissions[section]),
146 edit_url=h.route_path('user_edit', user_id=c.user.user_id, _anchor='admin'), edit_global_url=None)}
146 edit_url=h.route_path('user_edit', user_id=c.user.user_id, _anchor='admin'), edit_global_url=None)}
147
147
148 ${glob(_('Inherit permissions'), get_section_perms('hg.inherit_default_perms.', permissions[section]),
148 ${glob(_('Inherit permissions'), get_section_perms('hg.inherit_default_perms.', permissions[section]),
149 edit_url=h.route_path('user_edit_global_perms', user_id=c.user.user_id), edit_global_url=None)}
149 edit_url=h.route_path('user_edit_global_perms', user_id=c.user.user_id), edit_global_url=None)}
150
150
151 ${glob(_('Create repositories'), get_section_perms('hg.create.', permissions[section]),
151 ${glob(_('Create repositories'), get_section_perms('hg.create.', permissions[section]),
152 edit_url=h.route_path('user_edit_global_perms', user_id=c.user.user_id), edit_global_url=h.route_path('admin_permissions_object'))}
152 edit_url=h.route_path('user_edit_global_perms', user_id=c.user.user_id), edit_global_url=h.route_path('admin_permissions_object'))}
153
153
154 ${glob(_('Fork repositories'), get_section_perms('hg.fork.', permissions[section]),
154 ${glob(_('Fork repositories'), get_section_perms('hg.fork.', permissions[section]),
155 edit_url=h.route_path('user_edit_global_perms', user_id=c.user.user_id), edit_global_url=h.route_path('admin_permissions_object'))}
155 edit_url=h.route_path('user_edit_global_perms', user_id=c.user.user_id), edit_global_url=h.route_path('admin_permissions_object'))}
156
156
157 ${glob(_('Create repository groups'), get_section_perms('hg.repogroup.create.', permissions[section]),
157 ${glob(_('Create repository groups'), get_section_perms('hg.repogroup.create.', permissions[section]),
158 edit_url=h.route_path('user_edit_global_perms', user_id=c.user.user_id), edit_global_url=h.route_path('admin_permissions_object'))}
158 edit_url=h.route_path('user_edit_global_perms', user_id=c.user.user_id), edit_global_url=h.route_path('admin_permissions_object'))}
159
159
160 ${glob(_('Create user groups'), get_section_perms('hg.usergroup.create.', permissions[section]),
160 ${glob(_('Create user groups'), get_section_perms('hg.usergroup.create.', permissions[section]),
161 edit_url=h.route_path('user_edit_global_perms', user_id=c.user.user_id), edit_global_url=h.route_path('admin_permissions_object'))}
161 edit_url=h.route_path('user_edit_global_perms', user_id=c.user.user_id), edit_global_url=h.route_path('admin_permissions_object'))}
162
162
163 </tbody>
163 </tbody>
164 ## Branch perms
164 ## Branch perms
165 %elif section == 'repository_branches':
165 %elif section == 'repository_branches':
166 <thead>
166 <thead>
167 <tr>
167 <tr>
168 <th>${_('Name')}</th>
168 <th>${_('Name')}</th>
169 <th>${_('Pattern')}</th>
169 <th>${_('Pattern')}</th>
170 <th>${_('Permission')}</th>
170 <th>${_('Permission')}</th>
171 %if actions:
171 %if actions:
172 <th>${_('Edit Branch Permission')}</th>
172 <th>${_('Edit Branch Permission')}</th>
173 %endif
173 %endif
174 </thead>
174 </thead>
175 <tbody class="section_${section}">
175 <tbody class="section_${section}">
176 <%
176 <%
177 def name_sorter(permissions):
177 def name_sorter(permissions):
178 def custom_sorter(item):
178 def custom_sorter(item):
179 return item[0]
179 return item[0]
180 return sorted(permissions, key=custom_sorter)
180 return sorted(permissions, key=custom_sorter)
181
181
182 def branch_sorter(permissions):
182 def branch_sorter(permissions):
183 def custom_sorter(item):
183 def custom_sorter(item):
184 ## none, merge, push, push_force
184 ## none, merge, push, push_force
185 section = item[1].split('.')[-1]
185 section = item[1].split('.')[-1]
186 section_importance = {'none': u'0',
186 section_importance = {'none': u'0',
187 'merge': u'1',
187 'merge': u'1',
188 'push': u'2',
188 'push': u'2',
189 'push_force': u'3'}.get(section)
189 'push_force': u'3'}.get(section)
190 ## sort by importance + name
190 ## sort by importance + name
191 return section_importance + item[0]
191 return section_importance + item[0]
192 return sorted(permissions, key=custom_sorter)
192 return sorted(permissions, key=custom_sorter)
193 %>
193 %>
194 %for k, section_perms in name_sorter(permissions[section].items()):
194 %for k, section_perms in name_sorter(permissions[section].items()):
195 ## for display purposes, for non super-admins we need to check if shown
195 ## for display purposes, for non super-admins we need to check if shown
196 ## repository is actually accessible for user
196 ## repository is actually accessible for user
197 <% repo_perm = permissions['repositories'][k] %>
197 <% repo_perm = permissions['repositories'][k] %>
198 % if repo_perm == 'repository.none' and not c.rhodecode_user.is_admin:
198 % if repo_perm == 'repository.none' and not c.rhodecode_user.is_admin:
199 ## skip this entry
199 ## skip this entry
200 <% continue %>
200 <% continue %>
201 % endif
201 % endif
202
202
203 <% total_counter +=1 %>
203 <% total_counter +=1 %>
204 % for pattern, perm in branch_sorter(section_perms.items()):
204 % for pattern, perm in branch_sorter(section_perms.items()):
205 <tr class="perm_row ${'{}_{}'.format(section, perm.split('.')[-1])}">
205 <tr class="perm_row ${'{}_{}'.format(section, perm.split('.')[-1])}">
206 <td class="td-name">
206 <td class="td-name">
207 <a href="${h.route_path('repo_summary',repo_name=k)}">${k}</a>
207 <a href="${h.route_path('repo_summary',repo_name=k)}">${k}</a>
208 </td>
208 </td>
209 <td>${pattern}</td>
209 <td>${pattern}</td>
210 <td class="td-tags">
210 <td class="td-tags">
211 ## TODO: calculate origin somehow
211 ## TODO: calculate origin somehow
212 ## % for i, ((_pat, perm), origin) in enumerate((permissions[section].perm_origin_stack[k])):
212 ## % for i, ((_pat, perm), origin) in enumerate((permissions[section].perm_origin_stack[k])):
213
213
214 <div>
214 <div>
215 <% i = 0 %>
215 <% i = 0 %>
216 <% origin = 'unknown' %>
216 <% origin = 'unknown' %>
217 <% _css_class = i > 0 and 'perm_overriden' or '' %>
217 <% _css_class = i > 0 and 'perm_overriden' or '' %>
218
218
219 <span class="${_css_class} perm_tag ${perm.split('.')[-1]}">
219 <span class="${_css_class} perm_tag ${perm.split('.')[-1]}">
220 ${perm}
220 ${perm}
221 ##(${origin})
221 ##(${origin})
222 </span>
222 </span>
223 </div>
223 </div>
224 ## % endfor
224 ## % endfor
225 </td>
225 </td>
226 %if actions:
226 %if actions:
227 <td class="td-action">
227 <td class="td-action">
228 <a href="${h.route_path('edit_repo_perms_branch',repo_name=k)}">${_('edit')}</a>
228 <a href="${h.route_path('edit_repo_perms_branch',repo_name=k)}">${_('edit')}</a>
229 </td>
229 </td>
230 %endif
230 %endif
231 </tr>
231 </tr>
232 % endfor
232 % endfor
233 %endfor
233 %endfor
234 </tbody>
234 </tbody>
235
235
236 ## Repos/Repo Groups/users groups perms
236 ## Repos/Repo Groups/users groups perms
237 %else:
237 %else:
238
238
239 ## none/read/write/admin permissions on groups/repos etc
239 ## none/read/write/admin permissions on groups/repos etc
240 <thead>
240 <thead>
241 <tr>
241 <tr>
242 <th>${_('Name')}</th>
242 <th>${_('Name')}</th>
243 <th>${_('Permission')}</th>
243 <th>${_('Permission')}</th>
244 %if actions:
244 %if actions:
245 <th>${_('Edit Permission')}</th>
245 <th>${_('Edit Permission')}</th>
246 %endif
246 %endif
247 </thead>
247 </thead>
248 <tbody class="section_${section}">
248 <tbody class="section_${section}">
249 <%
249 <%
250 def sorter(permissions):
250 def sorter(permissions):
251 def custom_sorter(item):
251 def custom_sorter(item):
252 ## read/write/admin
252 ## read/write/admin
253 section = item[1].split('.')[-1]
253 section = item[1].split('.')[-1]
254 section_importance = {'none': u'0',
254 section_importance = {'none': u'0',
255 'read': u'1',
255 'read': u'1',
256 'write':u'2',
256 'write':u'2',
257 'admin':u'3'}.get(section)
257 'admin':u'3'}.get(section)
258 ## sort by group importance+name
258 ## sort by group importance+name
259 return section_importance+item[0]
259 return section_importance+item[0]
260 return sorted(permissions, key=custom_sorter)
260 return sorted(permissions, key=custom_sorter)
261 %>
261 %>
262 %for k, section_perm in sorter(permissions[section].items()):
262 %for k, section_perm in sorter(permissions[section].items()):
263 <% perm_value = section_perm.split('.')[-1] %>
263 <% perm_value = section_perm.split('.')[-1] %>
264 <% _css_class = 'display:none' if perm_value in ['none'] else '' %>
264 <% _css_class = 'display:none' if perm_value in ['none'] else '' %>
265
265
266 %if perm_value != 'none' or show_all:
266 %if perm_value != 'none' or show_all:
267 <tr class="perm_row ${'{}_{}'.format(section, section_perm.split('.')[-1])}" style="${_css_class}">
267 <tr class="perm_row ${'{}_{}'.format(section, section_perm.split('.')[-1])}" style="${_css_class}">
268 <td class="td-name">
268 <td class="td-name">
269 %if section == 'repositories':
269 %if section == 'repositories':
270 <a href="${h.route_path('repo_summary',repo_name=k)}">${k}</a>
270 <a href="${h.route_path('repo_summary',repo_name=k)}">${k}</a>
271 %elif section == 'repositories_groups':
271 %elif section == 'repositories_groups':
272 <a href="${h.route_path('repo_group_home', repo_group_name=k)}">${k}</a>
272 <a href="${h.route_path('repo_group_home', repo_group_name=k)}">${k}</a>
273 %elif section == 'user_groups':
273 %elif section == 'user_groups':
274 ##<a href="${h.route_path('edit_user_group',user_group_id=k)}">${k}</a>
274 ##<a href="${h.route_path('edit_user_group',user_group_id=k)}">${k}</a>
275 ${k}
275 ${k}
276 %endif
276 %endif
277 </td>
277 </td>
278 <td class="td-tags">
278 <td class="td-tags">
279 %if hasattr(permissions[section], 'perm_origin_stack'):
279 %if hasattr(permissions[section], 'perm_origin_stack'):
280 <div>
280 <div>
281 %for i, (perm, origin) in enumerate(reversed(permissions[section].perm_origin_stack[k])):
281 %for i, (perm, origin) in enumerate(reversed(permissions[section].perm_origin_stack[k])):
282 <% _css_class = i > 0 and 'perm_overriden' or '' %>
282 <% _css_class = i > 0 and 'perm_overriden' or '' %>
283 % if i > 0:
283 % if i > 0:
284 <div style="color: #979797">
284 <div style="color: #979797">
285 <i class="icon-arrow_up"></i>
285 <i class="icon-arrow_up"></i>
286 ${_('overridden by')}
286 ${_('overridden by')}
287 <i class="icon-arrow_up"></i>
287 <i class="icon-arrow_up"></i>
288 </div>
288 </div>
289 % endif
289 % endif
290
290
291 <div>
291 <div>
292 <span class="${_css_class} perm_tag ${perm.split('.')[-1]}">
292 <span class="${_css_class} perm_tag ${perm.split('.')[-1]}">
293 ${perm} (${origin})
293 ${perm} (${origin})
294 </span>
294 </span>
295 </div>
295 </div>
296
296
297 %endfor
297 %endfor
298 </div>
298 </div>
299 %else:
299 %else:
300 <span class="perm_tag ${section_perm.split('.')[-1]}">${section_perm}</span>
300 <span class="perm_tag ${section_perm.split('.')[-1]}">${section_perm}</span>
301 %endif
301 %endif
302 </td>
302 </td>
303 %if actions:
303 %if actions:
304 <td class="td-action">
304 <td class="td-action">
305 %if section == 'repositories':
305 %if section == 'repositories':
306 <a href="${h.route_path('edit_repo_perms',repo_name=k,_anchor='permissions_manage')}">${_('edit')}</a>
306 <a href="${h.route_path('edit_repo_perms',repo_name=k,_anchor='permissions_manage')}">${_('edit')}</a>
307 %elif section == 'repositories_groups':
307 %elif section == 'repositories_groups':
308 <a href="${h.route_path('edit_repo_group_perms',repo_group_name=k,_anchor='permissions_manage')}">${_('edit')}</a>
308 <a href="${h.route_path('edit_repo_group_perms',repo_group_name=k,_anchor='permissions_manage')}">${_('edit')}</a>
309 %elif section == 'user_groups':
309 %elif section == 'user_groups':
310 ##<a href="${h.route_path('edit_user_group',user_group_id=k)}">${_('edit')}</a>
310 ##<a href="${h.route_path('edit_user_group',user_group_id=k)}">${_('edit')}</a>
311 %endif
311 %endif
312 </td>
312 </td>
313 %endif
313 %endif
314 </tr>
314 </tr>
315 <% total_counter +=1 %>
315 <% total_counter +=1 %>
316 %endif
316 %endif
317
317
318 %endfor
318 %endfor
319
319
320 <tr id="empty_${section}" class="noborder" style="display:none;">
320 <tr id="empty_${section}" class="noborder" style="display:none;">
321 <td colspan="6">${_('No matching permission defined')}</td>
321 <td colspan="6">${_('No matching permission defined')}</td>
322 </tr>
322 </tr>
323
323
324 </tbody>
324 </tbody>
325 %endif
325 %endif
326 </table>
326 </table>
327 </div>
327 </div>
328 %endif
328 %endif
329 </div>
329 </div>
330 </div>
330 </div>
331 </div>
331 </div>
332
332
333 <script>
333 <script>
334 $('#total_count_${section}').html(${total_counter})
334 $('#total_count_${section}').html(${total_counter})
335 </script>
335 </script>
336
336
337 %endfor
337 %endfor
338 </div>
338 </div>
339
339
340 <script>
340 <script>
341 $(document).ready(function(){
341 $(document).ready(function(){
342 var showEmpty = function(section){
342 var showEmpty = function(section){
343 var visible = $('.section_{0} tr.perm_row:visible'.format(section)).length;
343 var visible = $('.section_{0} tr.perm_row:visible'.format(section)).length;
344 if(visible === 0){
344 if(visible === 0){
345 $('#empty_{0}'.format(section)).show();
345 $('#empty_{0}'.format(section)).show();
346 }
346 }
347 else{
347 else{
348 $('#empty_{0}'.format(section)).hide();
348 $('#empty_{0}'.format(section)).hide();
349 }
349 }
350 };
350 };
351
351
352 $('.perm_filter').on('change', function(e){
352 $('.perm_filter').on('change', function(e){
353 var self = this;
353 var self = this;
354 var section = $(this).attr('section');
354 var section = $(this).attr('section');
355
355
356 var opts = {};
356 var opts = {};
357 var elems = $('.filter_' + section).each(function(el){
357 var elems = $('.filter_' + section).each(function(el){
358 var perm_type = $(this).attr('perm_type');
358 var perm_type = $(this).attr('perm_type');
359 var checked = this.checked;
359 var checked = this.checked;
360 opts[perm_type] = checked;
360 opts[perm_type] = checked;
361 if(checked){
361 if(checked){
362 $('.'+section+'_'+perm_type).show();
362 $('.'+section+'_'+perm_type).show();
363 }
363 }
364 else{
364 else{
365 $('.'+section+'_'+perm_type).hide();
365 $('.'+section+'_'+perm_type).hide();
366 }
366 }
367 });
367 });
368 showEmpty(section);
368 showEmpty(section);
369 })
369 })
370 })
370 })
371 </script>
371 </script>
372 </%def>
372 </%def>
General Comments 0
You need to be logged in to leave comments. Login now