##// END OF EJS Templates
fixed repo_create hooks for forks
marcink -
r2185:eac0d619 beta
parent child Browse files
Show More
@@ -1,416 +1,421 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.celerylib.tasks
3 rhodecode.lib.celerylib.tasks
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 RhodeCode task modules, containing all task that suppose to be run
6 RhodeCode task modules, containing all task that suppose to be run
7 by celery daemon
7 by celery daemon
8
8
9 :created_on: Oct 6, 2010
9 :created_on: Oct 6, 2010
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
17 # (at your option) any later version.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 from celery.decorators import task
26 from celery.decorators import task
27
27
28 import os
28 import os
29 import traceback
29 import traceback
30 import logging
30 import logging
31 from os.path import join as jn
31 from os.path import join as jn
32
32
33 from time import mktime
33 from time import mktime
34 from operator import itemgetter
34 from operator import itemgetter
35 from string import lower
35 from string import lower
36
36
37 from pylons import config, url
37 from pylons import config, url
38 from pylons.i18n.translation import _
38 from pylons.i18n.translation import _
39
39
40 from rhodecode.lib.vcs import get_backend
40 from rhodecode.lib.vcs import get_backend
41
41
42 from rhodecode import CELERY_ON
42 from rhodecode import CELERY_ON
43 from rhodecode.lib.utils2 import safe_str
43 from rhodecode.lib.utils2 import safe_str
44 from rhodecode.lib.celerylib import run_task, locked_task, dbsession, \
44 from rhodecode.lib.celerylib import run_task, locked_task, dbsession, \
45 str2bool, __get_lockkey, LockHeld, DaemonLock, get_session
45 str2bool, __get_lockkey, LockHeld, DaemonLock, get_session
46 from rhodecode.lib.helpers import person
46 from rhodecode.lib.helpers import person
47 from rhodecode.lib.rcmail.smtp_mailer import SmtpMailer
47 from rhodecode.lib.rcmail.smtp_mailer import SmtpMailer
48 from rhodecode.lib.utils import add_cache, action_logger
48 from rhodecode.lib.utils import add_cache, action_logger
49 from rhodecode.lib.compat import json, OrderedDict
49 from rhodecode.lib.compat import json, OrderedDict
50 from rhodecode.lib.hooks import log_create_repository
50
51
51 from rhodecode.model.db import Statistics, Repository, User
52 from rhodecode.model.db import Statistics, Repository, User
52
53
53
54
54 add_cache(config)
55 add_cache(config)
55
56
56 __all__ = ['whoosh_index', 'get_commits_stats',
57 __all__ = ['whoosh_index', 'get_commits_stats',
57 'reset_user_password', 'send_email']
58 'reset_user_password', 'send_email']
58
59
59
60
60 def get_logger(cls):
61 def get_logger(cls):
61 if CELERY_ON:
62 if CELERY_ON:
62 try:
63 try:
63 log = cls.get_logger()
64 log = cls.get_logger()
64 except:
65 except:
65 log = logging.getLogger(__name__)
66 log = logging.getLogger(__name__)
66 else:
67 else:
67 log = logging.getLogger(__name__)
68 log = logging.getLogger(__name__)
68
69
69 return log
70 return log
70
71
71
72
72 @task(ignore_result=True)
73 @task(ignore_result=True)
73 @locked_task
74 @locked_task
74 @dbsession
75 @dbsession
75 def whoosh_index(repo_location, full_index):
76 def whoosh_index(repo_location, full_index):
76 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
77 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
77 log = whoosh_index.get_logger(whoosh_index)
78 log = whoosh_index.get_logger(whoosh_index)
78 DBS = get_session()
79 DBS = get_session()
79
80
80 index_location = config['index_dir']
81 index_location = config['index_dir']
81 WhooshIndexingDaemon(index_location=index_location,
82 WhooshIndexingDaemon(index_location=index_location,
82 repo_location=repo_location, sa=DBS)\
83 repo_location=repo_location, sa=DBS)\
83 .run(full_index=full_index)
84 .run(full_index=full_index)
84
85
85
86
86 @task(ignore_result=True)
87 @task(ignore_result=True)
87 @dbsession
88 @dbsession
88 def get_commits_stats(repo_name, ts_min_y, ts_max_y):
89 def get_commits_stats(repo_name, ts_min_y, ts_max_y):
89 log = get_logger(get_commits_stats)
90 log = get_logger(get_commits_stats)
90 DBS = get_session()
91 DBS = get_session()
91 lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y,
92 lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y,
92 ts_max_y)
93 ts_max_y)
93 lockkey_path = config['here']
94 lockkey_path = config['here']
94
95
95 log.info('running task with lockkey %s' % lockkey)
96 log.info('running task with lockkey %s' % lockkey)
96
97
97 try:
98 try:
98 lock = l = DaemonLock(file_=jn(lockkey_path, lockkey))
99 lock = l = DaemonLock(file_=jn(lockkey_path, lockkey))
99
100
100 # for js data compatibility cleans the key for person from '
101 # for js data compatibility cleans the key for person from '
101 akc = lambda k: person(k).replace('"', "")
102 akc = lambda k: person(k).replace('"', "")
102
103
103 co_day_auth_aggr = {}
104 co_day_auth_aggr = {}
104 commits_by_day_aggregate = {}
105 commits_by_day_aggregate = {}
105 repo = Repository.get_by_repo_name(repo_name)
106 repo = Repository.get_by_repo_name(repo_name)
106 if repo is None:
107 if repo is None:
107 return True
108 return True
108
109
109 repo = repo.scm_instance
110 repo = repo.scm_instance
110 repo_size = repo.count()
111 repo_size = repo.count()
111 # return if repo have no revisions
112 # return if repo have no revisions
112 if repo_size < 1:
113 if repo_size < 1:
113 lock.release()
114 lock.release()
114 return True
115 return True
115
116
116 skip_date_limit = True
117 skip_date_limit = True
117 parse_limit = int(config['app_conf'].get('commit_parse_limit'))
118 parse_limit = int(config['app_conf'].get('commit_parse_limit'))
118 last_rev = None
119 last_rev = None
119 last_cs = None
120 last_cs = None
120 timegetter = itemgetter('time')
121 timegetter = itemgetter('time')
121
122
122 dbrepo = DBS.query(Repository)\
123 dbrepo = DBS.query(Repository)\
123 .filter(Repository.repo_name == repo_name).scalar()
124 .filter(Repository.repo_name == repo_name).scalar()
124 cur_stats = DBS.query(Statistics)\
125 cur_stats = DBS.query(Statistics)\
125 .filter(Statistics.repository == dbrepo).scalar()
126 .filter(Statistics.repository == dbrepo).scalar()
126
127
127 if cur_stats is not None:
128 if cur_stats is not None:
128 last_rev = cur_stats.stat_on_revision
129 last_rev = cur_stats.stat_on_revision
129
130
130 if last_rev == repo.get_changeset().revision and repo_size > 1:
131 if last_rev == repo.get_changeset().revision and repo_size > 1:
131 # pass silently without any work if we're not on first revision or
132 # pass silently without any work if we're not on first revision or
132 # current state of parsing revision(from db marker) is the
133 # current state of parsing revision(from db marker) is the
133 # last revision
134 # last revision
134 lock.release()
135 lock.release()
135 return True
136 return True
136
137
137 if cur_stats:
138 if cur_stats:
138 commits_by_day_aggregate = OrderedDict(json.loads(
139 commits_by_day_aggregate = OrderedDict(json.loads(
139 cur_stats.commit_activity_combined))
140 cur_stats.commit_activity_combined))
140 co_day_auth_aggr = json.loads(cur_stats.commit_activity)
141 co_day_auth_aggr = json.loads(cur_stats.commit_activity)
141
142
142 log.debug('starting parsing %s' % parse_limit)
143 log.debug('starting parsing %s' % parse_limit)
143 lmktime = mktime
144 lmktime = mktime
144
145
145 last_rev = last_rev + 1 if last_rev >= 0 else 0
146 last_rev = last_rev + 1 if last_rev >= 0 else 0
146 log.debug('Getting revisions from %s to %s' % (
147 log.debug('Getting revisions from %s to %s' % (
147 last_rev, last_rev + parse_limit)
148 last_rev, last_rev + parse_limit)
148 )
149 )
149 for cs in repo[last_rev:last_rev + parse_limit]:
150 for cs in repo[last_rev:last_rev + parse_limit]:
150 log.debug('parsing %s' % cs)
151 log.debug('parsing %s' % cs)
151 last_cs = cs # remember last parsed changeset
152 last_cs = cs # remember last parsed changeset
152 k = lmktime([cs.date.timetuple()[0], cs.date.timetuple()[1],
153 k = lmktime([cs.date.timetuple()[0], cs.date.timetuple()[1],
153 cs.date.timetuple()[2], 0, 0, 0, 0, 0, 0])
154 cs.date.timetuple()[2], 0, 0, 0, 0, 0, 0])
154
155
155 if akc(cs.author) in co_day_auth_aggr:
156 if akc(cs.author) in co_day_auth_aggr:
156 try:
157 try:
157 l = [timegetter(x) for x in
158 l = [timegetter(x) for x in
158 co_day_auth_aggr[akc(cs.author)]['data']]
159 co_day_auth_aggr[akc(cs.author)]['data']]
159 time_pos = l.index(k)
160 time_pos = l.index(k)
160 except ValueError:
161 except ValueError:
161 time_pos = False
162 time_pos = False
162
163
163 if time_pos >= 0 and time_pos is not False:
164 if time_pos >= 0 and time_pos is not False:
164
165
165 datadict = \
166 datadict = \
166 co_day_auth_aggr[akc(cs.author)]['data'][time_pos]
167 co_day_auth_aggr[akc(cs.author)]['data'][time_pos]
167
168
168 datadict["commits"] += 1
169 datadict["commits"] += 1
169 datadict["added"] += len(cs.added)
170 datadict["added"] += len(cs.added)
170 datadict["changed"] += len(cs.changed)
171 datadict["changed"] += len(cs.changed)
171 datadict["removed"] += len(cs.removed)
172 datadict["removed"] += len(cs.removed)
172
173
173 else:
174 else:
174 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
175 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
175
176
176 datadict = {"time": k,
177 datadict = {"time": k,
177 "commits": 1,
178 "commits": 1,
178 "added": len(cs.added),
179 "added": len(cs.added),
179 "changed": len(cs.changed),
180 "changed": len(cs.changed),
180 "removed": len(cs.removed),
181 "removed": len(cs.removed),
181 }
182 }
182 co_day_auth_aggr[akc(cs.author)]['data']\
183 co_day_auth_aggr[akc(cs.author)]['data']\
183 .append(datadict)
184 .append(datadict)
184
185
185 else:
186 else:
186 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
187 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
187 co_day_auth_aggr[akc(cs.author)] = {
188 co_day_auth_aggr[akc(cs.author)] = {
188 "label": akc(cs.author),
189 "label": akc(cs.author),
189 "data": [{"time":k,
190 "data": [{"time":k,
190 "commits":1,
191 "commits":1,
191 "added":len(cs.added),
192 "added":len(cs.added),
192 "changed":len(cs.changed),
193 "changed":len(cs.changed),
193 "removed":len(cs.removed),
194 "removed":len(cs.removed),
194 }],
195 }],
195 "schema": ["commits"],
196 "schema": ["commits"],
196 }
197 }
197
198
198 #gather all data by day
199 #gather all data by day
199 if k in commits_by_day_aggregate:
200 if k in commits_by_day_aggregate:
200 commits_by_day_aggregate[k] += 1
201 commits_by_day_aggregate[k] += 1
201 else:
202 else:
202 commits_by_day_aggregate[k] = 1
203 commits_by_day_aggregate[k] = 1
203
204
204 overview_data = sorted(commits_by_day_aggregate.items(),
205 overview_data = sorted(commits_by_day_aggregate.items(),
205 key=itemgetter(0))
206 key=itemgetter(0))
206
207
207 if not co_day_auth_aggr:
208 if not co_day_auth_aggr:
208 co_day_auth_aggr[akc(repo.contact)] = {
209 co_day_auth_aggr[akc(repo.contact)] = {
209 "label": akc(repo.contact),
210 "label": akc(repo.contact),
210 "data": [0, 1],
211 "data": [0, 1],
211 "schema": ["commits"],
212 "schema": ["commits"],
212 }
213 }
213
214
214 stats = cur_stats if cur_stats else Statistics()
215 stats = cur_stats if cur_stats else Statistics()
215 stats.commit_activity = json.dumps(co_day_auth_aggr)
216 stats.commit_activity = json.dumps(co_day_auth_aggr)
216 stats.commit_activity_combined = json.dumps(overview_data)
217 stats.commit_activity_combined = json.dumps(overview_data)
217
218
218 log.debug('last revison %s' % last_rev)
219 log.debug('last revison %s' % last_rev)
219 leftovers = len(repo.revisions[last_rev:])
220 leftovers = len(repo.revisions[last_rev:])
220 log.debug('revisions to parse %s' % leftovers)
221 log.debug('revisions to parse %s' % leftovers)
221
222
222 if last_rev == 0 or leftovers < parse_limit:
223 if last_rev == 0 or leftovers < parse_limit:
223 log.debug('getting code trending stats')
224 log.debug('getting code trending stats')
224 stats.languages = json.dumps(__get_codes_stats(repo_name))
225 stats.languages = json.dumps(__get_codes_stats(repo_name))
225
226
226 try:
227 try:
227 stats.repository = dbrepo
228 stats.repository = dbrepo
228 stats.stat_on_revision = last_cs.revision if last_cs else 0
229 stats.stat_on_revision = last_cs.revision if last_cs else 0
229 DBS.add(stats)
230 DBS.add(stats)
230 DBS.commit()
231 DBS.commit()
231 except:
232 except:
232 log.error(traceback.format_exc())
233 log.error(traceback.format_exc())
233 DBS.rollback()
234 DBS.rollback()
234 lock.release()
235 lock.release()
235 return False
236 return False
236
237
237 # final release
238 # final release
238 lock.release()
239 lock.release()
239
240
240 # execute another task if celery is enabled
241 # execute another task if celery is enabled
241 if len(repo.revisions) > 1 and CELERY_ON:
242 if len(repo.revisions) > 1 and CELERY_ON:
242 run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y)
243 run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y)
243 return True
244 return True
244 except LockHeld:
245 except LockHeld:
245 log.info('LockHeld')
246 log.info('LockHeld')
246 return 'Task with key %s already running' % lockkey
247 return 'Task with key %s already running' % lockkey
247
248
248 @task(ignore_result=True)
249 @task(ignore_result=True)
249 @dbsession
250 @dbsession
250 def send_password_link(user_email):
251 def send_password_link(user_email):
251 from rhodecode.model.notification import EmailNotificationModel
252 from rhodecode.model.notification import EmailNotificationModel
252
253
253 log = get_logger(send_password_link)
254 log = get_logger(send_password_link)
254 DBS = get_session()
255 DBS = get_session()
255
256
256 try:
257 try:
257 user = User.get_by_email(user_email)
258 user = User.get_by_email(user_email)
258 if user:
259 if user:
259 log.debug('password reset user found %s' % user)
260 log.debug('password reset user found %s' % user)
260 link = url('reset_password_confirmation', key=user.api_key,
261 link = url('reset_password_confirmation', key=user.api_key,
261 qualified=True)
262 qualified=True)
262 reg_type = EmailNotificationModel.TYPE_PASSWORD_RESET
263 reg_type = EmailNotificationModel.TYPE_PASSWORD_RESET
263 body = EmailNotificationModel().get_email_tmpl(reg_type,
264 body = EmailNotificationModel().get_email_tmpl(reg_type,
264 **{'user':user.short_contact,
265 **{'user':user.short_contact,
265 'reset_url':link})
266 'reset_url':link})
266 log.debug('sending email')
267 log.debug('sending email')
267 run_task(send_email, user_email,
268 run_task(send_email, user_email,
268 _("password reset link"), body)
269 _("password reset link"), body)
269 log.info('send new password mail to %s' % user_email)
270 log.info('send new password mail to %s' % user_email)
270 else:
271 else:
271 log.debug("password reset email %s not found" % user_email)
272 log.debug("password reset email %s not found" % user_email)
272 except:
273 except:
273 log.error(traceback.format_exc())
274 log.error(traceback.format_exc())
274 return False
275 return False
275
276
276 return True
277 return True
277
278
278 @task(ignore_result=True)
279 @task(ignore_result=True)
279 @dbsession
280 @dbsession
280 def reset_user_password(user_email):
281 def reset_user_password(user_email):
281 from rhodecode.lib import auth
282 from rhodecode.lib import auth
282
283
283 log = get_logger(reset_user_password)
284 log = get_logger(reset_user_password)
284 DBS = get_session()
285 DBS = get_session()
285
286
286 try:
287 try:
287 try:
288 try:
288 user = User.get_by_email(user_email)
289 user = User.get_by_email(user_email)
289 new_passwd = auth.PasswordGenerator().gen_password(8,
290 new_passwd = auth.PasswordGenerator().gen_password(8,
290 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
291 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
291 if user:
292 if user:
292 user.password = auth.get_crypt_password(new_passwd)
293 user.password = auth.get_crypt_password(new_passwd)
293 user.api_key = auth.generate_api_key(user.username)
294 user.api_key = auth.generate_api_key(user.username)
294 DBS.add(user)
295 DBS.add(user)
295 DBS.commit()
296 DBS.commit()
296 log.info('change password for %s' % user_email)
297 log.info('change password for %s' % user_email)
297 if new_passwd is None:
298 if new_passwd is None:
298 raise Exception('unable to generate new password')
299 raise Exception('unable to generate new password')
299 except:
300 except:
300 log.error(traceback.format_exc())
301 log.error(traceback.format_exc())
301 DBS.rollback()
302 DBS.rollback()
302
303
303 run_task(send_email, user_email,
304 run_task(send_email, user_email,
304 'Your new password',
305 'Your new password',
305 'Your new RhodeCode password:%s' % (new_passwd))
306 'Your new RhodeCode password:%s' % (new_passwd))
306 log.info('send new password mail to %s' % user_email)
307 log.info('send new password mail to %s' % user_email)
307
308
308 except:
309 except:
309 log.error('Failed to update user password')
310 log.error('Failed to update user password')
310 log.error(traceback.format_exc())
311 log.error(traceback.format_exc())
311
312
312 return True
313 return True
313
314
314
315
315 @task(ignore_result=True)
316 @task(ignore_result=True)
316 @dbsession
317 @dbsession
317 def send_email(recipients, subject, body, html_body=''):
318 def send_email(recipients, subject, body, html_body=''):
318 """
319 """
319 Sends an email with defined parameters from the .ini files.
320 Sends an email with defined parameters from the .ini files.
320
321
321 :param recipients: list of recipients, it this is empty the defined email
322 :param recipients: list of recipients, it this is empty the defined email
322 address from field 'email_to' is used instead
323 address from field 'email_to' is used instead
323 :param subject: subject of the mail
324 :param subject: subject of the mail
324 :param body: body of the mail
325 :param body: body of the mail
325 :param html_body: html version of body
326 :param html_body: html version of body
326 """
327 """
327 log = get_logger(send_email)
328 log = get_logger(send_email)
328 DBS = get_session()
329 DBS = get_session()
329
330
330 email_config = config
331 email_config = config
331 subject = "%s %s" % (email_config.get('email_prefix', ''), subject)
332 subject = "%s %s" % (email_config.get('email_prefix', ''), subject)
332 if not recipients:
333 if not recipients:
333 # if recipients are not defined we send to email_config + all admins
334 # if recipients are not defined we send to email_config + all admins
334 admins = [u.email for u in User.query()
335 admins = [u.email for u in User.query()
335 .filter(User.admin == True).all()]
336 .filter(User.admin == True).all()]
336 recipients = [email_config.get('email_to')] + admins
337 recipients = [email_config.get('email_to')] + admins
337
338
338 mail_from = email_config.get('app_email_from', 'RhodeCode')
339 mail_from = email_config.get('app_email_from', 'RhodeCode')
339 user = email_config.get('smtp_username')
340 user = email_config.get('smtp_username')
340 passwd = email_config.get('smtp_password')
341 passwd = email_config.get('smtp_password')
341 mail_server = email_config.get('smtp_server')
342 mail_server = email_config.get('smtp_server')
342 mail_port = email_config.get('smtp_port')
343 mail_port = email_config.get('smtp_port')
343 tls = str2bool(email_config.get('smtp_use_tls'))
344 tls = str2bool(email_config.get('smtp_use_tls'))
344 ssl = str2bool(email_config.get('smtp_use_ssl'))
345 ssl = str2bool(email_config.get('smtp_use_ssl'))
345 debug = str2bool(config.get('debug'))
346 debug = str2bool(config.get('debug'))
346 smtp_auth = email_config.get('smtp_auth')
347 smtp_auth = email_config.get('smtp_auth')
347
348
348 try:
349 try:
349 m = SmtpMailer(mail_from, user, passwd, mail_server, smtp_auth,
350 m = SmtpMailer(mail_from, user, passwd, mail_server, smtp_auth,
350 mail_port, ssl, tls, debug=debug)
351 mail_port, ssl, tls, debug=debug)
351 m.send(recipients, subject, body, html_body)
352 m.send(recipients, subject, body, html_body)
352 except:
353 except:
353 log.error('Mail sending failed')
354 log.error('Mail sending failed')
354 log.error(traceback.format_exc())
355 log.error(traceback.format_exc())
355 return False
356 return False
356 return True
357 return True
357
358
358
359
359 @task(ignore_result=True)
360 @task(ignore_result=True)
360 @dbsession
361 @dbsession
361 def create_repo_fork(form_data, cur_user):
362 def create_repo_fork(form_data, cur_user):
362 """
363 """
363 Creates a fork of repository using interval VCS methods
364 Creates a fork of repository using interval VCS methods
364
365
365 :param form_data:
366 :param form_data:
366 :param cur_user:
367 :param cur_user:
367 """
368 """
368 from rhodecode.model.repo import RepoModel
369 from rhodecode.model.repo import RepoModel
369
370
370 log = get_logger(create_repo_fork)
371 log = get_logger(create_repo_fork)
371 DBS = get_session()
372 DBS = get_session()
372
373
373 base_path = Repository.base_path()
374 base_path = Repository.base_path()
374
375
375 RepoModel(DBS).create(form_data, cur_user, just_db=True, fork=True)
376 fork_repo = RepoModel(DBS).create(form_data, cur_user,
377 just_db=True, fork=True)
376
378
377 alias = form_data['repo_type']
379 alias = form_data['repo_type']
378 org_repo_name = form_data['org_path']
380 org_repo_name = form_data['org_path']
379 fork_name = form_data['repo_name_full']
381 fork_name = form_data['repo_name_full']
380 update_after_clone = form_data['update_after_clone']
382 update_after_clone = form_data['update_after_clone']
381 source_repo_path = os.path.join(base_path, org_repo_name)
383 source_repo_path = os.path.join(base_path, org_repo_name)
382 destination_fork_path = os.path.join(base_path, fork_name)
384 destination_fork_path = os.path.join(base_path, fork_name)
383
385
384 log.info('creating fork of %s as %s', source_repo_path,
386 log.info('creating fork of %s as %s', source_repo_path,
385 destination_fork_path)
387 destination_fork_path)
386 backend = get_backend(alias)
388 backend = get_backend(alias)
387 backend(safe_str(destination_fork_path), create=True,
389 backend(safe_str(destination_fork_path), create=True,
388 src_url=safe_str(source_repo_path),
390 src_url=safe_str(source_repo_path),
389 update_after_clone=update_after_clone)
391 update_after_clone=update_after_clone)
392 log_create_repository(fork_repo.get_dict(), created_by=cur_user.username)
393
390 action_logger(cur_user, 'user_forked_repo:%s' % fork_name,
394 action_logger(cur_user, 'user_forked_repo:%s' % fork_name,
391 org_repo_name, '', DBS)
395 org_repo_name, '', DBS)
392
396
393 action_logger(cur_user, 'user_created_fork:%s' % fork_name,
397 action_logger(cur_user, 'user_created_fork:%s' % fork_name,
394 fork_name, '', DBS)
398 fork_name, '', DBS)
395 # finally commit at latest possible stage
399 # finally commit at latest possible stage
396 DBS.commit()
400 DBS.commit()
397
401
402
398 def __get_codes_stats(repo_name):
403 def __get_codes_stats(repo_name):
399 from rhodecode.config.conf import LANGUAGES_EXTENSIONS_MAP
404 from rhodecode.config.conf import LANGUAGES_EXTENSIONS_MAP
400 repo = Repository.get_by_repo_name(repo_name).scm_instance
405 repo = Repository.get_by_repo_name(repo_name).scm_instance
401
406
402 tip = repo.get_changeset()
407 tip = repo.get_changeset()
403 code_stats = {}
408 code_stats = {}
404
409
405 def aggregate(cs):
410 def aggregate(cs):
406 for f in cs[2]:
411 for f in cs[2]:
407 ext = lower(f.extension)
412 ext = lower(f.extension)
408 if ext in LANGUAGES_EXTENSIONS_MAP.keys() and not f.is_binary:
413 if ext in LANGUAGES_EXTENSIONS_MAP.keys() and not f.is_binary:
409 if ext in code_stats:
414 if ext in code_stats:
410 code_stats[ext] += 1
415 code_stats[ext] += 1
411 else:
416 else:
412 code_stats[ext] = 1
417 code_stats[ext] = 1
413
418
414 map(aggregate, tip.walk('/'))
419 map(aggregate, tip.walk('/'))
415
420
416 return code_stats or {}
421 return code_stats or {}
@@ -1,499 +1,499 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.repo
3 rhodecode.model.repo
4 ~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 Repository model for rhodecode
6 Repository model for rhodecode
7
7
8 :created_on: Jun 5, 2010
8 :created_on: Jun 5, 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 shutil
26 import shutil
27 import logging
27 import logging
28 import traceback
28 import traceback
29 from datetime import datetime
29 from datetime import datetime
30
30
31 from rhodecode.lib.vcs.backends import get_backend
31 from rhodecode.lib.vcs.backends import get_backend
32 from rhodecode.lib.compat import json
32 from rhodecode.lib.compat import json
33 from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode
33 from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode
34 from rhodecode.lib.caching_query import FromCache
34 from rhodecode.lib.caching_query import FromCache
35 from rhodecode.lib.hooks import log_create_repository
35 from rhodecode.lib.hooks import log_create_repository
36
36
37 from rhodecode.model import BaseModel
37 from rhodecode.model import BaseModel
38 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
38 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
39 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup
39 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup
40 from rhodecode.lib import helpers as h
40 from rhodecode.lib import helpers as h
41
41
42
42
43 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
44
44
45
45
46 class RepoModel(BaseModel):
46 class RepoModel(BaseModel):
47
47
48 def __get_user(self, user):
48 def __get_user(self, user):
49 return self._get_instance(User, user, callback=User.get_by_username)
49 return self._get_instance(User, user, callback=User.get_by_username)
50
50
51 def __get_users_group(self, users_group):
51 def __get_users_group(self, users_group):
52 return self._get_instance(UsersGroup, users_group,
52 return self._get_instance(UsersGroup, users_group,
53 callback=UsersGroup.get_by_group_name)
53 callback=UsersGroup.get_by_group_name)
54
54
55 def __get_repos_group(self, repos_group):
55 def __get_repos_group(self, repos_group):
56 return self._get_instance(RepoGroup, repos_group,
56 return self._get_instance(RepoGroup, repos_group,
57 callback=RepoGroup.get_by_group_name)
57 callback=RepoGroup.get_by_group_name)
58
58
59 def __get_repo(self, repository):
59 def __get_repo(self, repository):
60 return self._get_instance(Repository, repository,
60 return self._get_instance(Repository, repository,
61 callback=Repository.get_by_repo_name)
61 callback=Repository.get_by_repo_name)
62
62
63 def __get_perm(self, permission):
63 def __get_perm(self, permission):
64 return self._get_instance(Permission, permission,
64 return self._get_instance(Permission, permission,
65 callback=Permission.get_by_key)
65 callback=Permission.get_by_key)
66
66
67 @LazyProperty
67 @LazyProperty
68 def repos_path(self):
68 def repos_path(self):
69 """
69 """
70 Get's the repositories root path from database
70 Get's the repositories root path from database
71 """
71 """
72
72
73 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
73 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
74 return q.ui_value
74 return q.ui_value
75
75
76 def get(self, repo_id, cache=False):
76 def get(self, repo_id, cache=False):
77 repo = self.sa.query(Repository)\
77 repo = self.sa.query(Repository)\
78 .filter(Repository.repo_id == repo_id)
78 .filter(Repository.repo_id == repo_id)
79
79
80 if cache:
80 if cache:
81 repo = repo.options(FromCache("sql_cache_short",
81 repo = repo.options(FromCache("sql_cache_short",
82 "get_repo_%s" % repo_id))
82 "get_repo_%s" % repo_id))
83 return repo.scalar()
83 return repo.scalar()
84
84
85 def get_repo(self, repository):
85 def get_repo(self, repository):
86 return self.__get_repo(repository)
86 return self.__get_repo(repository)
87
87
88 def get_by_repo_name(self, repo_name, cache=False):
88 def get_by_repo_name(self, repo_name, cache=False):
89 repo = self.sa.query(Repository)\
89 repo = self.sa.query(Repository)\
90 .filter(Repository.repo_name == repo_name)
90 .filter(Repository.repo_name == repo_name)
91
91
92 if cache:
92 if cache:
93 repo = repo.options(FromCache("sql_cache_short",
93 repo = repo.options(FromCache("sql_cache_short",
94 "get_repo_%s" % repo_name))
94 "get_repo_%s" % repo_name))
95 return repo.scalar()
95 return repo.scalar()
96
96
97 def get_users_js(self):
97 def get_users_js(self):
98 users = self.sa.query(User).filter(User.active == True).all()
98 users = self.sa.query(User).filter(User.active == True).all()
99 return json.dumps([
99 return json.dumps([
100 {
100 {
101 'id': u.user_id,
101 'id': u.user_id,
102 'fname': u.name,
102 'fname': u.name,
103 'lname': u.lastname,
103 'lname': u.lastname,
104 'nname': u.username,
104 'nname': u.username,
105 'gravatar_lnk': h.gravatar_url(u.email, 14)
105 'gravatar_lnk': h.gravatar_url(u.email, 14)
106 } for u in users]
106 } for u in users]
107 )
107 )
108
108
109 def get_users_groups_js(self):
109 def get_users_groups_js(self):
110 users_groups = self.sa.query(UsersGroup)\
110 users_groups = self.sa.query(UsersGroup)\
111 .filter(UsersGroup.users_group_active == True).all()
111 .filter(UsersGroup.users_group_active == True).all()
112
112
113 return json.dumps([
113 return json.dumps([
114 {
114 {
115 'id': gr.users_group_id,
115 'id': gr.users_group_id,
116 'grname': gr.users_group_name,
116 'grname': gr.users_group_name,
117 'grmembers': len(gr.members),
117 'grmembers': len(gr.members),
118 } for gr in users_groups]
118 } for gr in users_groups]
119 )
119 )
120
120
121 def _get_defaults(self, repo_name):
121 def _get_defaults(self, repo_name):
122 """
122 """
123 Get's information about repository, and returns a dict for
123 Get's information about repository, and returns a dict for
124 usage in forms
124 usage in forms
125
125
126 :param repo_name:
126 :param repo_name:
127 """
127 """
128
128
129 repo_info = Repository.get_by_repo_name(repo_name)
129 repo_info = Repository.get_by_repo_name(repo_name)
130
130
131 if repo_info is None:
131 if repo_info is None:
132 return None
132 return None
133
133
134 defaults = repo_info.get_dict()
134 defaults = repo_info.get_dict()
135 group, repo_name = repo_info.groups_and_repo
135 group, repo_name = repo_info.groups_and_repo
136 defaults['repo_name'] = repo_name
136 defaults['repo_name'] = repo_name
137 defaults['repo_group'] = getattr(group[-1] if group else None,
137 defaults['repo_group'] = getattr(group[-1] if group else None,
138 'group_id', None)
138 'group_id', None)
139
139
140 # fill owner
140 # fill owner
141 if repo_info.user:
141 if repo_info.user:
142 defaults.update({'user': repo_info.user.username})
142 defaults.update({'user': repo_info.user.username})
143 else:
143 else:
144 replacement_user = User.query().filter(User.admin ==
144 replacement_user = User.query().filter(User.admin ==
145 True).first().username
145 True).first().username
146 defaults.update({'user': replacement_user})
146 defaults.update({'user': replacement_user})
147
147
148 # fill repository users
148 # fill repository users
149 for p in repo_info.repo_to_perm:
149 for p in repo_info.repo_to_perm:
150 defaults.update({'u_perm_%s' % p.user.username:
150 defaults.update({'u_perm_%s' % p.user.username:
151 p.permission.permission_name})
151 p.permission.permission_name})
152
152
153 # fill repository groups
153 # fill repository groups
154 for p in repo_info.users_group_to_perm:
154 for p in repo_info.users_group_to_perm:
155 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
155 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
156 p.permission.permission_name})
156 p.permission.permission_name})
157
157
158 return defaults
158 return defaults
159
159
160 def update(self, repo_name, form_data):
160 def update(self, repo_name, form_data):
161 try:
161 try:
162 cur_repo = self.get_by_repo_name(repo_name, cache=False)
162 cur_repo = self.get_by_repo_name(repo_name, cache=False)
163
163
164 # update permissions
164 # update permissions
165 for member, perm, member_type in form_data['perms_updates']:
165 for member, perm, member_type in form_data['perms_updates']:
166 if member_type == 'user':
166 if member_type == 'user':
167 # this updates existing one
167 # this updates existing one
168 RepoModel().grant_user_permission(
168 RepoModel().grant_user_permission(
169 repo=cur_repo, user=member, perm=perm
169 repo=cur_repo, user=member, perm=perm
170 )
170 )
171 else:
171 else:
172 RepoModel().grant_users_group_permission(
172 RepoModel().grant_users_group_permission(
173 repo=cur_repo, group_name=member, perm=perm
173 repo=cur_repo, group_name=member, perm=perm
174 )
174 )
175 # set new permissions
175 # set new permissions
176 for member, perm, member_type in form_data['perms_new']:
176 for member, perm, member_type in form_data['perms_new']:
177 if member_type == 'user':
177 if member_type == 'user':
178 RepoModel().grant_user_permission(
178 RepoModel().grant_user_permission(
179 repo=cur_repo, user=member, perm=perm
179 repo=cur_repo, user=member, perm=perm
180 )
180 )
181 else:
181 else:
182 RepoModel().grant_users_group_permission(
182 RepoModel().grant_users_group_permission(
183 repo=cur_repo, group_name=member, perm=perm
183 repo=cur_repo, group_name=member, perm=perm
184 )
184 )
185
185
186 # update current repo
186 # update current repo
187 for k, v in form_data.items():
187 for k, v in form_data.items():
188 if k == 'user':
188 if k == 'user':
189 cur_repo.user = User.get_by_username(v)
189 cur_repo.user = User.get_by_username(v)
190 elif k == 'repo_name':
190 elif k == 'repo_name':
191 pass
191 pass
192 elif k == 'repo_group':
192 elif k == 'repo_group':
193 cur_repo.group = RepoGroup.get(v)
193 cur_repo.group = RepoGroup.get(v)
194
194
195 else:
195 else:
196 setattr(cur_repo, k, v)
196 setattr(cur_repo, k, v)
197
197
198 new_name = cur_repo.get_new_name(form_data['repo_name'])
198 new_name = cur_repo.get_new_name(form_data['repo_name'])
199 cur_repo.repo_name = new_name
199 cur_repo.repo_name = new_name
200
200
201 self.sa.add(cur_repo)
201 self.sa.add(cur_repo)
202
202
203 if repo_name != new_name:
203 if repo_name != new_name:
204 # rename repository
204 # rename repository
205 self.__rename_repo(old=repo_name, new=new_name)
205 self.__rename_repo(old=repo_name, new=new_name)
206
206
207 return cur_repo
207 return cur_repo
208 except:
208 except:
209 log.error(traceback.format_exc())
209 log.error(traceback.format_exc())
210 raise
210 raise
211
211
212 def create(self, form_data, cur_user, just_db=False, fork=False):
212 def create(self, form_data, cur_user, just_db=False, fork=False):
213 from rhodecode.model.scm import ScmModel
213 from rhodecode.model.scm import ScmModel
214
214
215 try:
215 try:
216 if fork:
216 if fork:
217 fork_parent_id = form_data['fork_parent_id']
217 fork_parent_id = form_data['fork_parent_id']
218
218
219 # repo name is just a name of repository
219 # repo name is just a name of repository
220 # while repo_name_full is a full qualified name that is combined
220 # while repo_name_full is a full qualified name that is combined
221 # with name and path of group
221 # with name and path of group
222 repo_name = form_data['repo_name']
222 repo_name = form_data['repo_name']
223 repo_name_full = form_data['repo_name_full']
223 repo_name_full = form_data['repo_name_full']
224
224
225 new_repo = Repository()
225 new_repo = Repository()
226 new_repo.enable_statistics = False
226 new_repo.enable_statistics = False
227
227
228 for k, v in form_data.items():
228 for k, v in form_data.items():
229 if k == 'repo_name':
229 if k == 'repo_name':
230 v = repo_name_full
230 v = repo_name_full
231 if k == 'repo_group':
231 if k == 'repo_group':
232 k = 'group_id'
232 k = 'group_id'
233 if k == 'description':
233 if k == 'description':
234 v = v or repo_name
234 v = v or repo_name
235
235
236 setattr(new_repo, k, v)
236 setattr(new_repo, k, v)
237
237
238 if fork:
238 if fork:
239 parent_repo = Repository.get(fork_parent_id)
239 parent_repo = Repository.get(fork_parent_id)
240 new_repo.fork = parent_repo
240 new_repo.fork = parent_repo
241
241
242 new_repo.user_id = cur_user.user_id
242 new_repo.user_id = cur_user.user_id
243 self.sa.add(new_repo)
243 self.sa.add(new_repo)
244
244
245 def _create_default_perms():
245 def _create_default_perms():
246 # create default permission
246 # create default permission
247 repo_to_perm = UserRepoToPerm()
247 repo_to_perm = UserRepoToPerm()
248 default = 'repository.read'
248 default = 'repository.read'
249 for p in User.get_by_username('default').user_perms:
249 for p in User.get_by_username('default').user_perms:
250 if p.permission.permission_name.startswith('repository.'):
250 if p.permission.permission_name.startswith('repository.'):
251 default = p.permission.permission_name
251 default = p.permission.permission_name
252 break
252 break
253
253
254 default_perm = 'repository.none' if form_data['private'] else default
254 default_perm = 'repository.none' if form_data['private'] else default
255
255
256 repo_to_perm.permission_id = self.sa.query(Permission)\
256 repo_to_perm.permission_id = self.sa.query(Permission)\
257 .filter(Permission.permission_name == default_perm)\
257 .filter(Permission.permission_name == default_perm)\
258 .one().permission_id
258 .one().permission_id
259
259
260 repo_to_perm.repository = new_repo
260 repo_to_perm.repository = new_repo
261 repo_to_perm.user_id = User.get_by_username('default').user_id
261 repo_to_perm.user_id = User.get_by_username('default').user_id
262
262
263 self.sa.add(repo_to_perm)
263 self.sa.add(repo_to_perm)
264
264
265 if fork:
265 if fork:
266 if form_data.get('copy_permissions'):
266 if form_data.get('copy_permissions'):
267 repo = Repository.get(fork_parent_id)
267 repo = Repository.get(fork_parent_id)
268 user_perms = UserRepoToPerm.query()\
268 user_perms = UserRepoToPerm.query()\
269 .filter(UserRepoToPerm.repository == repo).all()
269 .filter(UserRepoToPerm.repository == repo).all()
270 group_perms = UsersGroupRepoToPerm.query()\
270 group_perms = UsersGroupRepoToPerm.query()\
271 .filter(UsersGroupRepoToPerm.repository == repo).all()
271 .filter(UsersGroupRepoToPerm.repository == repo).all()
272
272
273 for perm in user_perms:
273 for perm in user_perms:
274 UserRepoToPerm.create(perm.user, new_repo,
274 UserRepoToPerm.create(perm.user, new_repo,
275 perm.permission)
275 perm.permission)
276
276
277 for perm in group_perms:
277 for perm in group_perms:
278 UsersGroupRepoToPerm.create(perm.users_group, new_repo,
278 UsersGroupRepoToPerm.create(perm.users_group, new_repo,
279 perm.permission)
279 perm.permission)
280 else:
280 else:
281 _create_default_perms()
281 _create_default_perms()
282 else:
282 else:
283 _create_default_perms()
283 _create_default_perms()
284
284
285 if not just_db:
285 if not just_db:
286 self.__create_repo(repo_name, form_data['repo_type'],
286 self.__create_repo(repo_name, form_data['repo_type'],
287 form_data['repo_group'],
287 form_data['repo_group'],
288 form_data['clone_uri'])
288 form_data['clone_uri'])
289 log_create_repository(new_repo.get_dict(),
290 created_by=cur_user.username)
289
291
290 # now automatically start following this repository as owner
292 # now automatically start following this repository as owner
291 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
293 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
292 cur_user.user_id)
294 cur_user.user_id)
293 log_create_repository(new_repo.get_dict(),
294 created_by=cur_user.username)
295 return new_repo
295 return new_repo
296 except:
296 except:
297 log.error(traceback.format_exc())
297 log.error(traceback.format_exc())
298 raise
298 raise
299
299
300 def create_fork(self, form_data, cur_user):
300 def create_fork(self, form_data, cur_user):
301 """
301 """
302 Simple wrapper into executing celery task for fork creation
302 Simple wrapper into executing celery task for fork creation
303
303
304 :param form_data:
304 :param form_data:
305 :param cur_user:
305 :param cur_user:
306 """
306 """
307 from rhodecode.lib.celerylib import tasks, run_task
307 from rhodecode.lib.celerylib import tasks, run_task
308 run_task(tasks.create_repo_fork, form_data, cur_user)
308 run_task(tasks.create_repo_fork, form_data, cur_user)
309
309
310 def delete(self, repo):
310 def delete(self, repo):
311 repo = self.__get_repo(repo)
311 repo = self.__get_repo(repo)
312 try:
312 try:
313 self.sa.delete(repo)
313 self.sa.delete(repo)
314 self.__delete_repo(repo)
314 self.__delete_repo(repo)
315 except:
315 except:
316 log.error(traceback.format_exc())
316 log.error(traceback.format_exc())
317 raise
317 raise
318
318
319 def grant_user_permission(self, repo, user, perm):
319 def grant_user_permission(self, repo, user, perm):
320 """
320 """
321 Grant permission for user on given repository, or update existing one
321 Grant permission for user on given repository, or update existing one
322 if found
322 if found
323
323
324 :param repo: Instance of Repository, repository_id, or repository name
324 :param repo: Instance of Repository, repository_id, or repository name
325 :param user: Instance of User, user_id or username
325 :param user: Instance of User, user_id or username
326 :param perm: Instance of Permission, or permission_name
326 :param perm: Instance of Permission, or permission_name
327 """
327 """
328 user = self.__get_user(user)
328 user = self.__get_user(user)
329 repo = self.__get_repo(repo)
329 repo = self.__get_repo(repo)
330 permission = self.__get_perm(perm)
330 permission = self.__get_perm(perm)
331
331
332 # check if we have that permission already
332 # check if we have that permission already
333 obj = self.sa.query(UserRepoToPerm)\
333 obj = self.sa.query(UserRepoToPerm)\
334 .filter(UserRepoToPerm.user == user)\
334 .filter(UserRepoToPerm.user == user)\
335 .filter(UserRepoToPerm.repository == repo)\
335 .filter(UserRepoToPerm.repository == repo)\
336 .scalar()
336 .scalar()
337 if obj is None:
337 if obj is None:
338 # create new !
338 # create new !
339 obj = UserRepoToPerm()
339 obj = UserRepoToPerm()
340 obj.repository = repo
340 obj.repository = repo
341 obj.user = user
341 obj.user = user
342 obj.permission = permission
342 obj.permission = permission
343 self.sa.add(obj)
343 self.sa.add(obj)
344
344
345 def revoke_user_permission(self, repo, user):
345 def revoke_user_permission(self, repo, user):
346 """
346 """
347 Revoke permission for user on given repository
347 Revoke permission for user on given repository
348
348
349 :param repo: Instance of Repository, repository_id, or repository name
349 :param repo: Instance of Repository, repository_id, or repository name
350 :param user: Instance of User, user_id or username
350 :param user: Instance of User, user_id or username
351 """
351 """
352
352
353 user = self.__get_user(user)
353 user = self.__get_user(user)
354 repo = self.__get_repo(repo)
354 repo = self.__get_repo(repo)
355
355
356 obj = self.sa.query(UserRepoToPerm)\
356 obj = self.sa.query(UserRepoToPerm)\
357 .filter(UserRepoToPerm.repository == repo)\
357 .filter(UserRepoToPerm.repository == repo)\
358 .filter(UserRepoToPerm.user == user)\
358 .filter(UserRepoToPerm.user == user)\
359 .one()
359 .one()
360 self.sa.delete(obj)
360 self.sa.delete(obj)
361
361
362 def grant_users_group_permission(self, repo, group_name, perm):
362 def grant_users_group_permission(self, repo, group_name, perm):
363 """
363 """
364 Grant permission for users group on given repository, or update
364 Grant permission for users group on given repository, or update
365 existing one if found
365 existing one if found
366
366
367 :param repo: Instance of Repository, repository_id, or repository name
367 :param repo: Instance of Repository, repository_id, or repository name
368 :param group_name: Instance of UserGroup, users_group_id,
368 :param group_name: Instance of UserGroup, users_group_id,
369 or users group name
369 or users group name
370 :param perm: Instance of Permission, or permission_name
370 :param perm: Instance of Permission, or permission_name
371 """
371 """
372 repo = self.__get_repo(repo)
372 repo = self.__get_repo(repo)
373 group_name = self.__get_users_group(group_name)
373 group_name = self.__get_users_group(group_name)
374 permission = self.__get_perm(perm)
374 permission = self.__get_perm(perm)
375
375
376 # check if we have that permission already
376 # check if we have that permission already
377 obj = self.sa.query(UsersGroupRepoToPerm)\
377 obj = self.sa.query(UsersGroupRepoToPerm)\
378 .filter(UsersGroupRepoToPerm.users_group == group_name)\
378 .filter(UsersGroupRepoToPerm.users_group == group_name)\
379 .filter(UsersGroupRepoToPerm.repository == repo)\
379 .filter(UsersGroupRepoToPerm.repository == repo)\
380 .scalar()
380 .scalar()
381
381
382 if obj is None:
382 if obj is None:
383 # create new
383 # create new
384 obj = UsersGroupRepoToPerm()
384 obj = UsersGroupRepoToPerm()
385
385
386 obj.repository = repo
386 obj.repository = repo
387 obj.users_group = group_name
387 obj.users_group = group_name
388 obj.permission = permission
388 obj.permission = permission
389 self.sa.add(obj)
389 self.sa.add(obj)
390
390
391 def revoke_users_group_permission(self, repo, group_name):
391 def revoke_users_group_permission(self, repo, group_name):
392 """
392 """
393 Revoke permission for users group on given repository
393 Revoke permission for users group on given repository
394
394
395 :param repo: Instance of Repository, repository_id, or repository name
395 :param repo: Instance of Repository, repository_id, or repository name
396 :param group_name: Instance of UserGroup, users_group_id,
396 :param group_name: Instance of UserGroup, users_group_id,
397 or users group name
397 or users group name
398 """
398 """
399 repo = self.__get_repo(repo)
399 repo = self.__get_repo(repo)
400 group_name = self.__get_users_group(group_name)
400 group_name = self.__get_users_group(group_name)
401
401
402 obj = self.sa.query(UsersGroupRepoToPerm)\
402 obj = self.sa.query(UsersGroupRepoToPerm)\
403 .filter(UsersGroupRepoToPerm.repository == repo)\
403 .filter(UsersGroupRepoToPerm.repository == repo)\
404 .filter(UsersGroupRepoToPerm.users_group == group_name)\
404 .filter(UsersGroupRepoToPerm.users_group == group_name)\
405 .one()
405 .one()
406 self.sa.delete(obj)
406 self.sa.delete(obj)
407
407
408 def delete_stats(self, repo_name):
408 def delete_stats(self, repo_name):
409 """
409 """
410 removes stats for given repo
410 removes stats for given repo
411
411
412 :param repo_name:
412 :param repo_name:
413 """
413 """
414 try:
414 try:
415 obj = self.sa.query(Statistics)\
415 obj = self.sa.query(Statistics)\
416 .filter(Statistics.repository ==
416 .filter(Statistics.repository ==
417 self.get_by_repo_name(repo_name))\
417 self.get_by_repo_name(repo_name))\
418 .one()
418 .one()
419 self.sa.delete(obj)
419 self.sa.delete(obj)
420 except:
420 except:
421 log.error(traceback.format_exc())
421 log.error(traceback.format_exc())
422 raise
422 raise
423
423
424 def __create_repo(self, repo_name, alias, new_parent_id, clone_uri=False):
424 def __create_repo(self, repo_name, alias, new_parent_id, clone_uri=False):
425 """
425 """
426 makes repository on filesystem. It's group aware means it'll create
426 makes repository on filesystem. It's group aware means it'll create
427 a repository within a group, and alter the paths accordingly of
427 a repository within a group, and alter the paths accordingly of
428 group location
428 group location
429
429
430 :param repo_name:
430 :param repo_name:
431 :param alias:
431 :param alias:
432 :param parent_id:
432 :param parent_id:
433 :param clone_uri:
433 :param clone_uri:
434 """
434 """
435 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
435 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
436
436
437 if new_parent_id:
437 if new_parent_id:
438 paths = RepoGroup.get(new_parent_id)\
438 paths = RepoGroup.get(new_parent_id)\
439 .full_path.split(RepoGroup.url_sep())
439 .full_path.split(RepoGroup.url_sep())
440 new_parent_path = os.sep.join(paths)
440 new_parent_path = os.sep.join(paths)
441 else:
441 else:
442 new_parent_path = ''
442 new_parent_path = ''
443
443
444 # we need to make it str for mercurial
444 # we need to make it str for mercurial
445 repo_path = os.path.join(*map(lambda x: safe_str(x),
445 repo_path = os.path.join(*map(lambda x: safe_str(x),
446 [self.repos_path, new_parent_path, repo_name]))
446 [self.repos_path, new_parent_path, repo_name]))
447
447
448 # check if this path is not a repository
448 # check if this path is not a repository
449 if is_valid_repo(repo_path, self.repos_path):
449 if is_valid_repo(repo_path, self.repos_path):
450 raise Exception('This path %s is a valid repository' % repo_path)
450 raise Exception('This path %s is a valid repository' % repo_path)
451
451
452 # check if this path is a group
452 # check if this path is a group
453 if is_valid_repos_group(repo_path, self.repos_path):
453 if is_valid_repos_group(repo_path, self.repos_path):
454 raise Exception('This path %s is a valid group' % repo_path)
454 raise Exception('This path %s is a valid group' % repo_path)
455
455
456 log.info('creating repo %s in %s @ %s' % (
456 log.info('creating repo %s in %s @ %s' % (
457 repo_name, safe_unicode(repo_path), clone_uri
457 repo_name, safe_unicode(repo_path), clone_uri
458 )
458 )
459 )
459 )
460 backend = get_backend(alias)
460 backend = get_backend(alias)
461
461
462 backend(repo_path, create=True, src_url=clone_uri)
462 backend(repo_path, create=True, src_url=clone_uri)
463
463
464 def __rename_repo(self, old, new):
464 def __rename_repo(self, old, new):
465 """
465 """
466 renames repository on filesystem
466 renames repository on filesystem
467
467
468 :param old: old name
468 :param old: old name
469 :param new: new name
469 :param new: new name
470 """
470 """
471 log.info('renaming repo from %s to %s' % (old, new))
471 log.info('renaming repo from %s to %s' % (old, new))
472
472
473 old_path = os.path.join(self.repos_path, old)
473 old_path = os.path.join(self.repos_path, old)
474 new_path = os.path.join(self.repos_path, new)
474 new_path = os.path.join(self.repos_path, new)
475 if os.path.isdir(new_path):
475 if os.path.isdir(new_path):
476 raise Exception(
476 raise Exception(
477 'Was trying to rename to already existing dir %s' % new_path
477 'Was trying to rename to already existing dir %s' % new_path
478 )
478 )
479 shutil.move(old_path, new_path)
479 shutil.move(old_path, new_path)
480
480
481 def __delete_repo(self, repo):
481 def __delete_repo(self, repo):
482 """
482 """
483 removes repo from filesystem, the removal is acctually made by
483 removes repo from filesystem, the removal is acctually made by
484 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
484 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
485 repository is no longer valid for rhodecode, can be undeleted later on
485 repository is no longer valid for rhodecode, can be undeleted later on
486 by reverting the renames on this repository
486 by reverting the renames on this repository
487
487
488 :param repo: repo object
488 :param repo: repo object
489 """
489 """
490 rm_path = os.path.join(self.repos_path, repo.repo_name)
490 rm_path = os.path.join(self.repos_path, repo.repo_name)
491 log.info("Removing %s" % (rm_path))
491 log.info("Removing %s" % (rm_path))
492 # disable hg/git
492 # disable hg/git
493 alias = repo.repo_type
493 alias = repo.repo_type
494 shutil.move(os.path.join(rm_path, '.%s' % alias),
494 shutil.move(os.path.join(rm_path, '.%s' % alias),
495 os.path.join(rm_path, 'rm__.%s' % alias))
495 os.path.join(rm_path, 'rm__.%s' % alias))
496 # disable repo
496 # disable repo
497 _d = 'rm__%s__%s' % (datetime.now().strftime('%Y%m%d_%H%M%S_%f'),
497 _d = 'rm__%s__%s' % (datetime.now().strftime('%Y%m%d_%H%M%S_%f'),
498 repo.repo_name)
498 repo.repo_name)
499 shutil.move(rm_path, os.path.join(self.repos_path, _d))
499 shutil.move(rm_path, os.path.join(self.repos_path, _d))
General Comments 0
You need to be logged in to leave comments. Login now