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