##// END OF EJS Templates
Include the current user as a created_by/deleted_by attribute for USER_HOOK extensions.
Jonathan Sternberg -
r4017:509923da default
parent child Browse files
Show More
@@ -1,190 +1,192 b''
1 # Additional mappings that are not present in the pygments lexers
1 # Additional mappings that are not present in the pygments lexers
2 # used for building stats
2 # used for building stats
3 # format is {'ext':['Names']} eg. {'py':['Python']} note: there can be
3 # format is {'ext':['Names']} eg. {'py':['Python']} note: there can be
4 # more than one name for extension
4 # more than one name for extension
5 # NOTE: that this will overide any mappings in LANGUAGES_EXTENSIONS_MAP
5 # NOTE: that this will overide any mappings in LANGUAGES_EXTENSIONS_MAP
6 # build by pygments
6 # build by pygments
7 EXTRA_MAPPINGS = {}
7 EXTRA_MAPPINGS = {}
8
8
9 # additional lexer definitions for custom files
9 # additional lexer definitions for custom files
10 # it's overrides pygments lexers, and uses defined name of lexer to colorize the
10 # it's overrides pygments lexers, and uses defined name of lexer to colorize the
11 # files. Format is {'ext': 'lexer_name'}
11 # files. Format is {'ext': 'lexer_name'}
12 # List of lexers can be printed running:
12 # List of lexers can be printed running:
13 # python -c "import pprint;from pygments import lexers;pprint.pprint([(x[0], x[1]) for x in lexers.get_all_lexers()]);"
13 # python -c "import pprint;from pygments import lexers;pprint.pprint([(x[0], x[1]) for x in lexers.get_all_lexers()]);"
14
14
15 EXTRA_LEXERS = {}
15 EXTRA_LEXERS = {}
16
16
17 #==============================================================================
17 #==============================================================================
18 # WHOOSH INDEX EXTENSIONS
18 # WHOOSH INDEX EXTENSIONS
19 #==============================================================================
19 #==============================================================================
20 # if INDEX_EXTENSIONS is [] it'll use pygments lexers extensions by default.
20 # if INDEX_EXTENSIONS is [] it'll use pygments lexers extensions by default.
21 # To set your own just add to this list extensions to index with content
21 # To set your own just add to this list extensions to index with content
22 INDEX_EXTENSIONS = []
22 INDEX_EXTENSIONS = []
23
23
24 # additional extensions for indexing besides the default from pygments
24 # additional extensions for indexing besides the default from pygments
25 # those get's added to INDEX_EXTENSIONS
25 # those get's added to INDEX_EXTENSIONS
26 EXTRA_INDEX_EXTENSIONS = []
26 EXTRA_INDEX_EXTENSIONS = []
27
27
28
28
29 #==============================================================================
29 #==============================================================================
30 # POST CREATE REPOSITORY HOOK
30 # POST CREATE REPOSITORY HOOK
31 #==============================================================================
31 #==============================================================================
32 # this function will be executed after each repository is created
32 # this function will be executed after each repository is created
33 def _crrepohook(*args, **kwargs):
33 def _crrepohook(*args, **kwargs):
34 """
34 """
35 Post create repository HOOK
35 Post create repository HOOK
36 kwargs available:
36 kwargs available:
37 :param repo_name:
37 :param repo_name:
38 :param repo_type:
38 :param repo_type:
39 :param description:
39 :param description:
40 :param private:
40 :param private:
41 :param created_on:
41 :param created_on:
42 :param enable_downloads:
42 :param enable_downloads:
43 :param repo_id:
43 :param repo_id:
44 :param user_id:
44 :param user_id:
45 :param enable_statistics:
45 :param enable_statistics:
46 :param clone_uri:
46 :param clone_uri:
47 :param fork_id:
47 :param fork_id:
48 :param group_id:
48 :param group_id:
49 :param created_by:
49 :param created_by:
50 """
50 """
51 return 0
51 return 0
52 CREATE_REPO_HOOK = _crrepohook
52 CREATE_REPO_HOOK = _crrepohook
53
53
54
54
55 #==============================================================================
55 #==============================================================================
56 # POST CREATE USER HOOK
56 # POST CREATE USER HOOK
57 #==============================================================================
57 #==============================================================================
58 # this function will be executed after each user is created
58 # this function will be executed after each user is created
59 def _cruserhook(*args, **kwargs):
59 def _cruserhook(*args, **kwargs):
60 """
60 """
61 Post create user HOOK
61 Post create user HOOK
62 kwargs available:
62 kwargs available:
63 :param username:
63 :param username:
64 :param full_name_or_username:
64 :param full_name_or_username:
65 :param full_contact:
65 :param full_contact:
66 :param user_id:
66 :param user_id:
67 :param name:
67 :param name:
68 :param firstname:
68 :param firstname:
69 :param short_contact:
69 :param short_contact:
70 :param admin:
70 :param admin:
71 :param lastname:
71 :param lastname:
72 :param ip_addresses:
72 :param ip_addresses:
73 :param ldap_dn:
73 :param ldap_dn:
74 :param email:
74 :param email:
75 :param api_key:
75 :param api_key:
76 :param last_login:
76 :param last_login:
77 :param full_name:
77 :param full_name:
78 :param active:
78 :param active:
79 :param password:
79 :param password:
80 :param emails:
80 :param emails:
81 :param inherit_default_permissions:
81 :param inherit_default_permissions:
82 :param created_by:
82 """
83 """
83 return 0
84 return 0
84 CREATE_USER_HOOK = _cruserhook
85 CREATE_USER_HOOK = _cruserhook
85
86
86
87
87 #==============================================================================
88 #==============================================================================
88 # POST DELETE REPOSITORY HOOK
89 # POST DELETE REPOSITORY HOOK
89 #==============================================================================
90 #==============================================================================
90 # this function will be executed after each repository deletion
91 # this function will be executed after each repository deletion
91 def _dlrepohook(*args, **kwargs):
92 def _dlrepohook(*args, **kwargs):
92 """
93 """
93 Post delete repository HOOK
94 Post delete repository HOOK
94 kwargs available:
95 kwargs available:
95 :param repo_name:
96 :param repo_name:
96 :param repo_type:
97 :param repo_type:
97 :param description:
98 :param description:
98 :param private:
99 :param private:
99 :param created_on:
100 :param created_on:
100 :param enable_downloads:
101 :param enable_downloads:
101 :param repo_id:
102 :param repo_id:
102 :param user_id:
103 :param user_id:
103 :param enable_statistics:
104 :param enable_statistics:
104 :param clone_uri:
105 :param clone_uri:
105 :param fork_id:
106 :param fork_id:
106 :param group_id:
107 :param group_id:
107 :param deleted_by:
108 :param deleted_by:
108 :param deleted_on:
109 :param deleted_on:
109 """
110 """
110 return 0
111 return 0
111 DELETE_REPO_HOOK = _dlrepohook
112 DELETE_REPO_HOOK = _dlrepohook
112
113
113
114
114 #==============================================================================
115 #==============================================================================
115 # POST DELETE USER HOOK
116 # POST DELETE USER HOOK
116 #==============================================================================
117 #==============================================================================
117 # this function will be executed after each user is deleted
118 # this function will be executed after each user is deleted
118 def _dluserhook(*args, **kwargs):
119 def _dluserhook(*args, **kwargs):
119 """
120 """
120 Post delete user HOOK
121 Post delete user HOOK
121 kwargs available:
122 kwargs available:
122 :param username:
123 :param username:
123 :param full_name_or_username:
124 :param full_name_or_username:
124 :param full_contact:
125 :param full_contact:
125 :param user_id:
126 :param user_id:
126 :param name:
127 :param name:
127 :param firstname:
128 :param firstname:
128 :param short_contact:
129 :param short_contact:
129 :param admin:
130 :param admin:
130 :param lastname:
131 :param lastname:
131 :param ip_addresses:
132 :param ip_addresses:
132 :param ldap_dn:
133 :param ldap_dn:
133 :param email:
134 :param email:
134 :param api_key:
135 :param api_key:
135 :param last_login:
136 :param last_login:
136 :param full_name:
137 :param full_name:
137 :param active:
138 :param active:
138 :param password:
139 :param password:
139 :param emails:
140 :param emails:
140 :param inherit_default_permissions:
141 :param inherit_default_permissions:
142 :param deleted_by:
141 """
143 """
142 return 0
144 return 0
143 DELETE_USER_HOOK = _dluserhook
145 DELETE_USER_HOOK = _dluserhook
144
146
145
147
146 #==============================================================================
148 #==============================================================================
147 # POST PUSH HOOK
149 # POST PUSH HOOK
148 #==============================================================================
150 #==============================================================================
149
151
150 # this function will be executed after each push it's executed after the
152 # this function will be executed after each push it's executed after the
151 # build-in hook that RhodeCode uses for logging pushes
153 # build-in hook that RhodeCode uses for logging pushes
152 def _pushhook(*args, **kwargs):
154 def _pushhook(*args, **kwargs):
153 """
155 """
154 Post push hook
156 Post push hook
155 kwargs available:
157 kwargs available:
156
158
157 :param server_url: url of instance that triggered this hook
159 :param server_url: url of instance that triggered this hook
158 :param config: path to .ini config used
160 :param config: path to .ini config used
159 :param scm: type of VS 'git' or 'hg'
161 :param scm: type of VS 'git' or 'hg'
160 :param username: name of user who pushed
162 :param username: name of user who pushed
161 :param ip: ip of who pushed
163 :param ip: ip of who pushed
162 :param action: push
164 :param action: push
163 :param repository: repository name
165 :param repository: repository name
164 :param pushed_revs: list of pushed revisions
166 :param pushed_revs: list of pushed revisions
165 """
167 """
166 return 0
168 return 0
167 PUSH_HOOK = _pushhook
169 PUSH_HOOK = _pushhook
168
170
169
171
170 #==============================================================================
172 #==============================================================================
171 # POST PULL HOOK
173 # POST PULL HOOK
172 #==============================================================================
174 #==============================================================================
173
175
174 # this function will be executed after each push it's executed after the
176 # this function will be executed after each push it's executed after the
175 # build-in hook that RhodeCode uses for logging pulls
177 # build-in hook that RhodeCode uses for logging pulls
176 def _pullhook(*args, **kwargs):
178 def _pullhook(*args, **kwargs):
177 """
179 """
178 Post pull hook
180 Post pull hook
179 kwargs available::
181 kwargs available::
180
182
181 :param server_url: url of instance that triggered this hook
183 :param server_url: url of instance that triggered this hook
182 :param config: path to .ini config used
184 :param config: path to .ini config used
183 :param scm: type of VS 'git' or 'hg'
185 :param scm: type of VS 'git' or 'hg'
184 :param username: name of user who pulled
186 :param username: name of user who pulled
185 :param ip: ip of who pulled
187 :param ip: ip of who pulled
186 :param action: pull
188 :param action: pull
187 :param repository: repository name
189 :param repository: repository name
188 """
190 """
189 return 0
191 return 0
190 PULL_HOOK = _pullhook
192 PULL_HOOK = _pullhook
@@ -1,463 +1,463 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.hooks
3 rhodecode.lib.hooks
4 ~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~
5
5
6 Hooks runned by rhodecode
6 Hooks runned by rhodecode
7
7
8 :created_on: Aug 6, 2010
8 :created_on: Aug 6, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 import os
25 import os
26 import sys
26 import sys
27 import time
27 import time
28 import binascii
28 import binascii
29 import traceback
29 import traceback
30 from inspect import isfunction
30 from inspect import isfunction
31
31
32 from rhodecode.lib.vcs.utils.hgcompat import nullrev, revrange
32 from rhodecode.lib.vcs.utils.hgcompat import nullrev, revrange
33 from rhodecode.lib import helpers as h
33 from rhodecode.lib import helpers as h
34 from rhodecode.lib.utils import action_logger
34 from rhodecode.lib.utils import action_logger
35 from rhodecode.lib.vcs.backends.base import EmptyChangeset
35 from rhodecode.lib.vcs.backends.base import EmptyChangeset
36 from rhodecode.lib.compat import json
36 from rhodecode.lib.compat import json
37 from rhodecode.lib.exceptions import HTTPLockedRC
37 from rhodecode.lib.exceptions import HTTPLockedRC
38 from rhodecode.lib.utils2 import safe_str, _extract_extras
38 from rhodecode.lib.utils2 import safe_str, _extract_extras
39 from rhodecode.model.db import Repository, User
39 from rhodecode.model.db import Repository, User
40
40
41
41
42 def _get_scm_size(alias, root_path):
42 def _get_scm_size(alias, root_path):
43
43
44 if not alias.startswith('.'):
44 if not alias.startswith('.'):
45 alias += '.'
45 alias += '.'
46
46
47 size_scm, size_root = 0, 0
47 size_scm, size_root = 0, 0
48 for path, dirs, files in os.walk(safe_str(root_path)):
48 for path, dirs, files in os.walk(safe_str(root_path)):
49 if path.find(alias) != -1:
49 if path.find(alias) != -1:
50 for f in files:
50 for f in files:
51 try:
51 try:
52 size_scm += os.path.getsize(os.path.join(path, f))
52 size_scm += os.path.getsize(os.path.join(path, f))
53 except OSError:
53 except OSError:
54 pass
54 pass
55 else:
55 else:
56 for f in files:
56 for f in files:
57 try:
57 try:
58 size_root += os.path.getsize(os.path.join(path, f))
58 size_root += os.path.getsize(os.path.join(path, f))
59 except OSError:
59 except OSError:
60 pass
60 pass
61
61
62 size_scm_f = h.format_byte_size(size_scm)
62 size_scm_f = h.format_byte_size(size_scm)
63 size_root_f = h.format_byte_size(size_root)
63 size_root_f = h.format_byte_size(size_root)
64 size_total_f = h.format_byte_size(size_root + size_scm)
64 size_total_f = h.format_byte_size(size_root + size_scm)
65
65
66 return size_scm_f, size_root_f, size_total_f
66 return size_scm_f, size_root_f, size_total_f
67
67
68
68
69 def repo_size(ui, repo, hooktype=None, **kwargs):
69 def repo_size(ui, repo, hooktype=None, **kwargs):
70 """
70 """
71 Presents size of repository after push
71 Presents size of repository after push
72
72
73 :param ui:
73 :param ui:
74 :param repo:
74 :param repo:
75 :param hooktype:
75 :param hooktype:
76 """
76 """
77
77
78 size_hg_f, size_root_f, size_total_f = _get_scm_size('.hg', repo.root)
78 size_hg_f, size_root_f, size_total_f = _get_scm_size('.hg', repo.root)
79
79
80 last_cs = repo[len(repo) - 1]
80 last_cs = repo[len(repo) - 1]
81
81
82 msg = ('Repository size .hg:%s repo:%s total:%s\n'
82 msg = ('Repository size .hg:%s repo:%s total:%s\n'
83 'Last revision is now r%s:%s\n') % (
83 'Last revision is now r%s:%s\n') % (
84 size_hg_f, size_root_f, size_total_f, last_cs.rev(), last_cs.hex()[:12]
84 size_hg_f, size_root_f, size_total_f, last_cs.rev(), last_cs.hex()[:12]
85 )
85 )
86
86
87 sys.stdout.write(msg)
87 sys.stdout.write(msg)
88
88
89
89
90 def pre_push(ui, repo, **kwargs):
90 def pre_push(ui, repo, **kwargs):
91 # pre push function, currently used to ban pushing when
91 # pre push function, currently used to ban pushing when
92 # repository is locked
92 # repository is locked
93 ex = _extract_extras()
93 ex = _extract_extras()
94
94
95 usr = User.get_by_username(ex.username)
95 usr = User.get_by_username(ex.username)
96 if ex.locked_by[0] and usr.user_id != int(ex.locked_by[0]):
96 if ex.locked_by[0] and usr.user_id != int(ex.locked_by[0]):
97 locked_by = User.get(ex.locked_by[0]).username
97 locked_by = User.get(ex.locked_by[0]).username
98 # this exception is interpreted in git/hg middlewares and based
98 # this exception is interpreted in git/hg middlewares and based
99 # on that proper return code is server to client
99 # on that proper return code is server to client
100 _http_ret = HTTPLockedRC(ex.repository, locked_by)
100 _http_ret = HTTPLockedRC(ex.repository, locked_by)
101 if str(_http_ret.code).startswith('2'):
101 if str(_http_ret.code).startswith('2'):
102 #2xx Codes don't raise exceptions
102 #2xx Codes don't raise exceptions
103 sys.stdout.write(_http_ret.title)
103 sys.stdout.write(_http_ret.title)
104 else:
104 else:
105 raise _http_ret
105 raise _http_ret
106
106
107
107
108 def pre_pull(ui, repo, **kwargs):
108 def pre_pull(ui, repo, **kwargs):
109 # pre push function, currently used to ban pushing when
109 # pre push function, currently used to ban pushing when
110 # repository is locked
110 # repository is locked
111 ex = _extract_extras()
111 ex = _extract_extras()
112 if ex.locked_by[0]:
112 if ex.locked_by[0]:
113 locked_by = User.get(ex.locked_by[0]).username
113 locked_by = User.get(ex.locked_by[0]).username
114 # this exception is interpreted in git/hg middlewares and based
114 # this exception is interpreted in git/hg middlewares and based
115 # on that proper return code is server to client
115 # on that proper return code is server to client
116 _http_ret = HTTPLockedRC(ex.repository, locked_by)
116 _http_ret = HTTPLockedRC(ex.repository, locked_by)
117 if str(_http_ret.code).startswith('2'):
117 if str(_http_ret.code).startswith('2'):
118 #2xx Codes don't raise exceptions
118 #2xx Codes don't raise exceptions
119 sys.stdout.write(_http_ret.title)
119 sys.stdout.write(_http_ret.title)
120 else:
120 else:
121 raise _http_ret
121 raise _http_ret
122
122
123
123
124 def log_pull_action(ui, repo, **kwargs):
124 def log_pull_action(ui, repo, **kwargs):
125 """
125 """
126 Logs user last pull action
126 Logs user last pull action
127
127
128 :param ui:
128 :param ui:
129 :param repo:
129 :param repo:
130 """
130 """
131 ex = _extract_extras()
131 ex = _extract_extras()
132
132
133 user = User.get_by_username(ex.username)
133 user = User.get_by_username(ex.username)
134 action = 'pull'
134 action = 'pull'
135 action_logger(user, action, ex.repository, ex.ip, commit=True)
135 action_logger(user, action, ex.repository, ex.ip, commit=True)
136 # extension hook call
136 # extension hook call
137 from rhodecode import EXTENSIONS
137 from rhodecode import EXTENSIONS
138 callback = getattr(EXTENSIONS, 'PULL_HOOK', None)
138 callback = getattr(EXTENSIONS, 'PULL_HOOK', None)
139 if isfunction(callback):
139 if isfunction(callback):
140 kw = {}
140 kw = {}
141 kw.update(ex)
141 kw.update(ex)
142 callback(**kw)
142 callback(**kw)
143
143
144 if ex.make_lock is not None and ex.make_lock:
144 if ex.make_lock is not None and ex.make_lock:
145 Repository.lock(Repository.get_by_repo_name(ex.repository), user.user_id)
145 Repository.lock(Repository.get_by_repo_name(ex.repository), user.user_id)
146 #msg = 'Made lock on repo `%s`' % repository
146 #msg = 'Made lock on repo `%s`' % repository
147 #sys.stdout.write(msg)
147 #sys.stdout.write(msg)
148
148
149 if ex.locked_by[0]:
149 if ex.locked_by[0]:
150 locked_by = User.get(ex.locked_by[0]).username
150 locked_by = User.get(ex.locked_by[0]).username
151 _http_ret = HTTPLockedRC(ex.repository, locked_by)
151 _http_ret = HTTPLockedRC(ex.repository, locked_by)
152 if str(_http_ret.code).startswith('2'):
152 if str(_http_ret.code).startswith('2'):
153 #2xx Codes don't raise exceptions
153 #2xx Codes don't raise exceptions
154 sys.stdout.write(_http_ret.title)
154 sys.stdout.write(_http_ret.title)
155 return 0
155 return 0
156
156
157
157
158 def log_push_action(ui, repo, **kwargs):
158 def log_push_action(ui, repo, **kwargs):
159 """
159 """
160 Maps user last push action to new changeset id, from mercurial
160 Maps user last push action to new changeset id, from mercurial
161
161
162 :param ui:
162 :param ui:
163 :param repo: repo object containing the `ui` object
163 :param repo: repo object containing the `ui` object
164 """
164 """
165
165
166 ex = _extract_extras()
166 ex = _extract_extras()
167
167
168 action = ex.action + ':%s'
168 action = ex.action + ':%s'
169
169
170 if ex.scm == 'hg':
170 if ex.scm == 'hg':
171 node = kwargs['node']
171 node = kwargs['node']
172
172
173 def get_revs(repo, rev_opt):
173 def get_revs(repo, rev_opt):
174 if rev_opt:
174 if rev_opt:
175 revs = revrange(repo, rev_opt)
175 revs = revrange(repo, rev_opt)
176
176
177 if len(revs) == 0:
177 if len(revs) == 0:
178 return (nullrev, nullrev)
178 return (nullrev, nullrev)
179 return (max(revs), min(revs))
179 return (max(revs), min(revs))
180 else:
180 else:
181 return (len(repo) - 1, 0)
181 return (len(repo) - 1, 0)
182
182
183 stop, start = get_revs(repo, [node + ':'])
183 stop, start = get_revs(repo, [node + ':'])
184 h = binascii.hexlify
184 h = binascii.hexlify
185 revs = [h(repo[r].node()) for r in xrange(start, stop + 1)]
185 revs = [h(repo[r].node()) for r in xrange(start, stop + 1)]
186 elif ex.scm == 'git':
186 elif ex.scm == 'git':
187 revs = kwargs.get('_git_revs', [])
187 revs = kwargs.get('_git_revs', [])
188 if '_git_revs' in kwargs:
188 if '_git_revs' in kwargs:
189 kwargs.pop('_git_revs')
189 kwargs.pop('_git_revs')
190
190
191 action = action % ','.join(revs)
191 action = action % ','.join(revs)
192
192
193 action_logger(ex.username, action, ex.repository, ex.ip, commit=True)
193 action_logger(ex.username, action, ex.repository, ex.ip, commit=True)
194
194
195 # extension hook call
195 # extension hook call
196 from rhodecode import EXTENSIONS
196 from rhodecode import EXTENSIONS
197 callback = getattr(EXTENSIONS, 'PUSH_HOOK', None)
197 callback = getattr(EXTENSIONS, 'PUSH_HOOK', None)
198 if isfunction(callback):
198 if isfunction(callback):
199 kw = {'pushed_revs': revs}
199 kw = {'pushed_revs': revs}
200 kw.update(ex)
200 kw.update(ex)
201 callback(**kw)
201 callback(**kw)
202
202
203 if ex.make_lock is not None and not ex.make_lock:
203 if ex.make_lock is not None and not ex.make_lock:
204 Repository.unlock(Repository.get_by_repo_name(ex.repository))
204 Repository.unlock(Repository.get_by_repo_name(ex.repository))
205 msg = 'Released lock on repo `%s`\n' % ex.repository
205 msg = 'Released lock on repo `%s`\n' % ex.repository
206 sys.stdout.write(msg)
206 sys.stdout.write(msg)
207
207
208 if ex.locked_by[0]:
208 if ex.locked_by[0]:
209 locked_by = User.get(ex.locked_by[0]).username
209 locked_by = User.get(ex.locked_by[0]).username
210 _http_ret = HTTPLockedRC(ex.repository, locked_by)
210 _http_ret = HTTPLockedRC(ex.repository, locked_by)
211 if str(_http_ret.code).startswith('2'):
211 if str(_http_ret.code).startswith('2'):
212 #2xx Codes don't raise exceptions
212 #2xx Codes don't raise exceptions
213 sys.stdout.write(_http_ret.title)
213 sys.stdout.write(_http_ret.title)
214
214
215 return 0
215 return 0
216
216
217
217
218 def log_create_repository(repository_dict, created_by, **kwargs):
218 def log_create_repository(repository_dict, created_by, **kwargs):
219 """
219 """
220 Post create repository Hook. This is a dummy function for admins to re-use
220 Post create repository Hook. This is a dummy function for admins to re-use
221 if needed. It's taken from rhodecode-extensions module and executed
221 if needed. It's taken from rhodecode-extensions module and executed
222 if present
222 if present
223
223
224 :param repository: dict dump of repository object
224 :param repository: dict dump of repository object
225 :param created_by: username who created repository
225 :param created_by: username who created repository
226
226
227 available keys of repository_dict:
227 available keys of repository_dict:
228
228
229 'repo_type',
229 'repo_type',
230 'description',
230 'description',
231 'private',
231 'private',
232 'created_on',
232 'created_on',
233 'enable_downloads',
233 'enable_downloads',
234 'repo_id',
234 'repo_id',
235 'user_id',
235 'user_id',
236 'enable_statistics',
236 'enable_statistics',
237 'clone_uri',
237 'clone_uri',
238 'fork_id',
238 'fork_id',
239 'group_id',
239 'group_id',
240 'repo_name'
240 'repo_name'
241
241
242 """
242 """
243 from rhodecode import EXTENSIONS
243 from rhodecode import EXTENSIONS
244 callback = getattr(EXTENSIONS, 'CREATE_REPO_HOOK', None)
244 callback = getattr(EXTENSIONS, 'CREATE_REPO_HOOK', None)
245 if isfunction(callback):
245 if isfunction(callback):
246 kw = {}
246 kw = {}
247 kw.update(repository_dict)
247 kw.update(repository_dict)
248 kw.update({'created_by': created_by})
248 kw.update({'created_by': created_by})
249 kw.update(kwargs)
249 kw.update(kwargs)
250 return callback(**kw)
250 return callback(**kw)
251
251
252 return 0
252 return 0
253
253
254
254
255 def log_create_user(user_dict, **kwargs):
255 def log_create_user(user_dict, created_by, **kwargs):
256 """
256 """
257 Post create user Hook. This is a dummy function for admins to re-use
257 Post create user Hook. This is a dummy function for admins to re-use
258 if needed. It's taken from rhodecode-extensions module and executed
258 if needed. It's taken from rhodecode-extensions module and executed
259 if present
259 if present
260
260
261 :param user_dict: dict dump of user object
261 :param user_dict: dict dump of user object
262
262
263 available keys for user_dict:
263 available keys for user_dict:
264
264
265 'username',
265 'username',
266 'full_name_or_username',
266 'full_name_or_username',
267 'full_contact',
267 'full_contact',
268 'user_id',
268 'user_id',
269 'name',
269 'name',
270 'firstname',
270 'firstname',
271 'short_contact',
271 'short_contact',
272 'admin',
272 'admin',
273 'lastname',
273 'lastname',
274 'ip_addresses',
274 'ip_addresses',
275 'ldap_dn',
275 'ldap_dn',
276 'email',
276 'email',
277 'api_key',
277 'api_key',
278 'last_login',
278 'last_login',
279 'full_name',
279 'full_name',
280 'active',
280 'active',
281 'password',
281 'password',
282 'emails',
282 'emails',
283 'inherit_default_permissions'
283 'inherit_default_permissions'
284
284
285 """
285 """
286 from rhodecode import EXTENSIONS
286 from rhodecode import EXTENSIONS
287 callback = getattr(EXTENSIONS, 'CREATE_USER_HOOK', None)
287 callback = getattr(EXTENSIONS, 'CREATE_USER_HOOK', None)
288 if isfunction(callback):
288 if isfunction(callback):
289 return callback(**user_dict)
289 return callback(created_by=created_by, **user_dict)
290
290
291 return 0
291 return 0
292
292
293
293
294 def log_delete_repository(repository_dict, deleted_by, **kwargs):
294 def log_delete_repository(repository_dict, deleted_by, **kwargs):
295 """
295 """
296 Post delete repository Hook. This is a dummy function for admins to re-use
296 Post delete repository Hook. This is a dummy function for admins to re-use
297 if needed. It's taken from rhodecode-extensions module and executed
297 if needed. It's taken from rhodecode-extensions module and executed
298 if present
298 if present
299
299
300 :param repository: dict dump of repository object
300 :param repository: dict dump of repository object
301 :param deleted_by: username who deleted the repository
301 :param deleted_by: username who deleted the repository
302
302
303 available keys of repository_dict:
303 available keys of repository_dict:
304
304
305 'repo_type',
305 'repo_type',
306 'description',
306 'description',
307 'private',
307 'private',
308 'created_on',
308 'created_on',
309 'enable_downloads',
309 'enable_downloads',
310 'repo_id',
310 'repo_id',
311 'user_id',
311 'user_id',
312 'enable_statistics',
312 'enable_statistics',
313 'clone_uri',
313 'clone_uri',
314 'fork_id',
314 'fork_id',
315 'group_id',
315 'group_id',
316 'repo_name'
316 'repo_name'
317
317
318 """
318 """
319 from rhodecode import EXTENSIONS
319 from rhodecode import EXTENSIONS
320 callback = getattr(EXTENSIONS, 'DELETE_REPO_HOOK', None)
320 callback = getattr(EXTENSIONS, 'DELETE_REPO_HOOK', None)
321 if isfunction(callback):
321 if isfunction(callback):
322 kw = {}
322 kw = {}
323 kw.update(repository_dict)
323 kw.update(repository_dict)
324 kw.update({'deleted_by': deleted_by,
324 kw.update({'deleted_by': deleted_by,
325 'deleted_on': time.time()})
325 'deleted_on': time.time()})
326 kw.update(kwargs)
326 kw.update(kwargs)
327 return callback(**kw)
327 return callback(**kw)
328
328
329 return 0
329 return 0
330
330
331
331
332 def log_delete_user(user_dict, **kwargs):
332 def log_delete_user(user_dict, deleted_by, **kwargs):
333 """
333 """
334 Post delete user Hook. This is a dummy function for admins to re-use
334 Post delete user Hook. This is a dummy function for admins to re-use
335 if needed. It's taken from rhodecode-extensions module and executed
335 if needed. It's taken from rhodecode-extensions module and executed
336 if present
336 if present
337
337
338 :param user_dict: dict dump of user object
338 :param user_dict: dict dump of user object
339
339
340 available keys for user_dict:
340 available keys for user_dict:
341
341
342 'username',
342 'username',
343 'full_name_or_username',
343 'full_name_or_username',
344 'full_contact',
344 'full_contact',
345 'user_id',
345 'user_id',
346 'name',
346 'name',
347 'firstname',
347 'firstname',
348 'short_contact',
348 'short_contact',
349 'admin',
349 'admin',
350 'lastname',
350 'lastname',
351 'ip_addresses',
351 'ip_addresses',
352 'ldap_dn',
352 'ldap_dn',
353 'email',
353 'email',
354 'api_key',
354 'api_key',
355 'last_login',
355 'last_login',
356 'full_name',
356 'full_name',
357 'active',
357 'active',
358 'password',
358 'password',
359 'emails',
359 'emails',
360 'inherit_default_permissions'
360 'inherit_default_permissions'
361
361
362 """
362 """
363 from rhodecode import EXTENSIONS
363 from rhodecode import EXTENSIONS
364 callback = getattr(EXTENSIONS, 'DELETE_USER_HOOK', None)
364 callback = getattr(EXTENSIONS, 'DELETE_USER_HOOK', None)
365 if isfunction(callback):
365 if isfunction(callback):
366 return callback(**user_dict)
366 return callback(deleted_by=deleted_by, **user_dict)
367
367
368 return 0
368 return 0
369
369
370
370
371 handle_git_pre_receive = (lambda repo_path, revs, env:
371 handle_git_pre_receive = (lambda repo_path, revs, env:
372 handle_git_receive(repo_path, revs, env, hook_type='pre'))
372 handle_git_receive(repo_path, revs, env, hook_type='pre'))
373 handle_git_post_receive = (lambda repo_path, revs, env:
373 handle_git_post_receive = (lambda repo_path, revs, env:
374 handle_git_receive(repo_path, revs, env, hook_type='post'))
374 handle_git_receive(repo_path, revs, env, hook_type='post'))
375
375
376
376
377 def handle_git_receive(repo_path, revs, env, hook_type='post'):
377 def handle_git_receive(repo_path, revs, env, hook_type='post'):
378 """
378 """
379 A really hacky method that is runned by git post-receive hook and logs
379 A really hacky method that is runned by git post-receive hook and logs
380 an push action together with pushed revisions. It's executed by subprocess
380 an push action together with pushed revisions. It's executed by subprocess
381 thus needs all info to be able to create a on the fly pylons enviroment,
381 thus needs all info to be able to create a on the fly pylons enviroment,
382 connect to database and run the logging code. Hacky as sh*t but works.
382 connect to database and run the logging code. Hacky as sh*t but works.
383
383
384 :param repo_path:
384 :param repo_path:
385 :param revs:
385 :param revs:
386 :param env:
386 :param env:
387 """
387 """
388 from paste.deploy import appconfig
388 from paste.deploy import appconfig
389 from sqlalchemy import engine_from_config
389 from sqlalchemy import engine_from_config
390 from rhodecode.config.environment import load_environment
390 from rhodecode.config.environment import load_environment
391 from rhodecode.model import init_model
391 from rhodecode.model import init_model
392 from rhodecode.model.db import RhodeCodeUi
392 from rhodecode.model.db import RhodeCodeUi
393 from rhodecode.lib.utils import make_ui
393 from rhodecode.lib.utils import make_ui
394 extras = _extract_extras(env)
394 extras = _extract_extras(env)
395
395
396 path, ini_name = os.path.split(extras['config'])
396 path, ini_name = os.path.split(extras['config'])
397 conf = appconfig('config:%s' % ini_name, relative_to=path)
397 conf = appconfig('config:%s' % ini_name, relative_to=path)
398 load_environment(conf.global_conf, conf.local_conf)
398 load_environment(conf.global_conf, conf.local_conf)
399
399
400 engine = engine_from_config(conf, 'sqlalchemy.db1.')
400 engine = engine_from_config(conf, 'sqlalchemy.db1.')
401 init_model(engine)
401 init_model(engine)
402
402
403 baseui = make_ui('db')
403 baseui = make_ui('db')
404 # fix if it's not a bare repo
404 # fix if it's not a bare repo
405 if repo_path.endswith(os.sep + '.git'):
405 if repo_path.endswith(os.sep + '.git'):
406 repo_path = repo_path[:-5]
406 repo_path = repo_path[:-5]
407
407
408 repo = Repository.get_by_full_path(repo_path)
408 repo = Repository.get_by_full_path(repo_path)
409 if not repo:
409 if not repo:
410 raise OSError('Repository %s not found in database'
410 raise OSError('Repository %s not found in database'
411 % (safe_str(repo_path)))
411 % (safe_str(repo_path)))
412
412
413 _hooks = dict(baseui.configitems('hooks')) or {}
413 _hooks = dict(baseui.configitems('hooks')) or {}
414
414
415 if hook_type == 'pre':
415 if hook_type == 'pre':
416 repo = repo.scm_instance
416 repo = repo.scm_instance
417 else:
417 else:
418 #post push shouldn't use the cached instance never
418 #post push shouldn't use the cached instance never
419 repo = repo.scm_instance_no_cache()
419 repo = repo.scm_instance_no_cache()
420
420
421 if hook_type == 'pre':
421 if hook_type == 'pre':
422 pre_push(baseui, repo)
422 pre_push(baseui, repo)
423
423
424 # if push hook is enabled via web interface
424 # if push hook is enabled via web interface
425 elif hook_type == 'post' and _hooks.get(RhodeCodeUi.HOOK_PUSH):
425 elif hook_type == 'post' and _hooks.get(RhodeCodeUi.HOOK_PUSH):
426
426
427 rev_data = []
427 rev_data = []
428 for l in revs:
428 for l in revs:
429 old_rev, new_rev, ref = l.split(' ')
429 old_rev, new_rev, ref = l.split(' ')
430 _ref_data = ref.split('/')
430 _ref_data = ref.split('/')
431 if _ref_data[1] in ['tags', 'heads']:
431 if _ref_data[1] in ['tags', 'heads']:
432 rev_data.append({'old_rev': old_rev,
432 rev_data.append({'old_rev': old_rev,
433 'new_rev': new_rev,
433 'new_rev': new_rev,
434 'ref': ref,
434 'ref': ref,
435 'type': _ref_data[1],
435 'type': _ref_data[1],
436 'name': _ref_data[2].strip()})
436 'name': _ref_data[2].strip()})
437
437
438 git_revs = []
438 git_revs = []
439 for push_ref in rev_data:
439 for push_ref in rev_data:
440 _type = push_ref['type']
440 _type = push_ref['type']
441 if _type == 'heads':
441 if _type == 'heads':
442 if push_ref['old_rev'] == EmptyChangeset().raw_id:
442 if push_ref['old_rev'] == EmptyChangeset().raw_id:
443 cmd = "for-each-ref --format='%(refname)' 'refs/heads/*'"
443 cmd = "for-each-ref --format='%(refname)' 'refs/heads/*'"
444 heads = repo.run_git_command(cmd)[0]
444 heads = repo.run_git_command(cmd)[0]
445 heads = heads.replace(push_ref['ref'], '')
445 heads = heads.replace(push_ref['ref'], '')
446 heads = ' '.join(map(lambda c: c.strip('\n').strip(),
446 heads = ' '.join(map(lambda c: c.strip('\n').strip(),
447 heads.splitlines()))
447 heads.splitlines()))
448 cmd = (('log %(new_rev)s' % push_ref) +
448 cmd = (('log %(new_rev)s' % push_ref) +
449 ' --reverse --pretty=format:"%H" --not ' + heads)
449 ' --reverse --pretty=format:"%H" --not ' + heads)
450 git_revs += repo.run_git_command(cmd)[0].splitlines()
450 git_revs += repo.run_git_command(cmd)[0].splitlines()
451
451
452 elif push_ref['new_rev'] == EmptyChangeset().raw_id:
452 elif push_ref['new_rev'] == EmptyChangeset().raw_id:
453 #delete branch case
453 #delete branch case
454 git_revs += ['delete_branch=>%s' % push_ref['name']]
454 git_revs += ['delete_branch=>%s' % push_ref['name']]
455 else:
455 else:
456 cmd = (('log %(old_rev)s..%(new_rev)s' % push_ref) +
456 cmd = (('log %(old_rev)s..%(new_rev)s' % push_ref) +
457 ' --reverse --pretty=format:"%H"')
457 ' --reverse --pretty=format:"%H"')
458 git_revs += repo.run_git_command(cmd)[0].splitlines()
458 git_revs += repo.run_git_command(cmd)[0].splitlines()
459
459
460 elif _type == 'tags':
460 elif _type == 'tags':
461 git_revs += ['tag=>%s' % push_ref['name']]
461 git_revs += ['tag=>%s' % push_ref['name']]
462
462
463 log_push_action(baseui, repo, _git_revs=git_revs)
463 log_push_action(baseui, repo, _git_revs=git_revs)
@@ -1,819 +1,829 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.user
3 rhodecode.model.user
4 ~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 users model for RhodeCode
6 users model for RhodeCode
7
7
8 :created_on: Apr 9, 2010
8 :created_on: Apr 9, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28 import itertools
28 import itertools
29 import collections
29 import collections
30 from pylons import url
30 from pylons import url
31 from pylons.i18n.translation import _
31 from pylons.i18n.translation import _
32
32
33 from sqlalchemy.exc import DatabaseError
33 from sqlalchemy.exc import DatabaseError
34 from sqlalchemy.orm import joinedload
34 from sqlalchemy.orm import joinedload
35
35
36 from rhodecode.lib.utils2 import safe_unicode, generate_api_key
36 from rhodecode.lib.utils2 import safe_unicode, generate_api_key, get_current_rhodecode_user
37 from rhodecode.lib.caching_query import FromCache
37 from rhodecode.lib.caching_query import FromCache
38 from rhodecode.model import BaseModel
38 from rhodecode.model import BaseModel
39 from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
39 from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
40 UserToPerm, UserGroupRepoToPerm, UserGroupToPerm, UserGroupMember, \
40 UserToPerm, UserGroupRepoToPerm, UserGroupToPerm, UserGroupMember, \
41 Notification, RepoGroup, UserRepoGroupToPerm, UserGroupRepoGroupToPerm, \
41 Notification, RepoGroup, UserRepoGroupToPerm, UserGroupRepoGroupToPerm, \
42 UserEmailMap, UserIpMap, UserGroupUserGroupToPerm, UserGroup
42 UserEmailMap, UserIpMap, UserGroupUserGroupToPerm, UserGroup
43 from rhodecode.lib.exceptions import DefaultUserException, \
43 from rhodecode.lib.exceptions import DefaultUserException, \
44 UserOwnsReposException
44 UserOwnsReposException
45 from rhodecode.model.meta import Session
45 from rhodecode.model.meta import Session
46
46
47
47
48 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
49
49
50 PERM_WEIGHTS = Permission.PERM_WEIGHTS
50 PERM_WEIGHTS = Permission.PERM_WEIGHTS
51
51
52
52
53 class UserModel(BaseModel):
53 class UserModel(BaseModel):
54 cls = User
54 cls = User
55
55
56 def get(self, user_id, cache=False):
56 def get(self, user_id, cache=False):
57 user = self.sa.query(User)
57 user = self.sa.query(User)
58 if cache:
58 if cache:
59 user = user.options(FromCache("sql_cache_short",
59 user = user.options(FromCache("sql_cache_short",
60 "get_user_%s" % user_id))
60 "get_user_%s" % user_id))
61 return user.get(user_id)
61 return user.get(user_id)
62
62
63 def get_user(self, user):
63 def get_user(self, user):
64 return self._get_user(user)
64 return self._get_user(user)
65
65
66 def get_by_username(self, username, cache=False, case_insensitive=False):
66 def get_by_username(self, username, cache=False, case_insensitive=False):
67
67
68 if case_insensitive:
68 if case_insensitive:
69 user = self.sa.query(User).filter(User.username.ilike(username))
69 user = self.sa.query(User).filter(User.username.ilike(username))
70 else:
70 else:
71 user = self.sa.query(User)\
71 user = self.sa.query(User)\
72 .filter(User.username == username)
72 .filter(User.username == username)
73 if cache:
73 if cache:
74 user = user.options(FromCache("sql_cache_short",
74 user = user.options(FromCache("sql_cache_short",
75 "get_user_%s" % username))
75 "get_user_%s" % username))
76 return user.scalar()
76 return user.scalar()
77
77
78 def get_by_email(self, email, cache=False, case_insensitive=False):
78 def get_by_email(self, email, cache=False, case_insensitive=False):
79 return User.get_by_email(email, case_insensitive, cache)
79 return User.get_by_email(email, case_insensitive, cache)
80
80
81 def get_by_api_key(self, api_key, cache=False):
81 def get_by_api_key(self, api_key, cache=False):
82 return User.get_by_api_key(api_key, cache)
82 return User.get_by_api_key(api_key, cache)
83
83
84 def create(self, form_data):
84 def create(self, form_data, cur_user=None):
85 if not cur_user:
86 cur_user = getattr(get_current_rhodecode_user(), 'username', '?')
85 from rhodecode.lib.auth import get_crypt_password
87 from rhodecode.lib.auth import get_crypt_password
86 try:
88 try:
87 new_user = User()
89 new_user = User()
88 for k, v in form_data.items():
90 for k, v in form_data.items():
89 if k == 'password':
91 if k == 'password':
90 v = get_crypt_password(v)
92 v = get_crypt_password(v)
91 if k == 'firstname':
93 if k == 'firstname':
92 k = 'name'
94 k = 'name'
93 setattr(new_user, k, v)
95 setattr(new_user, k, v)
94
96
95 new_user.api_key = generate_api_key(form_data['username'])
97 new_user.api_key = generate_api_key(form_data['username'])
96 self.sa.add(new_user)
98 self.sa.add(new_user)
97
99
98 from rhodecode.lib.hooks import log_create_user
100 from rhodecode.lib.hooks import log_create_user
99 log_create_user(new_user.get_dict())
101 log_create_user(new_user.get_dict(), cur_user)
100 return new_user
102 return new_user
101 except Exception:
103 except Exception:
102 log.error(traceback.format_exc())
104 log.error(traceback.format_exc())
103 raise
105 raise
104
106
105 def create_or_update(self, username, password, email, firstname='',
107 def create_or_update(self, username, password, email, firstname='',
106 lastname='', active=True, admin=False, ldap_dn=None):
108 lastname='', active=True, admin=False, ldap_dn=None, cur_user=None):
107 """
109 """
108 Creates a new instance if not found, or updates current one
110 Creates a new instance if not found, or updates current one
109
111
110 :param username:
112 :param username:
111 :param password:
113 :param password:
112 :param email:
114 :param email:
113 :param active:
115 :param active:
114 :param firstname:
116 :param firstname:
115 :param lastname:
117 :param lastname:
116 :param active:
118 :param active:
117 :param admin:
119 :param admin:
118 :param ldap_dn:
120 :param ldap_dn:
119 """
121 """
122 if not cur_user:
123 cur_user = getattr(get_current_rhodecode_user(), 'username', '?')
120
124
121 from rhodecode.lib.auth import get_crypt_password
125 from rhodecode.lib.auth import get_crypt_password
122
126
123 log.debug('Checking for %s account in RhodeCode database' % username)
127 log.debug('Checking for %s account in RhodeCode database' % username)
124 user = User.get_by_username(username, case_insensitive=True)
128 user = User.get_by_username(username, case_insensitive=True)
125 if user is None:
129 if user is None:
126 log.debug('creating new user %s' % username)
130 log.debug('creating new user %s' % username)
127 new_user = User()
131 new_user = User()
128 edit = False
132 edit = False
129 else:
133 else:
130 log.debug('updating user %s' % username)
134 log.debug('updating user %s' % username)
131 new_user = user
135 new_user = user
132 edit = True
136 edit = True
133
137
134 try:
138 try:
135 new_user.username = username
139 new_user.username = username
136 new_user.admin = admin
140 new_user.admin = admin
137 # set password only if creating an user or password is changed
141 # set password only if creating an user or password is changed
138 if not edit or user.password != password:
142 if not edit or user.password != password:
139 new_user.password = get_crypt_password(password) if password else None
143 new_user.password = get_crypt_password(password) if password else None
140 new_user.api_key = generate_api_key(username)
144 new_user.api_key = generate_api_key(username)
141 new_user.email = email
145 new_user.email = email
142 new_user.active = active
146 new_user.active = active
143 new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None
147 new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None
144 new_user.name = firstname
148 new_user.name = firstname
145 new_user.lastname = lastname
149 new_user.lastname = lastname
146 self.sa.add(new_user)
150 self.sa.add(new_user)
147
151
148 if not edit:
152 if not edit:
149 from rhodecode.lib.hooks import log_create_user
153 from rhodecode.lib.hooks import log_create_user
150 log_create_user(new_user.get_dict())
154 log_create_user(new_user.get_dict(), cur_user)
151 return new_user
155 return new_user
152 except (DatabaseError,):
156 except (DatabaseError,):
153 log.error(traceback.format_exc())
157 log.error(traceback.format_exc())
154 raise
158 raise
155
159
156 def create_for_container_auth(self, username, attrs):
160 def create_for_container_auth(self, username, attrs, cur_user=None):
157 """
161 """
158 Creates the given user if it's not already in the database
162 Creates the given user if it's not already in the database
159
163
160 :param username:
164 :param username:
161 :param attrs:
165 :param attrs:
162 """
166 """
167 if not cur_user:
168 cur_user = getattr(get_current_rhodecode_user(), 'username', '?')
163 if self.get_by_username(username, case_insensitive=True) is None:
169 if self.get_by_username(username, case_insensitive=True) is None:
164
170
165 # autogenerate email for container account without one
171 # autogenerate email for container account without one
166 generate_email = lambda usr: '%s@container_auth.account' % usr
172 generate_email = lambda usr: '%s@container_auth.account' % usr
167
173
168 try:
174 try:
169 new_user = User()
175 new_user = User()
170 new_user.username = username
176 new_user.username = username
171 new_user.password = None
177 new_user.password = None
172 new_user.api_key = generate_api_key(username)
178 new_user.api_key = generate_api_key(username)
173 new_user.email = attrs['email']
179 new_user.email = attrs['email']
174 new_user.active = attrs.get('active', True)
180 new_user.active = attrs.get('active', True)
175 new_user.name = attrs['name'] or generate_email(username)
181 new_user.name = attrs['name'] or generate_email(username)
176 new_user.lastname = attrs['lastname']
182 new_user.lastname = attrs['lastname']
177
183
178 self.sa.add(new_user)
184 self.sa.add(new_user)
179
185
180 from rhodecode.lib.hooks import log_create_user
186 from rhodecode.lib.hooks import log_create_user
181 log_create_user(new_user.get_dict())
187 log_create_user(new_user.get_dict(), cur_user)
182 return new_user
188 return new_user
183 except (DatabaseError,):
189 except (DatabaseError,):
184 log.error(traceback.format_exc())
190 log.error(traceback.format_exc())
185 self.sa.rollback()
191 self.sa.rollback()
186 raise
192 raise
187 log.debug('User %s already exists. Skipping creation of account'
193 log.debug('User %s already exists. Skipping creation of account'
188 ' for container auth.', username)
194 ' for container auth.', username)
189 return None
195 return None
190
196
191 def create_ldap(self, username, password, user_dn, attrs):
197 def create_ldap(self, username, password, user_dn, attrs, cur_user=None):
192 """
198 """
193 Checks if user is in database, if not creates this user marked
199 Checks if user is in database, if not creates this user marked
194 as ldap user
200 as ldap user
195
201
196 :param username:
202 :param username:
197 :param password:
203 :param password:
198 :param user_dn:
204 :param user_dn:
199 :param attrs:
205 :param attrs:
200 """
206 """
207 if not cur_user:
208 cur_user = getattr(get_current_rhodecode_user(), 'username', '?')
201 from rhodecode.lib.auth import get_crypt_password
209 from rhodecode.lib.auth import get_crypt_password
202 log.debug('Checking for such ldap account in RhodeCode database')
210 log.debug('Checking for such ldap account in RhodeCode database')
203 if self.get_by_username(username, case_insensitive=True) is None:
211 if self.get_by_username(username, case_insensitive=True) is None:
204
212
205 # autogenerate email for ldap account without one
213 # autogenerate email for ldap account without one
206 generate_email = lambda usr: '%s@ldap.account' % usr
214 generate_email = lambda usr: '%s@ldap.account' % usr
207
215
208 try:
216 try:
209 new_user = User()
217 new_user = User()
210 username = username.lower()
218 username = username.lower()
211 # add ldap account always lowercase
219 # add ldap account always lowercase
212 new_user.username = username
220 new_user.username = username
213 new_user.password = get_crypt_password(password)
221 new_user.password = get_crypt_password(password)
214 new_user.api_key = generate_api_key(username)
222 new_user.api_key = generate_api_key(username)
215 new_user.email = attrs['email'] or generate_email(username)
223 new_user.email = attrs['email'] or generate_email(username)
216 new_user.active = attrs.get('active', True)
224 new_user.active = attrs.get('active', True)
217 new_user.ldap_dn = safe_unicode(user_dn)
225 new_user.ldap_dn = safe_unicode(user_dn)
218 new_user.name = attrs['name']
226 new_user.name = attrs['name']
219 new_user.lastname = attrs['lastname']
227 new_user.lastname = attrs['lastname']
220
228
221 self.sa.add(new_user)
229 self.sa.add(new_user)
222
230
223 from rhodecode.lib.hooks import log_create_user
231 from rhodecode.lib.hooks import log_create_user
224 log_create_user(new_user.get_dict())
232 log_create_user(new_user.get_dict(), cur_user)
225 return new_user
233 return new_user
226 except (DatabaseError,):
234 except (DatabaseError,):
227 log.error(traceback.format_exc())
235 log.error(traceback.format_exc())
228 self.sa.rollback()
236 self.sa.rollback()
229 raise
237 raise
230 log.debug('this %s user exists skipping creation of ldap account',
238 log.debug('this %s user exists skipping creation of ldap account',
231 username)
239 username)
232 return None
240 return None
233
241
234 def create_registration(self, form_data):
242 def create_registration(self, form_data):
235 from rhodecode.model.notification import NotificationModel
243 from rhodecode.model.notification import NotificationModel
236
244
237 try:
245 try:
238 form_data['admin'] = False
246 form_data['admin'] = False
239 new_user = self.create(form_data)
247 new_user = self.create(form_data)
240
248
241 self.sa.add(new_user)
249 self.sa.add(new_user)
242 self.sa.flush()
250 self.sa.flush()
243
251
244 # notification to admins
252 # notification to admins
245 subject = _('New user registration')
253 subject = _('New user registration')
246 body = ('New user registration\n'
254 body = ('New user registration\n'
247 '---------------------\n'
255 '---------------------\n'
248 '- Username: %s\n'
256 '- Username: %s\n'
249 '- Full Name: %s\n'
257 '- Full Name: %s\n'
250 '- Email: %s\n')
258 '- Email: %s\n')
251 body = body % (new_user.username, new_user.full_name,
259 body = body % (new_user.username, new_user.full_name,
252 new_user.email)
260 new_user.email)
253 edit_url = url('edit_user', id=new_user.user_id, qualified=True)
261 edit_url = url('edit_user', id=new_user.user_id, qualified=True)
254 kw = {'registered_user_url': edit_url}
262 kw = {'registered_user_url': edit_url}
255 NotificationModel().create(created_by=new_user, subject=subject,
263 NotificationModel().create(created_by=new_user, subject=subject,
256 body=body, recipients=None,
264 body=body, recipients=None,
257 type_=Notification.TYPE_REGISTRATION,
265 type_=Notification.TYPE_REGISTRATION,
258 email_kwargs=kw)
266 email_kwargs=kw)
259
267
260 except Exception:
268 except Exception:
261 log.error(traceback.format_exc())
269 log.error(traceback.format_exc())
262 raise
270 raise
263
271
264 def update(self, user_id, form_data, skip_attrs=[]):
272 def update(self, user_id, form_data, skip_attrs=[]):
265 from rhodecode.lib.auth import get_crypt_password
273 from rhodecode.lib.auth import get_crypt_password
266 try:
274 try:
267 user = self.get(user_id, cache=False)
275 user = self.get(user_id, cache=False)
268 if user.username == 'default':
276 if user.username == 'default':
269 raise DefaultUserException(
277 raise DefaultUserException(
270 _("You can't Edit this user since it's"
278 _("You can't Edit this user since it's"
271 " crucial for entire application"))
279 " crucial for entire application"))
272
280
273 for k, v in form_data.items():
281 for k, v in form_data.items():
274 if k in skip_attrs:
282 if k in skip_attrs:
275 continue
283 continue
276 if k == 'new_password' and v:
284 if k == 'new_password' and v:
277 user.password = get_crypt_password(v)
285 user.password = get_crypt_password(v)
278 user.api_key = generate_api_key(user.username)
286 user.api_key = generate_api_key(user.username)
279 else:
287 else:
280 if k == 'firstname':
288 if k == 'firstname':
281 k = 'name'
289 k = 'name'
282 setattr(user, k, v)
290 setattr(user, k, v)
283 self.sa.add(user)
291 self.sa.add(user)
284 except Exception:
292 except Exception:
285 log.error(traceback.format_exc())
293 log.error(traceback.format_exc())
286 raise
294 raise
287
295
288 def update_user(self, user, **kwargs):
296 def update_user(self, user, **kwargs):
289 from rhodecode.lib.auth import get_crypt_password
297 from rhodecode.lib.auth import get_crypt_password
290 try:
298 try:
291 user = self._get_user(user)
299 user = self._get_user(user)
292 if user.username == 'default':
300 if user.username == 'default':
293 raise DefaultUserException(
301 raise DefaultUserException(
294 _("You can't Edit this user since it's"
302 _("You can't Edit this user since it's"
295 " crucial for entire application")
303 " crucial for entire application")
296 )
304 )
297
305
298 for k, v in kwargs.items():
306 for k, v in kwargs.items():
299 if k == 'password' and v:
307 if k == 'password' and v:
300 v = get_crypt_password(v)
308 v = get_crypt_password(v)
301 user.api_key = generate_api_key(user.username)
309 user.api_key = generate_api_key(user.username)
302
310
303 setattr(user, k, v)
311 setattr(user, k, v)
304 self.sa.add(user)
312 self.sa.add(user)
305 return user
313 return user
306 except Exception:
314 except Exception:
307 log.error(traceback.format_exc())
315 log.error(traceback.format_exc())
308 raise
316 raise
309
317
310 def delete(self, user):
318 def delete(self, user, cur_user=None):
319 if not cur_user:
320 cur_user = getattr(get_current_rhodecode_user(), 'username', '?')
311 user = self._get_user(user)
321 user = self._get_user(user)
312
322
313 try:
323 try:
314 if user.username == 'default':
324 if user.username == 'default':
315 raise DefaultUserException(
325 raise DefaultUserException(
316 _(u"You can't remove this user since it's"
326 _(u"You can't remove this user since it's"
317 " crucial for entire application")
327 " crucial for entire application")
318 )
328 )
319 if user.repositories:
329 if user.repositories:
320 repos = [x.repo_name for x in user.repositories]
330 repos = [x.repo_name for x in user.repositories]
321 raise UserOwnsReposException(
331 raise UserOwnsReposException(
322 _(u'user "%s" still owns %s repositories and cannot be '
332 _(u'user "%s" still owns %s repositories and cannot be '
323 'removed. Switch owners or remove those repositories. %s')
333 'removed. Switch owners or remove those repositories. %s')
324 % (user.username, len(repos), ', '.join(repos))
334 % (user.username, len(repos), ', '.join(repos))
325 )
335 )
326 self.sa.delete(user)
336 self.sa.delete(user)
327
337
328 from rhodecode.lib.hooks import log_delete_user
338 from rhodecode.lib.hooks import log_delete_user
329 log_delete_user(user.get_dict())
339 log_delete_user(user.get_dict(), cur_user)
330 except Exception:
340 except Exception:
331 log.error(traceback.format_exc())
341 log.error(traceback.format_exc())
332 raise
342 raise
333
343
334 def reset_password_link(self, data):
344 def reset_password_link(self, data):
335 from rhodecode.lib.celerylib import tasks, run_task
345 from rhodecode.lib.celerylib import tasks, run_task
336 from rhodecode.model.notification import EmailNotificationModel
346 from rhodecode.model.notification import EmailNotificationModel
337 user_email = data['email']
347 user_email = data['email']
338 try:
348 try:
339 user = User.get_by_email(user_email)
349 user = User.get_by_email(user_email)
340 if user:
350 if user:
341 log.debug('password reset user found %s' % user)
351 log.debug('password reset user found %s' % user)
342 link = url('reset_password_confirmation', key=user.api_key,
352 link = url('reset_password_confirmation', key=user.api_key,
343 qualified=True)
353 qualified=True)
344 reg_type = EmailNotificationModel.TYPE_PASSWORD_RESET
354 reg_type = EmailNotificationModel.TYPE_PASSWORD_RESET
345 body = EmailNotificationModel().get_email_tmpl(reg_type,
355 body = EmailNotificationModel().get_email_tmpl(reg_type,
346 **{'user': user.short_contact,
356 **{'user': user.short_contact,
347 'reset_url': link})
357 'reset_url': link})
348 log.debug('sending email')
358 log.debug('sending email')
349 run_task(tasks.send_email, user_email,
359 run_task(tasks.send_email, user_email,
350 _("Password reset link"), body, body)
360 _("Password reset link"), body, body)
351 log.info('send new password mail to %s' % user_email)
361 log.info('send new password mail to %s' % user_email)
352 else:
362 else:
353 log.debug("password reset email %s not found" % user_email)
363 log.debug("password reset email %s not found" % user_email)
354 except Exception:
364 except Exception:
355 log.error(traceback.format_exc())
365 log.error(traceback.format_exc())
356 return False
366 return False
357
367
358 return True
368 return True
359
369
360 def reset_password(self, data):
370 def reset_password(self, data):
361 from rhodecode.lib.celerylib import tasks, run_task
371 from rhodecode.lib.celerylib import tasks, run_task
362 from rhodecode.lib import auth
372 from rhodecode.lib import auth
363 user_email = data['email']
373 user_email = data['email']
364 try:
374 try:
365 try:
375 try:
366 user = User.get_by_email(user_email)
376 user = User.get_by_email(user_email)
367 new_passwd = auth.PasswordGenerator().gen_password(8,
377 new_passwd = auth.PasswordGenerator().gen_password(8,
368 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
378 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
369 if user:
379 if user:
370 user.password = auth.get_crypt_password(new_passwd)
380 user.password = auth.get_crypt_password(new_passwd)
371 user.api_key = auth.generate_api_key(user.username)
381 user.api_key = auth.generate_api_key(user.username)
372 Session().add(user)
382 Session().add(user)
373 Session().commit()
383 Session().commit()
374 log.info('change password for %s' % user_email)
384 log.info('change password for %s' % user_email)
375 if new_passwd is None:
385 if new_passwd is None:
376 raise Exception('unable to generate new password')
386 raise Exception('unable to generate new password')
377 except Exception:
387 except Exception:
378 log.error(traceback.format_exc())
388 log.error(traceback.format_exc())
379 Session().rollback()
389 Session().rollback()
380
390
381 run_task(tasks.send_email, user_email,
391 run_task(tasks.send_email, user_email,
382 _('Your new password'),
392 _('Your new password'),
383 _('Your new RhodeCode password:%s') % (new_passwd))
393 _('Your new RhodeCode password:%s') % (new_passwd))
384 log.info('send new password mail to %s' % user_email)
394 log.info('send new password mail to %s' % user_email)
385
395
386 except Exception:
396 except Exception:
387 log.error('Failed to update user password')
397 log.error('Failed to update user password')
388 log.error(traceback.format_exc())
398 log.error(traceback.format_exc())
389
399
390 return True
400 return True
391
401
392 def fill_data(self, auth_user, user_id=None, api_key=None):
402 def fill_data(self, auth_user, user_id=None, api_key=None):
393 """
403 """
394 Fetches auth_user by user_id,or api_key if present.
404 Fetches auth_user by user_id,or api_key if present.
395 Fills auth_user attributes with those taken from database.
405 Fills auth_user attributes with those taken from database.
396 Additionally set's is_authenitated if lookup fails
406 Additionally set's is_authenitated if lookup fails
397 present in database
407 present in database
398
408
399 :param auth_user: instance of user to set attributes
409 :param auth_user: instance of user to set attributes
400 :param user_id: user id to fetch by
410 :param user_id: user id to fetch by
401 :param api_key: api key to fetch by
411 :param api_key: api key to fetch by
402 """
412 """
403 if user_id is None and api_key is None:
413 if user_id is None and api_key is None:
404 raise Exception('You need to pass user_id or api_key')
414 raise Exception('You need to pass user_id or api_key')
405
415
406 try:
416 try:
407 if api_key:
417 if api_key:
408 dbuser = self.get_by_api_key(api_key)
418 dbuser = self.get_by_api_key(api_key)
409 else:
419 else:
410 dbuser = self.get(user_id)
420 dbuser = self.get(user_id)
411
421
412 if dbuser is not None and dbuser.active:
422 if dbuser is not None and dbuser.active:
413 log.debug('filling %s data' % dbuser)
423 log.debug('filling %s data' % dbuser)
414 for k, v in dbuser.get_dict().items():
424 for k, v in dbuser.get_dict().items():
415 setattr(auth_user, k, v)
425 setattr(auth_user, k, v)
416 else:
426 else:
417 return False
427 return False
418
428
419 except Exception:
429 except Exception:
420 log.error(traceback.format_exc())
430 log.error(traceback.format_exc())
421 auth_user.is_authenticated = False
431 auth_user.is_authenticated = False
422 return False
432 return False
423
433
424 return True
434 return True
425
435
426 def fill_perms(self, user, explicit=True, algo='higherwin'):
436 def fill_perms(self, user, explicit=True, algo='higherwin'):
427 """
437 """
428 Fills user permission attribute with permissions taken from database
438 Fills user permission attribute with permissions taken from database
429 works for permissions given for repositories, and for permissions that
439 works for permissions given for repositories, and for permissions that
430 are granted to groups
440 are granted to groups
431
441
432 :param user: user instance to fill his perms
442 :param user: user instance to fill his perms
433 :param explicit: In case there are permissions both for user and a group
443 :param explicit: In case there are permissions both for user and a group
434 that user is part of, explicit flag will defiine if user will
444 that user is part of, explicit flag will defiine if user will
435 explicitly override permissions from group, if it's False it will
445 explicitly override permissions from group, if it's False it will
436 make decision based on the algo
446 make decision based on the algo
437 :param algo: algorithm to decide what permission should be choose if
447 :param algo: algorithm to decide what permission should be choose if
438 it's multiple defined, eg user in two different groups. It also
448 it's multiple defined, eg user in two different groups. It also
439 decides if explicit flag is turned off how to specify the permission
449 decides if explicit flag is turned off how to specify the permission
440 for case when user is in a group + have defined separate permission
450 for case when user is in a group + have defined separate permission
441 """
451 """
442 RK = 'repositories'
452 RK = 'repositories'
443 GK = 'repositories_groups'
453 GK = 'repositories_groups'
444 UK = 'user_groups'
454 UK = 'user_groups'
445 GLOBAL = 'global'
455 GLOBAL = 'global'
446 user.permissions[RK] = {}
456 user.permissions[RK] = {}
447 user.permissions[GK] = {}
457 user.permissions[GK] = {}
448 user.permissions[UK] = {}
458 user.permissions[UK] = {}
449 user.permissions[GLOBAL] = set()
459 user.permissions[GLOBAL] = set()
450
460
451 def _choose_perm(new_perm, cur_perm):
461 def _choose_perm(new_perm, cur_perm):
452 new_perm_val = PERM_WEIGHTS[new_perm]
462 new_perm_val = PERM_WEIGHTS[new_perm]
453 cur_perm_val = PERM_WEIGHTS[cur_perm]
463 cur_perm_val = PERM_WEIGHTS[cur_perm]
454 if algo == 'higherwin':
464 if algo == 'higherwin':
455 if new_perm_val > cur_perm_val:
465 if new_perm_val > cur_perm_val:
456 return new_perm
466 return new_perm
457 return cur_perm
467 return cur_perm
458 elif algo == 'lowerwin':
468 elif algo == 'lowerwin':
459 if new_perm_val < cur_perm_val:
469 if new_perm_val < cur_perm_val:
460 return new_perm
470 return new_perm
461 return cur_perm
471 return cur_perm
462
472
463 #======================================================================
473 #======================================================================
464 # fetch default permissions
474 # fetch default permissions
465 #======================================================================
475 #======================================================================
466 default_user = User.get_by_username('default', cache=True)
476 default_user = User.get_by_username('default', cache=True)
467 default_user_id = default_user.user_id
477 default_user_id = default_user.user_id
468
478
469 default_repo_perms = Permission.get_default_perms(default_user_id)
479 default_repo_perms = Permission.get_default_perms(default_user_id)
470 default_repo_groups_perms = Permission.get_default_group_perms(default_user_id)
480 default_repo_groups_perms = Permission.get_default_group_perms(default_user_id)
471 default_user_group_perms = Permission.get_default_user_group_perms(default_user_id)
481 default_user_group_perms = Permission.get_default_user_group_perms(default_user_id)
472
482
473 if user.is_admin:
483 if user.is_admin:
474 #==================================================================
484 #==================================================================
475 # admin user have all default rights for repositories
485 # admin user have all default rights for repositories
476 # and groups set to admin
486 # and groups set to admin
477 #==================================================================
487 #==================================================================
478 user.permissions[GLOBAL].add('hg.admin')
488 user.permissions[GLOBAL].add('hg.admin')
479
489
480 # repositories
490 # repositories
481 for perm in default_repo_perms:
491 for perm in default_repo_perms:
482 r_k = perm.UserRepoToPerm.repository.repo_name
492 r_k = perm.UserRepoToPerm.repository.repo_name
483 p = 'repository.admin'
493 p = 'repository.admin'
484 user.permissions[RK][r_k] = p
494 user.permissions[RK][r_k] = p
485
495
486 # repository groups
496 # repository groups
487 for perm in default_repo_groups_perms:
497 for perm in default_repo_groups_perms:
488 rg_k = perm.UserRepoGroupToPerm.group.group_name
498 rg_k = perm.UserRepoGroupToPerm.group.group_name
489 p = 'group.admin'
499 p = 'group.admin'
490 user.permissions[GK][rg_k] = p
500 user.permissions[GK][rg_k] = p
491
501
492 # user groups
502 # user groups
493 for perm in default_user_group_perms:
503 for perm in default_user_group_perms:
494 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
504 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
495 p = 'usergroup.admin'
505 p = 'usergroup.admin'
496 user.permissions[UK][u_k] = p
506 user.permissions[UK][u_k] = p
497 return user
507 return user
498
508
499 #==================================================================
509 #==================================================================
500 # SET DEFAULTS GLOBAL, REPOS, REPOSITORY GROUPS
510 # SET DEFAULTS GLOBAL, REPOS, REPOSITORY GROUPS
501 #==================================================================
511 #==================================================================
502 uid = user.user_id
512 uid = user.user_id
503
513
504 # default global permissions taken fron the default user
514 # default global permissions taken fron the default user
505 default_global_perms = self.sa.query(UserToPerm)\
515 default_global_perms = self.sa.query(UserToPerm)\
506 .filter(UserToPerm.user_id == default_user_id)
516 .filter(UserToPerm.user_id == default_user_id)
507
517
508 for perm in default_global_perms:
518 for perm in default_global_perms:
509 user.permissions[GLOBAL].add(perm.permission.permission_name)
519 user.permissions[GLOBAL].add(perm.permission.permission_name)
510
520
511 # defaults for repositories, taken from default user
521 # defaults for repositories, taken from default user
512 for perm in default_repo_perms:
522 for perm in default_repo_perms:
513 r_k = perm.UserRepoToPerm.repository.repo_name
523 r_k = perm.UserRepoToPerm.repository.repo_name
514 if perm.Repository.private and not (perm.Repository.user_id == uid):
524 if perm.Repository.private and not (perm.Repository.user_id == uid):
515 # disable defaults for private repos,
525 # disable defaults for private repos,
516 p = 'repository.none'
526 p = 'repository.none'
517 elif perm.Repository.user_id == uid:
527 elif perm.Repository.user_id == uid:
518 # set admin if owner
528 # set admin if owner
519 p = 'repository.admin'
529 p = 'repository.admin'
520 else:
530 else:
521 p = perm.Permission.permission_name
531 p = perm.Permission.permission_name
522
532
523 user.permissions[RK][r_k] = p
533 user.permissions[RK][r_k] = p
524
534
525 # defaults for repository groups taken from default user permission
535 # defaults for repository groups taken from default user permission
526 # on given group
536 # on given group
527 for perm in default_repo_groups_perms:
537 for perm in default_repo_groups_perms:
528 rg_k = perm.UserRepoGroupToPerm.group.group_name
538 rg_k = perm.UserRepoGroupToPerm.group.group_name
529 p = perm.Permission.permission_name
539 p = perm.Permission.permission_name
530 user.permissions[GK][rg_k] = p
540 user.permissions[GK][rg_k] = p
531
541
532 # defaults for user groups taken from default user permission
542 # defaults for user groups taken from default user permission
533 # on given user group
543 # on given user group
534 for perm in default_user_group_perms:
544 for perm in default_user_group_perms:
535 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
545 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
536 p = perm.Permission.permission_name
546 p = perm.Permission.permission_name
537 user.permissions[UK][u_k] = p
547 user.permissions[UK][u_k] = p
538
548
539 #======================================================================
549 #======================================================================
540 # !! OVERRIDE GLOBALS !! with user permissions if any found
550 # !! OVERRIDE GLOBALS !! with user permissions if any found
541 #======================================================================
551 #======================================================================
542 # those can be configured from groups or users explicitly
552 # those can be configured from groups or users explicitly
543 _configurable = set([
553 _configurable = set([
544 'hg.fork.none', 'hg.fork.repository',
554 'hg.fork.none', 'hg.fork.repository',
545 'hg.create.none', 'hg.create.repository',
555 'hg.create.none', 'hg.create.repository',
546 'hg.usergroup.create.false', 'hg.usergroup.create.true'
556 'hg.usergroup.create.false', 'hg.usergroup.create.true'
547 ])
557 ])
548
558
549 # USER GROUPS comes first
559 # USER GROUPS comes first
550 # user group global permissions
560 # user group global permissions
551 user_perms_from_users_groups = self.sa.query(UserGroupToPerm)\
561 user_perms_from_users_groups = self.sa.query(UserGroupToPerm)\
552 .options(joinedload(UserGroupToPerm.permission))\
562 .options(joinedload(UserGroupToPerm.permission))\
553 .join((UserGroupMember, UserGroupToPerm.users_group_id ==
563 .join((UserGroupMember, UserGroupToPerm.users_group_id ==
554 UserGroupMember.users_group_id))\
564 UserGroupMember.users_group_id))\
555 .filter(UserGroupMember.user_id == uid)\
565 .filter(UserGroupMember.user_id == uid)\
556 .order_by(UserGroupToPerm.users_group_id)\
566 .order_by(UserGroupToPerm.users_group_id)\
557 .all()
567 .all()
558 #need to group here by groups since user can be in more than one group
568 #need to group here by groups since user can be in more than one group
559 _grouped = [[x, list(y)] for x, y in
569 _grouped = [[x, list(y)] for x, y in
560 itertools.groupby(user_perms_from_users_groups,
570 itertools.groupby(user_perms_from_users_groups,
561 lambda x:x.users_group)]
571 lambda x:x.users_group)]
562 for gr, perms in _grouped:
572 for gr, perms in _grouped:
563 # since user can be in multiple groups iterate over them and
573 # since user can be in multiple groups iterate over them and
564 # select the lowest permissions first (more explicit)
574 # select the lowest permissions first (more explicit)
565 ##TODO: do this^^
575 ##TODO: do this^^
566 if not gr.inherit_default_permissions:
576 if not gr.inherit_default_permissions:
567 # NEED TO IGNORE all configurable permissions and
577 # NEED TO IGNORE all configurable permissions and
568 # replace them with explicitly set
578 # replace them with explicitly set
569 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
579 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
570 .difference(_configurable)
580 .difference(_configurable)
571 for perm in perms:
581 for perm in perms:
572 user.permissions[GLOBAL].add(perm.permission.permission_name)
582 user.permissions[GLOBAL].add(perm.permission.permission_name)
573
583
574 # user specific global permissions
584 # user specific global permissions
575 user_perms = self.sa.query(UserToPerm)\
585 user_perms = self.sa.query(UserToPerm)\
576 .options(joinedload(UserToPerm.permission))\
586 .options(joinedload(UserToPerm.permission))\
577 .filter(UserToPerm.user_id == uid).all()
587 .filter(UserToPerm.user_id == uid).all()
578
588
579 if not user.inherit_default_permissions:
589 if not user.inherit_default_permissions:
580 # NEED TO IGNORE all configurable permissions and
590 # NEED TO IGNORE all configurable permissions and
581 # replace them with explicitly set
591 # replace them with explicitly set
582 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
592 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
583 .difference(_configurable)
593 .difference(_configurable)
584
594
585 for perm in user_perms:
595 for perm in user_perms:
586 user.permissions[GLOBAL].add(perm.permission.permission_name)
596 user.permissions[GLOBAL].add(perm.permission.permission_name)
587 ## END GLOBAL PERMISSIONS
597 ## END GLOBAL PERMISSIONS
588
598
589 #======================================================================
599 #======================================================================
590 # !! PERMISSIONS FOR REPOSITORIES !!
600 # !! PERMISSIONS FOR REPOSITORIES !!
591 #======================================================================
601 #======================================================================
592 #======================================================================
602 #======================================================================
593 # check if user is part of user groups for this repository and
603 # check if user is part of user groups for this repository and
594 # fill in his permission from it. _choose_perm decides of which
604 # fill in his permission from it. _choose_perm decides of which
595 # permission should be selected based on selected method
605 # permission should be selected based on selected method
596 #======================================================================
606 #======================================================================
597
607
598 # user group for repositories permissions
608 # user group for repositories permissions
599 user_repo_perms_from_users_groups = \
609 user_repo_perms_from_users_groups = \
600 self.sa.query(UserGroupRepoToPerm, Permission, Repository,)\
610 self.sa.query(UserGroupRepoToPerm, Permission, Repository,)\
601 .join((Repository, UserGroupRepoToPerm.repository_id ==
611 .join((Repository, UserGroupRepoToPerm.repository_id ==
602 Repository.repo_id))\
612 Repository.repo_id))\
603 .join((Permission, UserGroupRepoToPerm.permission_id ==
613 .join((Permission, UserGroupRepoToPerm.permission_id ==
604 Permission.permission_id))\
614 Permission.permission_id))\
605 .join((UserGroupMember, UserGroupRepoToPerm.users_group_id ==
615 .join((UserGroupMember, UserGroupRepoToPerm.users_group_id ==
606 UserGroupMember.users_group_id))\
616 UserGroupMember.users_group_id))\
607 .filter(UserGroupMember.user_id == uid)\
617 .filter(UserGroupMember.user_id == uid)\
608 .all()
618 .all()
609
619
610 multiple_counter = collections.defaultdict(int)
620 multiple_counter = collections.defaultdict(int)
611 for perm in user_repo_perms_from_users_groups:
621 for perm in user_repo_perms_from_users_groups:
612 r_k = perm.UserGroupRepoToPerm.repository.repo_name
622 r_k = perm.UserGroupRepoToPerm.repository.repo_name
613 multiple_counter[r_k] += 1
623 multiple_counter[r_k] += 1
614 p = perm.Permission.permission_name
624 p = perm.Permission.permission_name
615 cur_perm = user.permissions[RK][r_k]
625 cur_perm = user.permissions[RK][r_k]
616
626
617 if perm.Repository.user_id == uid:
627 if perm.Repository.user_id == uid:
618 # set admin if owner
628 # set admin if owner
619 p = 'repository.admin'
629 p = 'repository.admin'
620 else:
630 else:
621 if multiple_counter[r_k] > 1:
631 if multiple_counter[r_k] > 1:
622 p = _choose_perm(p, cur_perm)
632 p = _choose_perm(p, cur_perm)
623 user.permissions[RK][r_k] = p
633 user.permissions[RK][r_k] = p
624
634
625 # user explicit permissions for repositories, overrides any specified
635 # user explicit permissions for repositories, overrides any specified
626 # by the group permission
636 # by the group permission
627 user_repo_perms = Permission.get_default_perms(uid)
637 user_repo_perms = Permission.get_default_perms(uid)
628 for perm in user_repo_perms:
638 for perm in user_repo_perms:
629 r_k = perm.UserRepoToPerm.repository.repo_name
639 r_k = perm.UserRepoToPerm.repository.repo_name
630 cur_perm = user.permissions[RK][r_k]
640 cur_perm = user.permissions[RK][r_k]
631 # set admin if owner
641 # set admin if owner
632 if perm.Repository.user_id == uid:
642 if perm.Repository.user_id == uid:
633 p = 'repository.admin'
643 p = 'repository.admin'
634 else:
644 else:
635 p = perm.Permission.permission_name
645 p = perm.Permission.permission_name
636 if not explicit:
646 if not explicit:
637 p = _choose_perm(p, cur_perm)
647 p = _choose_perm(p, cur_perm)
638 user.permissions[RK][r_k] = p
648 user.permissions[RK][r_k] = p
639
649
640 #======================================================================
650 #======================================================================
641 # !! PERMISSIONS FOR REPOSITORY GROUPS !!
651 # !! PERMISSIONS FOR REPOSITORY GROUPS !!
642 #======================================================================
652 #======================================================================
643 #======================================================================
653 #======================================================================
644 # check if user is part of user groups for this repository groups and
654 # check if user is part of user groups for this repository groups and
645 # fill in his permission from it. _choose_perm decides of which
655 # fill in his permission from it. _choose_perm decides of which
646 # permission should be selected based on selected method
656 # permission should be selected based on selected method
647 #======================================================================
657 #======================================================================
648 # user group for repo groups permissions
658 # user group for repo groups permissions
649 user_repo_group_perms_from_users_groups = \
659 user_repo_group_perms_from_users_groups = \
650 self.sa.query(UserGroupRepoGroupToPerm, Permission, RepoGroup)\
660 self.sa.query(UserGroupRepoGroupToPerm, Permission, RepoGroup)\
651 .join((RepoGroup, UserGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\
661 .join((RepoGroup, UserGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\
652 .join((Permission, UserGroupRepoGroupToPerm.permission_id
662 .join((Permission, UserGroupRepoGroupToPerm.permission_id
653 == Permission.permission_id))\
663 == Permission.permission_id))\
654 .join((UserGroupMember, UserGroupRepoGroupToPerm.users_group_id
664 .join((UserGroupMember, UserGroupRepoGroupToPerm.users_group_id
655 == UserGroupMember.users_group_id))\
665 == UserGroupMember.users_group_id))\
656 .filter(UserGroupMember.user_id == uid)\
666 .filter(UserGroupMember.user_id == uid)\
657 .all()
667 .all()
658
668
659 multiple_counter = collections.defaultdict(int)
669 multiple_counter = collections.defaultdict(int)
660 for perm in user_repo_group_perms_from_users_groups:
670 for perm in user_repo_group_perms_from_users_groups:
661 g_k = perm.UserGroupRepoGroupToPerm.group.group_name
671 g_k = perm.UserGroupRepoGroupToPerm.group.group_name
662 multiple_counter[g_k] += 1
672 multiple_counter[g_k] += 1
663 p = perm.Permission.permission_name
673 p = perm.Permission.permission_name
664 cur_perm = user.permissions[GK][g_k]
674 cur_perm = user.permissions[GK][g_k]
665 if multiple_counter[g_k] > 1:
675 if multiple_counter[g_k] > 1:
666 p = _choose_perm(p, cur_perm)
676 p = _choose_perm(p, cur_perm)
667 user.permissions[GK][g_k] = p
677 user.permissions[GK][g_k] = p
668
678
669 # user explicit permissions for repository groups
679 # user explicit permissions for repository groups
670 user_repo_groups_perms = Permission.get_default_group_perms(uid)
680 user_repo_groups_perms = Permission.get_default_group_perms(uid)
671 for perm in user_repo_groups_perms:
681 for perm in user_repo_groups_perms:
672 rg_k = perm.UserRepoGroupToPerm.group.group_name
682 rg_k = perm.UserRepoGroupToPerm.group.group_name
673 p = perm.Permission.permission_name
683 p = perm.Permission.permission_name
674 cur_perm = user.permissions[GK][rg_k]
684 cur_perm = user.permissions[GK][rg_k]
675 if not explicit:
685 if not explicit:
676 p = _choose_perm(p, cur_perm)
686 p = _choose_perm(p, cur_perm)
677 user.permissions[GK][rg_k] = p
687 user.permissions[GK][rg_k] = p
678
688
679 #======================================================================
689 #======================================================================
680 # !! PERMISSIONS FOR USER GROUPS !!
690 # !! PERMISSIONS FOR USER GROUPS !!
681 #======================================================================
691 #======================================================================
682 # user group for user group permissions
692 # user group for user group permissions
683 user_group_user_groups_perms = \
693 user_group_user_groups_perms = \
684 self.sa.query(UserGroupUserGroupToPerm, Permission, UserGroup)\
694 self.sa.query(UserGroupUserGroupToPerm, Permission, UserGroup)\
685 .join((UserGroup, UserGroupUserGroupToPerm.target_user_group_id
695 .join((UserGroup, UserGroupUserGroupToPerm.target_user_group_id
686 == UserGroup.users_group_id))\
696 == UserGroup.users_group_id))\
687 .join((Permission, UserGroupUserGroupToPerm.permission_id
697 .join((Permission, UserGroupUserGroupToPerm.permission_id
688 == Permission.permission_id))\
698 == Permission.permission_id))\
689 .join((UserGroupMember, UserGroupUserGroupToPerm.user_group_id
699 .join((UserGroupMember, UserGroupUserGroupToPerm.user_group_id
690 == UserGroupMember.users_group_id))\
700 == UserGroupMember.users_group_id))\
691 .filter(UserGroupMember.user_id == uid)\
701 .filter(UserGroupMember.user_id == uid)\
692 .all()
702 .all()
693
703
694 multiple_counter = collections.defaultdict(int)
704 multiple_counter = collections.defaultdict(int)
695 for perm in user_group_user_groups_perms:
705 for perm in user_group_user_groups_perms:
696 g_k = perm.UserGroupUserGroupToPerm.target_user_group.users_group_name
706 g_k = perm.UserGroupUserGroupToPerm.target_user_group.users_group_name
697 multiple_counter[g_k] += 1
707 multiple_counter[g_k] += 1
698 p = perm.Permission.permission_name
708 p = perm.Permission.permission_name
699 cur_perm = user.permissions[UK][g_k]
709 cur_perm = user.permissions[UK][g_k]
700 if multiple_counter[g_k] > 1:
710 if multiple_counter[g_k] > 1:
701 p = _choose_perm(p, cur_perm)
711 p = _choose_perm(p, cur_perm)
702 user.permissions[UK][g_k] = p
712 user.permissions[UK][g_k] = p
703
713
704 #user explicit permission for user groups
714 #user explicit permission for user groups
705 user_user_groups_perms = Permission.get_default_user_group_perms(uid)
715 user_user_groups_perms = Permission.get_default_user_group_perms(uid)
706 for perm in user_user_groups_perms:
716 for perm in user_user_groups_perms:
707 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
717 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
708 p = perm.Permission.permission_name
718 p = perm.Permission.permission_name
709 cur_perm = user.permissions[UK][u_k]
719 cur_perm = user.permissions[UK][u_k]
710 if not explicit:
720 if not explicit:
711 p = _choose_perm(p, cur_perm)
721 p = _choose_perm(p, cur_perm)
712 user.permissions[UK][u_k] = p
722 user.permissions[UK][u_k] = p
713
723
714 return user
724 return user
715
725
716 def has_perm(self, user, perm):
726 def has_perm(self, user, perm):
717 perm = self._get_perm(perm)
727 perm = self._get_perm(perm)
718 user = self._get_user(user)
728 user = self._get_user(user)
719
729
720 return UserToPerm.query().filter(UserToPerm.user == user)\
730 return UserToPerm.query().filter(UserToPerm.user == user)\
721 .filter(UserToPerm.permission == perm).scalar() is not None
731 .filter(UserToPerm.permission == perm).scalar() is not None
722
732
723 def grant_perm(self, user, perm):
733 def grant_perm(self, user, perm):
724 """
734 """
725 Grant user global permissions
735 Grant user global permissions
726
736
727 :param user:
737 :param user:
728 :param perm:
738 :param perm:
729 """
739 """
730 user = self._get_user(user)
740 user = self._get_user(user)
731 perm = self._get_perm(perm)
741 perm = self._get_perm(perm)
732 # if this permission is already granted skip it
742 # if this permission is already granted skip it
733 _perm = UserToPerm.query()\
743 _perm = UserToPerm.query()\
734 .filter(UserToPerm.user == user)\
744 .filter(UserToPerm.user == user)\
735 .filter(UserToPerm.permission == perm)\
745 .filter(UserToPerm.permission == perm)\
736 .scalar()
746 .scalar()
737 if _perm:
747 if _perm:
738 return
748 return
739 new = UserToPerm()
749 new = UserToPerm()
740 new.user = user
750 new.user = user
741 new.permission = perm
751 new.permission = perm
742 self.sa.add(new)
752 self.sa.add(new)
743
753
744 def revoke_perm(self, user, perm):
754 def revoke_perm(self, user, perm):
745 """
755 """
746 Revoke users global permissions
756 Revoke users global permissions
747
757
748 :param user:
758 :param user:
749 :param perm:
759 :param perm:
750 """
760 """
751 user = self._get_user(user)
761 user = self._get_user(user)
752 perm = self._get_perm(perm)
762 perm = self._get_perm(perm)
753
763
754 obj = UserToPerm.query()\
764 obj = UserToPerm.query()\
755 .filter(UserToPerm.user == user)\
765 .filter(UserToPerm.user == user)\
756 .filter(UserToPerm.permission == perm)\
766 .filter(UserToPerm.permission == perm)\
757 .scalar()
767 .scalar()
758 if obj:
768 if obj:
759 self.sa.delete(obj)
769 self.sa.delete(obj)
760
770
761 def add_extra_email(self, user, email):
771 def add_extra_email(self, user, email):
762 """
772 """
763 Adds email address to UserEmailMap
773 Adds email address to UserEmailMap
764
774
765 :param user:
775 :param user:
766 :param email:
776 :param email:
767 """
777 """
768 from rhodecode.model import forms
778 from rhodecode.model import forms
769 form = forms.UserExtraEmailForm()()
779 form = forms.UserExtraEmailForm()()
770 data = form.to_python(dict(email=email))
780 data = form.to_python(dict(email=email))
771 user = self._get_user(user)
781 user = self._get_user(user)
772
782
773 obj = UserEmailMap()
783 obj = UserEmailMap()
774 obj.user = user
784 obj.user = user
775 obj.email = data['email']
785 obj.email = data['email']
776 self.sa.add(obj)
786 self.sa.add(obj)
777 return obj
787 return obj
778
788
779 def delete_extra_email(self, user, email_id):
789 def delete_extra_email(self, user, email_id):
780 """
790 """
781 Removes email address from UserEmailMap
791 Removes email address from UserEmailMap
782
792
783 :param user:
793 :param user:
784 :param email_id:
794 :param email_id:
785 """
795 """
786 user = self._get_user(user)
796 user = self._get_user(user)
787 obj = UserEmailMap.query().get(email_id)
797 obj = UserEmailMap.query().get(email_id)
788 if obj:
798 if obj:
789 self.sa.delete(obj)
799 self.sa.delete(obj)
790
800
791 def add_extra_ip(self, user, ip):
801 def add_extra_ip(self, user, ip):
792 """
802 """
793 Adds ip address to UserIpMap
803 Adds ip address to UserIpMap
794
804
795 :param user:
805 :param user:
796 :param ip:
806 :param ip:
797 """
807 """
798 from rhodecode.model import forms
808 from rhodecode.model import forms
799 form = forms.UserExtraIpForm()()
809 form = forms.UserExtraIpForm()()
800 data = form.to_python(dict(ip=ip))
810 data = form.to_python(dict(ip=ip))
801 user = self._get_user(user)
811 user = self._get_user(user)
802
812
803 obj = UserIpMap()
813 obj = UserIpMap()
804 obj.user = user
814 obj.user = user
805 obj.ip_addr = data['ip']
815 obj.ip_addr = data['ip']
806 self.sa.add(obj)
816 self.sa.add(obj)
807 return obj
817 return obj
808
818
809 def delete_extra_ip(self, user, ip_id):
819 def delete_extra_ip(self, user, ip_id):
810 """
820 """
811 Removes ip address from UserIpMap
821 Removes ip address from UserIpMap
812
822
813 :param user:
823 :param user:
814 :param ip_id:
824 :param ip_id:
815 """
825 """
816 user = self._get_user(user)
826 user = self._get_user(user)
817 obj = UserIpMap.query().get(ip_id)
827 obj = UserIpMap.query().get(ip_id)
818 if obj:
828 if obj:
819 self.sa.delete(obj)
829 self.sa.delete(obj)
General Comments 0
You need to be logged in to leave comments. Login now