Show More
@@ -36,12 +36,12 b' log = logging.getLogger(__name__)' | |||
|
36 | 36 | |
|
37 | 37 | class BookmarksController(BaseRepoController): |
|
38 | 38 | |
|
39 | def __before__(self): | |
|
40 | super(BookmarksController, self).__before__() | |
|
41 | ||
|
39 | 42 | @LoginRequired() |
|
40 | 43 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
41 | 44 | 'repository.admin') |
|
42 | def __before__(self): | |
|
43 | super(BookmarksController, self).__before__() | |
|
44 | ||
|
45 | 45 | def index(self): |
|
46 | 46 | if c.rhodecode_repo.alias != 'hg': |
|
47 | 47 | raise HTTPNotFound() |
@@ -38,12 +38,12 b' log = logging.getLogger(__name__)' | |||
|
38 | 38 | |
|
39 | 39 | class BranchesController(BaseRepoController): |
|
40 | 40 | |
|
41 | def __before__(self): | |
|
42 | super(BranchesController, self).__before__() | |
|
43 | ||
|
41 | 44 | @LoginRequired() |
|
42 | 45 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
43 | 46 | 'repository.admin') |
|
44 | def __before__(self): | |
|
45 | super(BranchesController, self).__before__() | |
|
46 | ||
|
47 | 47 | def index(self): |
|
48 | 48 | |
|
49 | 49 | def _branchtags(localrepo): |
@@ -72,5 +72,4 b' class BranchesController(BaseRepoControl' | |||
|
72 | 72 | key=lambda ctx: ctx[0], |
|
73 | 73 | reverse=False)) |
|
74 | 74 | |
|
75 | ||
|
76 | 75 | return render('branches/branches.html') |
@@ -44,13 +44,37 b' log = logging.getLogger(__name__)' | |||
|
44 | 44 | |
|
45 | 45 | class ChangelogController(BaseRepoController): |
|
46 | 46 | |
|
47 | @LoginRequired() | |
|
48 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
49 | 'repository.admin') | |
|
50 | 47 | def __before__(self): |
|
51 | 48 | super(ChangelogController, self).__before__() |
|
52 | 49 | c.affected_files_cut_off = 60 |
|
53 | 50 | |
|
51 | def _graph(self, repo, revs_int, repo_size, size, p): | |
|
52 | """ | |
|
53 | Generates a DAG graph for repo | |
|
54 | ||
|
55 | :param repo: | |
|
56 | :param revs_int: | |
|
57 | :param repo_size: | |
|
58 | :param size: | |
|
59 | :param p: | |
|
60 | """ | |
|
61 | if not revs_int: | |
|
62 | c.jsdata = json.dumps([]) | |
|
63 | return | |
|
64 | ||
|
65 | data = [] | |
|
66 | revs = revs_int | |
|
67 | ||
|
68 | dag = _dagwalker(repo, revs, repo.alias) | |
|
69 | dag = _colored(dag) | |
|
70 | for (id, type, ctx, vtx, edges) in dag: | |
|
71 | data.append(['', vtx, edges]) | |
|
72 | ||
|
73 | c.jsdata = json.dumps(data) | |
|
74 | ||
|
75 | @LoginRequired() | |
|
76 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
77 | 'repository.admin') | |
|
54 | 78 | def index(self): |
|
55 | 79 | limit = 100 |
|
56 | 80 | default = 20 |
@@ -89,31 +113,10 b' class ChangelogController(BaseRepoContro' | |||
|
89 | 113 | |
|
90 | 114 | return render('changelog/changelog.html') |
|
91 | 115 | |
|
116 | @LoginRequired() | |
|
117 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
118 | 'repository.admin') | |
|
92 | 119 | def changelog_details(self, cs): |
|
93 | 120 | if request.environ.get('HTTP_X_PARTIAL_XHR'): |
|
94 | 121 | c.cs = c.rhodecode_repo.get_changeset(cs) |
|
95 | 122 | return render('changelog/changelog_details.html') |
|
96 | ||
|
97 | def _graph(self, repo, revs_int, repo_size, size, p): | |
|
98 | """ | |
|
99 | Generates a DAG graph for repo | |
|
100 | ||
|
101 | :param repo: | |
|
102 | :param revs_int: | |
|
103 | :param repo_size: | |
|
104 | :param size: | |
|
105 | :param p: | |
|
106 | """ | |
|
107 | if not revs_int: | |
|
108 | c.jsdata = json.dumps([]) | |
|
109 | return | |
|
110 | ||
|
111 | data = [] | |
|
112 | revs = revs_int | |
|
113 | ||
|
114 | dag = _dagwalker(repo, revs, repo.alias) | |
|
115 | dag = _colored(dag) | |
|
116 | for (id, type, ctx, vtx, edges) in dag: | |
|
117 | data.append(['', vtx, edges]) | |
|
118 | ||
|
119 | c.jsdata = json.dumps(data) |
@@ -170,9 +170,6 b' def _context_url(GET, fileid=None):' | |||
|
170 | 170 | |
|
171 | 171 | class ChangesetController(BaseRepoController): |
|
172 | 172 | |
|
173 | @LoginRequired() | |
|
174 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
175 | 'repository.admin') | |
|
176 | 173 | def __before__(self): |
|
177 | 174 | super(ChangesetController, self).__before__() |
|
178 | 175 | c.affected_files_cut_off = 60 |
@@ -180,6 +177,9 b' class ChangesetController(BaseRepoContro' | |||
|
180 | 177 | c.users_array = repo_model.get_users_js() |
|
181 | 178 | c.users_groups_array = repo_model.get_users_groups_js() |
|
182 | 179 | |
|
180 | @LoginRequired() | |
|
181 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
182 | 'repository.admin') | |
|
183 | 183 | def index(self, revision, method='show'): |
|
184 | 184 | c.anchor_url = anchor_url |
|
185 | 185 | c.ignorews_url = _ignorews_url |
@@ -312,16 +312,28 b' class ChangesetController(BaseRepoContro' | |||
|
312 | 312 | else: |
|
313 | 313 | return render('changeset/changeset_range.html') |
|
314 | 314 | |
|
315 | @LoginRequired() | |
|
316 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
317 | 'repository.admin') | |
|
315 | 318 | def changeset_raw(self, revision): |
|
316 | 319 | return self.index(revision, method='raw') |
|
317 | 320 | |
|
321 | @LoginRequired() | |
|
322 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
323 | 'repository.admin') | |
|
318 | 324 | def changeset_patch(self, revision): |
|
319 | 325 | return self.index(revision, method='patch') |
|
320 | 326 | |
|
327 | @LoginRequired() | |
|
328 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
329 | 'repository.admin') | |
|
321 | 330 | def changeset_download(self, revision): |
|
322 | 331 | return self.index(revision, method='download') |
|
323 | 332 | |
|
333 | @LoginRequired() | |
|
324 | 334 | @NotAnonymous() |
|
335 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
336 | 'repository.admin') | |
|
325 | 337 | @jsonify |
|
326 | 338 | def comment(self, repo_name, revision): |
|
327 | 339 | status = request.POST.get('changeset_status') |
@@ -384,7 +396,10 b' class ChangesetController(BaseRepoContro' | |||
|
384 | 396 | |
|
385 | 397 | return data |
|
386 | 398 | |
|
399 | @LoginRequired() | |
|
387 | 400 | @NotAnonymous() |
|
401 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
402 | 'repository.admin') | |
|
388 | 403 | def preview_comment(self): |
|
389 | 404 | if not request.environ.get('HTTP_X_PARTIAL_XHR'): |
|
390 | 405 | raise HTTPBadRequest() |
@@ -393,7 +408,10 b' class ChangesetController(BaseRepoContro' | |||
|
393 | 408 | return h.rst_w_mentions(text) |
|
394 | 409 | return '' |
|
395 | 410 | |
|
411 | @LoginRequired() | |
|
396 | 412 | @NotAnonymous() |
|
413 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
414 | 'repository.admin') | |
|
397 | 415 | @jsonify |
|
398 | 416 | def delete_comment(self, repo_name, comment_id): |
|
399 | 417 | co = ChangesetComment.get(comment_id) |
@@ -405,6 +423,9 b' class ChangesetController(BaseRepoContro' | |||
|
405 | 423 | else: |
|
406 | 424 | raise HTTPForbidden() |
|
407 | 425 | |
|
426 | @LoginRequired() | |
|
427 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
428 | 'repository.admin') | |
|
408 | 429 | @jsonify |
|
409 | 430 | def changeset_info(self, repo_name, revision): |
|
410 | 431 | if request.is_xhr: |
@@ -51,9 +51,6 b' log = logging.getLogger(__name__)' | |||
|
51 | 51 | |
|
52 | 52 | class CompareController(BaseRepoController): |
|
53 | 53 | |
|
54 | @LoginRequired() | |
|
55 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
56 | 'repository.admin') | |
|
57 | 54 | def __before__(self): |
|
58 | 55 | super(CompareController, self).__before__() |
|
59 | 56 | |
@@ -85,6 +82,82 b' class CompareController(BaseRepoControll' | |||
|
85 | 82 | redirect(h.url('summary_home', repo_name=repo.repo_name)) |
|
86 | 83 | raise HTTPBadRequest() |
|
87 | 84 | |
|
85 | def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref, merge): | |
|
86 | """ | |
|
87 | Returns a list of changesets that can be merged from org_repo@org_ref | |
|
88 | to other_repo@other_ref ... and the ancestor that would be used for merge | |
|
89 | ||
|
90 | :param org_repo: | |
|
91 | :param org_ref: | |
|
92 | :param other_repo: | |
|
93 | :param other_ref: | |
|
94 | :param tmp: | |
|
95 | """ | |
|
96 | ||
|
97 | ancestor = None | |
|
98 | ||
|
99 | if alias == 'hg': | |
|
100 | # lookup up the exact node id | |
|
101 | _revset_predicates = { | |
|
102 | 'branch': 'branch', | |
|
103 | 'book': 'bookmark', | |
|
104 | 'tag': 'tag', | |
|
105 | 'rev': 'id', | |
|
106 | } | |
|
107 | ||
|
108 | org_rev_spec = "max(%s('%s'))" % (_revset_predicates[org_ref[0]], | |
|
109 | safe_str(org_ref[1])) | |
|
110 | org_revs = scmutil.revrange(org_repo._repo, [org_rev_spec]) | |
|
111 | org_rev = org_repo._repo[org_revs[-1] if org_revs else -1].hex() | |
|
112 | ||
|
113 | other_rev_spec = "max(%s('%s'))" % (_revset_predicates[other_ref[0]], | |
|
114 | safe_str(other_ref[1])) | |
|
115 | other_revs = scmutil.revrange(other_repo._repo, [other_rev_spec]) | |
|
116 | other_rev = other_repo._repo[other_revs[-1] if other_revs else -1].hex() | |
|
117 | ||
|
118 | #case two independent repos | |
|
119 | if org_repo != other_repo: | |
|
120 | hgrepo = unionrepo.unionrepository(other_repo.baseui, | |
|
121 | other_repo.path, | |
|
122 | org_repo.path) | |
|
123 | # all the changesets we are looking for will be in other_repo, | |
|
124 | # so rev numbers from hgrepo can be used in other_repo | |
|
125 | ||
|
126 | #no remote compare do it on the same repository | |
|
127 | else: | |
|
128 | hgrepo = other_repo._repo | |
|
129 | ||
|
130 | if merge: | |
|
131 | revs = ["ancestors(id('%s')) and not ancestors(id('%s')) and not id('%s')" % | |
|
132 | (other_rev, org_rev, org_rev)] | |
|
133 | ||
|
134 | ancestors = scmutil.revrange(hgrepo, | |
|
135 | ["ancestor(id('%s'), id('%s'))" % (org_rev, other_rev)]) | |
|
136 | if ancestors: | |
|
137 | # pick arbitrary ancestor - but there is usually only one | |
|
138 | ancestor = hgrepo[ancestors[0]].hex() | |
|
139 | else: | |
|
140 | # TODO: have both + and - changesets | |
|
141 | revs = ["id('%s') :: id('%s') - id('%s')" % | |
|
142 | (org_rev, other_rev, org_rev)] | |
|
143 | ||
|
144 | changesets = [other_repo.get_changeset(cs) | |
|
145 | for cs in scmutil.revrange(hgrepo, revs)] | |
|
146 | ||
|
147 | elif alias == 'git': | |
|
148 | assert org_repo == other_repo, (org_repo, other_repo) # no git support for different repos | |
|
149 | so, se = org_repo.run_git_command( | |
|
150 | 'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1], | |
|
151 | other_ref[1]) | |
|
152 | ) | |
|
153 | changesets = [org_repo.get_changeset(cs) | |
|
154 | for cs in re.findall(r'[0-9a-fA-F]{40}', so)] | |
|
155 | ||
|
156 | return changesets, ancestor | |
|
157 | ||
|
158 | @LoginRequired() | |
|
159 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
160 | 'repository.admin') | |
|
88 | 161 | def index(self, org_ref_type, org_ref, other_ref_type, other_ref): |
|
89 | 162 | # org_ref will be evaluated in org_repo |
|
90 | 163 | org_repo = c.rhodecode_db_repo.repo_name |
@@ -194,76 +267,3 b' class CompareController(BaseRepoControll' | |||
|
194 | 267 | c.changes[fid] = [f['operation'], f['filename'], diff] |
|
195 | 268 | |
|
196 | 269 | return render('compare/compare_diff.html') |
|
197 | ||
|
198 | def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref, merge): | |
|
199 | """ | |
|
200 | Returns a list of changesets that can be merged from org_repo@org_ref | |
|
201 | to other_repo@other_ref ... and the ancestor that would be used for merge | |
|
202 | ||
|
203 | :param org_repo: | |
|
204 | :param org_ref: | |
|
205 | :param other_repo: | |
|
206 | :param other_ref: | |
|
207 | :param tmp: | |
|
208 | """ | |
|
209 | ||
|
210 | ancestor = None | |
|
211 | ||
|
212 | if alias == 'hg': | |
|
213 | # lookup up the exact node id | |
|
214 | _revset_predicates = { | |
|
215 | 'branch': 'branch', | |
|
216 | 'book': 'bookmark', | |
|
217 | 'tag': 'tag', | |
|
218 | 'rev': 'id', | |
|
219 | } | |
|
220 | ||
|
221 | org_rev_spec = "max(%s('%s'))" % (_revset_predicates[org_ref[0]], | |
|
222 | safe_str(org_ref[1])) | |
|
223 | org_revs = scmutil.revrange(org_repo._repo, [org_rev_spec]) | |
|
224 | org_rev = org_repo._repo[org_revs[-1] if org_revs else -1].hex() | |
|
225 | ||
|
226 | other_rev_spec = "max(%s('%s'))" % (_revset_predicates[other_ref[0]], | |
|
227 | safe_str(other_ref[1])) | |
|
228 | other_revs = scmutil.revrange(other_repo._repo, [other_rev_spec]) | |
|
229 | other_rev = other_repo._repo[other_revs[-1] if other_revs else -1].hex() | |
|
230 | ||
|
231 | #case two independent repos | |
|
232 | if org_repo != other_repo: | |
|
233 | hgrepo = unionrepo.unionrepository(other_repo.baseui, | |
|
234 | other_repo.path, | |
|
235 | org_repo.path) | |
|
236 | # all the changesets we are looking for will be in other_repo, | |
|
237 | # so rev numbers from hgrepo can be used in other_repo | |
|
238 | ||
|
239 | #no remote compare do it on the same repository | |
|
240 | else: | |
|
241 | hgrepo = other_repo._repo | |
|
242 | ||
|
243 | if merge: | |
|
244 | revs = ["ancestors(id('%s')) and not ancestors(id('%s')) and not id('%s')" % | |
|
245 | (other_rev, org_rev, org_rev)] | |
|
246 | ||
|
247 | ancestors = scmutil.revrange(hgrepo, | |
|
248 | ["ancestor(id('%s'), id('%s'))" % (org_rev, other_rev)]) | |
|
249 | if ancestors: | |
|
250 | # pick arbitrary ancestor - but there is usually only one | |
|
251 | ancestor = hgrepo[ancestors[0]].hex() | |
|
252 | else: | |
|
253 | # TODO: have both + and - changesets | |
|
254 | revs = ["id('%s') :: id('%s') - id('%s')" % | |
|
255 | (org_rev, other_rev, org_rev)] | |
|
256 | ||
|
257 | changesets = [other_repo.get_changeset(cs) | |
|
258 | for cs in scmutil.revrange(hgrepo, revs)] | |
|
259 | ||
|
260 | elif alias == 'git': | |
|
261 | assert org_repo == other_repo, (org_repo, other_repo) # no git support for different repos | |
|
262 | so, se = org_repo.run_git_command( | |
|
263 | 'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1], | |
|
264 | other_ref[1]) | |
|
265 | ) | |
|
266 | changesets = [org_repo.get_changeset(cs) | |
|
267 | for cs in re.findall(r'[0-9a-fA-F]{40}', so)] | |
|
268 | ||
|
269 | return changesets, ancestor |
@@ -182,6 +182,9 b' class FilesController(BaseRepoController' | |||
|
182 | 182 | |
|
183 | 183 | return render('files/files.html') |
|
184 | 184 | |
|
185 | @LoginRequired() | |
|
186 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
187 | 'repository.admin') | |
|
185 | 188 | def history(self, repo_name, revision, f_path, annotate=False): |
|
186 | 189 | if request.environ.get('HTTP_X_PARTIAL_XHR'): |
|
187 | 190 | c.changeset = self.__get_cs_or_redirect(revision, repo_name) |
@@ -37,12 +37,12 b' log = logging.getLogger(__name__)' | |||
|
37 | 37 | |
|
38 | 38 | class FollowersController(BaseRepoController): |
|
39 | 39 | |
|
40 | def __before__(self): | |
|
41 | super(FollowersController, self).__before__() | |
|
42 | ||
|
40 | 43 | @LoginRequired() |
|
41 | 44 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
42 | 45 | 'repository.admin') |
|
43 | def __before__(self): | |
|
44 | super(FollowersController, self).__before__() | |
|
45 | ||
|
46 | 46 | def followers(self, repo_name): |
|
47 | 47 | p = safe_int(request.GET.get('page', 1), 1) |
|
48 | 48 | repo_id = c.rhodecode_db_repo.repo_id |
@@ -50,7 +50,6 b' log = logging.getLogger(__name__)' | |||
|
50 | 50 | |
|
51 | 51 | class ForksController(BaseRepoController): |
|
52 | 52 | |
|
53 | @LoginRequired() | |
|
54 | 53 | def __before__(self): |
|
55 | 54 | super(ForksController, self).__before__() |
|
56 | 55 | |
@@ -107,6 +106,7 b' class ForksController(BaseRepoController' | |||
|
107 | 106 | |
|
108 | 107 | return defaults |
|
109 | 108 | |
|
109 | @LoginRequired() | |
|
110 | 110 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
111 | 111 | 'repository.admin') |
|
112 | 112 | def forks(self, repo_name): |
@@ -128,6 +128,7 b' class ForksController(BaseRepoController' | |||
|
128 | 128 | |
|
129 | 129 | return render('/forks/forks.html') |
|
130 | 130 | |
|
131 | @LoginRequired() | |
|
131 | 132 | @NotAnonymous() |
|
132 | 133 | @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository') |
|
133 | 134 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
@@ -147,6 +148,7 b' class ForksController(BaseRepoController' | |||
|
147 | 148 | force_defaults=False |
|
148 | 149 | ) |
|
149 | 150 | |
|
151 | @LoginRequired() | |
|
150 | 152 | @NotAnonymous() |
|
151 | 153 | @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository') |
|
152 | 154 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
@@ -44,10 +44,10 b' log = logging.getLogger(__name__)' | |||
|
44 | 44 | |
|
45 | 45 | class HomeController(BaseController): |
|
46 | 46 | |
|
47 | @LoginRequired() | |
|
48 | 47 | def __before__(self): |
|
49 | 48 | super(HomeController, self).__before__() |
|
50 | 49 | |
|
50 | @LoginRequired() | |
|
51 | 51 | def index(self): |
|
52 | 52 | c.groups = self.scm_model.get_repos_groups() |
|
53 | 53 | c.group = None |
@@ -68,6 +68,7 b' class HomeController(BaseController):' | |||
|
68 | 68 | |
|
69 | 69 | return render('/index.html') |
|
70 | 70 | |
|
71 | @LoginRequired() | |
|
71 | 72 | def repo_switcher(self): |
|
72 | 73 | if request.is_xhr: |
|
73 | 74 | all_repos = Repository.query().order_by(Repository.repo_name).all() |
@@ -78,6 +79,7 b' class HomeController(BaseController):' | |||
|
78 | 79 | else: |
|
79 | 80 | raise HTTPBadRequest() |
|
80 | 81 | |
|
82 | @LoginRequired() | |
|
81 | 83 | def branch_tag_switcher(self, repo_name): |
|
82 | 84 | if request.is_xhr: |
|
83 | 85 | c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name) |
@@ -58,6 +58,137 b' class JournalController(BaseController):' | |||
|
58 | 58 | self.feed_nr = 20 |
|
59 | 59 | c.search_term = request.GET.get('filter') |
|
60 | 60 | |
|
61 | def _get_daily_aggregate(self, journal): | |
|
62 | groups = [] | |
|
63 | for k, g in groupby(journal, lambda x: x.action_as_day): | |
|
64 | user_group = [] | |
|
65 | #groupby username if it's a present value, else fallback to journal username | |
|
66 | for _, g2 in groupby(list(g), lambda x: x.user.username if x.user else x.username): | |
|
67 | l = list(g2) | |
|
68 | user_group.append((l[0].user, l)) | |
|
69 | ||
|
70 | groups.append((k, user_group,)) | |
|
71 | ||
|
72 | return groups | |
|
73 | ||
|
74 | def _get_journal_data(self, following_repos): | |
|
75 | repo_ids = [x.follows_repository.repo_id for x in following_repos | |
|
76 | if x.follows_repository is not None] | |
|
77 | user_ids = [x.follows_user.user_id for x in following_repos | |
|
78 | if x.follows_user is not None] | |
|
79 | ||
|
80 | filtering_criterion = None | |
|
81 | ||
|
82 | if repo_ids and user_ids: | |
|
83 | filtering_criterion = or_(UserLog.repository_id.in_(repo_ids), | |
|
84 | UserLog.user_id.in_(user_ids)) | |
|
85 | if repo_ids and not user_ids: | |
|
86 | filtering_criterion = UserLog.repository_id.in_(repo_ids) | |
|
87 | if not repo_ids and user_ids: | |
|
88 | filtering_criterion = UserLog.user_id.in_(user_ids) | |
|
89 | if filtering_criterion is not None: | |
|
90 | journal = self.sa.query(UserLog)\ | |
|
91 | .options(joinedload(UserLog.user))\ | |
|
92 | .options(joinedload(UserLog.repository)) | |
|
93 | #filter | |
|
94 | try: | |
|
95 | journal = _journal_filter(journal, c.search_term) | |
|
96 | except Exception: | |
|
97 | # we want this to crash for now | |
|
98 | raise | |
|
99 | journal = journal.filter(filtering_criterion)\ | |
|
100 | .order_by(UserLog.action_date.desc()) | |
|
101 | else: | |
|
102 | journal = [] | |
|
103 | ||
|
104 | return journal | |
|
105 | ||
|
106 | def _atom_feed(self, repos, public=True): | |
|
107 | journal = self._get_journal_data(repos) | |
|
108 | if public: | |
|
109 | _link = url('public_journal_atom', qualified=True) | |
|
110 | _desc = '%s %s %s' % (c.rhodecode_name, _('public journal'), | |
|
111 | 'atom feed') | |
|
112 | else: | |
|
113 | _link = url('journal_atom', qualified=True) | |
|
114 | _desc = '%s %s %s' % (c.rhodecode_name, _('journal'), 'atom feed') | |
|
115 | ||
|
116 | feed = Atom1Feed(title=_desc, | |
|
117 | link=_link, | |
|
118 | description=_desc, | |
|
119 | language=self.language, | |
|
120 | ttl=self.ttl) | |
|
121 | ||
|
122 | for entry in journal[:self.feed_nr]: | |
|
123 | user = entry.user | |
|
124 | if user is None: | |
|
125 | #fix deleted users | |
|
126 | user = AttributeDict({'short_contact': entry.username, | |
|
127 | 'email': '', | |
|
128 | 'full_contact': ''}) | |
|
129 | action, action_extra, ico = h.action_parser(entry, feed=True) | |
|
130 | title = "%s - %s %s" % (user.short_contact, action(), | |
|
131 | entry.repository.repo_name) | |
|
132 | desc = action_extra() | |
|
133 | _url = None | |
|
134 | if entry.repository is not None: | |
|
135 | _url = url('changelog_home', | |
|
136 | repo_name=entry.repository.repo_name, | |
|
137 | qualified=True) | |
|
138 | ||
|
139 | feed.add_item(title=title, | |
|
140 | pubdate=entry.action_date, | |
|
141 | link=_url or url('', qualified=True), | |
|
142 | author_email=user.email, | |
|
143 | author_name=user.full_contact, | |
|
144 | description=desc) | |
|
145 | ||
|
146 | response.content_type = feed.mime_type | |
|
147 | return feed.writeString('utf-8') | |
|
148 | ||
|
149 | def _rss_feed(self, repos, public=True): | |
|
150 | journal = self._get_journal_data(repos) | |
|
151 | if public: | |
|
152 | _link = url('public_journal_atom', qualified=True) | |
|
153 | _desc = '%s %s %s' % (c.rhodecode_name, _('public journal'), | |
|
154 | 'rss feed') | |
|
155 | else: | |
|
156 | _link = url('journal_atom', qualified=True) | |
|
157 | _desc = '%s %s %s' % (c.rhodecode_name, _('journal'), 'rss feed') | |
|
158 | ||
|
159 | feed = Rss201rev2Feed(title=_desc, | |
|
160 | link=_link, | |
|
161 | description=_desc, | |
|
162 | language=self.language, | |
|
163 | ttl=self.ttl) | |
|
164 | ||
|
165 | for entry in journal[:self.feed_nr]: | |
|
166 | user = entry.user | |
|
167 | if user is None: | |
|
168 | #fix deleted users | |
|
169 | user = AttributeDict({'short_contact': entry.username, | |
|
170 | 'email': '', | |
|
171 | 'full_contact': ''}) | |
|
172 | action, action_extra, ico = h.action_parser(entry, feed=True) | |
|
173 | title = "%s - %s %s" % (user.short_contact, action(), | |
|
174 | entry.repository.repo_name) | |
|
175 | desc = action_extra() | |
|
176 | _url = None | |
|
177 | if entry.repository is not None: | |
|
178 | _url = url('changelog_home', | |
|
179 | repo_name=entry.repository.repo_name, | |
|
180 | qualified=True) | |
|
181 | ||
|
182 | feed.add_item(title=title, | |
|
183 | pubdate=entry.action_date, | |
|
184 | link=_url or url('', qualified=True), | |
|
185 | author_email=user.email, | |
|
186 | author_name=user.full_contact, | |
|
187 | description=desc) | |
|
188 | ||
|
189 | response.content_type = feed.mime_type | |
|
190 | return feed.writeString('utf-8') | |
|
191 | ||
|
61 | 192 | @LoginRequired() |
|
62 | 193 | @NotAnonymous() |
|
63 | 194 | def index(self): |
@@ -172,51 +303,6 b' class JournalController(BaseController):' | |||
|
172 | 303 | .all() |
|
173 | 304 | return self._rss_feed(following, public=False) |
|
174 | 305 | |
|
175 | def _get_daily_aggregate(self, journal): | |
|
176 | groups = [] | |
|
177 | for k, g in groupby(journal, lambda x: x.action_as_day): | |
|
178 | user_group = [] | |
|
179 | #groupby username if it's a present value, else fallback to journal username | |
|
180 | for _, g2 in groupby(list(g), lambda x: x.user.username if x.user else x.username): | |
|
181 | l = list(g2) | |
|
182 | user_group.append((l[0].user, l)) | |
|
183 | ||
|
184 | groups.append((k, user_group,)) | |
|
185 | ||
|
186 | return groups | |
|
187 | ||
|
188 | def _get_journal_data(self, following_repos): | |
|
189 | repo_ids = [x.follows_repository.repo_id for x in following_repos | |
|
190 | if x.follows_repository is not None] | |
|
191 | user_ids = [x.follows_user.user_id for x in following_repos | |
|
192 | if x.follows_user is not None] | |
|
193 | ||
|
194 | filtering_criterion = None | |
|
195 | ||
|
196 | if repo_ids and user_ids: | |
|
197 | filtering_criterion = or_(UserLog.repository_id.in_(repo_ids), | |
|
198 | UserLog.user_id.in_(user_ids)) | |
|
199 | if repo_ids and not user_ids: | |
|
200 | filtering_criterion = UserLog.repository_id.in_(repo_ids) | |
|
201 | if not repo_ids and user_ids: | |
|
202 | filtering_criterion = UserLog.user_id.in_(user_ids) | |
|
203 | if filtering_criterion is not None: | |
|
204 | journal = self.sa.query(UserLog)\ | |
|
205 | .options(joinedload(UserLog.user))\ | |
|
206 | .options(joinedload(UserLog.repository)) | |
|
207 | #filter | |
|
208 | try: | |
|
209 | journal = _journal_filter(journal, c.search_term) | |
|
210 | except Exception: | |
|
211 | # we want this to crash for now | |
|
212 | raise | |
|
213 | journal = journal.filter(filtering_criterion)\ | |
|
214 | .order_by(UserLog.action_date.desc()) | |
|
215 | else: | |
|
216 | journal = [] | |
|
217 | ||
|
218 | return journal | |
|
219 | ||
|
220 | 306 | @LoginRequired() |
|
221 | 307 | @NotAnonymous() |
|
222 | 308 | def toggle_following(self): |
@@ -268,92 +354,6 b' class JournalController(BaseController):' | |||
|
268 | 354 | return c.journal_data |
|
269 | 355 | return render('journal/public_journal.html') |
|
270 | 356 | |
|
271 | def _atom_feed(self, repos, public=True): | |
|
272 | journal = self._get_journal_data(repos) | |
|
273 | if public: | |
|
274 | _link = url('public_journal_atom', qualified=True) | |
|
275 | _desc = '%s %s %s' % (c.rhodecode_name, _('public journal'), | |
|
276 | 'atom feed') | |
|
277 | else: | |
|
278 | _link = url('journal_atom', qualified=True) | |
|
279 | _desc = '%s %s %s' % (c.rhodecode_name, _('journal'), 'atom feed') | |
|
280 | ||
|
281 | feed = Atom1Feed(title=_desc, | |
|
282 | link=_link, | |
|
283 | description=_desc, | |
|
284 | language=self.language, | |
|
285 | ttl=self.ttl) | |
|
286 | ||
|
287 | for entry in journal[:self.feed_nr]: | |
|
288 | user = entry.user | |
|
289 | if user is None: | |
|
290 | #fix deleted users | |
|
291 | user = AttributeDict({'short_contact': entry.username, | |
|
292 | 'email': '', | |
|
293 | 'full_contact': ''}) | |
|
294 | action, action_extra, ico = h.action_parser(entry, feed=True) | |
|
295 | title = "%s - %s %s" % (user.short_contact, action(), | |
|
296 | entry.repository.repo_name) | |
|
297 | desc = action_extra() | |
|
298 | _url = None | |
|
299 | if entry.repository is not None: | |
|
300 | _url = url('changelog_home', | |
|
301 | repo_name=entry.repository.repo_name, | |
|
302 | qualified=True) | |
|
303 | ||
|
304 | feed.add_item(title=title, | |
|
305 | pubdate=entry.action_date, | |
|
306 | link=_url or url('', qualified=True), | |
|
307 | author_email=user.email, | |
|
308 | author_name=user.full_contact, | |
|
309 | description=desc) | |
|
310 | ||
|
311 | response.content_type = feed.mime_type | |
|
312 | return feed.writeString('utf-8') | |
|
313 | ||
|
314 | def _rss_feed(self, repos, public=True): | |
|
315 | journal = self._get_journal_data(repos) | |
|
316 | if public: | |
|
317 | _link = url('public_journal_atom', qualified=True) | |
|
318 | _desc = '%s %s %s' % (c.rhodecode_name, _('public journal'), | |
|
319 | 'rss feed') | |
|
320 | else: | |
|
321 | _link = url('journal_atom', qualified=True) | |
|
322 | _desc = '%s %s %s' % (c.rhodecode_name, _('journal'), 'rss feed') | |
|
323 | ||
|
324 | feed = Rss201rev2Feed(title=_desc, | |
|
325 | link=_link, | |
|
326 | description=_desc, | |
|
327 | language=self.language, | |
|
328 | ttl=self.ttl) | |
|
329 | ||
|
330 | for entry in journal[:self.feed_nr]: | |
|
331 | user = entry.user | |
|
332 | if user is None: | |
|
333 | #fix deleted users | |
|
334 | user = AttributeDict({'short_contact': entry.username, | |
|
335 | 'email': '', | |
|
336 | 'full_contact': ''}) | |
|
337 | action, action_extra, ico = h.action_parser(entry, feed=True) | |
|
338 | title = "%s - %s %s" % (user.short_contact, action(), | |
|
339 | entry.repository.repo_name) | |
|
340 | desc = action_extra() | |
|
341 | _url = None | |
|
342 | if entry.repository is not None: | |
|
343 | _url = url('changelog_home', | |
|
344 | repo_name=entry.repository.repo_name, | |
|
345 | qualified=True) | |
|
346 | ||
|
347 | feed.add_item(title=title, | |
|
348 | pubdate=entry.action_date, | |
|
349 | link=_url or url('', qualified=True), | |
|
350 | author_email=user.email, | |
|
351 | author_name=user.full_contact, | |
|
352 | description=desc) | |
|
353 | ||
|
354 | response.content_type = feed.mime_type | |
|
355 | return feed.writeString('utf-8') | |
|
356 | ||
|
357 | 357 | @LoginRequired(api_access=True) |
|
358 | 358 | def public_journal_atom(self): |
|
359 | 359 | """ |
@@ -62,9 +62,6 b' log = logging.getLogger(__name__)' | |||
|
62 | 62 | |
|
63 | 63 | class PullrequestsController(BaseRepoController): |
|
64 | 64 | |
|
65 | @LoginRequired() | |
|
66 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
67 | 'repository.admin') | |
|
68 | 65 | def __before__(self): |
|
69 | 66 | super(PullrequestsController, self).__before__() |
|
70 | 67 | repo_model = RepoModel() |
@@ -144,156 +141,6 b' class PullrequestsController(BaseRepoCon' | |||
|
144 | 141 | pull_request.reviewers] |
|
145 | 142 | return (self.rhodecode_user.admin or owner or reviewer) |
|
146 | 143 | |
|
147 | def show_all(self, repo_name): | |
|
148 | c.pull_requests = PullRequestModel().get_all(repo_name) | |
|
149 | c.repo_name = repo_name | |
|
150 | p = safe_int(request.GET.get('page', 1), 1) | |
|
151 | ||
|
152 | c.pullrequests_pager = Page(c.pull_requests, page=p, items_per_page=10) | |
|
153 | ||
|
154 | c.pullrequest_data = render('/pullrequests/pullrequest_data.html') | |
|
155 | ||
|
156 | if request.environ.get('HTTP_X_PARTIAL_XHR'): | |
|
157 | return c.pullrequest_data | |
|
158 | ||
|
159 | return render('/pullrequests/pullrequest_show_all.html') | |
|
160 | ||
|
161 | @NotAnonymous() | |
|
162 | def index(self): | |
|
163 | org_repo = c.rhodecode_db_repo | |
|
164 | ||
|
165 | if org_repo.scm_instance.alias != 'hg': | |
|
166 | log.error('Review not available for GIT REPOS') | |
|
167 | raise HTTPNotFound | |
|
168 | ||
|
169 | try: | |
|
170 | org_repo.scm_instance.get_changeset() | |
|
171 | except EmptyRepositoryError, e: | |
|
172 | h.flash(h.literal(_('There are no changesets yet')), | |
|
173 | category='warning') | |
|
174 | redirect(url('summary_home', repo_name=org_repo.repo_name)) | |
|
175 | ||
|
176 | org_rev = request.GET.get('rev_end') | |
|
177 | # rev_start is not directly useful - its parent could however be used | |
|
178 | # as default for other and thus give a simple compare view | |
|
179 | #other_rev = request.POST.get('rev_start') | |
|
180 | ||
|
181 | c.org_repos = [] | |
|
182 | c.org_repos.append((org_repo.repo_name, org_repo.repo_name)) | |
|
183 | c.default_org_repo = org_repo.repo_name | |
|
184 | c.org_refs, c.default_org_ref = self._get_repo_refs(org_repo.scm_instance, org_rev) | |
|
185 | ||
|
186 | c.other_repos = [] | |
|
187 | other_repos_info = {} | |
|
188 | ||
|
189 | def add_other_repo(repo, branch_rev=None): | |
|
190 | if repo.repo_name in other_repos_info: # shouldn't happen | |
|
191 | return | |
|
192 | c.other_repos.append((repo.repo_name, repo.repo_name)) | |
|
193 | other_refs, selected_other_ref = self._get_repo_refs(repo.scm_instance, branch_rev=branch_rev) | |
|
194 | other_repos_info[repo.repo_name] = { | |
|
195 | 'user': dict(user_id=repo.user.user_id, | |
|
196 | username=repo.user.username, | |
|
197 | firstname=repo.user.firstname, | |
|
198 | lastname=repo.user.lastname, | |
|
199 | gravatar_link=h.gravatar_url(repo.user.email, 14)), | |
|
200 | 'description': repo.description.split('\n', 1)[0], | |
|
201 | 'revs': h.select('other_ref', selected_other_ref, other_refs, class_='refs') | |
|
202 | } | |
|
203 | ||
|
204 | # add org repo to other so we can open pull request against peer branches on itself | |
|
205 | add_other_repo(org_repo, branch_rev=org_rev) | |
|
206 | c.default_other_repo = org_repo.repo_name | |
|
207 | ||
|
208 | # gather forks and add to this list ... even though it is rare to | |
|
209 | # request forks to pull from their parent | |
|
210 | for fork in org_repo.forks: | |
|
211 | add_other_repo(fork) | |
|
212 | ||
|
213 | # add parents of this fork also, but only if it's not empty | |
|
214 | if org_repo.parent and org_repo.parent.scm_instance.revisions: | |
|
215 | add_other_repo(org_repo.parent) | |
|
216 | c.default_other_repo = org_repo.parent.repo_name | |
|
217 | ||
|
218 | c.default_other_repo_info = other_repos_info[c.default_other_repo] | |
|
219 | c.other_repos_info = json.dumps(other_repos_info) | |
|
220 | ||
|
221 | return render('/pullrequests/pullrequest.html') | |
|
222 | ||
|
223 | @NotAnonymous() | |
|
224 | def create(self, repo_name): | |
|
225 | repo = RepoModel()._get_repo(repo_name) | |
|
226 | try: | |
|
227 | _form = PullRequestForm(repo.repo_id)().to_python(request.POST) | |
|
228 | except formencode.Invalid, errors: | |
|
229 | log.error(traceback.format_exc()) | |
|
230 | if errors.error_dict.get('revisions'): | |
|
231 | msg = 'Revisions: %s' % errors.error_dict['revisions'] | |
|
232 | elif errors.error_dict.get('pullrequest_title'): | |
|
233 | msg = _('Pull request requires a title with min. 3 chars') | |
|
234 | else: | |
|
235 | msg = _('Error creating pull request') | |
|
236 | ||
|
237 | h.flash(msg, 'error') | |
|
238 | return redirect(url('pullrequest_home', repo_name=repo_name)) | |
|
239 | ||
|
240 | org_repo = _form['org_repo'] | |
|
241 | org_ref = 'rev:merge:%s' % _form['merge_rev'] | |
|
242 | other_repo = _form['other_repo'] | |
|
243 | other_ref = 'rev:ancestor:%s' % _form['ancestor_rev'] | |
|
244 | revisions = reversed(_form['revisions']) | |
|
245 | reviewers = _form['review_members'] | |
|
246 | ||
|
247 | title = _form['pullrequest_title'] | |
|
248 | description = _form['pullrequest_desc'] | |
|
249 | ||
|
250 | try: | |
|
251 | pull_request = PullRequestModel().create( | |
|
252 | self.rhodecode_user.user_id, org_repo, org_ref, other_repo, | |
|
253 | other_ref, revisions, reviewers, title, description | |
|
254 | ) | |
|
255 | Session().commit() | |
|
256 | h.flash(_('Successfully opened new pull request'), | |
|
257 | category='success') | |
|
258 | except Exception: | |
|
259 | h.flash(_('Error occurred during sending pull request'), | |
|
260 | category='error') | |
|
261 | log.error(traceback.format_exc()) | |
|
262 | return redirect(url('pullrequest_home', repo_name=repo_name)) | |
|
263 | ||
|
264 | return redirect(url('pullrequest_show', repo_name=other_repo, | |
|
265 | pull_request_id=pull_request.pull_request_id)) | |
|
266 | ||
|
267 | @NotAnonymous() | |
|
268 | @jsonify | |
|
269 | def update(self, repo_name, pull_request_id): | |
|
270 | pull_request = PullRequest.get_or_404(pull_request_id) | |
|
271 | if pull_request.is_closed(): | |
|
272 | raise HTTPForbidden() | |
|
273 | #only owner or admin can update it | |
|
274 | owner = pull_request.author.user_id == c.rhodecode_user.user_id | |
|
275 | if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner: | |
|
276 | reviewers_ids = map(int, filter(lambda v: v not in [None, ''], | |
|
277 | request.POST.get('reviewers_ids', '').split(','))) | |
|
278 | ||
|
279 | PullRequestModel().update_reviewers(pull_request_id, reviewers_ids) | |
|
280 | Session().commit() | |
|
281 | return True | |
|
282 | raise HTTPForbidden() | |
|
283 | ||
|
284 | @NotAnonymous() | |
|
285 | @jsonify | |
|
286 | def delete(self, repo_name, pull_request_id): | |
|
287 | pull_request = PullRequest.get_or_404(pull_request_id) | |
|
288 | #only owner can delete it ! | |
|
289 | if pull_request.author.user_id == c.rhodecode_user.user_id: | |
|
290 | PullRequestModel().delete(pull_request) | |
|
291 | Session().commit() | |
|
292 | h.flash(_('Successfully deleted pull request'), | |
|
293 | category='success') | |
|
294 | return redirect(url('admin_settings_my_account', anchor='pullrequests')) | |
|
295 | raise HTTPForbidden() | |
|
296 | ||
|
297 | 144 | def _load_compare_data(self, pull_request, enable_comments=True): |
|
298 | 145 | """ |
|
299 | 146 | Load context data needed for generating compare diff |
@@ -361,6 +208,174 b' class PullrequestsController(BaseRepoCon' | |||
|
361 | 208 | parsed_lines=[f]) |
|
362 | 209 | c.changes[fid] = [f['operation'], f['filename'], diff] |
|
363 | 210 | |
|
211 | @LoginRequired() | |
|
212 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
213 | 'repository.admin') | |
|
214 | def show_all(self, repo_name): | |
|
215 | c.pull_requests = PullRequestModel().get_all(repo_name) | |
|
216 | c.repo_name = repo_name | |
|
217 | p = safe_int(request.GET.get('page', 1), 1) | |
|
218 | ||
|
219 | c.pullrequests_pager = Page(c.pull_requests, page=p, items_per_page=10) | |
|
220 | ||
|
221 | c.pullrequest_data = render('/pullrequests/pullrequest_data.html') | |
|
222 | ||
|
223 | if request.environ.get('HTTP_X_PARTIAL_XHR'): | |
|
224 | return c.pullrequest_data | |
|
225 | ||
|
226 | return render('/pullrequests/pullrequest_show_all.html') | |
|
227 | ||
|
228 | @LoginRequired() | |
|
229 | @NotAnonymous() | |
|
230 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
231 | 'repository.admin') | |
|
232 | def index(self): | |
|
233 | org_repo = c.rhodecode_db_repo | |
|
234 | ||
|
235 | if org_repo.scm_instance.alias != 'hg': | |
|
236 | log.error('Review not available for GIT REPOS') | |
|
237 | raise HTTPNotFound | |
|
238 | ||
|
239 | try: | |
|
240 | org_repo.scm_instance.get_changeset() | |
|
241 | except EmptyRepositoryError, e: | |
|
242 | h.flash(h.literal(_('There are no changesets yet')), | |
|
243 | category='warning') | |
|
244 | redirect(url('summary_home', repo_name=org_repo.repo_name)) | |
|
245 | ||
|
246 | org_rev = request.GET.get('rev_end') | |
|
247 | # rev_start is not directly useful - its parent could however be used | |
|
248 | # as default for other and thus give a simple compare view | |
|
249 | #other_rev = request.POST.get('rev_start') | |
|
250 | ||
|
251 | c.org_repos = [] | |
|
252 | c.org_repos.append((org_repo.repo_name, org_repo.repo_name)) | |
|
253 | c.default_org_repo = org_repo.repo_name | |
|
254 | c.org_refs, c.default_org_ref = self._get_repo_refs(org_repo.scm_instance, org_rev) | |
|
255 | ||
|
256 | c.other_repos = [] | |
|
257 | other_repos_info = {} | |
|
258 | ||
|
259 | def add_other_repo(repo, branch_rev=None): | |
|
260 | if repo.repo_name in other_repos_info: # shouldn't happen | |
|
261 | return | |
|
262 | c.other_repos.append((repo.repo_name, repo.repo_name)) | |
|
263 | other_refs, selected_other_ref = self._get_repo_refs(repo.scm_instance, branch_rev=branch_rev) | |
|
264 | other_repos_info[repo.repo_name] = { | |
|
265 | 'user': dict(user_id=repo.user.user_id, | |
|
266 | username=repo.user.username, | |
|
267 | firstname=repo.user.firstname, | |
|
268 | lastname=repo.user.lastname, | |
|
269 | gravatar_link=h.gravatar_url(repo.user.email, 14)), | |
|
270 | 'description': repo.description.split('\n', 1)[0], | |
|
271 | 'revs': h.select('other_ref', selected_other_ref, other_refs, class_='refs') | |
|
272 | } | |
|
273 | ||
|
274 | # add org repo to other so we can open pull request against peer branches on itself | |
|
275 | add_other_repo(org_repo, branch_rev=org_rev) | |
|
276 | c.default_other_repo = org_repo.repo_name | |
|
277 | ||
|
278 | # gather forks and add to this list ... even though it is rare to | |
|
279 | # request forks to pull from their parent | |
|
280 | for fork in org_repo.forks: | |
|
281 | add_other_repo(fork) | |
|
282 | ||
|
283 | # add parents of this fork also, but only if it's not empty | |
|
284 | if org_repo.parent and org_repo.parent.scm_instance.revisions: | |
|
285 | add_other_repo(org_repo.parent) | |
|
286 | c.default_other_repo = org_repo.parent.repo_name | |
|
287 | ||
|
288 | c.default_other_repo_info = other_repos_info[c.default_other_repo] | |
|
289 | c.other_repos_info = json.dumps(other_repos_info) | |
|
290 | ||
|
291 | return render('/pullrequests/pullrequest.html') | |
|
292 | ||
|
293 | @LoginRequired() | |
|
294 | @NotAnonymous() | |
|
295 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
296 | 'repository.admin') | |
|
297 | def create(self, repo_name): | |
|
298 | repo = RepoModel()._get_repo(repo_name) | |
|
299 | try: | |
|
300 | _form = PullRequestForm(repo.repo_id)().to_python(request.POST) | |
|
301 | except formencode.Invalid, errors: | |
|
302 | log.error(traceback.format_exc()) | |
|
303 | if errors.error_dict.get('revisions'): | |
|
304 | msg = 'Revisions: %s' % errors.error_dict['revisions'] | |
|
305 | elif errors.error_dict.get('pullrequest_title'): | |
|
306 | msg = _('Pull request requires a title with min. 3 chars') | |
|
307 | else: | |
|
308 | msg = _('Error creating pull request') | |
|
309 | ||
|
310 | h.flash(msg, 'error') | |
|
311 | return redirect(url('pullrequest_home', repo_name=repo_name)) | |
|
312 | ||
|
313 | org_repo = _form['org_repo'] | |
|
314 | org_ref = 'rev:merge:%s' % _form['merge_rev'] | |
|
315 | other_repo = _form['other_repo'] | |
|
316 | other_ref = 'rev:ancestor:%s' % _form['ancestor_rev'] | |
|
317 | revisions = reversed(_form['revisions']) | |
|
318 | reviewers = _form['review_members'] | |
|
319 | ||
|
320 | title = _form['pullrequest_title'] | |
|
321 | description = _form['pullrequest_desc'] | |
|
322 | ||
|
323 | try: | |
|
324 | pull_request = PullRequestModel().create( | |
|
325 | self.rhodecode_user.user_id, org_repo, org_ref, other_repo, | |
|
326 | other_ref, revisions, reviewers, title, description | |
|
327 | ) | |
|
328 | Session().commit() | |
|
329 | h.flash(_('Successfully opened new pull request'), | |
|
330 | category='success') | |
|
331 | except Exception: | |
|
332 | h.flash(_('Error occurred during sending pull request'), | |
|
333 | category='error') | |
|
334 | log.error(traceback.format_exc()) | |
|
335 | return redirect(url('pullrequest_home', repo_name=repo_name)) | |
|
336 | ||
|
337 | return redirect(url('pullrequest_show', repo_name=other_repo, | |
|
338 | pull_request_id=pull_request.pull_request_id)) | |
|
339 | ||
|
340 | @LoginRequired() | |
|
341 | @NotAnonymous() | |
|
342 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
343 | 'repository.admin') | |
|
344 | @jsonify | |
|
345 | def update(self, repo_name, pull_request_id): | |
|
346 | pull_request = PullRequest.get_or_404(pull_request_id) | |
|
347 | if pull_request.is_closed(): | |
|
348 | raise HTTPForbidden() | |
|
349 | #only owner or admin can update it | |
|
350 | owner = pull_request.author.user_id == c.rhodecode_user.user_id | |
|
351 | if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner: | |
|
352 | reviewers_ids = map(int, filter(lambda v: v not in [None, ''], | |
|
353 | request.POST.get('reviewers_ids', '').split(','))) | |
|
354 | ||
|
355 | PullRequestModel().update_reviewers(pull_request_id, reviewers_ids) | |
|
356 | Session().commit() | |
|
357 | return True | |
|
358 | raise HTTPForbidden() | |
|
359 | ||
|
360 | @LoginRequired() | |
|
361 | @NotAnonymous() | |
|
362 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
363 | 'repository.admin') | |
|
364 | @jsonify | |
|
365 | def delete(self, repo_name, pull_request_id): | |
|
366 | pull_request = PullRequest.get_or_404(pull_request_id) | |
|
367 | #only owner can delete it ! | |
|
368 | if pull_request.author.user_id == c.rhodecode_user.user_id: | |
|
369 | PullRequestModel().delete(pull_request) | |
|
370 | Session().commit() | |
|
371 | h.flash(_('Successfully deleted pull request'), | |
|
372 | category='success') | |
|
373 | return redirect(url('admin_settings_my_account', anchor='pullrequests')) | |
|
374 | raise HTTPForbidden() | |
|
375 | ||
|
376 | @LoginRequired() | |
|
377 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
378 | 'repository.admin') | |
|
364 | 379 | def show(self, repo_name, pull_request_id): |
|
365 | 380 | repo_model = RepoModel() |
|
366 | 381 | c.users_array = repo_model.get_users_js() |
@@ -429,7 +444,10 b' class PullrequestsController(BaseRepoCon' | |||
|
429 | 444 | c.ancestor = None # there is one - but right here we don't know which |
|
430 | 445 | return render('/pullrequests/pullrequest_show.html') |
|
431 | 446 | |
|
447 | @LoginRequired() | |
|
432 | 448 | @NotAnonymous() |
|
449 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
450 | 'repository.admin') | |
|
433 | 451 | @jsonify |
|
434 | 452 | def comment(self, repo_name, pull_request_id): |
|
435 | 453 | pull_request = PullRequest.get_or_404(pull_request_id) |
@@ -504,7 +522,10 b' class PullrequestsController(BaseRepoCon' | |||
|
504 | 522 | |
|
505 | 523 | return data |
|
506 | 524 | |
|
525 | @LoginRequired() | |
|
507 | 526 | @NotAnonymous() |
|
527 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
528 | 'repository.admin') | |
|
508 | 529 | @jsonify |
|
509 | 530 | def delete_comment(self, repo_name, comment_id): |
|
510 | 531 | co = ChangesetComment.get(comment_id) |
@@ -48,10 +48,10 b' log = logging.getLogger(__name__)' | |||
|
48 | 48 | |
|
49 | 49 | class SearchController(BaseRepoController): |
|
50 | 50 | |
|
51 | @LoginRequired() | |
|
52 | 51 | def __before__(self): |
|
53 | 52 | super(SearchController, self).__before__() |
|
54 | 53 | |
|
54 | @LoginRequired() | |
|
55 | 55 | def index(self, repo_name=None): |
|
56 | 56 | c.repo_name = repo_name |
|
57 | 57 | c.formated_results = [] |
@@ -42,9 +42,6 b' log = logging.getLogger(__name__)' | |||
|
42 | 42 | |
|
43 | 43 | class ShortlogController(BaseRepoController): |
|
44 | 44 | |
|
45 | @LoginRequired() | |
|
46 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
47 | 'repository.admin') | |
|
48 | 45 | def __before__(self): |
|
49 | 46 | super(ShortlogController, self).__before__() |
|
50 | 47 | |
@@ -63,6 +60,9 b' class ShortlogController(BaseRepoControl' | |||
|
63 | 60 | h.flash(str(e), category='warning') |
|
64 | 61 | redirect(h.url('shortlog_home', repo_name=repo_name)) |
|
65 | 62 | |
|
63 | @LoginRequired() | |
|
64 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
65 | 'repository.admin') | |
|
66 | 66 | def index(self, repo_name, revision=None, f_path=None): |
|
67 | 67 | p = safe_int(request.GET.get('page', 1), 1) |
|
68 | 68 | size = safe_int(request.GET.get('size', 20), 20) |
@@ -65,12 +65,75 b" README_FILES = [''.join([x[0][0], x[1][0" | |||
|
65 | 65 | |
|
66 | 66 | class SummaryController(BaseRepoController): |
|
67 | 67 | |
|
68 | def __before__(self): | |
|
69 | super(SummaryController, self).__before__() | |
|
70 | ||
|
71 | def _get_download_links(self, repo): | |
|
72 | ||
|
73 | download_l = [] | |
|
74 | ||
|
75 | branches_group = ([], _("Branches")) | |
|
76 | tags_group = ([], _("Tags")) | |
|
77 | ||
|
78 | for name, chs in c.rhodecode_repo.branches.items(): | |
|
79 | #chs = chs.split(':')[-1] | |
|
80 | branches_group[0].append((chs, name),) | |
|
81 | download_l.append(branches_group) | |
|
82 | ||
|
83 | for name, chs in c.rhodecode_repo.tags.items(): | |
|
84 | #chs = chs.split(':')[-1] | |
|
85 | tags_group[0].append((chs, name),) | |
|
86 | download_l.append(tags_group) | |
|
87 | ||
|
88 | return download_l | |
|
89 | ||
|
90 | ||
|
91 | def __get_readme_data(self, db_repo): | |
|
92 | repo_name = db_repo.repo_name | |
|
93 | ||
|
94 | @cache_region('long_term') | |
|
95 | def _get_readme_from_cache(key): | |
|
96 | readme_data = None | |
|
97 | readme_file = None | |
|
98 | log.debug('Looking for README file') | |
|
99 | try: | |
|
100 | # get's the landing revision! or tip if fails | |
|
101 | cs = db_repo.get_landing_changeset() | |
|
102 | if isinstance(cs, EmptyChangeset): | |
|
103 | raise EmptyRepositoryError() | |
|
104 | renderer = MarkupRenderer() | |
|
105 | for f in README_FILES: | |
|
106 | try: | |
|
107 | readme = cs.get_node(f) | |
|
108 | if not isinstance(readme, FileNode): | |
|
109 | continue | |
|
110 | readme_file = f | |
|
111 | log.debug('Found README file `%s` rendering...' % | |
|
112 | readme_file) | |
|
113 | readme_data = renderer.render(readme.content, f) | |
|
114 | break | |
|
115 | except NodeDoesNotExistError: | |
|
116 | continue | |
|
117 | except ChangesetError: | |
|
118 | log.error(traceback.format_exc()) | |
|
119 | pass | |
|
120 | except EmptyRepositoryError: | |
|
121 | pass | |
|
122 | except Exception: | |
|
123 | log.error(traceback.format_exc()) | |
|
124 | ||
|
125 | return readme_data, readme_file | |
|
126 | ||
|
127 | key = repo_name + '_README' | |
|
128 | inv = CacheInvalidation.invalidate(key) | |
|
129 | if inv is not None: | |
|
130 | region_invalidate(_get_readme_from_cache, None, key) | |
|
131 | CacheInvalidation.set_valid(inv.cache_key) | |
|
132 | return _get_readme_from_cache(key) | |
|
133 | ||
|
68 | 134 | @LoginRequired() |
|
69 | 135 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
70 | 136 | 'repository.admin') |
|
71 | def __before__(self): | |
|
72 | super(SummaryController, self).__before__() | |
|
73 | ||
|
74 | 137 | def index(self, repo_name): |
|
75 | 138 | c.dbrepo = dbrepo = c.rhodecode_db_repo |
|
76 | 139 | |
@@ -189,72 +252,13 b' class SummaryController(BaseRepoControll' | |||
|
189 | 252 | self.__get_readme_data(c.rhodecode_db_repo) |
|
190 | 253 | return render('summary/summary.html') |
|
191 | 254 | |
|
255 | @LoginRequired() | |
|
192 | 256 | @NotAnonymous() |
|
257 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
258 | 'repository.admin') | |
|
193 | 259 | @jsonify |
|
194 | 260 | def repo_size(self, repo_name): |
|
195 | 261 | if request.is_xhr: |
|
196 | 262 | return c.rhodecode_db_repo._repo_size() |
|
197 | 263 | else: |
|
198 | 264 | raise HTTPBadRequest() |
|
199 | ||
|
200 | def __get_readme_data(self, db_repo): | |
|
201 | repo_name = db_repo.repo_name | |
|
202 | ||
|
203 | @cache_region('long_term') | |
|
204 | def _get_readme_from_cache(key): | |
|
205 | readme_data = None | |
|
206 | readme_file = None | |
|
207 | log.debug('Looking for README file') | |
|
208 | try: | |
|
209 | # get's the landing revision! or tip if fails | |
|
210 | cs = db_repo.get_landing_changeset() | |
|
211 | if isinstance(cs, EmptyChangeset): | |
|
212 | raise EmptyRepositoryError() | |
|
213 | renderer = MarkupRenderer() | |
|
214 | for f in README_FILES: | |
|
215 | try: | |
|
216 | readme = cs.get_node(f) | |
|
217 | if not isinstance(readme, FileNode): | |
|
218 | continue | |
|
219 | readme_file = f | |
|
220 | log.debug('Found README file `%s` rendering...' % | |
|
221 | readme_file) | |
|
222 | readme_data = renderer.render(readme.content, f) | |
|
223 | break | |
|
224 | except NodeDoesNotExistError: | |
|
225 | continue | |
|
226 | except ChangesetError: | |
|
227 | log.error(traceback.format_exc()) | |
|
228 | pass | |
|
229 | except EmptyRepositoryError: | |
|
230 | pass | |
|
231 | except Exception: | |
|
232 | log.error(traceback.format_exc()) | |
|
233 | ||
|
234 | return readme_data, readme_file | |
|
235 | ||
|
236 | key = repo_name + '_README' | |
|
237 | inv = CacheInvalidation.invalidate(key) | |
|
238 | if inv is not None: | |
|
239 | region_invalidate(_get_readme_from_cache, None, key) | |
|
240 | CacheInvalidation.set_valid(inv.cache_key) | |
|
241 | return _get_readme_from_cache(key) | |
|
242 | ||
|
243 | def _get_download_links(self, repo): | |
|
244 | ||
|
245 | download_l = [] | |
|
246 | ||
|
247 | branches_group = ([], _("Branches")) | |
|
248 | tags_group = ([], _("Tags")) | |
|
249 | ||
|
250 | for name, chs in c.rhodecode_repo.branches.items(): | |
|
251 | #chs = chs.split(':')[-1] | |
|
252 | branches_group[0].append((chs, name),) | |
|
253 | download_l.append(branches_group) | |
|
254 | ||
|
255 | for name, chs in c.rhodecode_repo.tags.items(): | |
|
256 | #chs = chs.split(':')[-1] | |
|
257 | tags_group[0].append((chs, name),) | |
|
258 | download_l.append(tags_group) | |
|
259 | ||
|
260 | return download_l |
@@ -35,12 +35,12 b' log = logging.getLogger(__name__)' | |||
|
35 | 35 | |
|
36 | 36 | class TagsController(BaseRepoController): |
|
37 | 37 | |
|
38 | def __before__(self): | |
|
39 | super(TagsController, self).__before__() | |
|
40 | ||
|
38 | 41 | @LoginRequired() |
|
39 | 42 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
40 | 43 | 'repository.admin') |
|
41 | def __before__(self): | |
|
42 | super(TagsController, self).__before__() | |
|
43 | ||
|
44 | 44 | def index(self): |
|
45 | 45 | c.repo_tags = OrderedDict() |
|
46 | 46 |
General Comments 0
You need to be logged in to leave comments.
Login now