##// END OF EJS Templates
#235 forking page repo group selection...
marcink -
r1722:e7eef7a1 beta
parent child Browse files
Show More
@@ -465,19 +465,20 b' def make_map(config):'
465 465 conditions=dict(function=check_repo))
466 466
467 467 rmap.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
468 controller='settings', action='fork_create',
468 controller='forks', action='fork_create',
469 469 conditions=dict(function=check_repo, method=["POST"]))
470 470
471 471 rmap.connect('repo_fork_home', '/{repo_name:.*}/fork',
472 controller='settings', action='fork',
472 controller='forks', action='fork',
473 473 conditions=dict(function=check_repo))
474 474
475 rmap.connect('repo_forks_home', '/{repo_name:.*}/forks',
476 controller='forks', action='forks',
477 conditions=dict(function=check_repo))
478
475 479 rmap.connect('repo_followers_home', '/{repo_name:.*}/followers',
476 480 controller='followers', action='followers',
477 481 conditions=dict(function=check_repo))
478 482
479 rmap.connect('repo_forks_home', '/{repo_name:.*}/forks',
480 controller='forks', action='forks',
481 conditions=dict(function=check_repo))
482 483
483 484 return rmap
@@ -29,9 +29,10 b' import formencode'
29 29 from formencode import htmlfill
30 30
31 31 from paste.httpexceptions import HTTPInternalServerError
32 from pylons import request, response, session, tmpl_context as c, url
33 from pylons.controllers.util import abort, redirect
32 from pylons import request, session, tmpl_context as c, url
33 from pylons.controllers.util import redirect
34 34 from pylons.i18n.translation import _
35 from sqlalchemy.exc import IntegrityError
35 36
36 37 from rhodecode.lib import helpers as h
37 38 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
@@ -39,11 +40,11 b' from rhodecode.lib.auth import LoginRequ'
39 40 from rhodecode.lib.base import BaseController, render
40 41 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
41 42 from rhodecode.lib.helpers import get_token
43 from rhodecode.model.meta import Session
42 44 from rhodecode.model.db import User, Repository, UserFollowing, RepoGroup
43 45 from rhodecode.model.forms import RepoForm
44 46 from rhodecode.model.scm import ScmModel
45 47 from rhodecode.model.repo import RepoModel
46 from sqlalchemy.exc import IntegrityError
47 48
48 49 log = logging.getLogger(__name__)
49 50
@@ -65,7 +66,7 b' class ReposController(BaseController):'
65 66 def __load_defaults(self):
66 67 c.repo_groups = RepoGroup.groups_choices()
67 68 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
68
69
69 70 repo_model = RepoModel()
70 71 c.users_array = repo_model.get_users_js()
71 72 c.users_groups_array = repo_model.get_users_groups_js()
@@ -127,13 +128,13 b' class ReposController(BaseController):'
127 128 """
128 129 POST /repos: Create a new item"""
129 130 # url('repos')
130 repo_model = RepoModel()
131
131 132 self.__load_defaults()
132 133 form_result = {}
133 134 try:
134 135 form_result = RepoForm(repo_groups=c.repo_groups_choices)()\
135 136 .to_python(dict(request.POST))
136 repo_model.create(form_result, self.rhodecode_user)
137 RepoModel().create(form_result, self.rhodecode_user)
137 138 if form_result['clone_uri']:
138 139 h.flash(_('created repository %s from %s') \
139 140 % (form_result['repo_name'], form_result['clone_uri']),
@@ -143,13 +144,13 b' class ReposController(BaseController):'
143 144 category='success')
144 145
145 146 if request.POST.get('user_created'):
146 #created by regular non admin user
147 # created by regular non admin user
147 148 action_logger(self.rhodecode_user, 'user_created_repo',
148 149 form_result['repo_name_full'], '', self.sa)
149 150 else:
150 151 action_logger(self.rhodecode_user, 'admin_created_repo',
151 152 form_result['repo_name_full'], '', self.sa)
152
153 Session().commit()
153 154 except formencode.Invalid, errors:
154 155
155 156 c.new_repo = errors.value['repo_name']
@@ -207,7 +208,7 b' class ReposController(BaseController):'
207 208 changed_name = repo.repo_name
208 209 action_logger(self.rhodecode_user, 'admin_updated_repo',
209 210 changed_name, '', self.sa)
210
211 Session().commit()
211 212 except formencode.Invalid, errors:
212 213 defaults = self.__load_data(repo_name)
213 214 defaults.update(errors.value)
@@ -251,7 +252,7 b' class ReposController(BaseController):'
251 252 repo_model.delete(repo)
252 253 invalidate_cache('get_repo_cached_%s' % repo_name)
253 254 h.flash(_('deleted repository %s') % repo_name, category='success')
254
255 Session().commit()
255 256 except IntegrityError, e:
256 257 if e.message.find('repositories_fork_id_fkey'):
257 258 log.error(traceback.format_exc())
@@ -23,13 +23,23 b''
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25 import logging
26 import formencode
27 import traceback
28 from formencode import htmlfill
26 29
27 from pylons import tmpl_context as c, request
30 from pylons import tmpl_context as c, request, url
31 from pylons.controllers.util import redirect
32 from pylons.i18n.translation import _
33
34 import rhodecode.lib.helpers as h
28 35
29 36 from rhodecode.lib.helpers import Page
30 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
37 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \
38 NotAnonymous
31 39 from rhodecode.lib.base import BaseRepoController, render
32 from rhodecode.model.db import Repository, User, UserFollowing
40 from rhodecode.model.db import Repository, RepoGroup, UserFollowing, User
41 from rhodecode.model.repo import RepoModel
42 from rhodecode.model.forms import RepoForkForm
33 43
34 44 log = logging.getLogger(__name__)
35 45
@@ -37,11 +47,59 b' log = logging.getLogger(__name__)'
37 47 class ForksController(BaseRepoController):
38 48
39 49 @LoginRequired()
40 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
41 'repository.admin')
42 50 def __before__(self):
43 51 super(ForksController, self).__before__()
44 52
53 def __load_defaults(self):
54 c.repo_groups = RepoGroup.groups_choices()
55 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
56
57 def __load_data(self, repo_name=None):
58 """
59 Load defaults settings for edit, and update
60
61 :param repo_name:
62 """
63 self.__load_defaults()
64
65 c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
66 repo = db_repo.scm_instance
67
68 if c.repo_info is None:
69 h.flash(_('%s repository is not mapped to db perhaps'
70 ' it was created or renamed from the filesystem'
71 ' please run the application again'
72 ' in order to rescan repositories') % repo_name,
73 category='error')
74
75 return redirect(url('repos'))
76
77 c.default_user_id = User.get_by_username('default').user_id
78 c.in_public_journal = UserFollowing.query()\
79 .filter(UserFollowing.user_id == c.default_user_id)\
80 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
81
82 if c.repo_info.stats:
83 last_rev = c.repo_info.stats.stat_on_revision
84 else:
85 last_rev = 0
86 c.stats_revision = last_rev
87
88 c.repo_last_rev = repo.count() - 1 if repo.revisions else 0
89
90 if last_rev == 0 or c.repo_last_rev == 0:
91 c.stats_percentage = 0
92 else:
93 c.stats_percentage = '%.2f' % ((float((last_rev)) /
94 c.repo_last_rev) * 100)
95
96 defaults = RepoModel()._get_defaults(repo_name)
97 # add prefix to fork
98 defaults['repo_name'] = 'fork-' + defaults['repo_name']
99 return defaults
100
101 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
102 'repository.admin')
45 103 def forks(self, repo_name):
46 104 p = int(request.params.get('page', 1))
47 105 repo_id = c.rhodecode_db_repo.repo_id
@@ -54,3 +112,63 b' class ForksController(BaseRepoController'
54 112 return c.forks_data
55 113
56 114 return render('/forks/forks.html')
115
116 @NotAnonymous()
117 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
118 'repository.admin')
119 def fork(self, repo_name):
120 c.repo_info = Repository.get_by_repo_name(repo_name)
121 if not c.repo_info:
122 h.flash(_('%s repository is not mapped to db perhaps'
123 ' it was created or renamed from the file system'
124 ' please run the application again'
125 ' in order to rescan repositories') % repo_name,
126 category='error')
127
128 return redirect(url('home'))
129
130 defaults = self.__load_data(repo_name)
131
132 return htmlfill.render(
133 render('forks/fork.html'),
134 defaults=defaults,
135 encoding="UTF-8",
136 force_defaults=False
137 )
138
139
140 @NotAnonymous()
141 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
142 'repository.admin')
143 def fork_create(self, repo_name):
144 self.__load_defaults()
145 c.repo_info = Repository.get_by_repo_name(repo_name)
146 _form = RepoForkForm(old_data={'repo_type': c.repo_info.repo_type},
147 repo_groups=c.repo_groups_choices,)()
148 form_result = {}
149 try:
150 form_result = _form.to_python(dict(request.POST))
151 # add org_path of repo so we can do a clone from it later
152 form_result['org_path'] = c.repo_info.repo_name
153
154 # create fork is done sometimes async on celery, db transaction
155 # management is handled there.
156 RepoModel().create_fork(form_result, self.rhodecode_user)
157 h.flash(_('forked %s repository as %s') \
158 % (repo_name, form_result['repo_name']),
159 category='success')
160 except formencode.Invalid, errors:
161 c.new_repo = errors.value['repo_name']
162
163 return htmlfill.render(
164 render('forks/fork.html'),
165 defaults=errors.value,
166 errors=errors.error_dict or {},
167 prefix_error=False,
168 encoding="UTF-8")
169 except Exception:
170 log.error(traceback.format_exc())
171 h.flash(_('An error occurred during repository forking %s') %
172 repo_name, category='error')
173
174 return redirect(url('home'))
@@ -23,21 +23,22 b''
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25 import logging
26 from itertools import groupby
26 27
27 28 from sqlalchemy import or_
28 from sqlalchemy.orm import joinedload, make_transient
29 from sqlalchemy.orm import joinedload
29 30 from webhelpers.paginate import Page
30 from itertools import groupby
31 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
31 32
32 33 from paste.httpexceptions import HTTPBadRequest
33 34 from pylons import request, tmpl_context as c, response, url
34 35 from pylons.i18n.translation import _
35 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
36 36
37 37 import rhodecode.lib.helpers as h
38 38 from rhodecode.lib.auth import LoginRequired, NotAnonymous
39 39 from rhodecode.lib.base import BaseController, render
40 40 from rhodecode.model.db import UserLog, UserFollowing
41 from rhodecode.model.meta import Session
41 42
42 43 log = logging.getLogger(__name__)
43 44
@@ -124,6 +125,7 b' class JournalController(BaseController):'
124 125 try:
125 126 self.scm_model.toggle_following_user(user_id,
126 127 self.rhodecode_user.user_id)
128 Session().commit()
127 129 return 'ok'
128 130 except:
129 131 raise HTTPBadRequest()
@@ -133,6 +135,7 b' class JournalController(BaseController):'
133 135 try:
134 136 self.scm_model.toggle_following_repo(repo_id,
135 137 self.rhodecode_user.user_id)
138 Session().commit()
136 139 return 'ok'
137 140 except:
138 141 raise HTTPBadRequest()
@@ -35,14 +35,14 b' from pylons.i18n.translation import _'
35 35
36 36 import rhodecode.lib.helpers as h
37 37
38 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator, \
39 HasRepoPermissionAnyDecorator, NotAnonymous
38 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator
40 39 from rhodecode.lib.base import BaseRepoController, render
41 40 from rhodecode.lib.utils import invalidate_cache, action_logger
42 41
43 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
42 from rhodecode.model.forms import RepoSettingsForm
44 43 from rhodecode.model.repo import RepoModel
45 44 from rhodecode.model.db import RepoGroup
45 from rhodecode.model.meta import Session
46 46
47 47 log = logging.getLogger(__name__)
48 48
@@ -52,15 +52,15 b' class SettingsController(BaseRepoControl'
52 52 @LoginRequired()
53 53 def __before__(self):
54 54 super(SettingsController, self).__before__()
55
55
56 56 def __load_defaults(self):
57 57 c.repo_groups = RepoGroup.groups_choices()
58 58 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
59
59
60 60 repo_model = RepoModel()
61 61 c.users_array = repo_model.get_users_js()
62 62 c.users_groups_array = repo_model.get_users_groups_js()
63
63
64 64 @HasRepoPermissionAllDecorator('repository.admin')
65 65 def index(self, repo_name):
66 66 repo_model = RepoModel()
@@ -89,15 +89,15 b' class SettingsController(BaseRepoControl'
89 89 def update(self, repo_name):
90 90 repo_model = RepoModel()
91 91 changed_name = repo_name
92
92
93 93 self.__load_defaults()
94
94
95 95 _form = RepoSettingsForm(edit=True,
96 96 old_data={'repo_name': repo_name},
97 97 repo_groups=c.repo_groups_choices)()
98 98 try:
99 99 form_result = _form.to_python(dict(request.POST))
100
100
101 101 repo_model.update(repo_name, form_result)
102 102 invalidate_cache('get_repo_cached_%s' % repo_name)
103 103 h.flash(_('Repository %s updated successfully' % repo_name),
@@ -105,6 +105,7 b' class SettingsController(BaseRepoControl'
105 105 changed_name = form_result['repo_name_full']
106 106 action_logger(self.rhodecode_user, 'user_updated_repo',
107 107 changed_name, '', self.sa)
108 Session().commit()
108 109 except formencode.Invalid, errors:
109 110 c.repo_info = repo_model.get_by_repo_name(repo_name)
110 111 c.users_array = repo_model.get_users_js()
@@ -148,61 +149,10 b' class SettingsController(BaseRepoControl'
148 149 repo_model.delete(repo)
149 150 invalidate_cache('get_repo_cached_%s' % repo_name)
150 151 h.flash(_('deleted repository %s') % repo_name, category='success')
152 Session().commit()
151 153 except Exception:
152 154 log.error(traceback.format_exc())
153 155 h.flash(_('An error occurred during deletion of %s') % repo_name,
154 156 category='error')
155 157
156 158 return redirect(url('home'))
157
158 @NotAnonymous()
159 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
160 'repository.admin')
161 def fork(self, repo_name):
162 repo_model = RepoModel()
163 c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
164 if not repo:
165 h.flash(_('%s repository is not mapped to db perhaps'
166 ' it was created or renamed from the file system'
167 ' please run the application again'
168 ' in order to rescan repositories') % repo_name,
169 category='error')
170
171 return redirect(url('home'))
172
173 return render('settings/repo_fork.html')
174
175 @NotAnonymous()
176 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
177 'repository.admin')
178 def fork_create(self, repo_name):
179 repo_model = RepoModel()
180 c.repo_info = repo_model.get_by_repo_name(repo_name)
181 _form = RepoForkForm(old_data={'repo_type': c.repo_info.repo_type})()
182 form_result = {}
183 try:
184 form_result = _form.to_python(dict(request.POST))
185 form_result.update({'repo_name': repo_name})
186 repo_model.create_fork(form_result, self.rhodecode_user)
187 h.flash(_('forked %s repository as %s') \
188 % (repo_name, form_result['fork_name']),
189 category='success')
190 action_logger(self.rhodecode_user,
191 'user_forked_repo:%s' % form_result['fork_name'],
192 repo_name, '', self.sa)
193 except formencode.Invalid, errors:
194 c.new_repo = errors.value['fork_name']
195 r = render('settings/repo_fork.html')
196
197 return htmlfill.render(
198 r,
199 defaults=errors.value,
200 errors=errors.error_dict or {},
201 prefix_error=False,
202 encoding="UTF-8")
203 except Exception:
204 log.error(traceback.format_exc())
205 h.flash(_('An error occurred during repository forking %s') %
206 repo_name, category='error')
207
208 return redirect(url('home'))
@@ -37,29 +37,28 b' from string import lower'
37 37 from pylons import config, url
38 38 from pylons.i18n.translation import _
39 39
40 from vcs import get_backend
40 41
41 42 from rhodecode.lib import LANGUAGES_EXTENSIONS_MAP, safe_str
42 43 from rhodecode.lib.celerylib import run_task, locked_task, str2bool, \
43 44 __get_lockkey, LockHeld, DaemonLock
44 45 from rhodecode.lib.helpers import person
45 46 from rhodecode.lib.rcmail.smtp_mailer import SmtpMailer
46 from rhodecode.lib.utils import add_cache
47 from rhodecode.lib.utils import add_cache, action_logger
47 48 from rhodecode.lib.compat import json, OrderedDict
48 49
49 50 from rhodecode.model import init_model
50 51 from rhodecode.model import meta
51 from rhodecode.model.db import RhodeCodeUi, Statistics, Repository, User
52
53 from vcs.backends import get_repo
52 from rhodecode.model.db import Statistics, Repository, User
54 53
55 54 from sqlalchemy import engine_from_config
56 55
57
58 56 add_cache(config)
59 57
60 58 __all__ = ['whoosh_index', 'get_commits_stats',
61 59 'reset_user_password', 'send_email']
62 60
61
63 62 CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
64 63
65 64
@@ -81,17 +80,13 b' def get_logger(cls):'
81 80
82 81 return log
83 82
84 def get_repos_path():
85 sa = get_session()
86 q = sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
87 return q.ui_value
88
89
90 83 @task(ignore_result=True)
91 84 @locked_task
92 85 def whoosh_index(repo_location, full_index):
86 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
87
93 88 #log = whoosh_index.get_logger()
94 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
89
95 90 index_location = config['index_dir']
96 91 WhooshIndexingDaemon(index_location=index_location,
97 92 repo_location=repo_location, sa=get_session())\
@@ -111,13 +106,12 b' def get_commits_stats(repo_name, ts_min_'
111 106 sa = get_session()
112 107 lock = l = DaemonLock(file_=jn(lockkey_path, lockkey))
113 108
114 #for js data compatibilty cleans the key for person from '
109 # for js data compatibilty cleans the key for person from '
115 110 akc = lambda k: person(k).replace('"', "")
116 111
117 112 co_day_auth_aggr = {}
118 113 commits_by_day_aggregate = {}
119 repos_path = get_repos_path()
120 repo = get_repo(safe_str(os.path.join(repos_path, repo_name)))
114 repo = Repository.get_by_repo_name(repo_name).scm_instance
121 115 repo_size = len(repo.revisions)
122 116 #return if repo have no revisions
123 117 if repo_size < 1:
@@ -139,9 +133,9 b' def get_commits_stats(repo_name, ts_min_'
139 133 last_rev = cur_stats.stat_on_revision
140 134
141 135 if last_rev == repo.get_changeset().revision and repo_size > 1:
142 #pass silently without any work if we're not on first revision or
143 #current state of parsing revision(from db marker) is the
144 #last revision
136 # pass silently without any work if we're not on first revision or
137 # current state of parsing revision(from db marker) is the
138 # last revision
145 139 lock.release()
146 140 return True
147 141
@@ -255,10 +249,11 b' def get_commits_stats(repo_name, ts_min_'
255 249
256 250 @task(ignore_result=True)
257 251 def send_password_link(user_email):
252 from rhodecode.model.notification import EmailNotificationModel
253
258 254 log = get_logger(send_password_link)
259 255
260 256 try:
261 from rhodecode.model.notification import EmailNotificationModel
262 257 sa = get_session()
263 258 user = User.get_by_email(user_email)
264 259 if user:
@@ -283,9 +278,9 b' def send_password_link(user_email):'
283 278
284 279 @task(ignore_result=True)
285 280 def reset_user_password(user_email):
286 log = get_logger(reset_user_password)
281 from rhodecode.lib import auth
287 282
288 from rhodecode.lib import auth
283 log = get_logger(reset_user_password)
289 284
290 285 try:
291 286 try:
@@ -361,27 +356,39 b' def send_email(recipients, subject, body'
361 356
362 357 @task(ignore_result=True)
363 358 def create_repo_fork(form_data, cur_user):
359 """
360 Creates a fork of repository using interval VCS methods
361
362 :param form_data:
363 :param cur_user:
364 """
365 from rhodecode.model.repo import RepoModel
366
364 367 log = get_logger(create_repo_fork)
365 368
366 from rhodecode.model.repo import RepoModel
367 from vcs import get_backend
369 Session = get_session()
370 base_path = Repository.base_path()
371
372 RepoModel(Session).create(form_data, cur_user, just_db=True, fork=True)
373
374 alias = form_data['repo_type']
375 org_repo_name = form_data['org_path']
376 source_repo_path = os.path.join(base_path, org_repo_name)
377 destination_fork_path = os.path.join(base_path, form_data['repo_name_full'])
368 378
369 repo_model = RepoModel(get_session())
370 repo_model.create(form_data, cur_user, just_db=True, fork=True)
371 repo_name = form_data['repo_name']
372 repos_path = get_repos_path()
373 repo_path = os.path.join(repos_path, repo_name)
374 repo_fork_path = os.path.join(repos_path, form_data['fork_name'])
375 alias = form_data['repo_type']
376
377 log.info('creating repo fork %s as %s', repo_name, repo_path)
379 log.info('creating fork of %s as %s', source_repo_path,
380 destination_fork_path)
378 381 backend = get_backend(alias)
379 backend(str(repo_fork_path), create=True, src_url=str(repo_path))
380
382 backend(safe_str(destination_fork_path), create=True,
383 src_url=safe_str(source_repo_path))
384 action_logger(cur_user, 'user_forked_repo:%s' % org_repo_name,
385 org_repo_name, '', Session)
386 # finally commit at latest possible stage
387 Session.commit()
381 388
382 389 def __get_codes_stats(repo_name):
383 repos_path = get_repos_path()
384 repo = get_repo(safe_str(os.path.join(repos_path, repo_name)))
390 repo = Repository.get_by_repo_name(repo_name).scm_instance
391
385 392 tip = repo.get_changeset()
386 393 code_stats = {}
387 394
@@ -33,7 +33,8 b' from rhodecode.lib.utils import action_l'
33 33
34 34
35 35 def repo_size(ui, repo, hooktype=None, **kwargs):
36 """Presents size of repository after push
36 """
37 Presents size of repository after push
37 38
38 39 :param ui:
39 40 :param repo:
@@ -65,7 +66,8 b' def repo_size(ui, repo, hooktype=None, *'
65 66
66 67
67 68 def log_pull_action(ui, repo, **kwargs):
68 """Logs user last pull action
69 """
70 Logs user last pull action
69 71
70 72 :param ui:
71 73 :param repo:
@@ -76,13 +78,15 b' def log_pull_action(ui, repo, **kwargs):'
76 78 repository = extra_params['repository']
77 79 action = 'pull'
78 80
79 action_logger(username, action, repository, extra_params['ip'])
81 action_logger(username, action, repository, extra_params['ip'],
82 commit=True)
80 83
81 84 return 0
82 85
83 86
84 87 def log_push_action(ui, repo, **kwargs):
85 """Maps user last push action to new changeset id, from mercurial
88 """
89 Maps user last push action to new changeset id, from mercurial
86 90
87 91 :param ui:
88 92 :param repo:
@@ -110,6 +114,7 b' def log_push_action(ui, repo, **kwargs):'
110 114
111 115 action = action % ','.join(revs)
112 116
113 action_logger(username, action, repository, extra_params['ip'])
117 action_logger(username, action, repository, extra_params['ip'],
118 commit=True)
114 119
115 120 return 0
@@ -93,7 +93,7 b' def get_repo_slug(request):'
93 93 return request.environ['pylons.routes_dict'].get('repo_name')
94 94
95 95
96 def action_logger(user, action, repo, ipaddr='', sa=None):
96 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
97 97 """
98 98 Action logger for various actions made by users
99 99
@@ -138,12 +138,13 b' def action_logger(user, action, repo, ip'
138 138 user_log.action_date = datetime.datetime.now()
139 139 user_log.user_ip = ipaddr
140 140 sa.add(user_log)
141 sa.commit()
142 141
143 142 log.info('Adding user %s, action %s on %s', user_obj, action, repo)
143 if commit:
144 sa.commit()
144 145 except:
145 146 log.error(traceback.format_exc())
146 sa.rollback()
147 raise
147 148
148 149
149 150 def get_repos(path, recursive=False):
@@ -185,7 +185,7 b' class ValidPassword(formencode.validator'
185 185 class ValidPasswordsMatch(formencode.validators.FancyValidator):
186 186
187 187 def validate_python(self, value, state):
188
188
189 189 pass_val = value.get('password') or value.get('new_password')
190 190 if pass_val != value['password_confirmation']:
191 191 e_dict = {'password_confirmation':
@@ -198,7 +198,7 b' class ValidAuth(formencode.validators.Fa'
198 198 'invalid_login':_('invalid user name'),
199 199 'disabled_account':_('Your account is disabled')
200 200 }
201
201
202 202 # error mapping
203 203 e_dict = {'username':messages['invalid_login'],
204 204 'password':messages['invalid_password']}
@@ -208,7 +208,7 b' class ValidAuth(formencode.validators.Fa'
208 208 password = value['password']
209 209 username = value['username']
210 210 user = User.get_by_username(username)
211
211
212 212 if authenticate(username, password):
213 213 return value
214 214 else:
@@ -254,7 +254,7 b' def ValidRepoName(edit, old_data):'
254 254 # db key This is an actual just the name to store in the
255 255 # database
256 256 repo_name_full = group_path + RepoGroup.url_sep() + repo_name
257
257
258 258 else:
259 259 group_path = ''
260 260 repo_name_full = repo_name
@@ -289,24 +289,8 b' def ValidRepoName(edit, old_data):'
289 289
290 290 return _ValidRepoName
291 291
292 def ValidForkName():
293 class _ValidForkName(formencode.validators.FancyValidator):
294 def to_python(self, value, state):
295
296 repo_name = value.get('fork_name')
297
298 slug = repo_name_slug(repo_name)
299 if slug in [ADMIN_PREFIX, '']:
300 e_dict = {'repo_name': _('This repository name is disallowed')}
301 raise formencode.Invalid('', value, state, error_dict=e_dict)
302
303 if RepoModel().get_by_repo_name(repo_name):
304 e_dict = {'fork_name':_('This repository '
305 'already exists')}
306 raise formencode.Invalid('', value, state,
307 error_dict=e_dict)
308 return value
309 return _ValidForkName
292 def ValidForkName(*args, **kwargs):
293 return ValidRepoName(*args, **kwargs)
310 294
311 295
312 296 def SlugifyName():
@@ -513,7 +497,7 b' def UserForm(edit=False, old_data={}):'
513 497 else:
514 498 password = All(UnicodeString(strip=True, min=6, not_empty=True))
515 499 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
516
500
517 501 active = StringBoolean(if_missing=False)
518 502 name = UnicodeString(strip=True, min=1, not_empty=True)
519 503 lastname = UnicodeString(strip=True, min=1, not_empty=True)
@@ -605,17 +589,20 b' def RepoForm(edit=False, old_data={}, su'
605 589 chained_validators = [ValidRepoName(edit, old_data), ValidPerms]
606 590 return _RepoForm
607 591
608 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
592 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
593 repo_groups=[]):
609 594 class _RepoForkForm(formencode.Schema):
610 595 allow_extra_fields = True
611 596 filter_extra_fields = False
612 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
597 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
613 598 SlugifyName())
599 repo_group = OneOf(repo_groups, hideList=True)
600 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
614 601 description = UnicodeString(strip=True, min=1, not_empty=True)
615 602 private = StringBoolean(if_missing=False)
616 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
617
618 chained_validators = [ValidForkName()]
603 copy_permissions = StringBoolean(if_missing=False)
604 fork_parent_id = UnicodeString()
605 chained_validators = [ValidForkName(edit, old_data)]
619 606
620 607 return _RepoForkForm
621 608
@@ -630,7 +617,7 b' def RepoSettingsForm(edit=False, old_dat'
630 617 repo_group = OneOf(repo_groups, hideList=True)
631 618 private = StringBoolean(if_missing=False)
632 619
633 chained_validators = [ValidRepoName(edit, old_data), ValidPerms,
620 chained_validators = [ValidRepoName(edit, old_data), ValidPerms,
634 621 ValidSettings]
635 622 return _RepoForm
636 623
@@ -35,8 +35,6 b' from pylons.i18n.translation import _'
35 35 from rhodecode.lib import helpers as h
36 36 from rhodecode.model import BaseModel
37 37 from rhodecode.model.db import Notification, User, UserNotification
38 from rhodecode.lib.celerylib import run_task
39 from rhodecode.lib.celerylib.tasks import send_email
40 38
41 39 log = logging.getLogger(__name__)
42 40
@@ -74,6 +72,7 b' class NotificationModel(BaseModel):'
74 72 :param recipients: list of int, str or User objects
75 73 :param type_: type of notification
76 74 """
75 from rhodecode.lib.celerylib import tasks, run_task
77 76
78 77 if not getattr(recipients, '__iter__', False):
79 78 raise Exception('recipients must be a list of iterable')
@@ -100,7 +99,7 b' class NotificationModel(BaseModel):'
100 99 email_body_html = EmailNotificationModel()\
101 100 .get_email_tmpl(type_, **{'subject':subject,
102 101 'body':h.rst(body)})
103 run_task(send_email, rec.email, email_subject, email_body,
102 run_task(tasks.send_email, rec.email, email_subject, email_body,
104 103 email_body_html)
105 104
106 105 return notif
@@ -212,36 +212,33 b' class RepoModel(BaseModel):'
212 212 raise
213 213
214 214 def create(self, form_data, cur_user, just_db=False, fork=False):
215 from rhodecode.model.scm import ScmModel
215 216
216 217 try:
217 218 if fork:
218 repo_name = form_data['fork_name']
219 org_name = form_data['repo_name']
220 org_full_name = org_name
219 fork_parent_id = form_data['fork_parent_id']
221 220
222 else:
223 org_name = repo_name = form_data['repo_name']
224 repo_name_full = form_data['repo_name_full']
221 # repo name is just a name of repository
222 # while repo_name_full is a full qualified name that is combined
223 # with name and path of group
224 repo_name = form_data['repo_name']
225 repo_name_full = form_data['repo_name_full']
225 226
226 227 new_repo = Repository()
227 228 new_repo.enable_statistics = False
229
228 230 for k, v in form_data.items():
229 231 if k == 'repo_name':
230 if fork:
231 v = repo_name
232 else:
233 v = repo_name_full
232 v = repo_name_full
234 233 if k == 'repo_group':
235 234 k = 'group_id'
236
237 235 if k == 'description':
238 236 v = v or repo_name
239 237
240 238 setattr(new_repo, k, v)
241 239
242 240 if fork:
243 parent_repo = self.sa.query(Repository)\
244 .filter(Repository.repo_name == org_full_name).one()
241 parent_repo = Repository.get(fork_parent_id)
245 242 new_repo.fork = parent_repo
246 243
247 244 new_repo.user_id = cur_user.user_id
@@ -271,19 +268,21 b' class RepoModel(BaseModel):'
271 268 form_data['repo_group'],
272 269 form_data['clone_uri'])
273 270
274 self.sa.commit()
275
276 #now automatically start following this repository as owner
277 from rhodecode.model.scm import ScmModel
271 # now automatically start following this repository as owner
278 272 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
279 cur_user.user_id)
273 cur_user.user_id)
280 274 return new_repo
281 275 except:
282 276 log.error(traceback.format_exc())
283 self.sa.rollback()
284 277 raise
285 278
286 279 def create_fork(self, form_data, cur_user):
280 """
281 Simple wrapper into executing celery task for fork creation
282
283 :param form_data:
284 :param cur_user:
285 """
287 286 from rhodecode.lib.celerylib import tasks, run_task
288 287 run_task(tasks.create_repo_fork, form_data, cur_user)
289 288
@@ -325,6 +324,11 b' class RepoModel(BaseModel):'
325 324 raise
326 325
327 326 def delete_stats(self, repo_name):
327 """
328 removes stats for given repo
329
330 :param repo_name:
331 """
328 332 try:
329 333 obj = self.sa.query(Statistics)\
330 334 .filter(Statistics.repository == \
@@ -208,17 +208,14 b' class ScmModel(BaseModel):'
208 208 .filter(UserFollowing.user_id == user_id).scalar()
209 209
210 210 if f is not None:
211
212 211 try:
213 212 self.sa.delete(f)
214 self.sa.commit()
215 213 action_logger(UserTemp(user_id),
216 214 'stopped_following_repo',
217 215 RepoTemp(follow_repo_id))
218 216 return
219 217 except:
220 218 log.error(traceback.format_exc())
221 self.sa.rollback()
222 219 raise
223 220
224 221 try:
@@ -226,13 +223,12 b' class ScmModel(BaseModel):'
226 223 f.user_id = user_id
227 224 f.follows_repo_id = follow_repo_id
228 225 self.sa.add(f)
229 self.sa.commit()
226
230 227 action_logger(UserTemp(user_id),
231 228 'started_following_repo',
232 229 RepoTemp(follow_repo_id))
233 230 except:
234 231 log.error(traceback.format_exc())
235 self.sa.rollback()
236 232 raise
237 233
238 234 def toggle_following_user(self, follow_user_id, user_id):
@@ -243,11 +239,9 b' class ScmModel(BaseModel):'
243 239 if f is not None:
244 240 try:
245 241 self.sa.delete(f)
246 self.sa.commit()
247 242 return
248 243 except:
249 244 log.error(traceback.format_exc())
250 self.sa.rollback()
251 245 raise
252 246
253 247 try:
@@ -255,10 +249,8 b' class ScmModel(BaseModel):'
255 249 f.user_id = user_id
256 250 f.follows_user_id = follow_user_id
257 251 self.sa.add(f)
258 self.sa.commit()
259 252 except:
260 253 log.error(traceback.format_exc())
261 self.sa.rollback()
262 254 raise
263 255
264 256 def is_following_repo(self, repo_name, user_id, cache=False):
@@ -317,8 +309,8 b' class ScmModel(BaseModel):'
317 309 log.error(traceback.format_exc())
318 310 raise
319 311
320 def commit_change(self, repo, repo_name, cs, user, author, message, content,
321 f_path):
312 def commit_change(self, repo, repo_name, cs, user, author, message,
313 content, f_path):
322 314
323 315 if repo.alias == 'hg':
324 316 from vcs.backends.hg import MercurialInMemoryChangeset as IMC
@@ -1790,6 +1790,10 b' div.form div.fields div.field div.button'
1790 1790 padding: 0 !important;
1791 1791 }
1792 1792
1793 .trending_language_tbl,.trending_language_tbl tr {
1794 border-spacing: 1px;
1795 }
1796
1793 1797 .trending_language {
1794 1798 background-color: #003367;
1795 1799 color: #FFF;
@@ -1797,7 +1801,7 b' div.form div.fields div.field div.button'
1797 1801 min-width: 20px;
1798 1802 text-decoration: none;
1799 1803 height: 12px;
1800 margin-bottom: 4px;
1804 margin-bottom: 0px;
1801 1805 margin-left: 5px;
1802 1806 white-space: pre;
1803 1807 padding: 3px;
@@ -27,14 +27,23 b''
27 27 <!-- fields -->
28 28 <div class="fields">
29 29 <div class="field">
30 <div class="label">
31 <label for="repo_name">${_('Fork name')}:</label>
32 </div>
33 <div class="input">
34 ${h.text('fork_name',class_="small")}
35 ${h.hidden('repo_type',c.repo_info.repo_type)}
36 </div>
37 </div>
30 <div class="label">
31 <label for="repo_name">${_('Fork name')}:</label>
32 </div>
33 <div class="input">
34 ${h.text('repo_name',class_="small")}
35 ${h.hidden('repo_type',c.repo_info.repo_type)}
36 ${h.hidden('fork_parent_id',c.repo_info.repo_id)}
37 </div>
38 </div>
39 <div class="field">
40 <div class="label">
41 <label for="repo_group">${_('Repository group')}:</label>
42 </div>
43 <div class="input">
44 ${h.select('repo_group','',c.repo_groups,class_="medium")}
45 </div>
46 </div>
38 47 <div class="field">
39 48 <div class="label label-textarea">
40 49 <label for="description">${_('Description')}:</label>
@@ -50,7 +59,15 b''
50 59 <div class="checkboxes">
51 60 ${h.checkbox('private',value="True")}
52 61 </div>
53 </div>
62 </div>
63 <div class="field">
64 <div class="label label-checkbox">
65 <label for="private">${_('Copy permissions')}:</label>
66 </div>
67 <div class="checkboxes">
68 ${h.checkbox('copy_permissions',value="True")}
69 </div>
70 </div>
54 71 <div class="buttons">
55 72 ${h.submit('',_('fork this repository'),class_="ui-button")}
56 73 </div>
General Comments 0
You need to be logged in to leave comments. Login now