##// END OF EJS Templates
release: Merge default into stable for release preparation
marcink -
r2510:9b59b118 merge stable
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -0,0 +1,101 b''
1 .. _sec-your-server:
2
3 Securing Your Server via Sophos UTM 9
4 -------------------------------------
5
6
7
8 Below is an example configuration for Sophos UTM 9 Webserver Protection::
9
10 Sophos UTM 9 Webserver Protection
11 Web Application Firewall based on apache2 modesecurity2
12 --------------------------------------------------
13 1. Firewall Profiles -> Firewall Profile
14 --------------------------------------------------
15 Name: RhodeCode (can be anything)
16 Mode: Reject
17 Hardening & Signing:
18 [ ] Static URL hardeninig
19 [ ] Form hardening
20 [x] Cookie Signing
21 Filtering:
22 [x] Block clients with bad reputation
23 [x] Common Threats Filter
24 [ ] Rigid Filtering
25 Skip Filter Rules:
26 960015
27 950120
28 981173
29 970901
30 960010
31 960032
32 960035
33 958291
34 970903
35 970003
36 Common Threat Filter Categories:
37 [x] Protocol violations
38 [x] Protocol anomalies
39 [x] Request limit
40 [x] HTTP policy
41 [x] Bad robots
42 [x] Generic attacks
43 [x] SQL injection attacks
44 [x] XSS attacks
45 [x] Tight security
46 [x] Trojans
47 [x] Outbound
48 Scanning:
49 [ ] Enable antivirus scanning
50 [ ] Block uploads by MIME type
51 --------------------------------------------------
52 2. Web Application Firewall -> Real Webservers
53 --------------------------------------------------
54 Name: RhodeCode (can be anything)
55 Host: Your RhodeCode-Server (UTM object)
56 Type: Encrypted (HTTPS)
57 Port: 443
58 --------------------------------------------------
59 3. Web Application Firewall -> Virual Webservers
60 --------------------------------------------------
61 Name: RhodeCode (can be anything)
62 Interface: WAN (your WAN interface)
63 Type: Encrypted (HTTPS) & redirect
64 Certificate: Wildcard or matching domain certificate
65 Domains (in case of Wildcard certificate):
66 rhodecode.yourcompany.com (match your DNS configuration)
67 gist.yourcompany.com (match your DNS & RhodeCode configuration)
68 Real Webservers for path '/':
69 [x] RhodeCode (created in step 2)
70 Firewall: RhodeCode (created in step 1)
71 --------------------------------------------------
72 4. Firewall Profiles -> Exceptions
73 --------------------------------------------------
74 Name: RhodeCode exceptions (can be anything)
75 Skip these checks:
76 [ ] Cookie signing
77 [ ] Static URL Hardening
78 [ ] Form hardening
79 [x] Antivirus scanning
80 [x] True file type control
81 [ ] Block clients with bad reputation
82 Skip these categories:
83 [ ] Protocol violations
84 [x] Protocol anomalies
85 [x] Request limits
86 [ ] HTTP policy
87 [ ] Bad robots
88 [ ] Generic attacks
89 [ ] SQL injection attacks
90 [ ] XSS attacks
91 [ ] Tight security
92 [ ] Trojans
93 [x] Outbound
94 Virtual Webservers:
95 [x] RhodeCode (created in step 3)
96 For All Requests:
97 Web requests matching this pattern:
98 /_channelstream/ws
99 /Repository1/*
100 /Repository2/*
101 /Repository3/* No newline at end of file
@@ -0,0 +1,152 b''
1 |RCE| 4.11.0 |RNS|
2 ------------------
3
4 Release Date
5 ^^^^^^^^^^^^
6
7 - 2018-02-01
8
9
10 New Features
11 ^^^^^^^^^^^^
12
13 - Default reviewers(EE only): introduced new voting rule logic that allows
14 defining how many members of user group need to vote for approvals. E.g
15 adding 4 people group with security people, it can be specified that at least
16 1 (or all) need to vote for approval from that group.
17 - Default reviewers(EE only): added source/target branch flow distinction and
18 option to add names to rules.
19 - RhodeCode-Scheduler (Beta, EE only): after celery 4.X upgrade we introduced a
20 new scheduler option. RhodeCode scheduler now allows specifying via super-admin
21 interface periodic tasks that should be run crontab style.
22 Currently available tasks are:
23 - repo maintenance: (repo quality/git gc)
24 - repo remote code pull: pull changed on periodic bases from given url
25 - repo remote code push: push all changes on periodic bases to given url
26 - check for updates
27 - Ui: a ssh clone uri was added to summary view for clone. This allows to
28 customize how the ssh clone url would look like, and also exposes SSH clone
29 url to summary page.
30 - Integrations: parse pushed tags, and lightweight tags for git.
31 - now aggregated as 'tags' key
32 - handles the case for email/webhook integrations
33 - Files browser: allow making a range selection of code lines with
34 shift-click from line numbers.
35 - Pull requests: allow opening PR from changelog based on selected refs for
36 git as well as hg.
37 - Process management: auto refresh option was added to the processes
38 page to live track usage.
39 - Api: pull-requests added option to fetch comments from a pull requests.
40 - Api: added new data called `permissions_summary` for user and
41 user_groups that expose the summary of permissions for each of those.
42
43
44 General
45 ^^^^^^^
46
47 - Core: removed all pylons dependencies and backward compatibility code.
48 RhodeCode is now 100% pyramid app.
49 - Audit logs: added user.register audit log entry.
50 - Celery: update celery support 4.X series.
51 - Logging: log traceback for errors that are known to help debugging.
52 - Pull requests: don't select first commit in case we don't have a default
53 branch for repository. Loading compare from commit 0 to something selected
54 is very heavy to compute. Now it's left to users to decide what
55 compare base to pick.
56 - Dependencies: bumped Mercurial version to 4.4.2
57 - Dependencies: bumped hgevolve to 7.0.1
58 - Dependencies: bumped libs not explicitly set by requirements
59 - ws4py to 0.4.2
60 - scandir to 1.6
61 - plaster to 1.0
62 - mistune to 0.8
63 - jupyter-core to 4.4.0
64 - Dependencies: pin to rhodecode-tools 0.14.0
65 - Dependencies: bumped click to 6.6.0
66 - Dependencies: bumped transifex-clients to 0.12.5
67 - Dependencies: bumped six to 1.11.0
68 - Dependencies: bumped waitress to 1.1.0
69 - Dependencies: bumped setproctitle 1.1.10
70 - Dependencies: bumped iso8601 to 0.1.12
71 - Dependencies: bumped repoze.lru to 0.7.0
72 - Dependencies: bumped python-ldap to 2.4.45
73 - Dependencies: bumped gnureadline 6.3.8
74 - Dependencies: bumped bottle to 0.12.13
75 - Dependencies: bumped psycopg2 2.7.3.2
76 - Dependencies: bumped alembic to 0.9.6
77 - Dependencies: bumped sqlalchemy to 1.1.15
78 - Dependencies: bumped markupsafe to 1.0.0
79 - Dependencies: bumped markdown to 2.6.9
80 - Dependencies: bumped objgraph to 3.1.1
81 - Dependencies: bumped psutil to 5.4.0
82 - Dependencies: bumped docutils to 0.14.0
83 - Dependencies: bumped decorator to 4.1.2
84 - Dependencies: bumped pyramid-jinja to 2.7.0
85 - Dependencies: bumped jinja to 2.9.6
86 - Dependencies: bumped colander to 1.4.0
87 - Dependencies: bumped mistune to 0.8.1
88 - Dependencies: bumped webob to 1.7.4
89 - Dependencies: dropped nose dependency.
90
91
92 Security
93 ^^^^^^^^
94
95 - Security(low): fix self xss on repo downloads picker for svn case.
96
97
98 Performance
99 ^^^^^^^^^^^
100
101 - Pyramid: removed pylons layer, this should result in general speed
102 improvement over previous version.
103 - Authentication: use cache_ttl for anonymous access taken from the
104 rhodecode main auth plugin. For operations like svn this boosts performance
105 significantly with anonymous access enabled.
106 - Issue trackers: cache the fetched issue tracker patterns in changelog
107 page before loop iteration to speed up fetching and parsing the tracker
108 patterns.
109
110
111 Fixes
112 ^^^^^
113
114 - Slack: expose the FULL message instead of title.
115 Slack uses it's own trim, we should avoid sending trimmed data and
116 let users via Slack trim logic control the data.
117 - Comments: place the left over comments (outdated/misplaced) to the left or
118 right side-by-side pane. This way the original context where they were
119 placed is kept.
120 - Comments: allow to properly initialize outdated comments that are attached
121 to the end of diffs. This allows resolving TODOs that are outdated.
122 - Git: handle cases of git push without branch specified in the eventing system.
123 - Git: merge simulation fixes. Fetch other branch data if it's different
124 from target. This prevents potentially missing commits error when doing a test merge.
125 Also fix edge cases using .gitattributes file modification that could
126 lead to the same problem.
127 - Age component: use local flag to fix the problem of wrongly reported last
128 update times on repository groups.
129
130
131 Upgrade notes
132 ^^^^^^^^^^^^^
133
134 Please note that this release is first in series that drops completely pylons
135 dependency. This means that certain `paster` commands are no longer available.
136
137 Commands changed after dropping pylons compatibility layer:
138 - paster upgrade-db /path/ini_file => rc-upgrade-db /path/ini_file
139 - paster setup-app /path/ini_file => rc-setup-app /path/ini_file
140 - paster ishell /path/ini_file => rc-ishell /path/ini_file
141 - paster celeryd /path/ini_file => celery worker --app rhodecode.lib.celerylib.loader /path/ini_file
142
143 Commands no longer available:
144 - paster make-config (replaced by rhodecode-config from rhodecode-tools package)
145 - paster update-repoinfo (replaced by API calls)
146 - paster cache-keys, no equivalent available, this command was removed.
147
148
149 RhodeCode 4.11 uses latest Celery 4.X series. This means that there's a new way to
150 run the celery workers. To upgrade to latest simply run
151 `rccontrol enable-module celery` to convert the currently running celery setup
152 into a new version that also powers the RhodeCode scheduler.
@@ -0,0 +1,8 b''
1 Sphinx==1.6.5
2 six==1.11.0
3 sphinx_rtd_theme==0.2.5b1
4 docutils==0.14.0
5 Pygments==2.2.0
6 MarkupSafe==1.0.0
7 Jinja2==2.9.6
8 pytz No newline at end of file
@@ -0,0 +1,82 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21
22 import pytest
23 import urlobject
24
25 from rhodecode.api.tests.utils import (
26 build_data, api_call, assert_error, assert_ok)
27 from rhodecode.lib import helpers as h
28 from rhodecode.lib.utils2 import safe_unicode
29
30 pytestmark = pytest.mark.backends("git", "hg")
31
32
33 @pytest.mark.usefixtures("testuser_api", "app")
34 class TestGetPullRequestComments(object):
35
36 def test_api_get_pull_request_comments(self, pr_util, http_host_only_stub):
37 from rhodecode.model.pull_request import PullRequestModel
38
39 pull_request = pr_util.create_pull_request(mergeable=True)
40 id_, params = build_data(
41 self.apikey, 'get_pull_request_comments',
42 pullrequestid=pull_request.pull_request_id)
43
44 response = api_call(self.app, params)
45
46 assert response.status == '200 OK'
47 resp_date = response.json['result'][0]['comment_created_on']
48 resp_comment_id = response.json['result'][0]['comment_id']
49
50 expected = [
51 {'comment_author': {'active': True,
52 'full_name_or_username': 'RhodeCode Admin',
53 'username': 'test_admin'},
54 'comment_created_on': resp_date,
55 'comment_f_path': None,
56 'comment_id': resp_comment_id,
57 'comment_lineno': None,
58 'comment_status': {'status': 'under_review',
59 'status_lbl': 'Under Review'},
60 'comment_text': 'Auto status change to |new_status|\n\n.. |new_status| replace:: *"Under Review"*',
61 'comment_type': 'note',
62 'pull_request_version': None}
63 ]
64 assert_ok(id_, expected, response.body)
65
66 def test_api_get_pull_request_comments_repo_error(self, pr_util):
67 pull_request = pr_util.create_pull_request()
68 id_, params = build_data(
69 self.apikey, 'get_pull_request_comments',
70 repoid=666, pullrequestid=pull_request.pull_request_id)
71 response = api_call(self.app, params)
72
73 expected = 'repository `666` does not exist'
74 assert_error(id_, expected, given=response.body)
75
76 def test_api_get_pull_request_comments_pull_request_error(self):
77 id_, params = build_data(
78 self.apikey, 'get_pull_request_comments', pullrequestid=666)
79 response = api_call(self.app, params)
80
81 expected = 'pull request `666` does not exist'
82 assert_error(id_, expected, given=response.body)
This diff has been collapsed as it changes many lines, (764 lines changed) Show them Hide them
@@ -0,0 +1,764 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21
22 import logging
23 import collections
24
25 import datetime
26 import formencode
27 import formencode.htmlfill
28
29 import rhodecode
30 from pyramid.view import view_config
31 from pyramid.httpexceptions import HTTPFound, HTTPNotFound
32 from pyramid.renderers import render
33 from pyramid.response import Response
34
35 from rhodecode.apps._base import BaseAppView
36 from rhodecode.apps.admin.navigation import navigation_list
37 from rhodecode.apps.svn_support.config_keys import generate_config
38 from rhodecode.lib import helpers as h
39 from rhodecode.lib.auth import (
40 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
41 from rhodecode.lib.celerylib import tasks, run_task
42 from rhodecode.lib.utils import repo2db_mapper
43 from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict
44 from rhodecode.lib.index import searcher_from_config
45
46 from rhodecode.model.db import RhodeCodeUi, Repository
47 from rhodecode.model.forms import (ApplicationSettingsForm,
48 ApplicationUiSettingsForm, ApplicationVisualisationForm,
49 LabsSettingsForm, IssueTrackerPatternsForm)
50 from rhodecode.model.repo_group import RepoGroupModel
51
52 from rhodecode.model.scm import ScmModel
53 from rhodecode.model.notification import EmailNotificationModel
54 from rhodecode.model.meta import Session
55 from rhodecode.model.settings import (
56 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
57 SettingsModel)
58
59
60 log = logging.getLogger(__name__)
61
62
63 class AdminSettingsView(BaseAppView):
64
65 def load_default_context(self):
66 c = self._get_local_tmpl_context()
67 c.labs_active = str2bool(
68 rhodecode.CONFIG.get('labs_settings_active', 'true'))
69 c.navlist = navigation_list(self.request)
70
71 return c
72
73 @classmethod
74 def _get_ui_settings(cls):
75 ret = RhodeCodeUi.query().all()
76
77 if not ret:
78 raise Exception('Could not get application ui settings !')
79 settings = {}
80 for each in ret:
81 k = each.ui_key
82 v = each.ui_value
83 if k == '/':
84 k = 'root_path'
85
86 if k in ['push_ssl', 'publish', 'enabled']:
87 v = str2bool(v)
88
89 if k.find('.') != -1:
90 k = k.replace('.', '_')
91
92 if each.ui_section in ['hooks', 'extensions']:
93 v = each.ui_active
94
95 settings[each.ui_section + '_' + k] = v
96 return settings
97
98 @classmethod
99 def _form_defaults(cls):
100 defaults = SettingsModel().get_all_settings()
101 defaults.update(cls._get_ui_settings())
102
103 defaults.update({
104 'new_svn_branch': '',
105 'new_svn_tag': '',
106 })
107 return defaults
108
109 @LoginRequired()
110 @HasPermissionAllDecorator('hg.admin')
111 @view_config(
112 route_name='admin_settings_vcs', request_method='GET',
113 renderer='rhodecode:templates/admin/settings/settings.mako')
114 def settings_vcs(self):
115 c = self.load_default_context()
116 c.active = 'vcs'
117 model = VcsSettingsModel()
118 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
119 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
120
121 settings = self.request.registry.settings
122 c.svn_proxy_generate_config = settings[generate_config]
123
124 defaults = self._form_defaults()
125
126 model.create_largeobjects_dirs_if_needed(defaults['paths_root_path'])
127
128 data = render('rhodecode:templates/admin/settings/settings.mako',
129 self._get_template_context(c), self.request)
130 html = formencode.htmlfill.render(
131 data,
132 defaults=defaults,
133 encoding="UTF-8",
134 force_defaults=False
135 )
136 return Response(html)
137
138 @LoginRequired()
139 @HasPermissionAllDecorator('hg.admin')
140 @CSRFRequired()
141 @view_config(
142 route_name='admin_settings_vcs_update', request_method='POST',
143 renderer='rhodecode:templates/admin/settings/settings.mako')
144 def settings_vcs_update(self):
145 _ = self.request.translate
146 c = self.load_default_context()
147 c.active = 'vcs'
148
149 model = VcsSettingsModel()
150 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
151 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
152
153 settings = self.request.registry.settings
154 c.svn_proxy_generate_config = settings[generate_config]
155
156 application_form = ApplicationUiSettingsForm(self.request.translate)()
157
158 try:
159 form_result = application_form.to_python(dict(self.request.POST))
160 except formencode.Invalid as errors:
161 h.flash(
162 _("Some form inputs contain invalid data."),
163 category='error')
164 data = render('rhodecode:templates/admin/settings/settings.mako',
165 self._get_template_context(c), self.request)
166 html = formencode.htmlfill.render(
167 data,
168 defaults=errors.value,
169 errors=errors.error_dict or {},
170 prefix_error=False,
171 encoding="UTF-8",
172 force_defaults=False
173 )
174 return Response(html)
175
176 try:
177 if c.visual.allow_repo_location_change:
178 model.update_global_path_setting(
179 form_result['paths_root_path'])
180
181 model.update_global_ssl_setting(form_result['web_push_ssl'])
182 model.update_global_hook_settings(form_result)
183
184 model.create_or_update_global_svn_settings(form_result)
185 model.create_or_update_global_hg_settings(form_result)
186 model.create_or_update_global_git_settings(form_result)
187 model.create_or_update_global_pr_settings(form_result)
188 except Exception:
189 log.exception("Exception while updating settings")
190 h.flash(_('Error occurred during updating '
191 'application settings'), category='error')
192 else:
193 Session().commit()
194 h.flash(_('Updated VCS settings'), category='success')
195 raise HTTPFound(h.route_path('admin_settings_vcs'))
196
197 data = render('rhodecode:templates/admin/settings/settings.mako',
198 self._get_template_context(c), self.request)
199 html = formencode.htmlfill.render(
200 data,
201 defaults=self._form_defaults(),
202 encoding="UTF-8",
203 force_defaults=False
204 )
205 return Response(html)
206
207 @LoginRequired()
208 @HasPermissionAllDecorator('hg.admin')
209 @CSRFRequired()
210 @view_config(
211 route_name='admin_settings_vcs_svn_pattern_delete', request_method='POST',
212 renderer='json_ext', xhr=True)
213 def settings_vcs_delete_svn_pattern(self):
214 delete_pattern_id = self.request.POST.get('delete_svn_pattern')
215 model = VcsSettingsModel()
216 try:
217 model.delete_global_svn_pattern(delete_pattern_id)
218 except SettingNotFound:
219 log.exception(
220 'Failed to delete svn_pattern with id %s', delete_pattern_id)
221 raise HTTPNotFound()
222
223 Session().commit()
224 return True
225
226 @LoginRequired()
227 @HasPermissionAllDecorator('hg.admin')
228 @view_config(
229 route_name='admin_settings_mapping', request_method='GET',
230 renderer='rhodecode:templates/admin/settings/settings.mako')
231 def settings_mapping(self):
232 c = self.load_default_context()
233 c.active = 'mapping'
234
235 data = render('rhodecode:templates/admin/settings/settings.mako',
236 self._get_template_context(c), self.request)
237 html = formencode.htmlfill.render(
238 data,
239 defaults=self._form_defaults(),
240 encoding="UTF-8",
241 force_defaults=False
242 )
243 return Response(html)
244
245 @LoginRequired()
246 @HasPermissionAllDecorator('hg.admin')
247 @CSRFRequired()
248 @view_config(
249 route_name='admin_settings_mapping_update', request_method='POST',
250 renderer='rhodecode:templates/admin/settings/settings.mako')
251 def settings_mapping_update(self):
252 _ = self.request.translate
253 c = self.load_default_context()
254 c.active = 'mapping'
255 rm_obsolete = self.request.POST.get('destroy', False)
256 invalidate_cache = self.request.POST.get('invalidate', False)
257 log.debug(
258 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
259
260 if invalidate_cache:
261 log.debug('invalidating all repositories cache')
262 for repo in Repository.get_all():
263 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
264
265 filesystem_repos = ScmModel().repo_scan()
266 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
267 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
268 h.flash(_('Repositories successfully '
269 'rescanned added: %s ; removed: %s') %
270 (_repr(added), _repr(removed)),
271 category='success')
272 raise HTTPFound(h.route_path('admin_settings_mapping'))
273
274 @LoginRequired()
275 @HasPermissionAllDecorator('hg.admin')
276 @view_config(
277 route_name='admin_settings', request_method='GET',
278 renderer='rhodecode:templates/admin/settings/settings.mako')
279 @view_config(
280 route_name='admin_settings_global', request_method='GET',
281 renderer='rhodecode:templates/admin/settings/settings.mako')
282 def settings_global(self):
283 c = self.load_default_context()
284 c.active = 'global'
285 c.personal_repo_group_default_pattern = RepoGroupModel()\
286 .get_personal_group_name_pattern()
287
288 data = render('rhodecode:templates/admin/settings/settings.mako',
289 self._get_template_context(c), self.request)
290 html = formencode.htmlfill.render(
291 data,
292 defaults=self._form_defaults(),
293 encoding="UTF-8",
294 force_defaults=False
295 )
296 return Response(html)
297
298 @LoginRequired()
299 @HasPermissionAllDecorator('hg.admin')
300 @CSRFRequired()
301 @view_config(
302 route_name='admin_settings_update', request_method='POST',
303 renderer='rhodecode:templates/admin/settings/settings.mako')
304 @view_config(
305 route_name='admin_settings_global_update', request_method='POST',
306 renderer='rhodecode:templates/admin/settings/settings.mako')
307 def settings_global_update(self):
308 _ = self.request.translate
309 c = self.load_default_context()
310 c.active = 'global'
311 c.personal_repo_group_default_pattern = RepoGroupModel()\
312 .get_personal_group_name_pattern()
313 application_form = ApplicationSettingsForm(self.request.translate)()
314 try:
315 form_result = application_form.to_python(dict(self.request.POST))
316 except formencode.Invalid as errors:
317 data = render('rhodecode:templates/admin/settings/settings.mako',
318 self._get_template_context(c), self.request)
319 html = formencode.htmlfill.render(
320 data,
321 defaults=errors.value,
322 errors=errors.error_dict or {},
323 prefix_error=False,
324 encoding="UTF-8",
325 force_defaults=False
326 )
327 return Response(html)
328
329 settings = [
330 ('title', 'rhodecode_title', 'unicode'),
331 ('realm', 'rhodecode_realm', 'unicode'),
332 ('pre_code', 'rhodecode_pre_code', 'unicode'),
333 ('post_code', 'rhodecode_post_code', 'unicode'),
334 ('captcha_public_key', 'rhodecode_captcha_public_key', 'unicode'),
335 ('captcha_private_key', 'rhodecode_captcha_private_key', 'unicode'),
336 ('create_personal_repo_group', 'rhodecode_create_personal_repo_group', 'bool'),
337 ('personal_repo_group_pattern', 'rhodecode_personal_repo_group_pattern', 'unicode'),
338 ]
339 try:
340 for setting, form_key, type_ in settings:
341 sett = SettingsModel().create_or_update_setting(
342 setting, form_result[form_key], type_)
343 Session().add(sett)
344
345 Session().commit()
346 SettingsModel().invalidate_settings_cache()
347 h.flash(_('Updated application settings'), category='success')
348 except Exception:
349 log.exception("Exception while updating application settings")
350 h.flash(
351 _('Error occurred during updating application settings'),
352 category='error')
353
354 raise HTTPFound(h.route_path('admin_settings_global'))
355
356 @LoginRequired()
357 @HasPermissionAllDecorator('hg.admin')
358 @view_config(
359 route_name='admin_settings_visual', request_method='GET',
360 renderer='rhodecode:templates/admin/settings/settings.mako')
361 def settings_visual(self):
362 c = self.load_default_context()
363 c.active = 'visual'
364
365 data = render('rhodecode:templates/admin/settings/settings.mako',
366 self._get_template_context(c), self.request)
367 html = formencode.htmlfill.render(
368 data,
369 defaults=self._form_defaults(),
370 encoding="UTF-8",
371 force_defaults=False
372 )
373 return Response(html)
374
375 @LoginRequired()
376 @HasPermissionAllDecorator('hg.admin')
377 @CSRFRequired()
378 @view_config(
379 route_name='admin_settings_visual_update', request_method='POST',
380 renderer='rhodecode:templates/admin/settings/settings.mako')
381 def settings_visual_update(self):
382 _ = self.request.translate
383 c = self.load_default_context()
384 c.active = 'visual'
385 application_form = ApplicationVisualisationForm(self.request.translate)()
386 try:
387 form_result = application_form.to_python(dict(self.request.POST))
388 except formencode.Invalid as errors:
389 data = render('rhodecode:templates/admin/settings/settings.mako',
390 self._get_template_context(c), self.request)
391 html = formencode.htmlfill.render(
392 data,
393 defaults=errors.value,
394 errors=errors.error_dict or {},
395 prefix_error=False,
396 encoding="UTF-8",
397 force_defaults=False
398 )
399 return Response(html)
400
401 try:
402 settings = [
403 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
404 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
405 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
406 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
407 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
408 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
409 ('show_version', 'rhodecode_show_version', 'bool'),
410 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
411 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
412 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
413 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
414 ('clone_uri_ssh_tmpl', 'rhodecode_clone_uri_ssh_tmpl', 'unicode'),
415 ('support_url', 'rhodecode_support_url', 'unicode'),
416 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
417 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
418 ]
419 for setting, form_key, type_ in settings:
420 sett = SettingsModel().create_or_update_setting(
421 setting, form_result[form_key], type_)
422 Session().add(sett)
423
424 Session().commit()
425 SettingsModel().invalidate_settings_cache()
426 h.flash(_('Updated visualisation settings'), category='success')
427 except Exception:
428 log.exception("Exception updating visualization settings")
429 h.flash(_('Error occurred during updating '
430 'visualisation settings'),
431 category='error')
432
433 raise HTTPFound(h.route_path('admin_settings_visual'))
434
435 @LoginRequired()
436 @HasPermissionAllDecorator('hg.admin')
437 @view_config(
438 route_name='admin_settings_issuetracker', request_method='GET',
439 renderer='rhodecode:templates/admin/settings/settings.mako')
440 def settings_issuetracker(self):
441 c = self.load_default_context()
442 c.active = 'issuetracker'
443 defaults = SettingsModel().get_all_settings()
444
445 entry_key = 'rhodecode_issuetracker_pat_'
446
447 c.issuetracker_entries = {}
448 for k, v in defaults.items():
449 if k.startswith(entry_key):
450 uid = k[len(entry_key):]
451 c.issuetracker_entries[uid] = None
452
453 for uid in c.issuetracker_entries:
454 c.issuetracker_entries[uid] = AttributeDict({
455 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
456 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
457 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
458 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
459 })
460
461 return self._get_template_context(c)
462
463 @LoginRequired()
464 @HasPermissionAllDecorator('hg.admin')
465 @CSRFRequired()
466 @view_config(
467 route_name='admin_settings_issuetracker_test', request_method='POST',
468 renderer='string', xhr=True)
469 def settings_issuetracker_test(self):
470 return h.urlify_commit_message(
471 self.request.POST.get('test_text', ''),
472 'repo_group/test_repo1')
473
474 @LoginRequired()
475 @HasPermissionAllDecorator('hg.admin')
476 @CSRFRequired()
477 @view_config(
478 route_name='admin_settings_issuetracker_update', request_method='POST',
479 renderer='rhodecode:templates/admin/settings/settings.mako')
480 def settings_issuetracker_update(self):
481 _ = self.request.translate
482 self.load_default_context()
483 settings_model = IssueTrackerSettingsModel()
484
485 try:
486 form = IssueTrackerPatternsForm(self.request.translate)()
487 data = form.to_python(self.request.POST)
488 except formencode.Invalid as errors:
489 log.exception('Failed to add new pattern')
490 error = errors
491 h.flash(_('Invalid issue tracker pattern: {}'.format(error)),
492 category='error')
493 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
494
495 if data:
496 for uid in data.get('delete_patterns', []):
497 settings_model.delete_entries(uid)
498
499 for pattern in data.get('patterns', []):
500 for setting, value, type_ in pattern:
501 sett = settings_model.create_or_update_setting(
502 setting, value, type_)
503 Session().add(sett)
504
505 Session().commit()
506
507 SettingsModel().invalidate_settings_cache()
508 h.flash(_('Updated issue tracker entries'), category='success')
509 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
510
511 @LoginRequired()
512 @HasPermissionAllDecorator('hg.admin')
513 @CSRFRequired()
514 @view_config(
515 route_name='admin_settings_issuetracker_delete', request_method='POST',
516 renderer='rhodecode:templates/admin/settings/settings.mako')
517 def settings_issuetracker_delete(self):
518 _ = self.request.translate
519 self.load_default_context()
520 uid = self.request.POST.get('uid')
521 try:
522 IssueTrackerSettingsModel().delete_entries(uid)
523 except Exception:
524 log.exception('Failed to delete issue tracker setting %s', uid)
525 raise HTTPNotFound()
526 h.flash(_('Removed issue tracker entry'), category='success')
527 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
528
529 @LoginRequired()
530 @HasPermissionAllDecorator('hg.admin')
531 @view_config(
532 route_name='admin_settings_email', request_method='GET',
533 renderer='rhodecode:templates/admin/settings/settings.mako')
534 def settings_email(self):
535 c = self.load_default_context()
536 c.active = 'email'
537 c.rhodecode_ini = rhodecode.CONFIG
538
539 data = render('rhodecode:templates/admin/settings/settings.mako',
540 self._get_template_context(c), self.request)
541 html = formencode.htmlfill.render(
542 data,
543 defaults=self._form_defaults(),
544 encoding="UTF-8",
545 force_defaults=False
546 )
547 return Response(html)
548
549 @LoginRequired()
550 @HasPermissionAllDecorator('hg.admin')
551 @CSRFRequired()
552 @view_config(
553 route_name='admin_settings_email_update', request_method='POST',
554 renderer='rhodecode:templates/admin/settings/settings.mako')
555 def settings_email_update(self):
556 _ = self.request.translate
557 c = self.load_default_context()
558 c.active = 'email'
559
560 test_email = self.request.POST.get('test_email')
561
562 if not test_email:
563 h.flash(_('Please enter email address'), category='error')
564 raise HTTPFound(h.route_path('admin_settings_email'))
565
566 email_kwargs = {
567 'date': datetime.datetime.now(),
568 'user': c.rhodecode_user,
569 'rhodecode_version': c.rhodecode_version
570 }
571
572 (subject, headers, email_body,
573 email_body_plaintext) = EmailNotificationModel().render_email(
574 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
575
576 recipients = [test_email] if test_email else None
577
578 run_task(tasks.send_email, recipients, subject,
579 email_body_plaintext, email_body)
580
581 h.flash(_('Send email task created'), category='success')
582 raise HTTPFound(h.route_path('admin_settings_email'))
583
584 @LoginRequired()
585 @HasPermissionAllDecorator('hg.admin')
586 @view_config(
587 route_name='admin_settings_hooks', request_method='GET',
588 renderer='rhodecode:templates/admin/settings/settings.mako')
589 def settings_hooks(self):
590 c = self.load_default_context()
591 c.active = 'hooks'
592
593 model = SettingsModel()
594 c.hooks = model.get_builtin_hooks()
595 c.custom_hooks = model.get_custom_hooks()
596
597 data = render('rhodecode:templates/admin/settings/settings.mako',
598 self._get_template_context(c), self.request)
599 html = formencode.htmlfill.render(
600 data,
601 defaults=self._form_defaults(),
602 encoding="UTF-8",
603 force_defaults=False
604 )
605 return Response(html)
606
607 @LoginRequired()
608 @HasPermissionAllDecorator('hg.admin')
609 @CSRFRequired()
610 @view_config(
611 route_name='admin_settings_hooks_update', request_method='POST',
612 renderer='rhodecode:templates/admin/settings/settings.mako')
613 @view_config(
614 route_name='admin_settings_hooks_delete', request_method='POST',
615 renderer='rhodecode:templates/admin/settings/settings.mako')
616 def settings_hooks_update(self):
617 _ = self.request.translate
618 c = self.load_default_context()
619 c.active = 'hooks'
620 if c.visual.allow_custom_hooks_settings:
621 ui_key = self.request.POST.get('new_hook_ui_key')
622 ui_value = self.request.POST.get('new_hook_ui_value')
623
624 hook_id = self.request.POST.get('hook_id')
625 new_hook = False
626
627 model = SettingsModel()
628 try:
629 if ui_value and ui_key:
630 model.create_or_update_hook(ui_key, ui_value)
631 h.flash(_('Added new hook'), category='success')
632 new_hook = True
633 elif hook_id:
634 RhodeCodeUi.delete(hook_id)
635 Session().commit()
636
637 # check for edits
638 update = False
639 _d = self.request.POST.dict_of_lists()
640 for k, v in zip(_d.get('hook_ui_key', []),
641 _d.get('hook_ui_value_new', [])):
642 model.create_or_update_hook(k, v)
643 update = True
644
645 if update and not new_hook:
646 h.flash(_('Updated hooks'), category='success')
647 Session().commit()
648 except Exception:
649 log.exception("Exception during hook creation")
650 h.flash(_('Error occurred during hook creation'),
651 category='error')
652
653 raise HTTPFound(h.route_path('admin_settings_hooks'))
654
655 @LoginRequired()
656 @HasPermissionAllDecorator('hg.admin')
657 @view_config(
658 route_name='admin_settings_search', request_method='GET',
659 renderer='rhodecode:templates/admin/settings/settings.mako')
660 def settings_search(self):
661 c = self.load_default_context()
662 c.active = 'search'
663
664 searcher = searcher_from_config(self.request.registry.settings)
665 c.statistics = searcher.statistics(self.request.translate)
666
667 return self._get_template_context(c)
668
669 @LoginRequired()
670 @HasPermissionAllDecorator('hg.admin')
671 @view_config(
672 route_name='admin_settings_labs', request_method='GET',
673 renderer='rhodecode:templates/admin/settings/settings.mako')
674 def settings_labs(self):
675 c = self.load_default_context()
676 if not c.labs_active:
677 raise HTTPFound(h.route_path('admin_settings'))
678
679 c.active = 'labs'
680 c.lab_settings = _LAB_SETTINGS
681
682 data = render('rhodecode:templates/admin/settings/settings.mako',
683 self._get_template_context(c), self.request)
684 html = formencode.htmlfill.render(
685 data,
686 defaults=self._form_defaults(),
687 encoding="UTF-8",
688 force_defaults=False
689 )
690 return Response(html)
691
692 @LoginRequired()
693 @HasPermissionAllDecorator('hg.admin')
694 @CSRFRequired()
695 @view_config(
696 route_name='admin_settings_labs_update', request_method='POST',
697 renderer='rhodecode:templates/admin/settings/settings.mako')
698 def settings_labs_update(self):
699 _ = self.request.translate
700 c = self.load_default_context()
701 c.active = 'labs'
702
703 application_form = LabsSettingsForm(self.request.translate)()
704 try:
705 form_result = application_form.to_python(dict(self.request.POST))
706 except formencode.Invalid as errors:
707 h.flash(
708 _('Some form inputs contain invalid data.'),
709 category='error')
710 data = render('rhodecode:templates/admin/settings/settings.mako',
711 self._get_template_context(c), self.request)
712 html = formencode.htmlfill.render(
713 data,
714 defaults=errors.value,
715 errors=errors.error_dict or {},
716 prefix_error=False,
717 encoding="UTF-8",
718 force_defaults=False
719 )
720 return Response(html)
721
722 try:
723 session = Session()
724 for setting in _LAB_SETTINGS:
725 setting_name = setting.key[len('rhodecode_'):]
726 sett = SettingsModel().create_or_update_setting(
727 setting_name, form_result[setting.key], setting.type)
728 session.add(sett)
729
730 except Exception:
731 log.exception('Exception while updating lab settings')
732 h.flash(_('Error occurred during updating labs settings'),
733 category='error')
734 else:
735 Session().commit()
736 SettingsModel().invalidate_settings_cache()
737 h.flash(_('Updated Labs settings'), category='success')
738 raise HTTPFound(h.route_path('admin_settings_labs'))
739
740 data = render('rhodecode:templates/admin/settings/settings.mako',
741 self._get_template_context(c), self.request)
742 html = formencode.htmlfill.render(
743 data,
744 defaults=self._form_defaults(),
745 encoding="UTF-8",
746 force_defaults=False
747 )
748 return Response(html)
749
750
751 # :param key: name of the setting including the 'rhodecode_' prefix
752 # :param type: the RhodeCodeSetting type to use.
753 # :param group: the i18ned group in which we should dispaly this setting
754 # :param label: the i18ned label we should display for this setting
755 # :param help: the i18ned help we should dispaly for this setting
756 LabSetting = collections.namedtuple(
757 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
758
759
760 # This list has to be kept in sync with the form
761 # rhodecode.model.forms.LabsSettingsForm.
762 _LAB_SETTINGS = [
763
764 ]
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,5 +1,5 b''
1 [bumpversion]
1 [bumpversion]
2 current_version = 4.10.6
2 current_version = 4.11.0
3 message = release: Bump version {current_version} to {new_version}
3 message = release: Bump version {current_version} to {new_version}
4
4
5 [bumpversion:file:rhodecode/VERSION]
5 [bumpversion:file:rhodecode/VERSION]
@@ -3,15 +3,11 b''
3 branch = True
3 branch = True
4
4
5 include =
5 include =
6 rhodecode/lib/*
6 rhodecode/*
7 rhodecode/model/*
8 rhodecode/controllers/*
9
7
10 omit =
8 omit =
11 rhodecode/lib/vcs/remote/*
12 rhodecode/lib/dbmigrate/*
9 rhodecode/lib/dbmigrate/*
13 rhodecode/lib/paster_commands/*
10 rhodecode/lib/paster_commands/*
14 rhodecode/tests/*
15
11
16 [report]
12 [report]
17
13
@@ -21,7 +21,7 b' syntax: regexp'
21 ^\.rhodecode$
21 ^\.rhodecode$
22
22
23 ^rcextensions
23 ^rcextensions
24 ^_dev
24 ^.dev
25 ^._dev
25 ^._dev
26 ^build/
26 ^build/
27 ^bower_components/
27 ^bower_components/
@@ -5,25 +5,20 b' done = false'
5 done = true
5 done = true
6
6
7 [task:rc_tools_pinned]
7 [task:rc_tools_pinned]
8 done = true
9
8
10 [task:fixes_on_stable]
9 [task:fixes_on_stable]
11 done = true
12
10
13 [task:pip2nix_generated]
11 [task:pip2nix_generated]
14 done = true
15
12
16 [task:changelog_updated]
13 [task:changelog_updated]
17 done = true
18
14
19 [task:generate_api_docs]
15 [task:generate_api_docs]
20 done = true
16
17 [task:updated_translation]
21
18
22 [release]
19 [release]
23 state = prepared
20 state = in_progress
24 version = 4.10.6
21 version = 4.11.0
25
26 [task:updated_translation]
27
22
28 [task:generate_js_routes]
23 [task:generate_js_routes]
29
24
@@ -79,7 +79,7 b' asyncore_use_poll = true'
79 #proc_name = rhodecode
79 #proc_name = rhodecode
80 ## type of worker class, one of sync, gevent
80 ## type of worker class, one of sync, gevent
81 ## recommended for bigger setup is using of of other than sync one
81 ## recommended for bigger setup is using of of other than sync one
82 #worker_class = sync
82 #worker_class = gevent
83 ## The maximum number of simultaneous clients. Valid only for Gevent
83 ## The maximum number of simultaneous clients. Valid only for Gevent
84 #worker_connections = 10
84 #worker_connections = 10
85 ## max number of requests that worker will handle before being gracefully
85 ## max number of requests that worker will handle before being gracefully
@@ -295,29 +295,21 b' labs_settings_active = true'
295 ####################################
295 ####################################
296 ### CELERY CONFIG ####
296 ### CELERY CONFIG ####
297 ####################################
297 ####################################
298 use_celery = false
298 ## run: /path/to/celery worker \
299 broker.host = localhost
299 ## -E --beat --app rhodecode.lib.celerylib.loader \
300 broker.vhost = rabbitmqhost
300 ## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \
301 broker.port = 5672
301 ## --loglevel DEBUG --ini /path/to/rhodecode.ini
302 broker.user = rabbitmq
303 broker.password = qweqwe
304
305 celery.imports = rhodecode.lib.celerylib.tasks
306
302
307 celery.result.backend = amqp
303 use_celery = false
308 celery.result.dburi = amqp://
309 celery.result.serialier = json
310
304
311 #celery.send.task.error.emails = true
305 ## connection url to the message broker (default rabbitmq)
312 #celery.amqp.task.result.expires = 18000
306 celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost
313
307
314 celeryd.concurrency = 2
308 ## maximum tasks to execute before worker restart
315 #celeryd.log.file = celeryd.log
309 celery.max_tasks_per_child = 100
316 celeryd.log.level = debug
317 celeryd.max.tasks.per.child = 1
318
310
319 ## tasks will never be sent to the queue, but executed locally instead.
311 ## tasks will never be sent to the queue, but executed locally instead.
320 celery.always.eager = false
312 celery.task_always_eager = false
321
313
322 ####################################
314 ####################################
323 ### BEAKER CACHE ####
315 ### BEAKER CACHE ####
@@ -567,7 +559,7 b' vcs.hooks.protocol = http'
567
559
568 vcs.server.log_level = debug
560 vcs.server.log_level = debug
569 ## Start VCSServer with this instance as a subprocess, usefull for development
561 ## Start VCSServer with this instance as a subprocess, usefull for development
570 vcs.start_server = true
562 vcs.start_server = false
571
563
572 ## List of enabled VCS backends, available options are:
564 ## List of enabled VCS backends, available options are:
573 ## `hg` - mercurial
565 ## `hg` - mercurial
@@ -649,7 +641,7 b' custom.conf = 1'
649 ### LOGGING CONFIGURATION ####
641 ### LOGGING CONFIGURATION ####
650 ################################
642 ################################
651 [loggers]
643 [loggers]
652 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper
644 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper, celery
653
645
654 [handlers]
646 [handlers]
655 keys = console, console_sql
647 keys = console, console_sql
@@ -688,6 +680,11 b' handlers ='
688 qualname = ssh_wrapper
680 qualname = ssh_wrapper
689 propagate = 1
681 propagate = 1
690
682
683 [logger_celery]
684 level = DEBUG
685 handlers =
686 qualname = celery
687
691
688
692 ##############
689 ##############
693 ## HANDLERS ##
690 ## HANDLERS ##
@@ -28,9 +28,30 b" accesslog = '-'"
28 loglevel = 'debug'
28 loglevel = 'debug'
29
29
30 # SECURITY
30 # SECURITY
31
32 # The maximum size of HTTP request line in bytes.
31 limit_request_line = 4094
33 limit_request_line = 4094
32 limit_request_fields = 100
34
33 limit_request_field_size = 8190
35 # Limit the number of HTTP headers fields in a request.
36 limit_request_fields = 1024
37
38 # Limit the allowed size of an HTTP request header field.
39 # Value is a positive number or 0.
40 # Setting it to 0 will allow unlimited header field sizes.
41 limit_request_field_size = 0
42
43
44 # Timeout for graceful workers restart.
45 # After receiving a restart signal, workers have this much time to finish
46 # serving requests. Workers still alive after the timeout (starting from the
47 # receipt of the restart signal) are force killed.
48 graceful_timeout = 30
49
50
51 # The number of seconds to wait for requests on a Keep-Alive connection.
52 # Generally set in the 1-5 seconds range.
53 keepalive = 2
54
34
55
35 # SERVER MECHANICS
56 # SERVER MECHANICS
36 # None == system temp dir
57 # None == system temp dir
@@ -57,10 +78,18 b' def pre_exec(server):'
57 server.log.info("Forked child, re-executing.")
78 server.log.info("Forked child, re-executing.")
58
79
59
80
81 def on_starting(server):
82 server.log.info("Server is starting.")
83
84
60 def when_ready(server):
85 def when_ready(server):
61 server.log.info("Server is ready. Spawning workers")
86 server.log.info("Server is ready. Spawning workers")
62
87
63
88
89 def on_reload(server):
90 pass
91
92
64 def worker_int(worker):
93 def worker_int(worker):
65 worker.log.info("[<%-10s>] worker received INT or QUIT signal", worker.pid)
94 worker.log.info("[<%-10s>] worker received INT or QUIT signal", worker.pid)
66
95
@@ -81,6 +110,14 b' def worker_abort(worker):'
81 worker.log.info("[<%-10s>] worker received SIGABRT signal", worker.pid)
110 worker.log.info("[<%-10s>] worker received SIGABRT signal", worker.pid)
82
111
83
112
113 def worker_exit(server, worker):
114 worker.log.info("[<%-10s>] worker exit", worker.pid)
115
116
117 def child_exit(server, worker):
118 worker.log.info("[<%-10s>] worker child exit", worker.pid)
119
120
84 def pre_request(worker, req):
121 def pre_request(worker, req):
85 return
122 return
86 worker.log.debug("[<%-10s>] PRE WORKER: %s %s",
123 worker.log.debug("[<%-10s>] PRE WORKER: %s %s",
@@ -93,6 +130,7 b' def post_request(worker, req, environ, r'
93 req.method, req.path, resp.status_code)
130 req.method, req.path, resp.status_code)
94
131
95
132
133
96 class RhodeCodeLogger(Logger):
134 class RhodeCodeLogger(Logger):
97 """
135 """
98 Custom Logger that allows some customization that gunicorn doesn't allow
136 Custom Logger that allows some customization that gunicorn doesn't allow
@@ -79,7 +79,7 b' workers = 2'
79 proc_name = rhodecode
79 proc_name = rhodecode
80 ## type of worker class, one of sync, gevent
80 ## type of worker class, one of sync, gevent
81 ## recommended for bigger setup is using of of other than sync one
81 ## recommended for bigger setup is using of of other than sync one
82 worker_class = sync
82 worker_class = gevent
83 ## The maximum number of simultaneous clients. Valid only for Gevent
83 ## The maximum number of simultaneous clients. Valid only for Gevent
84 #worker_connections = 10
84 #worker_connections = 10
85 ## max number of requests that worker will handle before being gracefully
85 ## max number of requests that worker will handle before being gracefully
@@ -270,29 +270,21 b' labs_settings_active = true'
270 ####################################
270 ####################################
271 ### CELERY CONFIG ####
271 ### CELERY CONFIG ####
272 ####################################
272 ####################################
273 use_celery = false
273 ## run: /path/to/celery worker \
274 broker.host = localhost
274 ## -E --beat --app rhodecode.lib.celerylib.loader \
275 broker.vhost = rabbitmqhost
275 ## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \
276 broker.port = 5672
276 ## --loglevel DEBUG --ini /path/to/rhodecode.ini
277 broker.user = rabbitmq
278 broker.password = qweqwe
279
280 celery.imports = rhodecode.lib.celerylib.tasks
281
277
282 celery.result.backend = amqp
278 use_celery = false
283 celery.result.dburi = amqp://
284 celery.result.serialier = json
285
279
286 #celery.send.task.error.emails = true
280 ## connection url to the message broker (default rabbitmq)
287 #celery.amqp.task.result.expires = 18000
281 celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost
288
282
289 celeryd.concurrency = 2
283 ## maximum tasks to execute before worker restart
290 #celeryd.log.file = celeryd.log
284 celery.max_tasks_per_child = 100
291 celeryd.log.level = debug
292 celeryd.max.tasks.per.child = 1
293
285
294 ## tasks will never be sent to the queue, but executed locally instead.
286 ## tasks will never be sent to the queue, but executed locally instead.
295 celery.always.eager = false
287 celery.task_always_eager = false
296
288
297 ####################################
289 ####################################
298 ### BEAKER CACHE ####
290 ### BEAKER CACHE ####
@@ -619,7 +611,7 b' custom.conf = 1'
619 ### LOGGING CONFIGURATION ####
611 ### LOGGING CONFIGURATION ####
620 ################################
612 ################################
621 [loggers]
613 [loggers]
622 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper
614 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper, celery
623
615
624 [handlers]
616 [handlers]
625 keys = console, console_sql
617 keys = console, console_sql
@@ -658,6 +650,11 b' handlers ='
658 qualname = ssh_wrapper
650 qualname = ssh_wrapper
659 propagate = 1
651 propagate = 1
660
652
653 [logger_celery]
654 level = DEBUG
655 handlers =
656 qualname = celery
657
661
658
662 ##############
659 ##############
663 ## HANDLERS ##
660 ## HANDLERS ##
@@ -185,6 +185,7 b' let'
185 ln -s ${self.supervisor}/bin/supervisor* $out/bin/
185 ln -s ${self.supervisor}/bin/supervisor* $out/bin/
186 ln -s ${self.PasteScript}/bin/paster $out/bin/
186 ln -s ${self.PasteScript}/bin/paster $out/bin/
187 ln -s ${self.channelstream}/bin/channelstream $out/bin/
187 ln -s ${self.channelstream}/bin/channelstream $out/bin/
188 ln -s ${self.celery}/bin/celery $out/bin/
188
189
189 # rhodecode-tools
190 # rhodecode-tools
190 ln -s ${self.rhodecode-tools}/bin/rhodecode-* $out/bin/
191 ln -s ${self.rhodecode-tools}/bin/rhodecode-* $out/bin/
@@ -70,7 +70,7 b' backup location:'
70 $ mysql -u <uname> -p <pass> rhodecode_db_name < mysql-db-backup
70 $ mysql -u <uname> -p <pass> rhodecode_db_name < mysql-db-backup
71
71
72 # For PostgreSQL DBs
72 # For PostgreSQL DBs
73 $ PGPASSWORD=<pass> pg_dump rhodecode_db_name > postgresql-db-backup
73 $ PGPASSWORD=<pass> pg_dump --inserts -U <uname> -h localhost rhodecode_db_name > postgresql-db-backup
74 # PosgreSQL restore
74 # PosgreSQL restore
75 $ PGPASSWORD=<pass> psql -U <uname> -h localhost -d rhodecode_db_name -1 -f postgresql-db-backup
75 $ PGPASSWORD=<pass> psql -U <uname> -h localhost -d rhodecode_db_name -1 -f postgresql-db-backup
76
76
@@ -47,7 +47,7 b' the ``debug`` level.'
47 ### LOGGING CONFIGURATION ####
47 ### LOGGING CONFIGURATION ####
48 ################################
48 ################################
49 [loggers]
49 [loggers]
50 keys = root, routes, rhodecode, sqlalchemy, beaker, templates
50 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper
51
51
52 [handlers]
52 [handlers]
53 keys = console, console_sql, file, file_rotating
53 keys = console, console_sql, file, file_rotating
@@ -75,12 +75,6 b' the ``debug`` level.'
75 qualname = beaker.container
75 qualname = beaker.container
76 propagate = 1
76 propagate = 1
77
77
78 [logger_templates]
79 level = INFO
80 handlers =
81 qualname = pylons.templating
82 propagate = 1
83
84 [logger_rhodecode]
78 [logger_rhodecode]
85 level = DEBUG
79 level = DEBUG
86 handlers =
80 handlers =
@@ -9,7 +9,7 b' timeout during large pushes.'
9 .. code-block:: nginx
9 .. code-block:: nginx
10
10
11 proxy_redirect off;
11 proxy_redirect off;
12 proxy_set_header Host $host;
12 proxy_set_header Host $http_host;
13
13
14 ## needed for container auth
14 ## needed for container auth
15 # proxy_set_header REMOTE_USER $remote_user;
15 # proxy_set_header REMOTE_USER $remote_user;
@@ -13,3 +13,4 b' instances are configured in as secure a '
13 sec-x-frame
13 sec-x-frame
14 sec-instance-basics
14 sec-instance-basics
15 sec-ip-white
15 sec-ip-white
16 sec-sophos-umc
@@ -38,13 +38,13 b' changeset_comment'
38
38
39 Example error output:
39 Example error output:
40
40
41 .. code-block:: javascript
41 .. code-block:: json
42
42
43 {
43 {
44 "id" : "<id_given_in_input>",
44 "id" : <id_given_in_input>,
45 "result" : {
45 "result" : {
46 "msg": "Commented on commit `<revision>` for repository `<repoid>`",
46 "msg": "Commented on commit `<revision>` for repository `<repoid>`",
47 "status_change": null or "<status>",
47 "status_change": null or <status>,
48 "success": true
48 "success": true
49 },
49 },
50 "error" : null
50 "error" : null
@@ -6,7 +6,7 b' pull_request methods'
6 close_pull_request
6 close_pull_request
7 ------------------
7 ------------------
8
8
9 .. py:function:: close_pull_request(apiuser, repoid, pullrequestid, userid=<Optional:<OptionalAttr:apiuser>>, message=<Optional:''>)
9 .. py:function:: close_pull_request(apiuser, pullrequestid, repoid=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>, message=<Optional:''>)
10
10
11 Close the pull request specified by `pullrequestid`.
11 Close the pull request specified by `pullrequestid`.
12
12
@@ -39,7 +39,7 b' close_pull_request'
39 comment_pull_request
39 comment_pull_request
40 --------------------
40 --------------------
41
41
42 .. py:function:: comment_pull_request(apiuser, repoid, pullrequestid, message=<Optional:None>, commit_id=<Optional:None>, status=<Optional:None>, comment_type=<Optional:u'note'>, resolves_comment_id=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
42 .. py:function:: comment_pull_request(apiuser, pullrequestid, repoid=<Optional:None>, message=<Optional:None>, commit_id=<Optional:None>, status=<Optional:None>, comment_type=<Optional:u'note'>, resolves_comment_id=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
43
43
44 Comment on the pull request specified with the `pullrequestid`,
44 Comment on the pull request specified with the `pullrequestid`,
45 in the |repo| specified by the `repoid`, and optionally change the
45 in the |repo| specified by the `repoid`, and optionally change the
@@ -47,7 +47,7 b' comment_pull_request'
47
47
48 :param apiuser: This is filled automatically from the |authtoken|.
48 :param apiuser: This is filled automatically from the |authtoken|.
49 :type apiuser: AuthUser
49 :type apiuser: AuthUser
50 :param repoid: The repository name or repository ID.
50 :param repoid: Optional repository name or repository ID.
51 :type repoid: str or int
51 :type repoid: str or int
52 :param pullrequestid: The pull request ID.
52 :param pullrequestid: The pull request ID.
53 :type pullrequestid: int
53 :type pullrequestid: int
@@ -120,14 +120,14 b' create_pull_request'
120 get_pull_request
120 get_pull_request
121 ----------------
121 ----------------
122
122
123 .. py:function:: get_pull_request(apiuser, repoid, pullrequestid)
123 .. py:function:: get_pull_request(apiuser, pullrequestid, repoid=<Optional:None>)
124
124
125 Get a pull request based on the given ID.
125 Get a pull request based on the given ID.
126
126
127 :param apiuser: This is filled automatically from the |authtoken|.
127 :param apiuser: This is filled automatically from the |authtoken|.
128 :type apiuser: AuthUser
128 :type apiuser: AuthUser
129 :param repoid: Repository name or repository ID from where the pull
129 :param repoid: Optional, repository name or repository ID from where
130 request was opened.
130 the pull request was opened.
131 :type repoid: str or int
131 :type repoid: str or int
132 :param pullrequestid: ID of the requested pull request.
132 :param pullrequestid: ID of the requested pull request.
133 :type pullrequestid: int
133 :type pullrequestid: int
@@ -199,6 +199,48 b' get_pull_request'
199 "error": null
199 "error": null
200
200
201
201
202 get_pull_request_comments
203 -------------------------
204
205 .. py:function:: get_pull_request_comments(apiuser, pullrequestid, repoid=<Optional:None>)
206
207 Get all comments of pull request specified with the `pullrequestid`
208
209 :param apiuser: This is filled automatically from the |authtoken|.
210 :type apiuser: AuthUser
211 :param repoid: Optional repository name or repository ID.
212 :type repoid: str or int
213 :param pullrequestid: The pull request ID.
214 :type pullrequestid: int
215
216 Example output:
217
218 .. code-block:: bash
219
220 id : <id_given_in_input>
221 result : [
222 {
223 "comment_author": {
224 "active": true,
225 "full_name_or_username": "Tom Gore",
226 "username": "admin"
227 },
228 "comment_created_on": "2017-01-02T18:43:45.533",
229 "comment_f_path": null,
230 "comment_id": 25,
231 "comment_lineno": null,
232 "comment_status": {
233 "status": "under_review",
234 "status_lbl": "Under Review"
235 },
236 "comment_text": "Example text",
237 "comment_type": null,
238 "pull_request_version": null
239 }
240 ],
241 error : null
242
243
202 get_pull_requests
244 get_pull_requests
203 -----------------
245 -----------------
204
246
@@ -208,7 +250,7 b' get_pull_requests'
208
250
209 :param apiuser: This is filled automatically from the |authtoken|.
251 :param apiuser: This is filled automatically from the |authtoken|.
210 :type apiuser: AuthUser
252 :type apiuser: AuthUser
211 :param repoid: Repository name or repository ID.
253 :param repoid: Optional repository name or repository ID.
212 :type repoid: str or int
254 :type repoid: str or int
213 :param status: Only return pull requests with the specified status.
255 :param status: Only return pull requests with the specified status.
214 Valid options are.
256 Valid options are.
@@ -289,14 +331,14 b' get_pull_requests'
289 merge_pull_request
331 merge_pull_request
290 ------------------
332 ------------------
291
333
292 .. py:function:: merge_pull_request(apiuser, repoid, pullrequestid, userid=<Optional:<OptionalAttr:apiuser>>)
334 .. py:function:: merge_pull_request(apiuser, pullrequestid, repoid=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
293
335
294 Merge the pull request specified by `pullrequestid` into its target
336 Merge the pull request specified by `pullrequestid` into its target
295 repository.
337 repository.
296
338
297 :param apiuser: This is filled automatically from the |authtoken|.
339 :param apiuser: This is filled automatically from the |authtoken|.
298 :type apiuser: AuthUser
340 :type apiuser: AuthUser
299 :param repoid: The Repository name or repository ID of the
341 :param repoid: Optional, repository name or repository ID of the
300 target repository to which the |pr| is to be merged.
342 target repository to which the |pr| is to be merged.
301 :type repoid: str or int
343 :type repoid: str or int
302 :param pullrequestid: ID of the pull request which shall be merged.
344 :param pullrequestid: ID of the pull request which shall be merged.
@@ -326,13 +368,13 b' merge_pull_request'
326 update_pull_request
368 update_pull_request
327 -------------------
369 -------------------
328
370
329 .. py:function:: update_pull_request(apiuser, repoid, pullrequestid, title=<Optional:''>, description=<Optional:''>, reviewers=<Optional:None>, update_commits=<Optional:None>)
371 .. py:function:: update_pull_request(apiuser, pullrequestid, repoid=<Optional:None>, title=<Optional:''>, description=<Optional:''>, reviewers=<Optional:None>, update_commits=<Optional:None>)
330
372
331 Updates a pull request.
373 Updates a pull request.
332
374
333 :param apiuser: This is filled automatically from the |authtoken|.
375 :param apiuser: This is filled automatically from the |authtoken|.
334 :type apiuser: AuthUser
376 :type apiuser: AuthUser
335 :param repoid: The repository name or repository ID.
377 :param repoid: Optional repository name or repository ID.
336 :type repoid: str or int
378 :type repoid: str or int
337 :param pullrequestid: The pull request ID.
379 :param pullrequestid: The pull request ID.
338 :type pullrequestid: int
380 :type pullrequestid: int
@@ -115,7 +115,7 b' get_repo_group'
115 "group_description": "repo group description",
115 "group_description": "repo group description",
116 "group_id": 14,
116 "group_id": 14,
117 "group_name": "group name",
117 "group_name": "group name",
118 "members": [
118 "permissions": [
119 {
119 {
120 "name": "super-admin-username",
120 "name": "super-admin-username",
121 "origin": "super-admin",
121 "origin": "super-admin",
@@ -306,26 +306,6 b' get_repo'
306 "lock_reason": null,
306 "lock_reason": null,
307 "locked_by": null,
307 "locked_by": null,
308 "locked_date": null,
308 "locked_date": null,
309 "members": [
310 {
311 "name": "super-admin-name",
312 "origin": "super-admin",
313 "permission": "repository.admin",
314 "type": "user"
315 },
316 {
317 "name": "owner-name",
318 "origin": "owner",
319 "permission": "repository.admin",
320 "type": "user"
321 },
322 {
323 "name": "user-group-name",
324 "origin": "permission",
325 "permission": "repository.write",
326 "type": "user_group"
327 }
328 ],
329 "owner": "owner-name",
309 "owner": "owner-name",
330 "permissions": [
310 "permissions": [
331 {
311 {
@@ -533,9 +513,6 b' get_repo_settings'
533 "hooks_outgoing_pull_logger": true,
513 "hooks_outgoing_pull_logger": true,
534 "phases_publish": "True",
514 "phases_publish": "True",
535 "rhodecode_hg_use_rebase_for_merging": true,
515 "rhodecode_hg_use_rebase_for_merging": true,
536 "rhodecode_hg_close_branch_before_merging": false,
537 "rhodecode_git_use_rebase_for_merging": true,
538 "rhodecode_git_close_branch_before_merging": false,
539 "rhodecode_pr_merge_enabled": true,
516 "rhodecode_pr_merge_enabled": true,
540 "rhodecode_use_outdated_comments": true
517 "rhodecode_use_outdated_comments": true
541 }
518 }
@@ -162,7 +162,7 b' get_user_group'
162 "active": true,
162 "active": true,
163 "group_description": "group description",
163 "group_description": "group description",
164 "group_name": "group name",
164 "group_name": "group name",
165 "members": [
165 "permissions": [
166 {
166 {
167 "name": "owner-name",
167 "name": "owner-name",
168 "origin": "owner",
168 "origin": "owner",
@@ -183,6 +183,12 b' get_user_group'
183 "type": "user_group"
183 "type": "user_group"
184 }
184 }
185 ],
185 ],
186 "permissions_summary": {
187 "repositories": {
188 "aa-root-level-repo-1": "repository.admin"
189 },
190 "repositories_groups": {}
191 },
186 "owner": "owner name",
192 "owner": "owner name",
187 "users": [],
193 "users": [],
188 "users_group_id": 2
194 "users_group_id": 2
@@ -160,7 +160,8 b' get_user'
160 "last_login": "Timestamp",
160 "last_login": "Timestamp",
161 "last_activity": "Timestamp",
161 "last_activity": "Timestamp",
162 "lastname": "surnae",
162 "lastname": "surnae",
163 "permissions": {
163 "permissions": <deprecated>,
164 "permissions_summary": {
164 "global": [
165 "global": [
165 "hg.inherit_default_perms.true",
166 "hg.inherit_default_perms.true",
166 "usergroup.read",
167 "usergroup.read",
@@ -178,7 +179,7 b' get_user'
178 "repositories": { "username/example": "repository.write"},
179 "repositories": { "username/example": "repository.write"},
179 "repositories_groups": { "user-group/repo": "group.none" },
180 "repositories_groups": { "user-group/repo": "group.none" },
180 "user_groups": { "user_group_name": "usergroup.read" }
181 "user_groups": { "user_group_name": "usergroup.read" }
181 },
182 }
182 "user_id": 32,
183 "user_id": 32,
183 "username": "username"
184 "username": "username"
184 }
185 }
@@ -64,7 +64,7 b' 2. Enable the SSH module on instance.'
64 ssh.wrapper_cmd_allow_shell = false
64 ssh.wrapper_cmd_allow_shell = false
65
65
66 ## Enables logging, and detailed output send back to the client during SSH
66 ## Enables logging, and detailed output send back to the client during SSH
67 ## operations. Usefull for debugging, shouldn't be used in production.
67 ## operations. Useful for debugging, shouldn't be used in production.
68 ssh.enable_debug_logging = false
68 ssh.enable_debug_logging = false
69
69
70 ## Paths to binary executable, by default they are the names, but we can
70 ## Paths to binary executable, by default they are the names, but we can
@@ -111,20 +111,22 b' 4. Add the public key to your user accou'
111 Then add, remove your SSH key and try connecting again.
111 Then add, remove your SSH key and try connecting again.
112 Debug logging will be printed to help find the problems on the server side.
112 Debug logging will be printed to help find the problems on the server side.
113
113
114 Test connection using the ssh command from the local machine
114 Test connection using the ssh command from the local machine. Make sure
115 to use the use who is running the |RCE| server, and not your username from
116 the web interface.
115
117
116
118
117 For SVN:
119 For SVN:
118
120
119 .. code-block:: bash
121 .. code-block:: bash
120
122
121 SVN_SSH="ssh -i ~/.ssh/id_rsa_test_ssh" svn checkout svn+ssh://rhodecode@rc-server/repo_name
123 SVN_SSH="ssh -i ~/.ssh/id_rsa_test_ssh_private.key" svn checkout svn+ssh://rhodecode@rc-server/repo_name
122
124
123 For GIT:
125 For GIT:
124
126
125 .. code-block:: bash
127 .. code-block:: bash
126
128
127 GIT_SSH_COMMAND='ssh -i ~/.ssh/id_rsa_test_ssh' git clone ssh://rhodecode@rc-server/repo_name
129 GIT_SSH_COMMAND='ssh -i ~/.ssh/id_rsa_test_ssh_private.key' git clone ssh://rhodecode@rc-server/repo_name
128
130
129 For Mercurial:
131 For Mercurial:
130
132
@@ -133,6 +135,6 b' 4. Add the public key to your user accou'
133 Add to hgrc:
135 Add to hgrc:
134
136
135 [ui]
137 [ui]
136 ssh = ssh -C -i ~/.ssh/id_rsa_test_ssh
138 ssh = ssh -C -i ~/.ssh/id_rsa_test_ssh_private.key
137
139
138 hg clone ssh://rhodecode@rc-server/repo_name
140 hg clone ssh://rhodecode@rc-server/repo_name
@@ -11,128 +11,253 b' let'
11 python = pkgs.python27Packages.python;
11 python = pkgs.python27Packages.python;
12
12
13 Jinja2 = buildPythonPackage rec {
13 Jinja2 = buildPythonPackage rec {
14 name = "Jinja2-2.7.3";
14 name = "Jinja2-2.9.6";
15 buildInputs = [];
16 doCheck = false;
17 propagatedBuildInputs = [MarkupSafe];
15 src = fetchurl {
18 src = fetchurl {
16 url = "http://pypi.python.org/packages/source/J/Jinja2/${name}.tar.gz";
19 url = "https://pypi.python.org/packages/90/61/f820ff0076a2599dd39406dcb858ecb239438c02ce706c8e91131ab9c7f1/Jinja2-2.9.6.tar.gz";
17 md5 = "b9dffd2f3b43d673802fe857c8445b1a";
20 md5 = "6411537324b4dba0956aaa8109f3c77b";
18 };
21 };
19 propagatedBuildInputs = [ MarkupSafe ];
20 };
22 };
21
23
22 MarkupSafe = buildPythonPackage rec {
24 MarkupSafe = buildPythonPackage rec {
23 name = "MarkupSafe-0.23";
25 name = "MarkupSafe-1.0";
26 buildInputs = [];
27 doCheck = false;
28 propagatedBuildInputs = [];
24 src = fetchurl {
29 src = fetchurl {
25 url = "https://pypi.python.org/packages/source/M/MarkupSafe/${name}.tar.gz";
30 url = "https://pypi.python.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz";
26 md5 = "f5ab3deee4c37cd6a922fb81e730da6e";
31 md5 = "2fcedc9284d50e577b5192e8e3578355";
27 };
32 };
28 };
33 };
29
34
30 Pygments = buildPythonPackage rec {
35 Pygments = buildPythonPackage {
31 name = "Pygments-2.1.3";
36 name = "Pygments-2.2.0";
37 buildInputs = [];
32 doCheck = false;
38 doCheck = false;
39 propagatedBuildInputs = [];
33 src = fetchurl {
40 src = fetchurl {
34 url = "https://pypi.python.org/packages/b8/67/ab177979be1c81bc99c8d0592ef22d547e70bb4c6815c383286ed5dec504/Pygments-2.1.3.tar.gz";
41 url = "https://pypi.python.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz";
35 md5 = "ed3fba2467c8afcda4d317e4ef2c6150";
42 md5 = "13037baca42f16917cbd5ad2fab50844";
36 };
37 };
38
39 alabaster = buildPythonPackage rec {
40 name = "alabaster-0.7.3";
41 src = fetchurl {
42 url = "https://pypi.python.org/packages/source/a/alabaster/${name}.tar.gz";
43 md5 = "67428d1383fd833f1282fed5deba0898";
44 };
43 };
45 };
44 };
46
45
47 six = buildPythonPackage rec {
46 Sphinx = buildPythonPackage (rec {
48 name = "six-1.9.0";
47 name = "Sphinx-1.6.5";
49 src = fetchurl {
48 src = fetchurl {
50 url = "https://pypi.python.org/packages/source/s/six/${name}.tar.gz";
49 url = "https://pypi.python.org/packages/8b/7e/b188d9a3b9c938e736e02a74c1363c2888e095d770df2c72b4c312f9fdcb/Sphinx-1.6.5.tar.gz";
51 md5 = "476881ef4012262dfc8adc645ee786c4";
50 md5 = "cd73118c21ec610432e63e6421ec54f1";
51 };
52 propagatedBuildInputs = [
53 six
54 Jinja2
55 Pygments
56 docutils
57 snowballstemmer
58 babel
59 alabaster
60 imagesize
61 requests
62 setuptools
63 sphinxcontrib-websupport
64 typing
65
66 # special cases
67 pytz
68 sphinx_rtd_theme
69
70 ];
71 });
72
73 alabaster = buildPythonPackage rec {
74 name = "alabaster-0.7.10";
75 buildInputs = [];
76 doCheck = false;
77 propagatedBuildInputs = [];
78 src = fetchurl {
79 url = "https://pypi.python.org/packages/d0/a5/e3a9ad3ee86aceeff71908ae562580643b955ea1b1d4f08ed6f7e8396bd7/alabaster-0.7.10.tar.gz";
80 md5 = "7934dccf38801faa105f6e7b4784f493";
52 };
81 };
53 };
82 };
54
83
55 snowballstemmer = buildPythonPackage rec {
84 babel = buildPythonPackage {
56 name = "snowballstemmer-1.2.0";
85 name = "babel-2.5.1";
86 buildInputs = [];
87 doCheck = false;
88 propagatedBuildInputs = [pytz];
57 src = fetchurl {
89 src = fetchurl {
58 url = "https://pypi.python.org/packages/source/s/snowballstemmer/${name}.tar.gz";
90 url = "https://pypi.python.org/packages/5a/22/63f1dbb8514bb7e0d0c8a85cc9b14506599a075e231985f98afd70430e1f/Babel-2.5.1.tar.gz";
59 md5 = "51f2ef829db8129dd0f2354f0b209970";
91 md5 = "60228b3ce93a203357158b909afe8ae1";
60 };
92 };
61 };
93 };
62
94
63 pytz = buildPythonPackage rec {
95 certifi = buildPythonPackage {
64 name = "pytz-2015.2";
96 name = "certifi-2017.11.5";
97 buildInputs = [];
98 doCheck = false;
99 propagatedBuildInputs = [];
65 src = fetchurl {
100 src = fetchurl {
66 url = "https://pypi.python.org/packages/source/p/pytz/${name}.tar.gz";
101 url = "https://pypi.python.org/packages/23/3f/8be01c50ed24a4bd6b8da799839066ce0288f66f5e11f0367323467f0cbc/certifi-2017.11.5.tar.gz";
67 md5 = "08440d994cfbbf13d3343362cc3173f7";
102 md5 = "c15ac46ed1fe4b607ff3405928f9a992";
103 };
104 };
105
106 chardet = buildPythonPackage {
107 name = "chardet-3.0.4";
108 buildInputs = [];
109 doCheck = false;
110 propagatedBuildInputs = [];
111 src = fetchurl {
112 url = "https://pypi.python.org/packages/fc/bb/a5768c230f9ddb03acc9ef3f0d4a3cf93462473795d18e9535498c8f929d/chardet-3.0.4.tar.gz";
113 md5 = "7dd1ba7f9c77e32351b0a0cfacf4055c";
68 };
114 };
69 };
115 };
70
116
71 babel = buildPythonPackage rec {
117 docutils = buildPythonPackage {
72 name = "Babel-1.3";
118 name = "docutils-0.14";
119 buildInputs = [];
120 doCheck = false;
121 propagatedBuildInputs = [];
73 src = fetchurl {
122 src = fetchurl {
74 url = "https://pypi.python.org/packages/source/B/Babel/${name}.tar.gz";
123 url = "https://pypi.python.org/packages/84/f4/5771e41fdf52aabebbadecc9381d11dea0fa34e4759b4071244fa094804c/docutils-0.14.tar.gz";
75 md5 = "5264ceb02717843cbc9ffce8e6e06bdb";
124 md5 = "c53768d63db3873b7d452833553469de";
76 };
125 };
77 propagatedBuildInputs = [
78 pytz
79 ];
80 };
126 };
81
127
82 imagesize = buildPythonPackage rec {
128 idna = buildPythonPackage {
129 name = "idna-2.6";
130 buildInputs = [];
131 doCheck = false;
132 propagatedBuildInputs = [];
133 src = fetchurl {
134 url = "https://pypi.python.org/packages/f4/bd/0467d62790828c23c47fc1dfa1b1f052b24efdf5290f071c7a91d0d82fd3/idna-2.6.tar.gz";
135 md5 = "c706e2790b016bd0ed4edd2d4ba4d147";
136 };
137 };
138
139 imagesize = buildPythonPackage {
83 name = "imagesize-0.7.1";
140 name = "imagesize-0.7.1";
141 buildInputs = [];
142 doCheck = false;
143 propagatedBuildInputs = [];
84 src = fetchurl {
144 src = fetchurl {
85 url = "https://pypi.python.org/packages/53/72/6c6f1e787d9cab2cc733cf042f125abec07209a58308831c9f292504e826/${name}.tar.gz";
145 url = "https://pypi.python.org/packages/53/72/6c6f1e787d9cab2cc733cf042f125abec07209a58308831c9f292504e826/imagesize-0.7.1.tar.gz";
86 md5 = "976148283286a6ba5f69b0f81aef8052";
146 md5 = "976148283286a6ba5f69b0f81aef8052";
87 };
147 };
88 };
148 };
89
149
90 Sphinx = buildPythonPackage (rec {
150 pytz = buildPythonPackage {
91 name = "Sphinx-1.4.8";
151 name = "pytz-2017.3";
152 buildInputs = [];
153 doCheck = false;
154 propagatedBuildInputs = [];
92 src = fetchurl {
155 src = fetchurl {
93 url = "https://pypi.python.org/packages/1f/f6/e54a7aad73e35232356103771ae76306dadd8546b024c646fbe75135571c/${name}.tar.gz";
156 url = "https://pypi.python.org/packages/60/88/d3152c234da4b2a1f7a989f89609ea488225eaea015bc16fbde2b3fdfefa/pytz-2017.3.zip";
94 md5 = "5ec718a4855917e149498bba91b74e67";
157 md5 = "7006b56c0d68a162d9fe57d4249c3171";
158 };
159 };
160
161 requests = buildPythonPackage {
162 name = "requests-2.18.4";
163 buildInputs = [];
164 doCheck = false;
165 propagatedBuildInputs = [chardet idna urllib3 certifi];
166 src = fetchurl {
167 url = "https://pypi.python.org/packages/b0/e1/eab4fc3752e3d240468a8c0b284607899d2fbfb236a56b7377a329aa8d09/requests-2.18.4.tar.gz";
168 md5 = "081412b2ef79bdc48229891af13f4d82";
95 };
169 };
96 propagatedBuildInputs = [
170 };
97 docutils
171
98 Jinja2
172 setuptools = buildPythonPackage {
99 Pygments
173 name = "setuptools-36.6.0";
100 alabaster
174 buildInputs = [];
101 six
175 doCheck = false;
102 snowballstemmer
176 propagatedBuildInputs = [];
103 pytz
177 src = fetchurl {
104 babel
178 url = "https://pypi.python.org/packages/45/29/8814bf414e7cd1031e1a3c8a4169218376e284ea2553cc0822a6ea1c2d78/setuptools-36.6.0.zip";
105 imagesize
179 md5 = "74663b15117d9a2cc5295d76011e6fd1";
180 };
181 };
106
182
107 # TODO: johbo: Had to include it here so that can be imported
183 six = buildPythonPackage {
108 sphinx_rtd_theme
184 name = "six-1.11.0";
109 ];
185 buildInputs = [];
110 });
186 doCheck = false;
187 propagatedBuildInputs = [];
188 src = fetchurl {
189 url = "https://pypi.python.org/packages/16/d8/bc6316cf98419719bd59c91742194c111b6f2e85abac88e496adefaf7afe/six-1.11.0.tar.gz";
190 md5 = "d12789f9baf7e9fb2524c0c64f1773f8";
191 };
192 };
111
193
112 docutils = buildPythonPackage rec {
194 snowballstemmer = buildPythonPackage {
113 name = "docutils-0.12";
195 name = "snowballstemmer-1.2.1";
196 buildInputs = [];
197 doCheck = false;
198 propagatedBuildInputs = [];
114 src = fetchurl {
199 src = fetchurl {
115 url = "https://pypi.python.org/packages/source/d/docutils/${name}.tar.gz";
200 url = "https://pypi.python.org/packages/20/6b/d2a7cb176d4d664d94a6debf52cd8dbae1f7203c8e42426daa077051d59c/snowballstemmer-1.2.1.tar.gz";
116 md5 = "4622263b62c5c771c03502afa3157768";
201 md5 = "643b019667a708a922172e33a99bf2fa";
117 };
202 };
118 };
203 };
119
204
120 sphinx_rtd_theme = buildPythonPackage rec {
205 sphinx-rtd-theme = buildPythonPackage {
121 name = "sphinx_rtd_theme-0.1.9";
206 name = "sphinx-rtd-theme-0.2.5b1";
207 buildInputs = [];
208 doCheck = false;
209 propagatedBuildInputs = [];
210 src = fetchurl {
211 url = "https://pypi.python.org/packages/59/e4/9e3a74a3271e6734911d3f549e8439db53b8ac29adf10c8f698e6c86246b/sphinx_rtd_theme-0.2.5b1.tar.gz";
212 md5 = "0923473a43bd2527f32151f195f2a521";
213 };
214 };
215
216 sphinxcontrib-websupport = buildPythonPackage {
217 name = "sphinxcontrib-websupport-1.0.1";
218 buildInputs = [];
219 doCheck = false;
220 propagatedBuildInputs = [];
122 src = fetchurl {
221 src = fetchurl {
123 url = "https://pypi.python.org/packages/source/s/sphinx_rtd_theme/${name}.tar.gz";
222 url = "https://pypi.python.org/packages/c5/6b/f0630436b931ad4f8331a9399ca18a7d447f0fcc0c7178fb56b1aee68d01/sphinxcontrib-websupport-1.0.1.tar.gz";
124 md5 = "86a25c8d47147c872e42dc84cc66f97b";
223 md5 = "84df26463b1ba65b07f926dbe2055665";
224 };
225 };
226
227 typing = buildPythonPackage {
228 name = "typing-3.6.2";
229 buildInputs = [];
230 doCheck = false;
231 propagatedBuildInputs = [];
232 src = fetchurl {
233 url = "https://pypi.python.org/packages/ca/38/16ba8d542e609997fdcd0214628421c971f8c395084085354b11ff4ac9c3/typing-3.6.2.tar.gz";
234 md5 = "143af0bf3afd1887622771f2f1ffe8e1";
235 };
236 };
237
238 urllib3 = buildPythonPackage {
239 name = "urllib3-1.22";
240 buildInputs = [];
241 doCheck = false;
242 propagatedBuildInputs = [];
243 src = fetchurl {
244 url = "https://pypi.python.org/packages/ee/11/7c59620aceedcc1ef65e156cc5ce5a24ef87be4107c2b74458464e437a5d/urllib3-1.22.tar.gz";
245 md5 = "0da7bed3fe94bf7dc59ae37885cc72f7";
246 };
247 };
248
249
250 sphinx_rtd_theme = buildPythonPackage rec {
251 name = "sphinx-rtd-theme-0.2.5b1";
252 buildInputs = [];
253 doCheck = false;
254 propagatedBuildInputs = [];
255 src = fetchurl {
256 url = "https://pypi.python.org/packages/59/e4/9e3a74a3271e6734911d3f549e8439db53b8ac29adf10c8f698e6c86246b/sphinx_rtd_theme-0.2.5b1.tar.gz";
257 md5 = "0923473a43bd2527f32151f195f2a521";
125 };
258 };
126
259
127 # Note: johbo: Sphinx needs this package and this package needs sphinx,
128 # ignore the requirements file to solve this cycle.
129 postPatch = ''
130 rm requirements.txt
131 touch requirements.txt
132 '';
133
260
134 # TODO: johbo: Tests would require sphinx and this creates recursion issues
135 doCheck = false;
136 };
261 };
137
262
138 in python.buildEnv.override {
263 in python.buildEnv.override {
@@ -9,6 +9,7 b' Release Notes'
9 .. toctree::
9 .. toctree::
10 :maxdepth: 1
10 :maxdepth: 1
11
11
12 release-notes-4.11.0.rst
12 release-notes-4.10.6.rst
13 release-notes-4.10.6.rst
13 release-notes-4.10.5.rst
14 release-notes-4.10.5.rst
14 release-notes-4.10.4.rst
15 release-notes-4.10.4.rst
@@ -42,6 +42,8 b''
42 "<%= dirs.js.src %>/bootstrap.js",
42 "<%= dirs.js.src %>/bootstrap.js",
43 "<%= dirs.js.src %>/i18n_utils.js",
43 "<%= dirs.js.src %>/i18n_utils.js",
44 "<%= dirs.js.src %>/deform.js",
44 "<%= dirs.js.src %>/deform.js",
45 "<%= dirs.js.src %>/ejs.js",
46 "<%= dirs.js.src %>/ejs_templates/utils.js",
45 "<%= dirs.js.src %>/plugins/jquery.pjax.js",
47 "<%= dirs.js.src %>/plugins/jquery.pjax.js",
46 "<%= dirs.js.src %>/plugins/jquery.dataTables.js",
48 "<%= dirs.js.src %>/plugins/jquery.dataTables.js",
47 "<%= dirs.js.src %>/plugins/flavoured_checkbox.js",
49 "<%= dirs.js.src %>/plugins/flavoured_checkbox.js",
@@ -7,7 +7,7 b' buildEnv { name = "bower-env"; ignoreCol'
7 (fetchbower "paper-tooltip" "PolymerElements/paper-tooltip#1.1.3" "PolymerElements/paper-tooltip#^1.1.2" "0vmrm1n8k9sk9nvqy03q177axy22pia6i3j1gxbk72j3pqiqvg6k")
7 (fetchbower "paper-tooltip" "PolymerElements/paper-tooltip#1.1.3" "PolymerElements/paper-tooltip#^1.1.2" "0vmrm1n8k9sk9nvqy03q177axy22pia6i3j1gxbk72j3pqiqvg6k")
8 (fetchbower "paper-toast" "PolymerElements/paper-toast#1.3.0" "PolymerElements/paper-toast#^1.3.0" "0x9rqxsks5455s8pk4aikpp99ijdn6kxr9gvhwh99nbcqdzcxq1m")
8 (fetchbower "paper-toast" "PolymerElements/paper-toast#1.3.0" "PolymerElements/paper-toast#^1.3.0" "0x9rqxsks5455s8pk4aikpp99ijdn6kxr9gvhwh99nbcqdzcxq1m")
9 (fetchbower "paper-toggle-button" "PolymerElements/paper-toggle-button#1.2.0" "PolymerElements/paper-toggle-button#^1.2.0" "0mphcng3ngspbpg4jjn0mb91nvr4xc1phq3qswib15h6sfww1b2w")
9 (fetchbower "paper-toggle-button" "PolymerElements/paper-toggle-button#1.2.0" "PolymerElements/paper-toggle-button#^1.2.0" "0mphcng3ngspbpg4jjn0mb91nvr4xc1phq3qswib15h6sfww1b2w")
10 (fetchbower "iron-ajax" "PolymerElements/iron-ajax#1.4.3" "PolymerElements/iron-ajax#^1.4.3" "1b1z3112ggjdflgrwbpmnbsh3kgcm4hn255wshvrlzds4w069gja")
10 (fetchbower "iron-ajax" "PolymerElements/iron-ajax#1.4.4" "PolymerElements/iron-ajax#^1.4.4" "0jpi7ik3zljw8yh2ccc85r26lcpzmkc2nl1kn6fqdx57zkzk9v5b")
11 (fetchbower "iron-autogrow-textarea" "PolymerElements/iron-autogrow-textarea#1.0.13" "PolymerElements/iron-autogrow-textarea#^1.0.13" "0zwhpl97vii1s8k0lgain8i9dnw29b0mxc5ixdscx9las13n2lqq")
11 (fetchbower "iron-autogrow-textarea" "PolymerElements/iron-autogrow-textarea#1.0.13" "PolymerElements/iron-autogrow-textarea#^1.0.13" "0zwhpl97vii1s8k0lgain8i9dnw29b0mxc5ixdscx9las13n2lqq")
12 (fetchbower "iron-a11y-keys" "PolymerElements/iron-a11y-keys#1.0.6" "PolymerElements/iron-a11y-keys#^1.0.6" "1xz3mgghfcxixq28sdb654iaxj4nyi1bzcwf77ydkms6fviqs9mv")
12 (fetchbower "iron-a11y-keys" "PolymerElements/iron-a11y-keys#1.0.6" "PolymerElements/iron-a11y-keys#^1.0.6" "1xz3mgghfcxixq28sdb654iaxj4nyi1bzcwf77ydkms6fviqs9mv")
13 (fetchbower "iron-flex-layout" "PolymerElements/iron-flex-layout#1.3.1" "PolymerElements/iron-flex-layout#^1.0.0" "0nswv3ih3bhflgcd2wjfmddqswzgqxb2xbq65jk9w3rkj26hplbl")
13 (fetchbower "iron-flex-layout" "PolymerElements/iron-flex-layout#1.3.1" "PolymerElements/iron-flex-layout#^1.0.0" "0nswv3ih3bhflgcd2wjfmddqswzgqxb2xbq65jk9w3rkj26hplbl")
@@ -31,6 +31,12 b' self: super: {'
31 };
31 };
32 });
32 });
33
33
34 testpath = super.testpath.override (attrs: {
35 meta = {
36 license = [ pkgs.lib.licenses.mit ];
37 };
38 });
39
34 gnureadline = super.gnureadline.override (attrs: {
40 gnureadline = super.gnureadline.override (attrs: {
35 buildInputs = attrs.buildInputs ++ [
41 buildInputs = attrs.buildInputs ++ [
36 pkgs.ncurses
42 pkgs.ncurses
@@ -61,23 +67,6 b' self: super: {'
61 ];
67 ];
62 });
68 });
63
69
64 celery = super.celery.override (attrs: {
65 # The current version of kombu needs some patching to work with the
66 # other libs. Should be removed once we update celery and kombu.
67 patches = [
68 ./patch-celery-dateutil.diff
69 ];
70 });
71
72 kombu = super.kombu.override (attrs: {
73 # The current version of kombu needs some patching to work with the
74 # other libs. Should be removed once we update celery and kombu.
75 patches = [
76 ./patch-kombu-py-2-7-11.diff
77 ./patch-kombu-msgpack.diff
78 ];
79 });
80
81 lxml = super.lxml.override (attrs: {
70 lxml = super.lxml.override (attrs: {
82 # johbo: On 16.09 we need this to compile on darwin, otherwise compilation
71 # johbo: On 16.09 we need this to compile on darwin, otherwise compilation
83 # fails on Darwin.
72 # fails on Darwin.
@@ -114,10 +103,6 b' self: super: {'
114 };
103 };
115 });
104 });
116
105
117 py-gfm = super.py-gfm.override {
118 name = "py-gfm-0.1.3.rhodecode-upstream1";
119 };
120
121 pycurl = super.pycurl.override (attrs: {
106 pycurl = super.pycurl.override (attrs: {
122 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
107 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
123 pkgs.curl
108 pkgs.curl
@@ -133,10 +118,6 b' self: super: {'
133 };
118 };
134 });
119 });
135
120
136 Pylons = super.Pylons.override (attrs: {
137 name = "Pylons-1.0.2.rhodecode-patch1";
138 });
139
140 pyramid = super.pyramid.override (attrs: {
121 pyramid = super.pyramid.override (attrs: {
141 postFixup = ''
122 postFixup = ''
142 wrapPythonPrograms
123 wrapPythonPrograms
@@ -208,12 +189,6 b' self: super: {'
208 };
189 };
209 });
190 });
210
191
211 amqplib = super.amqplib.override (attrs: {
212 meta = {
213 license = pkgs.lib.licenses.lgpl3;
214 };
215 });
216
217 docutils = super.docutils.override (attrs: {
192 docutils = super.docutils.override (attrs: {
218 meta = {
193 meta = {
219 license = pkgs.lib.licenses.bsd2;
194 license = pkgs.lib.licenses.bsd2;
@@ -68,13 +68,13 b''
68 };
68 };
69 };
69 };
70 Jinja2 = super.buildPythonPackage {
70 Jinja2 = super.buildPythonPackage {
71 name = "Jinja2-2.7.3";
71 name = "Jinja2-2.9.6";
72 buildInputs = with self; [];
72 buildInputs = with self; [];
73 doCheck = false;
73 doCheck = false;
74 propagatedBuildInputs = with self; [MarkupSafe];
74 propagatedBuildInputs = with self; [MarkupSafe];
75 src = fetchurl {
75 src = fetchurl {
76 url = "https://pypi.python.org/packages/b0/73/eab0bca302d6d6a0b5c402f47ad1760dc9cb2dd14bbc1873ad48db258e4d/Jinja2-2.7.3.tar.gz";
76 url = "https://pypi.python.org/packages/90/61/f820ff0076a2599dd39406dcb858ecb239438c02ce706c8e91131ab9c7f1/Jinja2-2.9.6.tar.gz";
77 md5 = "b9dffd2f3b43d673802fe857c8445b1a";
77 md5 = "6411537324b4dba0956aaa8109f3c77b";
78 };
78 };
79 meta = {
79 meta = {
80 license = [ pkgs.lib.licenses.bsdOriginal ];
80 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -94,26 +94,26 b''
94 };
94 };
95 };
95 };
96 Markdown = super.buildPythonPackage {
96 Markdown = super.buildPythonPackage {
97 name = "Markdown-2.6.8";
97 name = "Markdown-2.6.9";
98 buildInputs = with self; [];
98 buildInputs = with self; [];
99 doCheck = false;
99 doCheck = false;
100 propagatedBuildInputs = with self; [];
100 propagatedBuildInputs = with self; [];
101 src = fetchurl {
101 src = fetchurl {
102 url = "https://pypi.python.org/packages/1d/25/3f6d2cb31ec42ca5bd3bfbea99b63892b735d76e26f20dd2dcc34ffe4f0d/Markdown-2.6.8.tar.gz";
102 url = "https://pypi.python.org/packages/29/82/dfe242bcfd9eec0e7bf93a80a8f8d8515a95b980c44f5c0b45606397a423/Markdown-2.6.9.tar.gz";
103 md5 = "d9ef057a5bd185f6f536400a31fc5d45";
103 md5 = "56547d362a9abcf30955b8950b08b5e3";
104 };
104 };
105 meta = {
105 meta = {
106 license = [ pkgs.lib.licenses.bsdOriginal ];
106 license = [ pkgs.lib.licenses.bsdOriginal ];
107 };
107 };
108 };
108 };
109 MarkupSafe = super.buildPythonPackage {
109 MarkupSafe = super.buildPythonPackage {
110 name = "MarkupSafe-0.23";
110 name = "MarkupSafe-1.0";
111 buildInputs = with self; [];
111 buildInputs = with self; [];
112 doCheck = false;
112 doCheck = false;
113 propagatedBuildInputs = with self; [];
113 propagatedBuildInputs = with self; [];
114 src = fetchurl {
114 src = fetchurl {
115 url = "https://pypi.python.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-0.23.tar.gz";
115 url = "https://pypi.python.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz";
116 md5 = "f5ab3deee4c37cd6a922fb81e730da6e";
116 md5 = "2fcedc9284d50e577b5192e8e3578355";
117 };
117 };
118 meta = {
118 meta = {
119 license = [ pkgs.lib.licenses.bsdOriginal ];
119 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -159,13 +159,13 b''
159 };
159 };
160 };
160 };
161 PasteScript = super.buildPythonPackage {
161 PasteScript = super.buildPythonPackage {
162 name = "PasteScript-1.7.5";
162 name = "PasteScript-2.0.2";
163 buildInputs = with self; [];
163 buildInputs = with self; [];
164 doCheck = false;
164 doCheck = false;
165 propagatedBuildInputs = with self; [Paste PasteDeploy];
165 propagatedBuildInputs = with self; [Paste PasteDeploy six];
166 src = fetchurl {
166 src = fetchurl {
167 url = "https://pypi.python.org/packages/a5/05/fc60efa7c2f17a1dbaeccb2a903a1e90902d92b9d00eebabe3095829d806/PasteScript-1.7.5.tar.gz";
167 url = "https://pypi.python.org/packages/e5/f0/78e766c3dcc61a4f3a6f71dd8c95168ae9c7a31722b5663d19c1fdf62cb6/PasteScript-2.0.2.tar.gz";
168 md5 = "4c72d78dcb6bb993f30536842c16af4d";
168 md5 = "ccb3045445097192ca71a13b746c77b2";
169 };
169 };
170 meta = {
170 meta = {
171 license = [ pkgs.lib.licenses.mit ];
171 license = [ pkgs.lib.licenses.mit ];
@@ -184,56 +184,30 b''
184 license = [ pkgs.lib.licenses.bsdOriginal ];
184 license = [ pkgs.lib.licenses.bsdOriginal ];
185 };
185 };
186 };
186 };
187 Pylons = super.buildPythonPackage {
188 name = "Pylons-1.0.2.dev20171106";
189 buildInputs = with self; [];
190 doCheck = false;
191 propagatedBuildInputs = with self; [Routes WebHelpers Beaker Paste PasteDeploy PasteScript FormEncode simplejson decorator nose Mako WebError WebTest Tempita MarkupSafe WebOb];
192 src = fetchurl {
193 url = "https://code.rhodecode.com/upstream/pylons/archive/707354ee4261b9c10450404fc9852ccea4fd667d.tar.gz?md5=f26633726fa2cd3a340316ee6a5d218f";
194 md5 = "f26633726fa2cd3a340316ee6a5d218f";
195 };
196 meta = {
197 license = [ pkgs.lib.licenses.bsdOriginal ];
198 };
199 };
200 Routes = super.buildPythonPackage {
187 Routes = super.buildPythonPackage {
201 name = "Routes-1.13";
188 name = "Routes-2.4.1";
202 buildInputs = with self; [];
189 buildInputs = with self; [];
203 doCheck = false;
190 doCheck = false;
204 propagatedBuildInputs = with self; [repoze.lru];
191 propagatedBuildInputs = with self; [six repoze.lru];
205 src = fetchurl {
192 src = fetchurl {
206 url = "https://pypi.python.org/packages/88/d3/259c3b3cde8837eb9441ab5f574a660e8a4acea8f54a078441d4d2acac1c/Routes-1.13.tar.gz";
193 url = "https://pypi.python.org/packages/33/38/ea827837e68d9c7dde4cff7ec122a93c319f0effc08ce92a17095576603f/Routes-2.4.1.tar.gz";
207 md5 = "d527b0ab7dd9172b1275a41f97448783";
194 md5 = "c058dff6832941dec47e0d0052548ad8";
208 };
209 meta = {
210 license = [ pkgs.lib.licenses.bsdOriginal ];
211 };
212 };
213 SQLAlchemy = super.buildPythonPackage {
214 name = "SQLAlchemy-1.1.11";
215 buildInputs = with self; [];
216 doCheck = false;
217 propagatedBuildInputs = with self; [];
218 src = fetchurl {
219 url = "https://pypi.python.org/packages/59/f1/28f2205c3175e6bf32300c0f30f9d91dbc9eb910debbff3ffecb88d18528/SQLAlchemy-1.1.11.tar.gz";
220 md5 = "3de387eddb4012083a4562928c511e43";
221 };
195 };
222 meta = {
196 meta = {
223 license = [ pkgs.lib.licenses.mit ];
197 license = [ pkgs.lib.licenses.mit ];
224 };
198 };
225 };
199 };
226 Sphinx = super.buildPythonPackage {
200 SQLAlchemy = super.buildPythonPackage {
227 name = "Sphinx-1.2.2";
201 name = "SQLAlchemy-1.1.15";
228 buildInputs = with self; [];
202 buildInputs = with self; [];
229 doCheck = false;
203 doCheck = false;
230 propagatedBuildInputs = with self; [Pygments docutils Jinja2];
204 propagatedBuildInputs = with self; [];
231 src = fetchurl {
205 src = fetchurl {
232 url = "https://pypi.python.org/packages/0a/50/34017e6efcd372893a416aba14b84a1a149fc7074537b0e9cb6ca7b7abe9/Sphinx-1.2.2.tar.gz";
206 url = "https://pypi.python.org/packages/c2/f6/11fcc1ce19a7cb81b1c9377f4e27ce3813265611922e355905e57c44d164/SQLAlchemy-1.1.15.tar.gz";
233 md5 = "3dc73ccaa8d0bfb2d62fb671b1f7e8a4";
207 md5 = "077f9bd3339957f53068b5572a152674";
234 };
208 };
235 meta = {
209 meta = {
236 license = [ pkgs.lib.licenses.bsdOriginal ];
210 license = [ pkgs.lib.licenses.mit ];
237 };
211 };
238 };
212 };
239 Tempita = super.buildPythonPackage {
213 Tempita = super.buildPythonPackage {
@@ -315,13 +289,13 b''
315 };
289 };
316 };
290 };
317 WebTest = super.buildPythonPackage {
291 WebTest = super.buildPythonPackage {
318 name = "WebTest-2.0.27";
292 name = "WebTest-2.0.29";
319 buildInputs = with self; [];
293 buildInputs = with self; [];
320 doCheck = false;
294 doCheck = false;
321 propagatedBuildInputs = with self; [six WebOb waitress beautifulsoup4];
295 propagatedBuildInputs = with self; [six WebOb waitress beautifulsoup4];
322 src = fetchurl {
296 src = fetchurl {
323 url = "https://pypi.python.org/packages/80/fa/ca3a759985c72e3a124cbca3e1f8a2e931a07ffd31fd45d8f7bf21cb95cf/WebTest-2.0.27.tar.gz";
297 url = "https://pypi.python.org/packages/94/de/8f94738be649997da99c47b104aa3c3984ecec51a1d8153ed09638253d56/WebTest-2.0.29.tar.gz";
324 md5 = "54e6515ac71c51b6fc90179483c749ad";
298 md5 = "30b4cf0d340b9a5335fac4389e6f84fc";
325 };
299 };
326 meta = {
300 meta = {
327 license = [ pkgs.lib.licenses.mit ];
301 license = [ pkgs.lib.licenses.mit ];
@@ -341,52 +315,39 b''
341 };
315 };
342 };
316 };
343 alembic = super.buildPythonPackage {
317 alembic = super.buildPythonPackage {
344 name = "alembic-0.9.2";
318 name = "alembic-0.9.6";
345 buildInputs = with self; [];
319 buildInputs = with self; [];
346 doCheck = false;
320 doCheck = false;
347 propagatedBuildInputs = with self; [SQLAlchemy Mako python-editor python-dateutil];
321 propagatedBuildInputs = with self; [SQLAlchemy Mako python-editor python-dateutil];
348 src = fetchurl {
322 src = fetchurl {
349 url = "https://pypi.python.org/packages/78/48/b5b26e7218b415f40b60b92c53853d242e5456c0f19f6c66101d98ff5f2a/alembic-0.9.2.tar.gz";
323 url = "https://pypi.python.org/packages/bf/b3/b28ea715824f8455635ece3c12f59d5d205f98cc378858e414e3aa6ebdbc/alembic-0.9.6.tar.gz";
350 md5 = "40daf8bae50969beea40efaaf0839ff4";
324 md5 = "fcb096bccc87c8770bd07a04606cb989";
351 };
325 };
352 meta = {
326 meta = {
353 license = [ pkgs.lib.licenses.mit ];
327 license = [ pkgs.lib.licenses.mit ];
354 };
328 };
355 };
329 };
356 amqplib = super.buildPythonPackage {
330 amqp = super.buildPythonPackage {
357 name = "amqplib-1.0.2";
331 name = "amqp-2.2.2";
358 buildInputs = with self; [];
332 buildInputs = with self; [];
359 doCheck = false;
333 doCheck = false;
360 propagatedBuildInputs = with self; [];
334 propagatedBuildInputs = with self; [vine];
361 src = fetchurl {
335 src = fetchurl {
362 url = "https://pypi.python.org/packages/75/b7/8c2429bf8d92354a0118614f9a4d15e53bc69ebedce534284111de5a0102/amqplib-1.0.2.tgz";
336 url = "https://pypi.python.org/packages/e0/70/9ab9ccd8247fb7d2adb717e9f6a0ed358c9e1ab2c349048b0352f9e80ee2/amqp-2.2.2.tar.gz";
363 md5 = "5c92f17fbedd99b2b4a836d4352d1e2f";
337 md5 = "0971a3fd2d635ded45c349cfc17106bd";
364 };
365 meta = {
366 license = [ { fullName = "LGPL"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ];
367 };
368 };
369 anyjson = super.buildPythonPackage {
370 name = "anyjson-0.3.3";
371 buildInputs = with self; [];
372 doCheck = false;
373 propagatedBuildInputs = with self; [];
374 src = fetchurl {
375 url = "https://pypi.python.org/packages/c3/4d/d4089e1a3dd25b46bebdb55a992b0797cff657b4477bc32ce28038fdecbc/anyjson-0.3.3.tar.gz";
376 md5 = "2ea28d6ec311aeeebaf993cb3008b27c";
377 };
338 };
378 meta = {
339 meta = {
379 license = [ pkgs.lib.licenses.bsdOriginal ];
340 license = [ pkgs.lib.licenses.bsdOriginal ];
380 };
341 };
381 };
342 };
382 appenlight-client = super.buildPythonPackage {
343 appenlight-client = super.buildPythonPackage {
383 name = "appenlight-client-0.6.21";
344 name = "appenlight-client-0.6.22";
384 buildInputs = with self; [];
345 buildInputs = with self; [];
385 doCheck = false;
346 doCheck = false;
386 propagatedBuildInputs = with self; [WebOb requests six];
347 propagatedBuildInputs = with self; [WebOb requests six];
387 src = fetchurl {
348 src = fetchurl {
388 url = "https://pypi.python.org/packages/c9/23/91b66cfa0b963662c10b2a06ccaadf3f3a4848a7a2aa16255cb43d5160ec/appenlight_client-0.6.21.tar.gz";
349 url = "https://pypi.python.org/packages/73/37/0a64460fa9670b17c061adc433bc8be5079cba21e8b3a92d824adccb12bc/appenlight_client-0.6.22.tar.gz";
389 md5 = "273999ac854fdaefa8d0fb61965a4ed9";
350 md5 = "641afc114a9a3b3af4f75b11c70968ee";
390 };
351 };
391 meta = {
352 meta = {
392 license = [ pkgs.lib.licenses.bsdOriginal ];
353 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -431,27 +392,40 b''
431 license = [ pkgs.lib.licenses.mit ];
392 license = [ pkgs.lib.licenses.mit ];
432 };
393 };
433 };
394 };
395 billiard = super.buildPythonPackage {
396 name = "billiard-3.5.0.3";
397 buildInputs = with self; [];
398 doCheck = false;
399 propagatedBuildInputs = with self; [];
400 src = fetchurl {
401 url = "https://pypi.python.org/packages/39/ac/f5571210cca2e4f4532e38aaff242f26c8654c5e2436bee966c230647ccc/billiard-3.5.0.3.tar.gz";
402 md5 = "113ba481e48400adbf6fbbf59a2f8554";
403 };
404 meta = {
405 license = [ pkgs.lib.licenses.bsdOriginal ];
406 };
407 };
434 bleach = super.buildPythonPackage {
408 bleach = super.buildPythonPackage {
435 name = "bleach-1.5.0";
409 name = "bleach-2.1.1";
436 buildInputs = with self; [];
410 buildInputs = with self; [];
437 doCheck = false;
411 doCheck = false;
438 propagatedBuildInputs = with self; [six html5lib];
412 propagatedBuildInputs = with self; [six html5lib];
439 src = fetchurl {
413 src = fetchurl {
440 url = "https://pypi.python.org/packages/99/00/25a8fce4de102bf6e3cc76bc4ea60685b2fee33bde1b34830c70cacc26a7/bleach-1.5.0.tar.gz";
414 url = "https://pypi.python.org/packages/d4/3f/d517089af35b01bb9bc4eac5ea04bae342b37a5e9abbb27b7c3ce0eae070/bleach-2.1.1.tar.gz";
441 md5 = "b663300efdf421b3b727b19d7be9c7e7";
415 md5 = "7c5dfb1d66ea979b5a465afb12c82ec4";
442 };
416 };
443 meta = {
417 meta = {
444 license = [ pkgs.lib.licenses.asl20 ];
418 license = [ pkgs.lib.licenses.asl20 ];
445 };
419 };
446 };
420 };
447 bottle = super.buildPythonPackage {
421 bottle = super.buildPythonPackage {
448 name = "bottle-0.12.8";
422 name = "bottle-0.12.13";
449 buildInputs = with self; [];
423 buildInputs = with self; [];
450 doCheck = false;
424 doCheck = false;
451 propagatedBuildInputs = with self; [];
425 propagatedBuildInputs = with self; [];
452 src = fetchurl {
426 src = fetchurl {
453 url = "https://pypi.python.org/packages/52/df/e4a408f3a7af396d186d4ecd3b389dd764f0f943b4fa8d257bfe7b49d343/bottle-0.12.8.tar.gz";
427 url = "https://pypi.python.org/packages/bd/99/04dc59ced52a8261ee0f965a8968717a255ea84a36013e527944dbf3468c/bottle-0.12.13.tar.gz";
454 md5 = "13132c0a8f607bf860810a6ee9064c5b";
428 md5 = "d2fe1b48c1d49217e78bf326b1cad437";
455 };
429 };
456 meta = {
430 meta = {
457 license = [ pkgs.lib.licenses.mit ];
431 license = [ pkgs.lib.licenses.mit ];
@@ -471,13 +445,13 b''
471 };
445 };
472 };
446 };
473 celery = super.buildPythonPackage {
447 celery = super.buildPythonPackage {
474 name = "celery-2.2.10";
448 name = "celery-4.1.0";
475 buildInputs = with self; [];
449 buildInputs = with self; [];
476 doCheck = false;
450 doCheck = false;
477 propagatedBuildInputs = with self; [python-dateutil anyjson kombu pyparsing];
451 propagatedBuildInputs = with self; [pytz billiard kombu];
478 src = fetchurl {
452 src = fetchurl {
479 url = "https://pypi.python.org/packages/b1/64/860fd50e45844c83442e7953effcddeff66b2851d90b2d784f7201c111b8/celery-2.2.10.tar.gz";
453 url = "https://pypi.python.org/packages/07/65/88a2a45fc80f487872c93121a701a53bbbc3d3d832016876fac84fc8d46a/celery-4.1.0.tar.gz";
480 md5 = "898bc87e54f278055b561316ba73e222";
454 md5 = "db91e1d26936381127f01e150fe3054a";
481 };
455 };
482 meta = {
456 meta = {
483 license = [ pkgs.lib.licenses.bsdOriginal ];
457 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -497,26 +471,26 b''
497 };
471 };
498 };
472 };
499 click = super.buildPythonPackage {
473 click = super.buildPythonPackage {
500 name = "click-5.1";
474 name = "click-6.6";
501 buildInputs = with self; [];
475 buildInputs = with self; [];
502 doCheck = false;
476 doCheck = false;
503 propagatedBuildInputs = with self; [];
477 propagatedBuildInputs = with self; [];
504 src = fetchurl {
478 src = fetchurl {
505 url = "https://pypi.python.org/packages/b7/34/a496632c4fb6c1ee76efedf77bb8d28b29363d839953d95095b12defe791/click-5.1.tar.gz";
479 url = "https://pypi.python.org/packages/7a/00/c14926d8232b36b08218067bcd5853caefb4737cda3f0a47437151344792/click-6.6.tar.gz";
506 md5 = "9c5323008cccfe232a8b161fc8196d41";
480 md5 = "d0b09582123605220ad6977175f3e51d";
507 };
481 };
508 meta = {
482 meta = {
509 license = [ pkgs.lib.licenses.bsdOriginal ];
483 license = [ pkgs.lib.licenses.bsdOriginal ];
510 };
484 };
511 };
485 };
512 colander = super.buildPythonPackage {
486 colander = super.buildPythonPackage {
513 name = "colander-1.3.3";
487 name = "colander-1.4";
514 buildInputs = with self; [];
488 buildInputs = with self; [];
515 doCheck = false;
489 doCheck = false;
516 propagatedBuildInputs = with self; [translationstring iso8601];
490 propagatedBuildInputs = with self; [translationstring iso8601];
517 src = fetchurl {
491 src = fetchurl {
518 url = "https://pypi.python.org/packages/54/a9/9862a561e015b2c7b56404c0b13828a8bdc51e05ab3703bd792cec064487/colander-1.3.3.tar.gz";
492 url = "https://pypi.python.org/packages/cc/e2/c4e716ac4a426d8ad4dfe306c34f0018a22275d2420815784005bf771c84/colander-1.4.tar.gz";
519 md5 = "f5d783768c51d73695f49bbe95778ab4";
493 md5 = "cbb8e403c2ba05aeaa419d51fdb93736";
520 };
494 };
521 meta = {
495 meta = {
522 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
496 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
@@ -588,13 +562,13 b''
588 };
562 };
589 };
563 };
590 decorator = super.buildPythonPackage {
564 decorator = super.buildPythonPackage {
591 name = "decorator-4.0.11";
565 name = "decorator-4.1.2";
592 buildInputs = with self; [];
566 buildInputs = with self; [];
593 doCheck = false;
567 doCheck = false;
594 propagatedBuildInputs = with self; [];
568 propagatedBuildInputs = with self; [];
595 src = fetchurl {
569 src = fetchurl {
596 url = "https://pypi.python.org/packages/cc/ac/5a16f1fc0506ff72fcc8fd4e858e3a1c231f224ab79bb7c4c9b2094cc570/decorator-4.0.11.tar.gz";
570 url = "https://pypi.python.org/packages/bb/e0/f6e41e9091e130bf16d4437dabbac3993908e4d6485ecbc985ef1352db94/decorator-4.1.2.tar.gz";
597 md5 = "73644c8f0bd4983d1b6a34b49adec0ae";
571 md5 = "a0f7f4fe00ae2dde93494d90c192cf8c";
598 };
572 };
599 meta = {
573 meta = {
600 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "new BSD License"; } ];
574 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "new BSD License"; } ];
@@ -614,13 +588,13 b''
614 };
588 };
615 };
589 };
616 docutils = super.buildPythonPackage {
590 docutils = super.buildPythonPackage {
617 name = "docutils-0.13.1";
591 name = "docutils-0.14";
618 buildInputs = with self; [];
592 buildInputs = with self; [];
619 doCheck = false;
593 doCheck = false;
620 propagatedBuildInputs = with self; [];
594 propagatedBuildInputs = with self; [];
621 src = fetchurl {
595 src = fetchurl {
622 url = "https://pypi.python.org/packages/05/25/7b5484aca5d46915493f1fd4ecb63c38c333bd32aa9ad6e19da8d08895ae/docutils-0.13.1.tar.gz";
596 url = "https://pypi.python.org/packages/84/f4/5771e41fdf52aabebbadecc9381d11dea0fa34e4759b4071244fa094804c/docutils-0.14.tar.gz";
623 md5 = "ea4a893c633c788be9b8078b6b305d53";
597 md5 = "c53768d63db3873b7d452833553469de";
624 };
598 };
625 meta = {
599 meta = {
626 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.publicDomain pkgs.lib.licenses.gpl1 { fullName = "public domain, Python, 2-Clause BSD, GPL 3 (see COPYING.txt)"; } pkgs.lib.licenses.psfl ];
600 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.publicDomain pkgs.lib.licenses.gpl1 { fullName = "public domain, Python, 2-Clause BSD, GPL 3 (see COPYING.txt)"; } pkgs.lib.licenses.psfl ];
@@ -783,39 +757,39 b''
783 };
757 };
784 };
758 };
785 gnureadline = super.buildPythonPackage {
759 gnureadline = super.buildPythonPackage {
786 name = "gnureadline-6.3.3";
760 name = "gnureadline-6.3.8";
787 buildInputs = with self; [];
761 buildInputs = with self; [];
788 doCheck = false;
762 doCheck = false;
789 propagatedBuildInputs = with self; [];
763 propagatedBuildInputs = with self; [];
790 src = fetchurl {
764 src = fetchurl {
791 url = "https://pypi.python.org/packages/3a/ee/2c3f568b0a74974791ac590ec742ef6133e2fbd287a074ba72a53fa5e97c/gnureadline-6.3.3.tar.gz";
765 url = "https://pypi.python.org/packages/50/64/86085c823cd78f9df9d8e33dce0baa71618016f8860460b82cf6610e1eb3/gnureadline-6.3.8.tar.gz";
792 md5 = "c4af83c9a3fbeac8f2da9b5a7c60e51c";
766 md5 = "ba341f4b907250bd1f47dbc06290604f";
793 };
767 };
794 meta = {
768 meta = {
795 license = [ pkgs.lib.licenses.gpl1 ];
769 license = [ { fullName = "GNU General Public License v3 (GPLv3)"; } pkgs.lib.licenses.gpl1 ];
796 };
770 };
797 };
771 };
798 gprof2dot = super.buildPythonPackage {
772 gprof2dot = super.buildPythonPackage {
799 name = "gprof2dot-2016.10.13";
773 name = "gprof2dot-2017.9.19";
800 buildInputs = with self; [];
774 buildInputs = with self; [];
801 doCheck = false;
775 doCheck = false;
802 propagatedBuildInputs = with self; [];
776 propagatedBuildInputs = with self; [];
803 src = fetchurl {
777 src = fetchurl {
804 url = "https://pypi.python.org/packages/a0/e0/73c71baed306f0402a00a94ffc7b2be94ad1296dfcb8b46912655b93154c/gprof2dot-2016.10.13.tar.gz";
778 url = "https://pypi.python.org/packages/9d/36/f977122502979f3dfb50704979c9ed70e6b620787942b089bf1af15f5aba/gprof2dot-2017.9.19.tar.gz";
805 md5 = "0125401f15fd2afe1df686a76c64a4fd";
779 md5 = "cda2d552bb0d0b9f16e6824a9aabd225";
806 };
780 };
807 meta = {
781 meta = {
808 license = [ { fullName = "LGPL"; } ];
782 license = [ { fullName = "GNU Lesser General Public License v3 or later (LGPLv3+)"; } { fullName = "LGPL"; } ];
809 };
783 };
810 };
784 };
811 graphviz = super.buildPythonPackage {
785 graphviz = super.buildPythonPackage {
812 name = "graphviz-0.8";
786 name = "graphviz-0.8.1";
813 buildInputs = with self; [];
787 buildInputs = with self; [];
814 doCheck = false;
788 doCheck = false;
815 propagatedBuildInputs = with self; [];
789 propagatedBuildInputs = with self; [];
816 src = fetchurl {
790 src = fetchurl {
817 url = "https://pypi.python.org/packages/da/84/0e997520323d6b01124eb01c68d5c101814d0aab53083cd62bd75a90f70b/graphviz-0.8.zip";
791 url = "https://pypi.python.org/packages/a9/a6/ee6721349489a2da6eedd3dba124f2b5ac15ee1e0a7bd4d3cfdc4fff0327/graphviz-0.8.1.zip";
818 md5 = "9486a885360a5ee54a81eb2950470c71";
792 md5 = "88d8efa88c02a735b3659fe0feaf0b96";
819 };
793 };
820 meta = {
794 meta = {
821 license = [ pkgs.lib.licenses.mit ];
795 license = [ pkgs.lib.licenses.mit ];
@@ -848,13 +822,13 b''
848 };
822 };
849 };
823 };
850 html5lib = super.buildPythonPackage {
824 html5lib = super.buildPythonPackage {
851 name = "html5lib-0.9999999";
825 name = "html5lib-1.0b10";
852 buildInputs = with self; [];
826 buildInputs = with self; [];
853 doCheck = false;
827 doCheck = false;
854 propagatedBuildInputs = with self; [six];
828 propagatedBuildInputs = with self; [six webencodings setuptools];
855 src = fetchurl {
829 src = fetchurl {
856 url = "https://pypi.python.org/packages/ae/ae/bcb60402c60932b32dfaf19bb53870b29eda2cd17551ba5639219fb5ebf9/html5lib-0.9999999.tar.gz";
830 url = "https://pypi.python.org/packages/97/16/982214624095c1420c75f3bd295d9e658794aafb95fc075823de107e0ae4/html5lib-1.0b10.tar.gz";
857 md5 = "ef43cb05e9e799f25d65d1135838a96f";
831 md5 = "5ada1243b7a863624b2f35245b2186e9";
858 };
832 };
859 meta = {
833 meta = {
860 license = [ pkgs.lib.licenses.mit ];
834 license = [ pkgs.lib.licenses.mit ];
@@ -952,13 +926,13 b''
952 };
926 };
953 };
927 };
954 iso8601 = super.buildPythonPackage {
928 iso8601 = super.buildPythonPackage {
955 name = "iso8601-0.1.11";
929 name = "iso8601-0.1.12";
956 buildInputs = with self; [];
930 buildInputs = with self; [];
957 doCheck = false;
931 doCheck = false;
958 propagatedBuildInputs = with self; [];
932 propagatedBuildInputs = with self; [];
959 src = fetchurl {
933 src = fetchurl {
960 url = "https://pypi.python.org/packages/c0/75/c9209ee4d1b5975eb8c2cba4428bde6b61bd55664a98290dd015cdb18e98/iso8601-0.1.11.tar.gz";
934 url = "https://pypi.python.org/packages/45/13/3db24895497345fb44c4248c08b16da34a9eb02643cea2754b21b5ed08b0/iso8601-0.1.12.tar.gz";
961 md5 = "b06d11cd14a64096f907086044f0fe38";
935 md5 = "4de940f691c5ea759fb254384c8ddcf6";
962 };
936 };
963 meta = {
937 meta = {
964 license = [ pkgs.lib.licenses.mit ];
938 license = [ pkgs.lib.licenses.mit ];
@@ -1004,26 +978,26 b''
1004 };
978 };
1005 };
979 };
1006 jupyter-core = super.buildPythonPackage {
980 jupyter-core = super.buildPythonPackage {
1007 name = "jupyter-core-4.3.0";
981 name = "jupyter-core-4.4.0";
1008 buildInputs = with self; [];
982 buildInputs = with self; [];
1009 doCheck = false;
983 doCheck = false;
1010 propagatedBuildInputs = with self; [traitlets];
984 propagatedBuildInputs = with self; [traitlets];
1011 src = fetchurl {
985 src = fetchurl {
1012 url = "https://pypi.python.org/packages/2f/39/5138f975100ce14d150938df48a83cd852a3fd8e24b1244f4113848e69e2/jupyter_core-4.3.0.tar.gz";
986 url = "https://pypi.python.org/packages/b6/2d/2804f4de3a95583f65e5dcb4d7c8c7183124882323758996e867f47e72af/jupyter_core-4.4.0.tar.gz";
1013 md5 = "18819511a809afdeed9a995a9c27bcfb";
987 md5 = "7829fc07884ed98459e170f217e2a5ba";
1014 };
988 };
1015 meta = {
989 meta = {
1016 license = [ pkgs.lib.licenses.bsdOriginal ];
990 license = [ pkgs.lib.licenses.bsdOriginal ];
1017 };
991 };
1018 };
992 };
1019 kombu = super.buildPythonPackage {
993 kombu = super.buildPythonPackage {
1020 name = "kombu-1.5.1";
994 name = "kombu-4.1.0";
1021 buildInputs = with self; [];
995 buildInputs = with self; [];
1022 doCheck = false;
996 doCheck = false;
1023 propagatedBuildInputs = with self; [anyjson amqplib];
997 propagatedBuildInputs = with self; [amqp];
1024 src = fetchurl {
998 src = fetchurl {
1025 url = "https://pypi.python.org/packages/19/53/74bf2a624644b45f0850a638752514fc10a8e1cbd738f10804951a6df3f5/kombu-1.5.1.tar.gz";
999 url = "https://pypi.python.org/packages/03/5e/1a47d1e543d4943d65330af4e4406049f443878818fb65bfdc651bb93a96/kombu-4.1.0.tar.gz";
1026 md5 = "50662f3c7e9395b3d0721fb75d100b63";
1000 md5 = "2fb2be9fec0e6514231bba23a3779439";
1027 };
1001 };
1028 meta = {
1002 meta = {
1029 license = [ pkgs.lib.licenses.bsdOriginal ];
1003 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -1056,13 +1030,13 b''
1056 };
1030 };
1057 };
1031 };
1058 mistune = super.buildPythonPackage {
1032 mistune = super.buildPythonPackage {
1059 name = "mistune-0.7.4";
1033 name = "mistune-0.8.3";
1060 buildInputs = with self; [];
1034 buildInputs = with self; [];
1061 doCheck = false;
1035 doCheck = false;
1062 propagatedBuildInputs = with self; [];
1036 propagatedBuildInputs = with self; [];
1063 src = fetchurl {
1037 src = fetchurl {
1064 url = "https://pypi.python.org/packages/25/a4/12a584c0c59c9fed529f8b3c47ca8217c0cf8bcc5e1089d3256410cfbdbc/mistune-0.7.4.tar.gz";
1038 url = "https://pypi.python.org/packages/9d/be/e06d4346cc608a01dec6bf770d7d0303a4fd6db588b318ced18f5f257145/mistune-0.8.3.tar.gz";
1065 md5 = "92d01cb717e9e74429e9bde9d29ac43b";
1039 md5 = "a5e4043e93fb8f9082e27f29eeb5e054";
1066 };
1040 };
1067 meta = {
1041 meta = {
1068 license = [ pkgs.lib.licenses.bsdOriginal ];
1042 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -1095,52 +1069,39 b''
1095 };
1069 };
1096 };
1070 };
1097 nbconvert = super.buildPythonPackage {
1071 nbconvert = super.buildPythonPackage {
1098 name = "nbconvert-5.1.1";
1072 name = "nbconvert-5.3.1";
1099 buildInputs = with self; [];
1073 buildInputs = with self; [];
1100 doCheck = false;
1074 doCheck = false;
1101 propagatedBuildInputs = with self; [mistune Jinja2 Pygments traitlets jupyter-core nbformat entrypoints bleach pandocfilters testpath];
1075 propagatedBuildInputs = with self; [mistune Jinja2 Pygments traitlets jupyter-core nbformat entrypoints bleach pandocfilters testpath];
1102 src = fetchurl {
1076 src = fetchurl {
1103 url = "https://pypi.python.org/packages/95/58/df1c91f1658ee5df19097f915a1e71c91fc824a708d82d2b2e35f8b80e9a/nbconvert-5.1.1.tar.gz";
1077 url = "https://pypi.python.org/packages/b9/a4/d0a0938ad6f5eeb4dea4e73d255c617ef94b0b2849d51194c9bbdb838412/nbconvert-5.3.1.tar.gz";
1104 md5 = "d0263fb03a44db2f94eea09a608ed813";
1078 md5 = "c128d0d93d02f70a85429a383dae96d2";
1105 };
1079 };
1106 meta = {
1080 meta = {
1107 license = [ pkgs.lib.licenses.bsdOriginal ];
1081 license = [ pkgs.lib.licenses.bsdOriginal ];
1108 };
1082 };
1109 };
1083 };
1110 nbformat = super.buildPythonPackage {
1084 nbformat = super.buildPythonPackage {
1111 name = "nbformat-4.3.0";
1085 name = "nbformat-4.4.0";
1112 buildInputs = with self; [];
1086 buildInputs = with self; [];
1113 doCheck = false;
1087 doCheck = false;
1114 propagatedBuildInputs = with self; [ipython-genutils traitlets jsonschema jupyter-core];
1088 propagatedBuildInputs = with self; [ipython-genutils traitlets jsonschema jupyter-core];
1115 src = fetchurl {
1089 src = fetchurl {
1116 url = "https://pypi.python.org/packages/f9/c5/89df4abf906f766727f976e170caa85b4f1c1d1feb1f45d716016e68e19f/nbformat-4.3.0.tar.gz";
1090 url = "https://pypi.python.org/packages/6e/0e/160754f7ae3e984863f585a3743b0ed1702043a81245907c8fae2d537155/nbformat-4.4.0.tar.gz";
1117 md5 = "9a00d20425914cd5ba5f97769d9963ca";
1091 md5 = "2d5f873138d9fbc2a3f9eaaebca3b8a1";
1118 };
1092 };
1119 meta = {
1093 meta = {
1120 license = [ pkgs.lib.licenses.bsdOriginal ];
1094 license = [ pkgs.lib.licenses.bsdOriginal ];
1121 };
1095 };
1122 };
1096 };
1123 nose = super.buildPythonPackage {
1124 name = "nose-1.3.6";
1125 buildInputs = with self; [];
1126 doCheck = false;
1127 propagatedBuildInputs = with self; [];
1128 src = fetchurl {
1129 url = "https://pypi.python.org/packages/70/c7/469e68148d17a0d3db5ed49150242fd70a74a8147b8f3f8b87776e028d99/nose-1.3.6.tar.gz";
1130 md5 = "0ca546d81ca8309080fc80cb389e7a16";
1131 };
1132 meta = {
1133 license = [ { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "GNU LGPL"; } ];
1134 };
1135 };
1136 objgraph = super.buildPythonPackage {
1097 objgraph = super.buildPythonPackage {
1137 name = "objgraph-3.1.0";
1098 name = "objgraph-3.1.1";
1138 buildInputs = with self; [];
1099 buildInputs = with self; [];
1139 doCheck = false;
1100 doCheck = false;
1140 propagatedBuildInputs = with self; [graphviz];
1101 propagatedBuildInputs = with self; [graphviz];
1141 src = fetchurl {
1102 src = fetchurl {
1142 url = "https://pypi.python.org/packages/f4/b3/082e54e62094cb2ec84f8d5a49e0142cef99016491cecba83309cff920ae/objgraph-3.1.0.tar.gz";
1103 url = "https://pypi.python.org/packages/be/58/9ca81a20cc837054e94866df1475d899caaa94f3732b8a46006858b015f7/objgraph-3.1.1.tar.gz";
1143 md5 = "eddbd96039796bfbd13eee403701e64a";
1104 md5 = "253af9944763377877c3678d8aaebb8b";
1144 };
1105 };
1145 meta = {
1106 meta = {
1146 license = [ pkgs.lib.licenses.mit ];
1107 license = [ pkgs.lib.licenses.mit ];
@@ -1199,13 +1160,13 b''
1199 };
1160 };
1200 };
1161 };
1201 pexpect = super.buildPythonPackage {
1162 pexpect = super.buildPythonPackage {
1202 name = "pexpect-4.2.1";
1163 name = "pexpect-4.3.0";
1203 buildInputs = with self; [];
1164 buildInputs = with self; [];
1204 doCheck = false;
1165 doCheck = false;
1205 propagatedBuildInputs = with self; [ptyprocess];
1166 propagatedBuildInputs = with self; [ptyprocess];
1206 src = fetchurl {
1167 src = fetchurl {
1207 url = "https://pypi.python.org/packages/e8/13/d0b0599099d6cd23663043a2a0bb7c61e58c6ba359b2656e6fb000ef5b98/pexpect-4.2.1.tar.gz";
1168 url = "https://pypi.python.org/packages/f8/44/5466c30e49762bb92e442bbdf4472d6904608d211258eb3198a11f0309a4/pexpect-4.3.0.tar.gz";
1208 md5 = "3694410001a99dff83f0b500a1ca1c95";
1169 md5 = "047a486dcd26134b74f2e67046bb61a0";
1209 };
1170 };
1210 meta = {
1171 meta = {
1211 license = [ pkgs.lib.licenses.isc { fullName = "ISC License (ISCL)"; } ];
1172 license = [ pkgs.lib.licenses.isc { fullName = "ISC License (ISCL)"; } ];
@@ -1225,26 +1186,26 b''
1225 };
1186 };
1226 };
1187 };
1227 plaster = super.buildPythonPackage {
1188 plaster = super.buildPythonPackage {
1228 name = "plaster-0.5";
1189 name = "plaster-1.0";
1229 buildInputs = with self; [];
1190 buildInputs = with self; [];
1230 doCheck = false;
1191 doCheck = false;
1231 propagatedBuildInputs = with self; [setuptools];
1192 propagatedBuildInputs = with self; [setuptools];
1232 src = fetchurl {
1193 src = fetchurl {
1233 url = "https://pypi.python.org/packages/99/b3/d7ca1fe31d2b56dba68a238721fda6820770f9c2a3de17a582d4b5b2edcc/plaster-0.5.tar.gz";
1194 url = "https://pypi.python.org/packages/37/e1/56d04382d718d32751017d32f351214384e529b794084eee20bb52405563/plaster-1.0.tar.gz";
1234 md5 = "c59345a67a860cfcaa1bd6a81451399d";
1195 md5 = "80e6beb4760c16fea31754babcc0576e";
1235 };
1196 };
1236 meta = {
1197 meta = {
1237 license = [ pkgs.lib.licenses.mit ];
1198 license = [ pkgs.lib.licenses.mit ];
1238 };
1199 };
1239 };
1200 };
1240 plaster-pastedeploy = super.buildPythonPackage {
1201 plaster-pastedeploy = super.buildPythonPackage {
1241 name = "plaster-pastedeploy-0.4.1";
1202 name = "plaster-pastedeploy-0.4.2";
1242 buildInputs = with self; [];
1203 buildInputs = with self; [];
1243 doCheck = false;
1204 doCheck = false;
1244 propagatedBuildInputs = with self; [PasteDeploy plaster];
1205 propagatedBuildInputs = with self; [PasteDeploy plaster];
1245 src = fetchurl {
1206 src = fetchurl {
1246 url = "https://pypi.python.org/packages/9d/6e/f8be01ed41c94e6c54ac97cf2eb142a702aae0c8cce31c846f785e525b40/plaster_pastedeploy-0.4.1.tar.gz";
1207 url = "https://pypi.python.org/packages/2c/62/0daf9c0be958e785023e583e51baac15863699e956bfb3d448898d80edd8/plaster_pastedeploy-0.4.2.tar.gz";
1247 md5 = "f48d5344b922e56c4978eebf1cd2e0d3";
1208 md5 = "58fd7852002909378e818c9d5b71e90a";
1248 };
1209 };
1249 meta = {
1210 meta = {
1250 license = [ pkgs.lib.licenses.mit ];
1211 license = [ pkgs.lib.licenses.mit ];
@@ -1264,26 +1225,26 b''
1264 };
1225 };
1265 };
1226 };
1266 psutil = super.buildPythonPackage {
1227 psutil = super.buildPythonPackage {
1267 name = "psutil-4.3.1";
1228 name = "psutil-5.4.0";
1268 buildInputs = with self; [];
1229 buildInputs = with self; [];
1269 doCheck = false;
1230 doCheck = false;
1270 propagatedBuildInputs = with self; [];
1231 propagatedBuildInputs = with self; [];
1271 src = fetchurl {
1232 src = fetchurl {
1272 url = "https://pypi.python.org/packages/78/cc/f267a1371f229bf16db6a4e604428c3b032b823b83155bd33cef45e49a53/psutil-4.3.1.tar.gz";
1233 url = "https://pypi.python.org/packages/8d/96/1fc6468be91521192861966c40bd73fdf8b065eae6d82dd0f870b9825a65/psutil-5.4.0.tar.gz";
1273 md5 = "199a366dba829c88bddaf5b41d19ddc0";
1234 md5 = "01af6219b1e8fcfd53603023967713bf";
1274 };
1235 };
1275 meta = {
1236 meta = {
1276 license = [ pkgs.lib.licenses.bsdOriginal ];
1237 license = [ pkgs.lib.licenses.bsdOriginal ];
1277 };
1238 };
1278 };
1239 };
1279 psycopg2 = super.buildPythonPackage {
1240 psycopg2 = super.buildPythonPackage {
1280 name = "psycopg2-2.7.1";
1241 name = "psycopg2-2.7.3.2";
1281 buildInputs = with self; [];
1242 buildInputs = with self; [];
1282 doCheck = false;
1243 doCheck = false;
1283 propagatedBuildInputs = with self; [];
1244 propagatedBuildInputs = with self; [];
1284 src = fetchurl {
1245 src = fetchurl {
1285 url = "https://pypi.python.org/packages/f8/e9/5793369ce8a41bf5467623ded8d59a434dfef9c136351aca4e70c2657ba0/psycopg2-2.7.1.tar.gz";
1246 url = "https://pypi.python.org/packages/dd/47/000b405d73ca22980684fd7bd3318690cc03cfa3b2ae1c5b7fff8050b28a/psycopg2-2.7.3.2.tar.gz";
1286 md5 = "67848ac33af88336046802f6ef7081f3";
1247 md5 = "8114e672d5f23fa5329874a4314fbd6f";
1287 };
1248 };
1288 meta = {
1249 meta = {
1289 license = [ pkgs.lib.licenses.zpt21 { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "LGPL with exceptions or ZPL"; } ];
1250 license = [ pkgs.lib.licenses.zpt21 { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "LGPL with exceptions or ZPL"; } ];
@@ -1303,13 +1264,13 b''
1303 };
1264 };
1304 };
1265 };
1305 py = super.buildPythonPackage {
1266 py = super.buildPythonPackage {
1306 name = "py-1.4.34";
1267 name = "py-1.5.2";
1307 buildInputs = with self; [];
1268 buildInputs = with self; [];
1308 doCheck = false;
1269 doCheck = false;
1309 propagatedBuildInputs = with self; [];
1270 propagatedBuildInputs = with self; [];
1310 src = fetchurl {
1271 src = fetchurl {
1311 url = "https://pypi.python.org/packages/68/35/58572278f1c097b403879c1e9369069633d1cbad5239b9057944bb764782/py-1.4.34.tar.gz";
1272 url = "https://pypi.python.org/packages/90/e3/e075127d39d35f09a500ebb4a90afd10f9ef0a1d28a6d09abeec0e444fdd/py-1.5.2.tar.gz";
1312 md5 = "d9c3d8f734b0819ff48e355d77bf1730";
1273 md5 = "279ca69c632069e1b71e11b14641ca28";
1313 };
1274 };
1314 meta = {
1275 meta = {
1315 license = [ pkgs.lib.licenses.mit ];
1276 license = [ pkgs.lib.licenses.mit ];
@@ -1334,8 +1295,8 b''
1334 doCheck = false;
1295 doCheck = false;
1335 propagatedBuildInputs = with self; [setuptools Markdown];
1296 propagatedBuildInputs = with self; [setuptools Markdown];
1336 src = fetchurl {
1297 src = fetchurl {
1337 url = "https://code.rhodecode.com/upstream/py-gfm/archive/0d66a19bc16e3d49de273c0f797d4e4781e8c0f2.tar.gz?md5=0d0d5385bfb629eea636a80b9c2bfd16";
1298 url = "https://pypi.python.org/packages/12/e4/6b3d8678da04f97d7490d8264d8de51c2dc9fb91209ccee9c515c95e14c5/py-gfm-0.1.3.tar.gz";
1338 md5 = "0d0d5385bfb629eea636a80b9c2bfd16";
1299 md5 = "e588d9e69640a241b97e2c59c22527a6";
1339 };
1300 };
1340 meta = {
1301 meta = {
1341 license = [ pkgs.lib.licenses.bsdOriginal ];
1302 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -1433,26 +1394,26 b''
1433 };
1394 };
1434 };
1395 };
1435 pyramid-debugtoolbar = super.buildPythonPackage {
1396 pyramid-debugtoolbar = super.buildPythonPackage {
1436 name = "pyramid-debugtoolbar-4.2.1";
1397 name = "pyramid-debugtoolbar-4.3";
1437 buildInputs = with self; [];
1398 buildInputs = with self; [];
1438 doCheck = false;
1399 doCheck = false;
1439 propagatedBuildInputs = with self; [pyramid pyramid-mako repoze.lru Pygments ipaddress];
1400 propagatedBuildInputs = with self; [pyramid pyramid-mako repoze.lru Pygments ipaddress];
1440 src = fetchurl {
1401 src = fetchurl {
1441 url = "https://pypi.python.org/packages/db/26/94620b7752936e2cd74838263ff366db9b454f7394bfb62d1eb2f84b29c1/pyramid_debugtoolbar-4.2.1.tar.gz";
1402 url = "https://pypi.python.org/packages/a4/40/f09d8800bfc3c09bdb6c95f37bb61c890dc62c19c4e7caa304da7aa77403/pyramid_debugtoolbar-4.3.tar.gz";
1442 md5 = "3dfaced2fab1644ff5284017be9d92b9";
1403 md5 = "9c49029e9f0695130499ef6416ffaaf8";
1443 };
1404 };
1444 meta = {
1405 meta = {
1445 license = [ { fullName = "Repoze Public License"; } pkgs.lib.licenses.bsdOriginal ];
1406 license = [ { fullName = "Repoze Public License"; } pkgs.lib.licenses.bsdOriginal ];
1446 };
1407 };
1447 };
1408 };
1448 pyramid-jinja2 = super.buildPythonPackage {
1409 pyramid-jinja2 = super.buildPythonPackage {
1449 name = "pyramid-jinja2-2.5";
1410 name = "pyramid-jinja2-2.7";
1450 buildInputs = with self; [];
1411 buildInputs = with self; [];
1451 doCheck = false;
1412 doCheck = false;
1452 propagatedBuildInputs = with self; [pyramid zope.deprecation Jinja2 MarkupSafe];
1413 propagatedBuildInputs = with self; [pyramid zope.deprecation Jinja2 MarkupSafe];
1453 src = fetchurl {
1414 src = fetchurl {
1454 url = "https://pypi.python.org/packages/a1/80/595e26ffab7deba7208676b6936b7e5a721875710f982e59899013cae1ed/pyramid_jinja2-2.5.tar.gz";
1415 url = "https://pypi.python.org/packages/d8/80/d60a7233823de22ce77bd864a8a83736a1fe8b49884b08303a2e68b2c853/pyramid_jinja2-2.7.tar.gz";
1455 md5 = "07cb6547204ac5e6f0b22a954ccee928";
1416 md5 = "c2f8b2cd7b73a6f1d9a311fcfaf4fb92";
1456 };
1417 };
1457 meta = {
1418 meta = {
1458 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1419 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
@@ -1485,13 +1446,13 b''
1485 };
1446 };
1486 };
1447 };
1487 pytest = super.buildPythonPackage {
1448 pytest = super.buildPythonPackage {
1488 name = "pytest-3.1.2";
1449 name = "pytest-3.2.5";
1489 buildInputs = with self; [];
1450 buildInputs = with self; [];
1490 doCheck = false;
1451 doCheck = false;
1491 propagatedBuildInputs = with self; [py setuptools];
1452 propagatedBuildInputs = with self; [py setuptools];
1492 src = fetchurl {
1453 src = fetchurl {
1493 url = "https://pypi.python.org/packages/72/2b/2d3155e01f45a5a04427857352ee88220ee39550b2bc078f9db3190aea46/pytest-3.1.2.tar.gz";
1454 url = "https://pypi.python.org/packages/1f/f8/8cd74c16952163ce0db0bd95fdd8810cbf093c08be00e6e665ebf0dc3138/pytest-3.2.5.tar.gz";
1494 md5 = "c4d179f89043cc925e1c169d03128e02";
1455 md5 = "6dbe9bb093883f75394a689a1426ac6f";
1495 };
1456 };
1496 meta = {
1457 meta = {
1497 license = [ pkgs.lib.licenses.mit ];
1458 license = [ pkgs.lib.licenses.mit ];
@@ -1524,39 +1485,39 b''
1524 };
1485 };
1525 };
1486 };
1526 pytest-profiling = super.buildPythonPackage {
1487 pytest-profiling = super.buildPythonPackage {
1527 name = "pytest-profiling-1.2.6";
1488 name = "pytest-profiling-1.2.11";
1528 buildInputs = with self; [];
1489 buildInputs = with self; [];
1529 doCheck = false;
1490 doCheck = false;
1530 propagatedBuildInputs = with self; [six pytest gprof2dot];
1491 propagatedBuildInputs = with self; [six pytest gprof2dot];
1531 src = fetchurl {
1492 src = fetchurl {
1532 url = "https://pypi.python.org/packages/f9/0d/df67fb9ce16c2cef201693da956321b1bccfbf9a4ead39748b9f9d1d74cb/pytest-profiling-1.2.6.tar.gz";
1493 url = "https://pypi.python.org/packages/c0/4a/b4aa786e93c07a86f1f87c581a36bf355a9e06a9da7e00dbd05047626bd2/pytest-profiling-1.2.11.tar.gz";
1533 md5 = "50eb4c66c3762a2f1a49669bedc0b894";
1494 md5 = "9ef6b60248731be5d44477980408e8f7";
1534 };
1495 };
1535 meta = {
1496 meta = {
1536 license = [ pkgs.lib.licenses.mit ];
1497 license = [ pkgs.lib.licenses.mit ];
1537 };
1498 };
1538 };
1499 };
1539 pytest-runner = super.buildPythonPackage {
1500 pytest-runner = super.buildPythonPackage {
1540 name = "pytest-runner-2.11.1";
1501 name = "pytest-runner-3.0";
1541 buildInputs = with self; [];
1502 buildInputs = with self; [];
1542 doCheck = false;
1503 doCheck = false;
1543 propagatedBuildInputs = with self; [];
1504 propagatedBuildInputs = with self; [];
1544 src = fetchurl {
1505 src = fetchurl {
1545 url = "https://pypi.python.org/packages/9e/4d/08889e5e27a9f5d6096b9ad257f4dea1faabb03c5ded8f665ead448f5d8a/pytest-runner-2.11.1.tar.gz";
1506 url = "https://pypi.python.org/packages/65/b4/ae89338cd2d81e2cc54bd6db2e962bfe948f612303610d68ab24539ac2d1/pytest-runner-3.0.tar.gz";
1546 md5 = "bdb73eb18eca2727944a2dcf963c5a81";
1507 md5 = "8f8363a52bbabc4cedd5e239beb2ba11";
1547 };
1508 };
1548 meta = {
1509 meta = {
1549 license = [ pkgs.lib.licenses.mit ];
1510 license = [ pkgs.lib.licenses.mit ];
1550 };
1511 };
1551 };
1512 };
1552 pytest-sugar = super.buildPythonPackage {
1513 pytest-sugar = super.buildPythonPackage {
1553 name = "pytest-sugar-0.8.0";
1514 name = "pytest-sugar-0.9.0";
1554 buildInputs = with self; [];
1515 buildInputs = with self; [];
1555 doCheck = false;
1516 doCheck = false;
1556 propagatedBuildInputs = with self; [pytest termcolor];
1517 propagatedBuildInputs = with self; [pytest termcolor];
1557 src = fetchurl {
1518 src = fetchurl {
1558 url = "https://pypi.python.org/packages/a5/b0/b2773dee078f17773a5bf2dfad49b0be57b6354bbd84bbefe4313e509d87/pytest-sugar-0.8.0.tar.gz";
1519 url = "https://pypi.python.org/packages/49/d8/c5ff6cca3ce2ebd8b73eec89779bf6b4a7737456a70e8ea4d44c1ff90f71/pytest-sugar-0.9.0.tar.gz";
1559 md5 = "8cafbdad648068e0e44b8fc5f9faae42";
1520 md5 = "89fbff17277fa6a95a560a04b68cb9f9";
1560 };
1521 };
1561 meta = {
1522 meta = {
1562 license = [ pkgs.lib.licenses.bsdOriginal ];
1523 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -1576,16 +1537,16 b''
1576 };
1537 };
1577 };
1538 };
1578 python-dateutil = super.buildPythonPackage {
1539 python-dateutil = super.buildPythonPackage {
1579 name = "python-dateutil-2.1";
1540 name = "python-dateutil-2.6.1";
1580 buildInputs = with self; [];
1541 buildInputs = with self; [];
1581 doCheck = false;
1542 doCheck = false;
1582 propagatedBuildInputs = with self; [six];
1543 propagatedBuildInputs = with self; [six];
1583 src = fetchurl {
1544 src = fetchurl {
1584 url = "https://pypi.python.org/packages/65/52/9c18dac21f174ad31b65e22d24297864a954e6fe65876eba3f5773d2da43/python-dateutil-2.1.tar.gz";
1545 url = "https://pypi.python.org/packages/54/bb/f1db86504f7a49e1d9b9301531181b00a1c7325dc85a29160ee3eaa73a54/python-dateutil-2.6.1.tar.gz";
1585 md5 = "1534bb15cf311f07afaa3aacba1c028b";
1546 md5 = "db38f6b4511cefd76014745bb0cc45a4";
1586 };
1547 };
1587 meta = {
1548 meta = {
1588 license = [ { fullName = "Simplified BSD"; } ];
1549 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "Simplified BSD"; } ];
1589 };
1550 };
1590 };
1551 };
1591 python-editor = super.buildPythonPackage {
1552 python-editor = super.buildPythonPackage {
@@ -1602,13 +1563,13 b''
1602 };
1563 };
1603 };
1564 };
1604 python-ldap = super.buildPythonPackage {
1565 python-ldap = super.buildPythonPackage {
1605 name = "python-ldap-2.4.40";
1566 name = "python-ldap-2.4.45";
1606 buildInputs = with self; [];
1567 buildInputs = with self; [];
1607 doCheck = false;
1568 doCheck = false;
1608 propagatedBuildInputs = with self; [setuptools];
1569 propagatedBuildInputs = with self; [setuptools];
1609 src = fetchurl {
1570 src = fetchurl {
1610 url = "https://pypi.python.org/packages/4a/d8/7d70a7469058a3987d224061a81d778951ac2b48220bdcc511e4b1b37176/python-ldap-2.4.40.tar.gz";
1571 url = "https://pypi.python.org/packages/ce/52/6b5372d0166820f4a4b0a88ed73dc7504219355049fc1d266d8ccdb7942e/python-ldap-2.4.45.tar.gz";
1611 md5 = "aea0233f7d39b0c7549fcd310deeb0e5";
1572 md5 = "6108e189a44eea8bc7d1cc281c222978";
1612 };
1573 };
1613 meta = {
1574 meta = {
1614 license = [ pkgs.lib.licenses.psfl ];
1575 license = [ pkgs.lib.licenses.psfl ];
@@ -1641,13 +1602,13 b''
1641 };
1602 };
1642 };
1603 };
1643 pytz = super.buildPythonPackage {
1604 pytz = super.buildPythonPackage {
1644 name = "pytz-2015.4";
1605 name = "pytz-2017.3";
1645 buildInputs = with self; [];
1606 buildInputs = with self; [];
1646 doCheck = false;
1607 doCheck = false;
1647 propagatedBuildInputs = with self; [];
1608 propagatedBuildInputs = with self; [];
1648 src = fetchurl {
1609 src = fetchurl {
1649 url = "https://pypi.python.org/packages/7e/1a/f43b5c92df7b156822030fed151327ea096bcf417e45acc23bd1df43472f/pytz-2015.4.zip";
1610 url = "https://pypi.python.org/packages/60/88/d3152c234da4b2a1f7a989f89609ea488225eaea015bc16fbde2b3fdfefa/pytz-2017.3.zip";
1650 md5 = "233f2a2b370d03f9b5911700cc9ebf3c";
1611 md5 = "7006b56c0d68a162d9fe57d4249c3171";
1651 };
1612 };
1652 meta = {
1613 meta = {
1653 license = [ pkgs.lib.licenses.mit ];
1614 license = [ pkgs.lib.licenses.mit ];
@@ -1693,13 +1654,13 b''
1693 };
1654 };
1694 };
1655 };
1695 repoze.lru = super.buildPythonPackage {
1656 repoze.lru = super.buildPythonPackage {
1696 name = "repoze.lru-0.6";
1657 name = "repoze.lru-0.7";
1697 buildInputs = with self; [];
1658 buildInputs = with self; [];
1698 doCheck = false;
1659 doCheck = false;
1699 propagatedBuildInputs = with self; [];
1660 propagatedBuildInputs = with self; [];
1700 src = fetchurl {
1661 src = fetchurl {
1701 url = "https://pypi.python.org/packages/6e/1e/aa15cc90217e086dc8769872c8778b409812ff036bf021b15795638939e4/repoze.lru-0.6.tar.gz";
1662 url = "https://pypi.python.org/packages/12/bc/595a77c4b5e204847fdf19268314ef59c85193a9dc9f83630fc459c0fee5/repoze.lru-0.7.tar.gz";
1702 md5 = "2c3b64b17a8e18b405f55d46173e14dd";
1663 md5 = "c08cc030387e0b1fc53c5c7d964b35e2";
1703 };
1664 };
1704 meta = {
1665 meta = {
1705 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1666 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
@@ -1719,49 +1680,49 b''
1719 };
1680 };
1720 };
1681 };
1721 rhodecode-enterprise-ce = super.buildPythonPackage {
1682 rhodecode-enterprise-ce = super.buildPythonPackage {
1722 name = "rhodecode-enterprise-ce-4.10.6";
1683 name = "rhodecode-enterprise-ce-4.11.0";
1723 buildInputs = with self; [pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage configobj];
1684 buildInputs = with self; [pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage configobj];
1724 doCheck = true;
1685 doCheck = true;
1725 propagatedBuildInputs = with self; [Babel Beaker FormEncode Mako Markdown MarkupSafe MySQL-python Paste PasteDeploy PasteScript Pygments pygments-markdown-lexer Pylons Routes SQLAlchemy Tempita URLObject WebError WebHelpers WebHelpers2 WebOb WebTest Whoosh alembic amqplib anyjson appenlight-client authomatic cssselect celery channelstream colander decorator deform docutils gevent gunicorn infrae.cache ipython iso8601 kombu lxml msgpack-python nbconvert packaging psycopg2 py-gfm pycrypto pycurl pyparsing pyramid pyramid-debugtoolbar pyramid-mako pyramid-beaker pysqlite python-dateutil python-ldap python-memcached python-pam recaptcha-client redis repoze.lru requests simplejson sshpubkeys subprocess32 waitress zope.cachedescriptors dogpile.cache dogpile.core psutil py-bcrypt];
1686 propagatedBuildInputs = with self; [setuptools-scm amqp authomatic Babel Beaker celery Chameleon channelstream click colander configobj cssselect decorator deform docutils dogpile.cache dogpile.core ecdsa FormEncode future futures gnureadline infrae.cache iso8601 itsdangerous Jinja2 billiard kombu lxml Mako Markdown MarkupSafe msgpack-python MySQL-python objgraph packaging Paste PasteDeploy PasteScript pathlib2 peppercorn psutil psycopg2 py-bcrypt pycrypto pycurl pyflakes pygments-markdown-lexer Pygments pyparsing pyramid-beaker pyramid-debugtoolbar pyramid-jinja2 pyramid-mako pyramid pysqlite python-dateutil python-ldap python-memcached python-pam pytz pyzmq py-gfm recaptcha-client redis repoze.lru requests Routes setproctitle simplejson six SQLAlchemy sshpubkeys subprocess32 supervisor Tempita translationstring trollius urllib3 URLObject venusian WebError WebHelpers2 WebHelpers WebOb Whoosh wsgiref zope.cachedescriptors zope.deprecation zope.event zope.interface nbconvert bleach nbformat jupyter-client alembic invoke bumpversion transifex-client gevent greenlet gunicorn waitress uWSGI ipdb ipython CProfileV bottle rhodecode-tools appenlight-client pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage];
1726 src = ./.;
1687 src = ./.;
1727 meta = {
1688 meta = {
1728 license = [ { fullName = "Affero GNU General Public License v3 or later (AGPLv3+)"; } { fullName = "AGPLv3, and Commercial License"; } ];
1689 license = [ { fullName = "Affero GNU General Public License v3 or later (AGPLv3+)"; } { fullName = "AGPLv3, and Commercial License"; } ];
1729 };
1690 };
1730 };
1691 };
1731 rhodecode-tools = super.buildPythonPackage {
1692 rhodecode-tools = super.buildPythonPackage {
1732 name = "rhodecode-tools-0.13.1";
1693 name = "rhodecode-tools-0.14.1";
1733 buildInputs = with self; [];
1694 buildInputs = with self; [];
1734 doCheck = false;
1695 doCheck = false;
1735 propagatedBuildInputs = with self; [click future six Mako MarkupSafe requests elasticsearch elasticsearch-dsl urllib3 Whoosh];
1696 propagatedBuildInputs = with self; [click future six Mako MarkupSafe requests elasticsearch elasticsearch-dsl urllib3 Whoosh];
1736 src = fetchurl {
1697 src = fetchurl {
1737 url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.13.1.tar.gz?md5=f72add4690c9b341f87127a0a79573ae";
1698 url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.14.1.tar.gz?md5=0b9c2caad160b68889f8172ea54af7b2";
1738 md5 = "f72add4690c9b341f87127a0a79573ae";
1699 md5 = "0b9c2caad160b68889f8172ea54af7b2";
1739 };
1700 };
1740 meta = {
1701 meta = {
1741 license = [ { fullName = "AGPLv3 and Proprietary"; } ];
1702 license = [ { fullName = "AGPLv3 and Proprietary"; } ];
1742 };
1703 };
1743 };
1704 };
1744 scandir = super.buildPythonPackage {
1705 scandir = super.buildPythonPackage {
1745 name = "scandir-1.5";
1706 name = "scandir-1.6";
1746 buildInputs = with self; [];
1707 buildInputs = with self; [];
1747 doCheck = false;
1708 doCheck = false;
1748 propagatedBuildInputs = with self; [];
1709 propagatedBuildInputs = with self; [];
1749 src = fetchurl {
1710 src = fetchurl {
1750 url = "https://pypi.python.org/packages/bd/f4/3143e0289faf0883228017dbc6387a66d0b468df646645e29e1eb89ea10e/scandir-1.5.tar.gz";
1711 url = "https://pypi.python.org/packages/77/3f/916f524f50ee65e3f465a280d2851bd63685250fddb3020c212b3977664d/scandir-1.6.tar.gz";
1751 md5 = "a2713043de681bba6b084be42e7a8a44";
1712 md5 = "0180ddb97c96cbb2d4f25d2ae11c64ac";
1752 };
1713 };
1753 meta = {
1714 meta = {
1754 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "New BSD License"; } ];
1715 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "New BSD License"; } ];
1755 };
1716 };
1756 };
1717 };
1757 setproctitle = super.buildPythonPackage {
1718 setproctitle = super.buildPythonPackage {
1758 name = "setproctitle-1.1.8";
1719 name = "setproctitle-1.1.10";
1759 buildInputs = with self; [];
1720 buildInputs = with self; [];
1760 doCheck = false;
1721 doCheck = false;
1761 propagatedBuildInputs = with self; [];
1722 propagatedBuildInputs = with self; [];
1762 src = fetchurl {
1723 src = fetchurl {
1763 url = "https://pypi.python.org/packages/33/c3/ad367a4f4f1ca90468863ae727ac62f6edb558fc09a003d344a02cfc6ea6/setproctitle-1.1.8.tar.gz";
1724 url = "https://pypi.python.org/packages/5a/0d/dc0d2234aacba6cf1a729964383e3452c52096dc695581248b548786f2b3/setproctitle-1.1.10.tar.gz";
1764 md5 = "728f4c8c6031bbe56083a48594027edd";
1725 md5 = "2dcdd1b761700a5a13252fea3dfd1977";
1765 };
1726 };
1766 meta = {
1727 meta = {
1767 license = [ pkgs.lib.licenses.bsdOriginal ];
1728 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -1781,13 +1742,13 b''
1781 };
1742 };
1782 };
1743 };
1783 setuptools-scm = super.buildPythonPackage {
1744 setuptools-scm = super.buildPythonPackage {
1784 name = "setuptools-scm-1.15.0";
1745 name = "setuptools-scm-1.15.6";
1785 buildInputs = with self; [];
1746 buildInputs = with self; [];
1786 doCheck = false;
1747 doCheck = false;
1787 propagatedBuildInputs = with self; [];
1748 propagatedBuildInputs = with self; [];
1788 src = fetchurl {
1749 src = fetchurl {
1789 url = "https://pypi.python.org/packages/80/b7/31b6ae5fcb188e37f7e31abe75f9be90490a5456a72860fa6e643f8a3cbc/setuptools_scm-1.15.0.tar.gz";
1750 url = "https://pypi.python.org/packages/03/6d/aafdd01edd227ee879b691455bf19895091872af7e48192bea1758c82032/setuptools_scm-1.15.6.tar.gz";
1790 md5 = "b6916c78ed6253d6602444fad4279c5b";
1751 md5 = "f17493d53f0d842bb0152f214775640b";
1791 };
1752 };
1792 meta = {
1753 meta = {
1793 license = [ pkgs.lib.licenses.mit ];
1754 license = [ pkgs.lib.licenses.mit ];
@@ -1820,13 +1781,13 b''
1820 };
1781 };
1821 };
1782 };
1822 six = super.buildPythonPackage {
1783 six = super.buildPythonPackage {
1823 name = "six-1.9.0";
1784 name = "six-1.11.0";
1824 buildInputs = with self; [];
1785 buildInputs = with self; [];
1825 doCheck = false;
1786 doCheck = false;
1826 propagatedBuildInputs = with self; [];
1787 propagatedBuildInputs = with self; [];
1827 src = fetchurl {
1788 src = fetchurl {
1828 url = "https://pypi.python.org/packages/16/64/1dc5e5976b17466fd7d712e59cbe9fb1e18bec153109e5ba3ed6c9102f1a/six-1.9.0.tar.gz";
1789 url = "https://pypi.python.org/packages/16/d8/bc6316cf98419719bd59c91742194c111b6f2e85abac88e496adefaf7afe/six-1.11.0.tar.gz";
1829 md5 = "476881ef4012262dfc8adc645ee786c4";
1790 md5 = "d12789f9baf7e9fb2524c0c64f1773f8";
1830 };
1791 };
1831 meta = {
1792 meta = {
1832 license = [ pkgs.lib.licenses.mit ];
1793 license = [ pkgs.lib.licenses.mit ];
@@ -1911,13 +1872,13 b''
1911 };
1872 };
1912 };
1873 };
1913 transifex-client = super.buildPythonPackage {
1874 transifex-client = super.buildPythonPackage {
1914 name = "transifex-client-0.10";
1875 name = "transifex-client-0.12.5";
1915 buildInputs = with self; [];
1876 buildInputs = with self; [];
1916 doCheck = false;
1877 doCheck = false;
1917 propagatedBuildInputs = with self; [];
1878 propagatedBuildInputs = with self; [urllib3 six];
1918 src = fetchurl {
1879 src = fetchurl {
1919 url = "https://pypi.python.org/packages/f3/4e/7b925192aee656fb3e04fa6381c8b3dc40198047c3b4a356f6cfd642c809/transifex-client-0.10.tar.gz";
1880 url = "https://pypi.python.org/packages/7b/86/60f31a0c9b8d0b1266ce15b6c80b55f88522140c8acfc395d5aec5e23475/transifex-client-0.12.5.tar.gz";
1920 md5 = "5549538d84b8eede6b254cd81ae024fa";
1881 md5 = "e6e278117b23f60702c06e203b7e51ae";
1921 };
1882 };
1922 meta = {
1883 meta = {
1923 license = [ pkgs.lib.licenses.gpl2 ];
1884 license = [ pkgs.lib.licenses.gpl2 ];
@@ -1988,14 +1949,27 b''
1988 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1949 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1989 };
1950 };
1990 };
1951 };
1991 waitress = super.buildPythonPackage {
1952 vine = super.buildPythonPackage {
1992 name = "waitress-1.0.2";
1953 name = "vine-1.1.4";
1993 buildInputs = with self; [];
1954 buildInputs = with self; [];
1994 doCheck = false;
1955 doCheck = false;
1995 propagatedBuildInputs = with self; [];
1956 propagatedBuildInputs = with self; [];
1996 src = fetchurl {
1957 src = fetchurl {
1997 url = "https://pypi.python.org/packages/cd/f4/400d00863afa1e03618e31fd7e2092479a71b8c9718b00eb1eeb603746c6/waitress-1.0.2.tar.gz";
1958 url = "https://pypi.python.org/packages/32/23/36284986e011f3c130d802c3c66abd8f1aef371eae110ddf80c5ae22e1ff/vine-1.1.4.tar.gz";
1998 md5 = "b968f39e95d609f6194c6e50425d4bb7";
1959 md5 = "9fdb971e7fd15b181b84f3bfcf20d11c";
1960 };
1961 meta = {
1962 license = [ pkgs.lib.licenses.bsdOriginal ];
1963 };
1964 };
1965 waitress = super.buildPythonPackage {
1966 name = "waitress-1.1.0";
1967 buildInputs = with self; [];
1968 doCheck = false;
1969 propagatedBuildInputs = with self; [];
1970 src = fetchurl {
1971 url = "https://pypi.python.org/packages/3c/68/1c10dd5c556872ceebe88483b0436140048d39de83a84a06a8baa8136f4f/waitress-1.1.0.tar.gz";
1972 md5 = "0f1eb7fdfdbf2e6d18decbda1733045c";
1999 };
1973 };
2000 meta = {
1974 meta = {
2001 license = [ pkgs.lib.licenses.zpt21 ];
1975 license = [ pkgs.lib.licenses.zpt21 ];
@@ -2014,14 +1988,27 b''
2014 license = [ pkgs.lib.licenses.mit ];
1988 license = [ pkgs.lib.licenses.mit ];
2015 };
1989 };
2016 };
1990 };
2017 ws4py = super.buildPythonPackage {
1991 webencodings = super.buildPythonPackage {
2018 name = "ws4py-0.3.5";
1992 name = "webencodings-0.5.1";
2019 buildInputs = with self; [];
1993 buildInputs = with self; [];
2020 doCheck = false;
1994 doCheck = false;
2021 propagatedBuildInputs = with self; [];
1995 propagatedBuildInputs = with self; [];
2022 src = fetchurl {
1996 src = fetchurl {
2023 url = "https://pypi.python.org/packages/b6/4f/34af703be86939629479e74d6e650e39f3bd73b3b09212c34e5125764cbc/ws4py-0.3.5.zip";
1997 url = "https://pypi.python.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz";
2024 md5 = "a261b75c20b980e55ce7451a3576a867";
1998 md5 = "32f6e261d52e57bf7e1c4d41546d15b8";
1999 };
2000 meta = {
2001 license = [ pkgs.lib.licenses.bsdOriginal ];
2002 };
2003 };
2004 ws4py = super.buildPythonPackage {
2005 name = "ws4py-0.4.2";
2006 buildInputs = with self; [];
2007 doCheck = false;
2008 propagatedBuildInputs = with self; [];
2009 src = fetchurl {
2010 url = "https://pypi.python.org/packages/b8/98/a90f1d96ffcb15dfc220af524ce23e0a5881258dafa197673357ce1683dd/ws4py-0.4.2.tar.gz";
2011 md5 = "f0603ae376707a58d205bd87a67758a2";
2025 };
2012 };
2026 meta = {
2013 meta = {
2027 license = [ pkgs.lib.licenses.bsdOriginal ];
2014 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -1,12 +1,12 b''
1 [pytest]
1 [pytest]
2 testpaths = ./rhodecode
2 testpaths = rhodecode
3 pylons_config = rhodecode/tests/rhodecode.ini
3 norecursedirs = rhodecode/public rhodecode/templates tests/scripts
4
5 pyramid_config = rhodecode/tests/rhodecode.ini
4 vcsserver_protocol = http
6 vcsserver_protocol = http
5 vcsserver_config_http = rhodecode/tests/vcsserver_http.ini
7 vcsserver_config_http = rhodecode/tests/vcsserver_http.ini
6 norecursedirs = tests/scripts
7
8
8 addopts =
9 addopts =
9 -k "not _BaseTest"
10 --pdbcls=IPython.terminal.debugger:TerminalPdb
10 --pdbcls=IPython.terminal.debugger:TerminalPdb
11
11
12 markers =
12 markers =
@@ -1,51 +1,49 b''
1 ## core
1 ## core
2 setuptools==30.1.0
2 setuptools==30.1.0
3 setuptools-scm==1.15.0
3 setuptools-scm==1.15.6
4
4
5 amqplib==1.0.2
5 amqp==2.2.2
6 anyjson==0.3.3
7 authomatic==0.1.0.post1
6 authomatic==0.1.0.post1
8 Babel==1.3
7 Babel==1.3
9 Beaker==1.9.0
8 Beaker==1.9.0
10 celery==2.2.10
9 celery==4.1.0
11 Chameleon==2.24
10 Chameleon==2.24
12 channelstream==0.5.2
11 channelstream==0.5.2
13 click==5.1
12 click==6.6
14 colander==1.3.3
13 colander==1.4.0
15 configobj==5.0.6
14 configobj==5.0.6
16 cssselect==1.0.1
15 cssselect==1.0.1
17 decorator==4.0.11
16 decorator==4.1.2
18 deform==2.0.4
17 deform==2.0.4
19 docutils==0.13.1
18 docutils==0.14.0
20 dogpile.cache==0.6.4
19 dogpile.cache==0.6.4
21 dogpile.core==0.4.1
20 dogpile.core==0.4.1
22 ecdsa==0.13
21 ecdsa==0.13
23 FormEncode==1.2.4
22 FormEncode==1.2.4
24 future==0.14.3
23 future==0.14.3
25 futures==3.0.2
24 futures==3.0.2
26 gnureadline==6.3.3
25 gnureadline==6.3.8
27 infrae.cache==1.0.1
26 infrae.cache==1.0.1
28 iso8601==0.1.11
27 iso8601==0.1.12
29 itsdangerous==0.24
28 itsdangerous==0.24
30 Jinja2==2.7.3
29 Jinja2==2.9.6
31 kombu==1.5.1
30 billiard==3.5.0.3
31 kombu==4.1.0
32 lxml==3.7.3
32 lxml==3.7.3
33 Mako==1.0.7
33 Mako==1.0.7
34 Markdown==2.6.8
34 Markdown==2.6.9
35 MarkupSafe==0.23
35 MarkupSafe==1.0.0
36 meld3==1.0.2
37 msgpack-python==0.4.8
36 msgpack-python==0.4.8
38 MySQL-python==1.2.5
37 MySQL-python==1.2.5
39 nose==1.3.6
38 objgraph==3.1.1
40 objgraph==3.1.0
41 packaging==15.2
39 packaging==15.2
42 Paste==2.0.3
40 Paste==2.0.3
43 PasteDeploy==1.5.2
41 PasteDeploy==1.5.2
44 PasteScript==1.7.5
42 PasteScript==2.0.2
45 pathlib2==2.3.0
43 pathlib2==2.3.0
46 peppercorn==0.5
44 peppercorn==0.5
47 psutil==4.3.1
45 psutil==5.4.0
48 psycopg2==2.7.1
46 psycopg2==2.7.3.2
49 py-bcrypt==0.4
47 py-bcrypt==0.4
50 pycrypto==2.6.1
48 pycrypto==2.6.1
51 pycurl==7.19.5
49 pycurl==7.19.5
@@ -54,27 +52,27 b' pygments-markdown-lexer==0.1.0.dev39'
54 Pygments==2.2.0
52 Pygments==2.2.0
55 pyparsing==1.5.7
53 pyparsing==1.5.7
56 pyramid-beaker==0.8
54 pyramid-beaker==0.8
57 pyramid-debugtoolbar==4.2.1
55 pyramid-debugtoolbar==4.3.0
58 pyramid-jinja2==2.5
56 pyramid-jinja2==2.7
59 pyramid-mako==1.0.2
57 pyramid-mako==1.0.2
60 pyramid==1.9.1
58 pyramid==1.9.1
61 pysqlite==2.8.3
59 pysqlite==2.8.3
62 python-dateutil==2.1
60 python-dateutil
63 python-ldap==2.4.40
61 python-ldap==2.4.45
64 python-memcached==1.58
62 python-memcached==1.58
65 python-pam==1.8.2
63 python-pam==1.8.2
66 pytz==2015.4
64 pytz==2017.3
67 pyzmq==14.6.0
65 pyzmq==14.6.0
66 py-gfm==0.1.3
68 recaptcha-client==1.0.6
67 recaptcha-client==1.0.6
69 redis==2.10.6
68 redis==2.10.6
70 repoze.lru==0.6
69 repoze.lru==0.7
71 requests==2.9.1
70 requests==2.9.1
72 Routes==1.13
71 Routes==2.4.1
73 setproctitle==1.1.8
72 setproctitle==1.1.10
74 simplejson==3.11.1
73 simplejson==3.11.1
75 six==1.9.0
74 six==1.11.0
76 Sphinx==1.2.2
75 SQLAlchemy==1.1.15
77 SQLAlchemy==1.1.11
78 sshpubkeys==2.2.0
76 sshpubkeys==2.2.0
79 subprocess32==3.2.7
77 subprocess32==3.2.7
80 supervisor==3.3.3
78 supervisor==3.3.3
@@ -95,44 +93,39 b' zope.deprecation==4.1.2'
95 zope.event==4.0.3
93 zope.event==4.0.3
96 zope.interface==4.1.3
94 zope.interface==4.1.3
97
95
98 ## customized/patched libs
99 # our patched version of Pylons==1.0.2
100 https://code.rhodecode.com/upstream/pylons/archive/707354ee4261b9c10450404fc9852ccea4fd667d.tar.gz?md5=f26633726fa2cd3a340316ee6a5d218f#egg=Pylons==1.0.2.rhodecode-patch-1
101 # not released py-gfm==0.1.3
102 https://code.rhodecode.com/upstream/py-gfm/archive/0d66a19bc16e3d49de273c0f797d4e4781e8c0f2.tar.gz?md5=0d0d5385bfb629eea636a80b9c2bfd16#egg=py-gfm==0.1.3.rhodecode-upstream1
103
96
104 # IPYTHON RENDERING
97 # IPYTHON RENDERING
105 # entrypoints backport, pypi version doesn't support egg installs
98 # entrypoints backport, pypi version doesn't support egg installs
106 https://code.rhodecode.com/upstream/entrypoints/archive/96e6d645684e1af3d7df5b5272f3fe85a546b233.tar.gz?md5=7db37771aea9ac9fefe093e5d6987313#egg=entrypoints==0.2.2.rhodecode-upstream1
99 https://code.rhodecode.com/upstream/entrypoints/archive/96e6d645684e1af3d7df5b5272f3fe85a546b233.tar.gz?md5=7db37771aea9ac9fefe093e5d6987313#egg=entrypoints==0.2.2.rhodecode-upstream1
107 nbconvert==5.1.1
100 nbconvert==5.3.1
108 bleach==1.5.0
101 bleach==2.1.1
109 nbformat==4.3.0
102 nbformat==4.4.0
110 jupyter_client==5.0.0
103 jupyter_client==5.0.0
111
104
112 ## cli tools
105 ## cli tools
113 alembic==0.9.2
106 alembic==0.9.6
114 invoke==0.13.0
107 invoke==0.13.0
115 bumpversion==0.5.3
108 bumpversion==0.5.3
116 transifex-client==0.10
109 transifex-client==0.12.5
117
110
118 ## http servers
111 ## http servers
119 gevent==1.2.2
112 gevent==1.2.2
120 greenlet==0.4.12
113 greenlet==0.4.12
121 gunicorn==19.7.1
114 gunicorn==19.7.1
122 waitress==1.0.2
115 waitress==1.1.0
123 uWSGI==2.0.15
116 uWSGI==2.0.15
124
117
125 ## debug
118 ## debug
126 ipdb==0.10.3
119 ipdb==0.10.3
127 ipython==5.1.0
120 ipython==5.1.0
128 CProfileV==1.0.7
121 CProfileV==1.0.7
129 bottle==0.12.8
122 bottle==0.12.13
130
123
131 ## rhodecode-tools, special case
124 ## rhodecode-tools, special case
132 https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.13.1.tar.gz?md5=f72add4690c9b341f87127a0a79573ae#egg=rhodecode-tools==0.13.1
125 https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.14.1.tar.gz?md5=0b9c2caad160b68889f8172ea54af7b2#egg=rhodecode-tools==0.14.1
133
126
134 ## appenlight
127 ## appenlight
135 appenlight-client==0.6.21
128 appenlight-client==0.6.22
136
129
137 ## test related requirements
130 ## test related requirements
138 -r requirements_test.txt
131 -r requirements_test.txt
@@ -1,15 +1,15 b''
1 # test related requirements
1 # test related requirements
2 pytest==3.1.2
2 pytest==3.2.5
3 py==1.4.34
3 py==1.5.2
4 pytest-cov==2.5.1
4 pytest-cov==2.5.1
5 pytest-sugar==0.8.0
5 pytest-sugar==0.9.0
6 pytest-runner==2.11.1
6 pytest-runner==3.0.0
7 pytest-catchlog==1.2.2
7 pytest-catchlog==1.2.2
8 pytest-profiling==1.2.6
8 pytest-profiling==1.2.11
9 gprof2dot==2016.10.13
9 gprof2dot==2017.9.19
10 pytest-timeout==1.2.0
10 pytest-timeout==1.2.0
11
11
12 mock==1.0.1
12 mock==1.0.1
13 WebTest==2.0.27
13 WebTest==2.0.29
14 cov-core==1.15.0
14 cov-core==1.15.0
15 coverage==3.7.1
15 coverage==3.7.1
@@ -1,1 +1,1 b''
1 4.10.6 No newline at end of file
1 4.11.0 No newline at end of file
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -40,7 +40,7 b' BACKENDS = {'
40 CELERY_ENABLED = False
40 CELERY_ENABLED = False
41 CELERY_EAGER = False
41 CELERY_EAGER = False
42
42
43 # link to config for pylons
43 # link to config for pyramid
44 CONFIG = {}
44 CONFIG = {}
45
45
46 # Populated with the settings dictionary from application init in
46 # Populated with the settings dictionary from application init in
@@ -51,7 +51,7 b' PYRAMID_SETTINGS = {}'
51 EXTENSIONS = {}
51 EXTENSIONS = {}
52
52
53 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
53 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
54 __dbversion__ = 81 # defines current db version for migrations
54 __dbversion__ = 85 # defines current db version for migrations
55 __platform__ = platform.system()
55 __platform__ = platform.system()
56 __license__ = 'AGPLv3, and Commercial License'
56 __license__ = 'AGPLv3, and Commercial License'
57 __author__ = 'RhodeCode GmbH'
57 __author__ = 'RhodeCode GmbH'
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -27,7 +27,7 b' from rhodecode.tests import TEST_USER_AD'
27
27
28
28
29 @pytest.fixture(scope="class")
29 @pytest.fixture(scope="class")
30 def testuser_api(request, pylonsapp):
30 def testuser_api(request, baseapp):
31 cls = request.cls
31 cls = request.cls
32
32
33 # ADMIN USER
33 # ADMIN USER
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -86,7 +86,7 b' class TestApi(object):'
86 def test_api_non_existing_method_have_similar(self, request):
86 def test_api_non_existing_method_have_similar(self, request):
87 id_, params = build_data(self.apikey, 'comment', args='xx')
87 id_, params = build_data(self.apikey, 'comment', args='xx')
88 response = api_call(self.app, params)
88 response = api_call(self.app, params)
89 expected = 'No such method: comment. Similar methods: changeset_comment, comment_pull_request, comment_commit'
89 expected = 'No such method: comment. Similar methods: changeset_comment, comment_pull_request, get_pull_request_comments, comment_commit'
90 assert_error(id_, expected, given=response.body)
90 assert_error(id_, expected, given=response.body)
91
91
92 def test_api_disabled_user(self, request):
92 def test_api_disabled_user(self, request):
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -70,10 +70,11 b' class TestClosePullRequest(object):'
70 assert_error(id_, expected, given=response.body)
70 assert_error(id_, expected, given=response.body)
71
71
72 @pytest.mark.backends("git", "hg")
72 @pytest.mark.backends("git", "hg")
73 def test_api_close_pull_request_repo_error(self):
73 def test_api_close_pull_request_repo_error(self, pr_util):
74 pull_request = pr_util.create_pull_request()
74 id_, params = build_data(
75 id_, params = build_data(
75 self.apikey, 'close_pull_request',
76 self.apikey, 'close_pull_request',
76 repoid=666, pullrequestid=1)
77 repoid=666, pullrequestid=pull_request.pull_request_id)
77 response = api_call(self.app, params)
78 response = api_call(self.app, params)
78
79
79 expected = 'repository `666` does not exist'
80 expected = 'repository `666` does not exist'
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -170,10 +170,11 b' class TestCommentPullRequest(object):'
170 assert_error(id_, expected, given=response.body)
170 assert_error(id_, expected, given=response.body)
171
171
172 @pytest.mark.backends("git", "hg")
172 @pytest.mark.backends("git", "hg")
173 def test_api_comment_pull_request_repo_error(self):
173 def test_api_comment_pull_request_repo_error(self, pr_util):
174 pull_request = pr_util.create_pull_request()
174 id_, params = build_data(
175 id_, params = build_data(
175 self.apikey, 'comment_pull_request',
176 self.apikey, 'comment_pull_request',
176 repoid=666, pullrequestid=1)
177 repoid=666, pullrequestid=pull_request.pull_request_id)
177 response = api_call(self.app, params)
178 response = api_call(self.app, params)
178
179
179 expected = 'repository `666` does not exist'
180 expected = 'repository `666` does not exist'
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -38,11 +38,12 b' class TestGetMethod(object):'
38 response = api_call(self.app, params)
38 response = api_call(self.app, params)
39
39
40 expected = ['changeset_comment', 'comment_pull_request',
40 expected = ['changeset_comment', 'comment_pull_request',
41 'comment_commit']
41 'get_pull_request_comments', 'comment_commit']
42 assert_ok(id_, expected, given=response.body)
42 assert_ok(id_, expected, given=response.body)
43
43
44 def test_get_methods_on_single_match(self):
44 def test_get_methods_on_single_match(self):
45 id_, params = build_data(self.apikey, 'get_method', pattern='*comment_commit*')
45 id_, params = build_data(self.apikey, 'get_method',
46 pattern='*comment_commit*')
46 response = api_call(self.app, params)
47 response = api_call(self.app, params)
47
48
48 expected = ['comment_commit',
49 expected = ['comment_commit',
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -38,7 +38,6 b' class TestGetPullRequest(object):'
38 pull_request = pr_util.create_pull_request(mergeable=True)
38 pull_request = pr_util.create_pull_request(mergeable=True)
39 id_, params = build_data(
39 id_, params = build_data(
40 self.apikey, 'get_pull_request',
40 self.apikey, 'get_pull_request',
41 repoid=pull_request.target_repo.repo_name,
42 pullrequestid=pull_request.pull_request_id)
41 pullrequestid=pull_request.pull_request_id)
43
42
44 response = api_call(self.app, params)
43 response = api_call(self.app, params)
@@ -109,16 +108,17 b' class TestGetPullRequest(object):'
109 'reasons': reasons,
108 'reasons': reasons,
110 'review_status': st[0][1].status if st else 'not_reviewed',
109 'review_status': st[0][1].status if st else 'not_reviewed',
111 }
110 }
112 for reviewer, reasons, mandatory, st in
111 for obj, reviewer, reasons, mandatory, st in
113 pull_request.reviewers_statuses()
112 pull_request.reviewers_statuses()
114 ]
113 ]
115 }
114 }
116 assert_ok(id_, expected, response.body)
115 assert_ok(id_, expected, response.body)
117
116
118 def test_api_get_pull_request_repo_error(self):
117 def test_api_get_pull_request_repo_error(self, pr_util):
118 pull_request = pr_util.create_pull_request()
119 id_, params = build_data(
119 id_, params = build_data(
120 self.apikey, 'get_pull_request',
120 self.apikey, 'get_pull_request',
121 repoid=666, pullrequestid=1)
121 repoid=666, pullrequestid=pull_request.pull_request_id)
122 response = api_call(self.app, params)
122 response = api_call(self.app, params)
123
123
124 expected = 'repository `666` does not exist'
124 expected = 'repository `666` does not exist'
@@ -126,9 +126,17 b' class TestGetPullRequest(object):'
126
126
127 def test_api_get_pull_request_pull_request_error(self):
127 def test_api_get_pull_request_pull_request_error(self):
128 id_, params = build_data(
128 id_, params = build_data(
129 self.apikey, 'get_pull_request',
129 self.apikey, 'get_pull_request', pullrequestid=666)
130 repoid=1, pullrequestid=666)
131 response = api_call(self.app, params)
130 response = api_call(self.app, params)
132
131
133 expected = 'pull request `666` does not exist'
132 expected = 'pull request `666` does not exist'
134 assert_error(id_, expected, given=response.body)
133 assert_error(id_, expected, given=response.body)
134
135 def test_api_get_pull_request_pull_request_error_just_pr_id(self):
136 id_, params = build_data(
137 self.apikey, 'get_pull_request',
138 pullrequestid=666)
139 response = api_call(self.app, params)
140
141 expected = 'pull request `666` does not exist'
142 assert_error(id_, expected, given=response.body)
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -68,7 +68,6 b' class TestGetRepo(object):'
68 followers.append(user.user.get_api_data(
68 followers.append(user.user.get_api_data(
69 include_secrets=expect_secrets))
69 include_secrets=expect_secrets))
70
70
71 ret['members'] = permissions
72 ret['permissions'] = permissions
71 ret['permissions'] = permissions
73 ret['followers'] = followers
72 ret['followers'] = followers
74
73
@@ -106,7 +105,6 b' class TestGetRepo(object):'
106 for user in repo.followers:
105 for user in repo.followers:
107 followers.append(user.user.get_api_data())
106 followers.append(user.user.get_api_data())
108
107
109 ret['members'] = permissions
110 ret['permissions'] = permissions
108 ret['permissions'] = permissions
111 ret['followers'] = followers
109 ret['followers'] = followers
112
110
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -41,7 +41,7 b' class TestApiGetRepoGroup(object):'
41
41
42 permissions = expected_permissions(repo_group)
42 permissions = expected_permissions(repo_group)
43
43
44 ret['members'] = permissions
44 ret['permissions'] = permissions
45 expected = ret
45 expected = ret
46 assert_ok(id_, expected, given=response.body)
46 assert_ok(id_, expected, given=response.body)
47
47
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -36,7 +36,9 b' class TestGetUser(object):'
36
36
37 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
37 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
38 ret = usr.get_api_data(include_secrets=True)
38 ret = usr.get_api_data(include_secrets=True)
39 ret['permissions'] = AuthUser(usr.user_id).permissions
39 permissions = AuthUser(usr.user_id).permissions
40 ret['permissions'] = permissions
41 ret['permissions_summary'] = permissions
40
42
41 expected = ret
43 expected = ret
42 assert_ok(id_, expected, given=response.body)
44 assert_ok(id_, expected, given=response.body)
@@ -54,7 +56,9 b' class TestGetUser(object):'
54
56
55 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
57 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
56 ret = usr.get_api_data(include_secrets=True)
58 ret = usr.get_api_data(include_secrets=True)
57 ret['permissions'] = AuthUser(usr.user_id).permissions
59 permissions = AuthUser(usr.user_id).permissions
60 ret['permissions'] = permissions
61 ret['permissions_summary'] = permissions
58
62
59 expected = ret
63 expected = ret
60 assert_ok(id_, expected, given=response.body)
64 assert_ok(id_, expected, given=response.body)
@@ -65,7 +69,9 b' class TestGetUser(object):'
65
69
66 usr = UserModel().get_by_username(self.TEST_USER_LOGIN)
70 usr = UserModel().get_by_username(self.TEST_USER_LOGIN)
67 ret = usr.get_api_data(include_secrets=True)
71 ret = usr.get_api_data(include_secrets=True)
68 ret['permissions'] = AuthUser(usr.user_id).permissions
72 permissions = AuthUser(usr.user_id).permissions
73 ret['permissions'] = permissions
74 ret['permissions_summary'] = permissions
69
75
70 expected = ret
76 expected = ret
71 assert_ok(id_, expected, given=response.body)
77 assert_ok(id_, expected, given=response.body)
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -38,7 +38,8 b' class TestGetUserGroups(object):'
38
38
39 permissions = expected_permissions(group)
39 permissions = expected_permissions(group)
40
40
41 ret['members'] = permissions
41 ret['permissions'] = permissions
42 ret['permissions_summary'] = response.json['result']['permissions_summary']
42 expected = ret
43 expected = ret
43 assert_ok(id_, expected, given=response.body)
44 assert_ok(id_, expected, given=response.body)
44
45
@@ -54,7 +55,8 b' class TestGetUserGroups(object):'
54
55
55 permissions = expected_permissions(group)
56 permissions = expected_permissions(group)
56
57
57 ret['members'] = permissions
58 ret['permissions'] = permissions
59 ret['permissions_summary'] = response.json['result']['permissions_summary']
58 expected = ret
60 expected = ret
59 assert_ok(id_, expected, given=response.body)
61 assert_ok(id_, expected, given=response.body)
60
62
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -112,10 +112,11 b' class TestMergePullRequest(object):'
112 assert_error(id_, expected, given=response.body)
112 assert_error(id_, expected, given=response.body)
113
113
114 @pytest.mark.backends("git", "hg")
114 @pytest.mark.backends("git", "hg")
115 def test_api_merge_pull_request_repo_error(self):
115 def test_api_merge_pull_request_repo_error(self, pr_util):
116 pull_request = pr_util.create_pull_request()
116 id_, params = build_data(
117 id_, params = build_data(
117 self.apikey, 'merge_pull_request',
118 self.apikey, 'merge_pull_request',
118 repoid=666, pullrequestid=1)
119 repoid=666, pullrequestid=pull_request.pull_request_id)
119 response = api_call(self.app, params)
120 response = api_call(self.app, params)
120
121
121 expected = 'repository `666` does not exist'
122 expected = 'repository `666` does not exist'
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -133,7 +133,7 b' class TestUpdatePullRequest(object):'
133 removed = [a.username]
133 removed = [a.username]
134
134
135 pull_request = pr_util.create_pull_request(
135 pull_request = pr_util.create_pull_request(
136 reviewers=[(a.username, ['added via API'], False)])
136 reviewers=[(a.username, ['added via API'], False, [])])
137
137
138 id_, params = build_data(
138 id_, params = build_data(
139 self.apikey, 'update_pull_request',
139 self.apikey, 'update_pull_request',
@@ -168,10 +168,11 b' class TestUpdatePullRequest(object):'
168
168
169 @pytest.mark.backends("git", "hg")
169 @pytest.mark.backends("git", "hg")
170 def test_api_update_repo_error(self, pr_util):
170 def test_api_update_repo_error(self, pr_util):
171 pull_request = pr_util.create_pull_request()
171 id_, params = build_data(
172 id_, params = build_data(
172 self.apikey, 'update_pull_request',
173 self.apikey, 'update_pull_request',
173 repoid='fake',
174 repoid='fake',
174 pullrequestid='fake',
175 pullrequestid=pull_request.pull_request_id,
175 reviewers=[{'username': 'bad_name'}])
176 reviewers=[{'username': 'bad_name'}])
176 response = api_call(self.app, params)
177 response = api_call(self.app, params)
177
178
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2014-2017 RhodeCode GmbH
3 # Copyright (C) 2014-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2015-2017 RhodeCode GmbH
3 # Copyright (C) 2015-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -43,14 +43,14 b' log = logging.getLogger(__name__)'
43
43
44
44
45 @jsonrpc_method()
45 @jsonrpc_method()
46 def get_pull_request(request, apiuser, repoid, pullrequestid):
46 def get_pull_request(request, apiuser, pullrequestid, repoid=Optional(None)):
47 """
47 """
48 Get a pull request based on the given ID.
48 Get a pull request based on the given ID.
49
49
50 :param apiuser: This is filled automatically from the |authtoken|.
50 :param apiuser: This is filled automatically from the |authtoken|.
51 :type apiuser: AuthUser
51 :type apiuser: AuthUser
52 :param repoid: Repository name or repository ID from where the pull
52 :param repoid: Optional, repository name or repository ID from where
53 request was opened.
53 the pull request was opened.
54 :type repoid: str or int
54 :type repoid: str or int
55 :param pullrequestid: ID of the requested pull request.
55 :param pullrequestid: ID of the requested pull request.
56 :type pullrequestid: int
56 :type pullrequestid: int
@@ -121,11 +121,17 b' def get_pull_request(request, apiuser, r'
121 },
121 },
122 "error": null
122 "error": null
123 """
123 """
124 get_repo_or_error(repoid)
124
125 pull_request = get_pull_request_or_error(pullrequestid)
125 pull_request = get_pull_request_or_error(pullrequestid)
126 if Optional.extract(repoid):
127 repo = get_repo_or_error(repoid)
128 else:
129 repo = pull_request.target_repo
130
126 if not PullRequestModel().check_user_read(
131 if not PullRequestModel().check_user_read(
127 pull_request, apiuser, api=True):
132 pull_request, apiuser, api=True):
128 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
133 raise JSONRPCError('repository `%s` or pull request `%s` '
134 'does not exist' % (repoid, pullrequestid))
129 data = pull_request.get_api_data()
135 data = pull_request.get_api_data()
130 return data
136 return data
131
137
@@ -137,7 +143,7 b' def get_pull_requests(request, apiuser, '
137
143
138 :param apiuser: This is filled automatically from the |authtoken|.
144 :param apiuser: This is filled automatically from the |authtoken|.
139 :type apiuser: AuthUser
145 :type apiuser: AuthUser
140 :param repoid: Repository name or repository ID.
146 :param repoid: Optional repository name or repository ID.
141 :type repoid: str or int
147 :type repoid: str or int
142 :param status: Only return pull requests with the specified status.
148 :param status: Only return pull requests with the specified status.
143 Valid options are.
149 Valid options are.
@@ -229,7 +235,7 b' def get_pull_requests(request, apiuser, '
229
235
230 @jsonrpc_method()
236 @jsonrpc_method()
231 def merge_pull_request(
237 def merge_pull_request(
232 request, apiuser, repoid, pullrequestid,
238 request, apiuser, pullrequestid, repoid=Optional(None),
233 userid=Optional(OAttr('apiuser'))):
239 userid=Optional(OAttr('apiuser'))):
234 """
240 """
235 Merge the pull request specified by `pullrequestid` into its target
241 Merge the pull request specified by `pullrequestid` into its target
@@ -237,7 +243,7 b' def merge_pull_request('
237
243
238 :param apiuser: This is filled automatically from the |authtoken|.
244 :param apiuser: This is filled automatically from the |authtoken|.
239 :type apiuser: AuthUser
245 :type apiuser: AuthUser
240 :param repoid: The Repository name or repository ID of the
246 :param repoid: Optional, repository name or repository ID of the
241 target repository to which the |pr| is to be merged.
247 target repository to which the |pr| is to be merged.
242 :type repoid: str or int
248 :type repoid: str or int
243 :param pullrequestid: ID of the pull request which shall be merged.
249 :param pullrequestid: ID of the pull request which shall be merged.
@@ -263,7 +269,12 b' def merge_pull_request('
263 },
269 },
264 "error": null
270 "error": null
265 """
271 """
266 repo = get_repo_or_error(repoid)
272 pull_request = get_pull_request_or_error(pullrequestid)
273 if Optional.extract(repoid):
274 repo = get_repo_or_error(repoid)
275 else:
276 repo = pull_request.target_repo
277
267 if not isinstance(userid, Optional):
278 if not isinstance(userid, Optional):
268 if (has_superadmin_permission(apiuser) or
279 if (has_superadmin_permission(apiuser) or
269 HasRepoPermissionAnyApi('repository.admin')(
280 HasRepoPermissionAnyApi('repository.admin')(
@@ -272,8 +283,6 b' def merge_pull_request('
272 else:
283 else:
273 raise JSONRPCError('userid is not the same as your user')
284 raise JSONRPCError('userid is not the same as your user')
274
285
275 pull_request = get_pull_request_or_error(pullrequestid)
276
277 check = MergeCheck.validate(
286 check = MergeCheck.validate(
278 pull_request, user=apiuser, translator=request.translate)
287 pull_request, user=apiuser, translator=request.translate)
279 merge_possible = not check.failed
288 merge_possible = not check.failed
@@ -311,9 +320,112 b' def merge_pull_request('
311
320
312
321
313 @jsonrpc_method()
322 @jsonrpc_method()
323 def get_pull_request_comments(
324 request, apiuser, pullrequestid, repoid=Optional(None)):
325 """
326 Get all comments of pull request specified with the `pullrequestid`
327
328 :param apiuser: This is filled automatically from the |authtoken|.
329 :type apiuser: AuthUser
330 :param repoid: Optional repository name or repository ID.
331 :type repoid: str or int
332 :param pullrequestid: The pull request ID.
333 :type pullrequestid: int
334
335 Example output:
336
337 .. code-block:: bash
338
339 id : <id_given_in_input>
340 result : [
341 {
342 "comment_author": {
343 "active": true,
344 "full_name_or_username": "Tom Gore",
345 "username": "admin"
346 },
347 "comment_created_on": "2017-01-02T18:43:45.533",
348 "comment_f_path": null,
349 "comment_id": 25,
350 "comment_lineno": null,
351 "comment_status": {
352 "status": "under_review",
353 "status_lbl": "Under Review"
354 },
355 "comment_text": "Example text",
356 "comment_type": null,
357 "pull_request_version": null
358 }
359 ],
360 error : null
361 """
362
363 pull_request = get_pull_request_or_error(pullrequestid)
364 if Optional.extract(repoid):
365 repo = get_repo_or_error(repoid)
366 else:
367 repo = pull_request.target_repo
368
369 if not PullRequestModel().check_user_read(
370 pull_request, apiuser, api=True):
371 raise JSONRPCError('repository `%s` or pull request `%s` '
372 'does not exist' % (repoid, pullrequestid))
373
374 (pull_request_latest,
375 pull_request_at_ver,
376 pull_request_display_obj,
377 at_version) = PullRequestModel().get_pr_version(
378 pull_request.pull_request_id, version=None)
379
380 versions = pull_request_display_obj.versions()
381 ver_map = {
382 ver.pull_request_version_id: cnt
383 for cnt, ver in enumerate(versions, 1)
384 }
385
386 # GENERAL COMMENTS with versions #
387 q = CommentsModel()._all_general_comments_of_pull_request(pull_request)
388 q = q.order_by(ChangesetComment.comment_id.asc())
389 general_comments = q.all()
390
391 # INLINE COMMENTS with versions #
392 q = CommentsModel()._all_inline_comments_of_pull_request(pull_request)
393 q = q.order_by(ChangesetComment.comment_id.asc())
394 inline_comments = q.all()
395
396 data = []
397 for comment in inline_comments + general_comments:
398 full_data = comment.get_api_data()
399 pr_version_id = None
400 if comment.pull_request_version_id:
401 pr_version_id = 'v{}'.format(
402 ver_map[comment.pull_request_version_id])
403
404 # sanitize some entries
405
406 full_data['pull_request_version'] = pr_version_id
407 full_data['comment_author'] = {
408 'username': full_data['comment_author'].username,
409 'full_name_or_username': full_data['comment_author'].full_name_or_username,
410 'active': full_data['comment_author'].active,
411 }
412
413 if full_data['comment_status']:
414 full_data['comment_status'] = {
415 'status': full_data['comment_status'][0].status,
416 'status_lbl': full_data['comment_status'][0].status_lbl,
417 }
418 else:
419 full_data['comment_status'] = {}
420
421 data.append(full_data)
422 return data
423
424
425 @jsonrpc_method()
314 def comment_pull_request(
426 def comment_pull_request(
315 request, apiuser, repoid, pullrequestid, message=Optional(None),
427 request, apiuser, pullrequestid, repoid=Optional(None),
316 commit_id=Optional(None), status=Optional(None),
428 message=Optional(None), commit_id=Optional(None), status=Optional(None),
317 comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
429 comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
318 resolves_comment_id=Optional(None),
430 resolves_comment_id=Optional(None),
319 userid=Optional(OAttr('apiuser'))):
431 userid=Optional(OAttr('apiuser'))):
@@ -324,7 +436,7 b' def comment_pull_request('
324
436
325 :param apiuser: This is filled automatically from the |authtoken|.
437 :param apiuser: This is filled automatically from the |authtoken|.
326 :type apiuser: AuthUser
438 :type apiuser: AuthUser
327 :param repoid: The repository name or repository ID.
439 :param repoid: Optional repository name or repository ID.
328 :type repoid: str or int
440 :type repoid: str or int
329 :param pullrequestid: The pull request ID.
441 :param pullrequestid: The pull request ID.
330 :type pullrequestid: int
442 :type pullrequestid: int
@@ -356,7 +468,12 b' def comment_pull_request('
356 },
468 },
357 error : null
469 error : null
358 """
470 """
359 repo = get_repo_or_error(repoid)
471 pull_request = get_pull_request_or_error(pullrequestid)
472 if Optional.extract(repoid):
473 repo = get_repo_or_error(repoid)
474 else:
475 repo = pull_request.target_repo
476
360 if not isinstance(userid, Optional):
477 if not isinstance(userid, Optional):
361 if (has_superadmin_permission(apiuser) or
478 if (has_superadmin_permission(apiuser) or
362 HasRepoPermissionAnyApi('repository.admin')(
479 HasRepoPermissionAnyApi('repository.admin')(
@@ -365,7 +482,6 b' def comment_pull_request('
365 else:
482 else:
366 raise JSONRPCError('userid is not the same as your user')
483 raise JSONRPCError('userid is not the same as your user')
367
484
368 pull_request = get_pull_request_or_error(pullrequestid)
369 if not PullRequestModel().check_user_read(
485 if not PullRequestModel().check_user_read(
370 pull_request, apiuser, api=True):
486 pull_request, apiuser, api=True):
371 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
487 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
@@ -573,15 +689,15 b' def create_pull_request('
573
689
574 @jsonrpc_method()
690 @jsonrpc_method()
575 def update_pull_request(
691 def update_pull_request(
576 request, apiuser, repoid, pullrequestid, title=Optional(''),
692 request, apiuser, pullrequestid, repoid=Optional(None),
577 description=Optional(''), reviewers=Optional(None),
693 title=Optional(''), description=Optional(''), reviewers=Optional(None),
578 update_commits=Optional(None)):
694 update_commits=Optional(None)):
579 """
695 """
580 Updates a pull request.
696 Updates a pull request.
581
697
582 :param apiuser: This is filled automatically from the |authtoken|.
698 :param apiuser: This is filled automatically from the |authtoken|.
583 :type apiuser: AuthUser
699 :type apiuser: AuthUser
584 :param repoid: The repository name or repository ID.
700 :param repoid: Optional repository name or repository ID.
585 :type repoid: str or int
701 :type repoid: str or int
586 :param pullrequestid: The pull request ID.
702 :param pullrequestid: The pull request ID.
587 :type pullrequestid: int
703 :type pullrequestid: int
@@ -626,8 +742,12 b' def update_pull_request('
626 error : null
742 error : null
627 """
743 """
628
744
629 repo = get_repo_or_error(repoid)
630 pull_request = get_pull_request_or_error(pullrequestid)
745 pull_request = get_pull_request_or_error(pullrequestid)
746 if Optional.extract(repoid):
747 repo = get_repo_or_error(repoid)
748 else:
749 repo = pull_request.target_repo
750
631 if not PullRequestModel().check_user_update(
751 if not PullRequestModel().check_user_update(
632 pull_request, apiuser, api=True):
752 pull_request, apiuser, api=True):
633 raise JSONRPCError(
753 raise JSONRPCError(
@@ -705,7 +825,7 b' def update_pull_request('
705
825
706 @jsonrpc_method()
826 @jsonrpc_method()
707 def close_pull_request(
827 def close_pull_request(
708 request, apiuser, repoid, pullrequestid,
828 request, apiuser, pullrequestid, repoid=Optional(None),
709 userid=Optional(OAttr('apiuser')), message=Optional('')):
829 userid=Optional(OAttr('apiuser')), message=Optional('')):
710 """
830 """
711 Close the pull request specified by `pullrequestid`.
831 Close the pull request specified by `pullrequestid`.
@@ -738,7 +858,12 b' def close_pull_request('
738 """
858 """
739 _ = request.translate
859 _ = request.translate
740
860
741 repo = get_repo_or_error(repoid)
861 pull_request = get_pull_request_or_error(pullrequestid)
862 if Optional.extract(repoid):
863 repo = get_repo_or_error(repoid)
864 else:
865 repo = pull_request.target_repo
866
742 if not isinstance(userid, Optional):
867 if not isinstance(userid, Optional):
743 if (has_superadmin_permission(apiuser) or
868 if (has_superadmin_permission(apiuser) or
744 HasRepoPermissionAnyApi('repository.admin')(
869 HasRepoPermissionAnyApi('repository.admin')(
@@ -747,8 +872,6 b' def close_pull_request('
747 else:
872 else:
748 raise JSONRPCError('userid is not the same as your user')
873 raise JSONRPCError('userid is not the same as your user')
749
874
750 pull_request = get_pull_request_or_error(pullrequestid)
751
752 if pull_request.is_closed():
875 if pull_request.is_closed():
753 raise JSONRPCError(
876 raise JSONRPCError(
754 'pull request `%s` is already closed' % (pullrequestid,))
877 'pull request `%s` is already closed' % (pullrequestid,))
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -32,6 +32,7 b' from rhodecode.api.utils import ('
32 from rhodecode.lib import audit_logger
32 from rhodecode.lib import audit_logger
33 from rhodecode.lib import repo_maintenance
33 from rhodecode.lib import repo_maintenance
34 from rhodecode.lib.auth import HasPermissionAnyApi, HasUserGroupPermissionAnyApi
34 from rhodecode.lib.auth import HasPermissionAnyApi, HasUserGroupPermissionAnyApi
35 from rhodecode.lib.celerylib.utils import get_task_id
35 from rhodecode.lib.utils2 import str2bool, time_to_datetime
36 from rhodecode.lib.utils2 import str2bool, time_to_datetime
36 from rhodecode.lib.ext_json import json
37 from rhodecode.lib.ext_json import json
37 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
38 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
@@ -126,26 +127,6 b' def get_repo(request, apiuser, repoid, c'
126 "lock_reason": null,
127 "lock_reason": null,
127 "locked_by": null,
128 "locked_by": null,
128 "locked_date": null,
129 "locked_date": null,
129 "members": [
130 {
131 "name": "super-admin-name",
132 "origin": "super-admin",
133 "permission": "repository.admin",
134 "type": "user"
135 },
136 {
137 "name": "owner-name",
138 "origin": "owner",
139 "permission": "repository.admin",
140 "type": "user"
141 },
142 {
143 "name": "user-group-name",
144 "origin": "permission",
145 "permission": "repository.write",
146 "type": "user_group"
147 }
148 ],
149 "owner": "owner-name",
130 "owner": "owner-name",
150 "permissions": [
131 "permissions": [
151 {
132 {
@@ -213,7 +194,6 b' def get_repo(request, apiuser, repoid, c'
213 if not cache:
194 if not cache:
214 repo.update_commit_cache()
195 repo.update_commit_cache()
215 data = repo.get_api_data(include_secrets=include_secrets)
196 data = repo.get_api_data(include_secrets=include_secrets)
216 data['members'] = permissions # TODO: this should be deprecated soon
217 data['permissions'] = permissions
197 data['permissions'] = permissions
218 data['followers'] = following_users
198 data['followers'] = following_users
219 return data
199 return data
@@ -340,11 +320,7 b' def get_repo_changeset(request, apiuser,'
340 _cs_json = cs.__json__()
320 _cs_json = cs.__json__()
341 _cs_json['diff'] = build_commit_data(cs, changes_details)
321 _cs_json['diff'] = build_commit_data(cs, changes_details)
342 if changes_details == 'full':
322 if changes_details == 'full':
343 _cs_json['refs'] = {
323 _cs_json['refs'] = cs._get_refs()
344 'branches': [cs.branch],
345 'bookmarks': getattr(cs, 'bookmarks', []),
346 'tags': cs.tags
347 }
348 return _cs_json
324 return _cs_json
349
325
350
326
@@ -716,10 +692,7 b' def create_repo('
716 }
692 }
717
693
718 task = RepoModel().create(form_data=data, cur_user=owner)
694 task = RepoModel().create(form_data=data, cur_user=owner)
719 from celery.result import BaseAsyncResult
695 task_id = get_task_id(task)
720 task_id = None
721 if isinstance(task, BaseAsyncResult):
722 task_id = task.task_id
723 # no commit, it's done in RepoModel, or async via celery
696 # no commit, it's done in RepoModel, or async via celery
724 return {
697 return {
725 'msg': "Created new repository `%s`" % (schema_data['repo_name'],),
698 'msg': "Created new repository `%s`" % (schema_data['repo_name'],),
@@ -915,7 +888,8 b' def update_repo('
915 repo_enable_downloads=enable_downloads
888 repo_enable_downloads=enable_downloads
916 if not isinstance(enable_downloads, Optional) else repo.enable_downloads)
889 if not isinstance(enable_downloads, Optional) else repo.enable_downloads)
917
890
918 ref_choices, _labels = ScmModel().get_repo_landing_revs(repo=repo)
891 ref_choices, _labels = ScmModel().get_repo_landing_revs(
892 request.translate, repo=repo)
919
893
920 old_values = repo.get_api_data()
894 old_values = repo.get_api_data()
921 schema = repo_schema.RepoSchema().bind(
895 schema = repo_schema.RepoSchema().bind(
@@ -1108,10 +1082,8 b' def fork_repo(request, apiuser, repoid, '
1108
1082
1109 task = RepoModel().create_fork(data, cur_user=owner)
1083 task = RepoModel().create_fork(data, cur_user=owner)
1110 # no commit, it's done in RepoModel, or async via celery
1084 # no commit, it's done in RepoModel, or async via celery
1111 from celery.result import BaseAsyncResult
1085 task_id = get_task_id(task)
1112 task_id = None
1086
1113 if isinstance(task, BaseAsyncResult):
1114 task_id = task.task_id
1115 return {
1087 return {
1116 'msg': 'Created fork of `%s` as `%s`' % (
1088 'msg': 'Created fork of `%s` as `%s`' % (
1117 repo.repo_name, schema_data['repo_name']),
1089 repo.repo_name, schema_data['repo_name']),
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -63,7 +63,7 b' def get_repo_group(request, apiuser, rep'
63 "group_description": "repo group description",
63 "group_description": "repo group description",
64 "group_id": 14,
64 "group_id": 14,
65 "group_name": "group name",
65 "group_name": "group name",
66 "members": [
66 "permissions": [
67 {
67 {
68 "name": "super-admin-username",
68 "name": "super-admin-username",
69 "origin": "super-admin",
69 "origin": "super-admin",
@@ -119,7 +119,7 b' def get_repo_group(request, apiuser, rep'
119 permissions.append(user_group_data)
119 permissions.append(user_group_data)
120
120
121 data = repo_group.get_api_data()
121 data = repo_group.get_api_data()
122 data["members"] = permissions # TODO: this should be named permissions
122 data["permissions"] = permissions
123 return data
123 return data
124
124
125
125
@@ -221,7 +221,7 b' def create_repo_group('
221 repo_group = RepoGroupModel().create(
221 repo_group = RepoGroupModel().create(
222 owner=owner,
222 owner=owner,
223 group_name=validated_group_name,
223 group_name=validated_group_name,
224 group_description=schema_data['repo_group_name'],
224 group_description=schema_data['repo_group_description'],
225 copy_permissions=schema_data['repo_group_copy_permissions'])
225 copy_permissions=schema_data['repo_group_copy_permissions'])
226 Session().flush()
226 Session().flush()
227
227
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -79,7 +79,8 b' def get_user(request, apiuser, userid=Op'
79 "last_login": "Timestamp",
79 "last_login": "Timestamp",
80 "last_activity": "Timestamp",
80 "last_activity": "Timestamp",
81 "lastname": "surnae",
81 "lastname": "surnae",
82 "permissions": {
82 "permissions": <deprecated>,
83 "permissions_summary": {
83 "global": [
84 "global": [
84 "hg.inherit_default_perms.true",
85 "hg.inherit_default_perms.true",
85 "usergroup.read",
86 "usergroup.read",
@@ -97,7 +98,7 b' def get_user(request, apiuser, userid=Op'
97 "repositories": { "username/example": "repository.write"},
98 "repositories": { "username/example": "repository.write"},
98 "repositories_groups": { "user-group/repo": "group.none" },
99 "repositories_groups": { "user-group/repo": "group.none" },
99 "user_groups": { "user_group_name": "usergroup.read" }
100 "user_groups": { "user_group_name": "usergroup.read" }
100 },
101 }
101 "user_id": 32,
102 "user_id": 32,
102 "username": "username"
103 "username": "username"
103 }
104 }
@@ -115,7 +116,9 b' def get_user(request, apiuser, userid=Op'
115
116
116 user = get_user_or_error(userid)
117 user = get_user_or_error(userid)
117 data = user.get_api_data(include_secrets=True)
118 data = user.get_api_data(include_secrets=True)
118 data['permissions'] = AuthUser(user_id=user.user_id).permissions
119 permissions = AuthUser(user_id=user.user_id).permissions
120 data['permissions'] = permissions # TODO(marcink): should be deprecated
121 data['permissions_summary'] = permissions
119 return data
122 return data
120
123
121
124
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -61,7 +61,7 b' def get_user_group(request, apiuser, use'
61 "active": true,
61 "active": true,
62 "group_description": "group description",
62 "group_description": "group description",
63 "group_name": "group name",
63 "group_name": "group name",
64 "members": [
64 "permissions": [
65 {
65 {
66 "name": "owner-name",
66 "name": "owner-name",
67 "origin": "owner",
67 "origin": "owner",
@@ -82,6 +82,12 b' def get_user_group(request, apiuser, use'
82 "type": "user_group"
82 "type": "user_group"
83 }
83 }
84 ],
84 ],
85 "permissions_summary": {
86 "repositories": {
87 "aa-root-level-repo-1": "repository.admin"
88 },
89 "repositories_groups": {}
90 },
85 "owner": "owner name",
91 "owner": "owner name",
86 "users": [],
92 "users": [],
87 "users_group_id": 2
93 "users_group_id": 2
@@ -119,8 +125,9 b' def get_user_group(request, apiuser, use'
119 permissions.append(user_group_data)
125 permissions.append(user_group_data)
120
126
121 data = user_group.get_api_data()
127 data = user_group.get_api_data()
122 data['members'] = permissions
128 data["permissions"] = permissions
123
129 data["permissions_summary"] = UserGroupModel().get_perms_summary(
130 user_group.users_group_id)
124 return data
131 return data
125
132
126
133
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -147,46 +147,26 b' class BaseAppView(object):'
147 % repo_name)
147 % repo_name)
148 return msg
148 return msg
149
149
150 def _get_local_tmpl_context(self, include_app_defaults=False):
150 def _get_local_tmpl_context(self, include_app_defaults=True):
151 c = TemplateArgs()
151 c = TemplateArgs()
152 c.auth_user = self.request.user
152 c.auth_user = self.request.user
153 # TODO(marcink): migrate the usage of c.rhodecode_user to c.auth_user
153 # TODO(marcink): migrate the usage of c.rhodecode_user to c.auth_user
154 c.rhodecode_user = self.request.user
154 c.rhodecode_user = self.request.user
155
155
156 if include_app_defaults:
156 if include_app_defaults:
157 # NOTE(marcink): after full pyramid migration include_app_defaults
158 # should be turned on by default
159 from rhodecode.lib.base import attach_context_attributes
157 from rhodecode.lib.base import attach_context_attributes
160 attach_context_attributes(c, self.request, self.request.user.user_id)
158 attach_context_attributes(c, self.request, self.request.user.user_id)
161
159
162 return c
160 return c
163
161
164 def _register_global_c(self, tmpl_args):
162 def _get_template_context(self, tmpl_args, **kwargs):
165 """
166 Registers attributes to pylons global `c`
167 """
168
169 # TODO(marcink): remove once pyramid migration is finished
170 from pylons import tmpl_context as c
171 try:
172 for k, v in tmpl_args.items():
173 setattr(c, k, v)
174 except TypeError:
175 log.exception('Failed to register pylons C')
176 pass
177
178 def _get_template_context(self, tmpl_args):
179 self._register_global_c(tmpl_args)
180
163
181 local_tmpl_args = {
164 local_tmpl_args = {
182 'defaults': {},
165 'defaults': {},
183 'errors': {},
166 'errors': {},
184 # register a fake 'c' to be used in templates instead of global
167 'c': tmpl_args
185 # pylons c, after migration to pyramid we should rename it to 'c'
186 # make sure we replace usage of _c in templates too
187 '_c': tmpl_args
188 }
168 }
189 local_tmpl_args.update(tmpl_args)
169 local_tmpl_args.update(kwargs)
190 return local_tmpl_args
170 return local_tmpl_args
191
171
192 def load_default_context(self):
172 def load_default_context(self):
@@ -196,7 +176,7 b' class BaseAppView(object):'
196 def load_default_context(self):
176 def load_default_context(self):
197 c = self._get_local_tmpl_context()
177 c = self._get_local_tmpl_context()
198 c.custom_var = 'foobar'
178 c.custom_var = 'foobar'
199 self._register_global_c(c)
179
200 return c
180 return c
201 """
181 """
202 raise NotImplementedError('Needs implementation in view class')
182 raise NotImplementedError('Needs implementation in view class')
@@ -215,7 +195,7 b' class RepoAppView(BaseAppView):'
215 'Requirements are missing for repository %s: %s',
195 'Requirements are missing for repository %s: %s',
216 self.db_repo_name, error.message)
196 self.db_repo_name, error.message)
217
197
218 def _get_local_tmpl_context(self, include_app_defaults=False):
198 def _get_local_tmpl_context(self, include_app_defaults=True):
219 _ = self.request.translate
199 _ = self.request.translate
220 c = super(RepoAppView, self)._get_local_tmpl_context(
200 c = super(RepoAppView, self)._get_local_tmpl_context(
221 include_app_defaults=include_app_defaults)
201 include_app_defaults=include_app_defaults)
@@ -338,7 +318,7 b' class BaseReferencesView(RepoAppView):'
338 def load_default_context(self):
318 def load_default_context(self):
339 c = self._get_local_tmpl_context()
319 c = self._get_local_tmpl_context()
340
320
341 self._register_global_c(c)
321
342 return c
322 return c
343
323
344 def load_refs_context(self, ref_items, partials_template):
324 def load_refs_context(self, ref_items, partials_template):
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -19,9 +19,7 b''
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 from rhodecode.apps.admin.navigation import NavigationRegistry
22 from rhodecode.apps._base import ADMIN_PREFIX
23 from rhodecode.config.routing import ADMIN_PREFIX
24 from rhodecode.lib.utils2 import str2bool
25
23
26
24
27 def admin_routes(config):
25 def admin_routes(config):
@@ -72,8 +70,14 b' def admin_routes(config):'
72 name='admin_settings_process_management',
70 name='admin_settings_process_management',
73 pattern='/settings/process_management')
71 pattern='/settings/process_management')
74 config.add_route(
72 config.add_route(
73 name='admin_settings_process_management_data',
74 pattern='/settings/process_management/data')
75 config.add_route(
75 name='admin_settings_process_management_signal',
76 name='admin_settings_process_management_signal',
76 pattern='/settings/process_management/signal')
77 pattern='/settings/process_management/signal')
78 config.add_route(
79 name='admin_settings_process_management_master_signal',
80 pattern='/settings/process_management/master_signal')
77
81
78 # default settings
82 # default settings
79 config.add_route(
83 config.add_route(
@@ -83,6 +87,88 b' def admin_routes(config):'
83 name='admin_defaults_repositories_update',
87 name='admin_defaults_repositories_update',
84 pattern='/defaults/repositories/update')
88 pattern='/defaults/repositories/update')
85
89
90 # admin settings
91
92 config.add_route(
93 name='admin_settings',
94 pattern='/settings')
95 config.add_route(
96 name='admin_settings_update',
97 pattern='/settings/update')
98
99 config.add_route(
100 name='admin_settings_global',
101 pattern='/settings/global')
102 config.add_route(
103 name='admin_settings_global_update',
104 pattern='/settings/global/update')
105
106 config.add_route(
107 name='admin_settings_vcs',
108 pattern='/settings/vcs')
109 config.add_route(
110 name='admin_settings_vcs_update',
111 pattern='/settings/vcs/update')
112 config.add_route(
113 name='admin_settings_vcs_svn_pattern_delete',
114 pattern='/settings/vcs/svn_pattern_delete')
115
116 config.add_route(
117 name='admin_settings_mapping',
118 pattern='/settings/mapping')
119 config.add_route(
120 name='admin_settings_mapping_update',
121 pattern='/settings/mapping/update')
122
123 config.add_route(
124 name='admin_settings_visual',
125 pattern='/settings/visual')
126 config.add_route(
127 name='admin_settings_visual_update',
128 pattern='/settings/visual/update')
129
130
131 config.add_route(
132 name='admin_settings_issuetracker',
133 pattern='/settings/issue-tracker')
134 config.add_route(
135 name='admin_settings_issuetracker_update',
136 pattern='/settings/issue-tracker/update')
137 config.add_route(
138 name='admin_settings_issuetracker_test',
139 pattern='/settings/issue-tracker/test')
140 config.add_route(
141 name='admin_settings_issuetracker_delete',
142 pattern='/settings/issue-tracker/delete')
143
144 config.add_route(
145 name='admin_settings_email',
146 pattern='/settings/email')
147 config.add_route(
148 name='admin_settings_email_update',
149 pattern='/settings/email/update')
150
151 config.add_route(
152 name='admin_settings_hooks',
153 pattern='/settings/hooks')
154 config.add_route(
155 name='admin_settings_hooks_update',
156 pattern='/settings/hooks/update')
157 config.add_route(
158 name='admin_settings_hooks_delete',
159 pattern='/settings/hooks/delete')
160
161 config.add_route(
162 name='admin_settings_search',
163 pattern='/settings/search')
164
165 config.add_route(
166 name='admin_settings_labs',
167 pattern='/settings/labs')
168 config.add_route(
169 name='admin_settings_labs_update',
170 pattern='/settings/labs/update')
171
86 # global permissions
172 # global permissions
87
173
88 config.add_route(
174 config.add_route(
@@ -237,7 +323,7 b' def admin_routes(config):'
237 config.add_route(
323 config.add_route(
238 name='edit_user_ips_delete',
324 name='edit_user_ips_delete',
239 pattern='/users/{user_id:\d+}/edit/ips/delete',
325 pattern='/users/{user_id:\d+}/edit/ips/delete',
240 user_route_with_default=True) # enabled for default user too
326 user_route_with_default=True) # enabled for default user too
241
327
242 # user perms
328 # user perms
243 config.add_route(
329 config.add_route(
@@ -310,12 +396,10 b' def admin_routes(config):'
310
396
311
397
312 def includeme(config):
398 def includeme(config):
313 settings = config.get_settings()
399 from rhodecode.apps.admin.navigation import includeme as nav_includeme
314
400
315 # Create admin navigation registry and add it to the pyramid registry.
401 # Create admin navigation registry and add it to the pyramid registry.
316 labs_active = str2bool(settings.get('labs_settings_active', False))
402 nav_includeme(config)
317 navigation_registry = NavigationRegistry(labs_active=labs_active)
318 config.registry.registerUtility(navigation_registry)
319
403
320 # main admin routes
404 # main admin routes
321 config.add_route(name='admin_home', pattern=ADMIN_PREFIX)
405 config.add_route(name='admin_home', pattern=ADMIN_PREFIX)
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -25,13 +25,14 b' import collections'
25 from zope.interface import implementer
25 from zope.interface import implementer
26
26
27 from rhodecode.apps.admin.interfaces import IAdminNavigationRegistry
27 from rhodecode.apps.admin.interfaces import IAdminNavigationRegistry
28 from rhodecode.lib.utils import get_registry
28 from rhodecode.lib.utils2 import str2bool
29 from rhodecode.translation import _
29 from rhodecode.translation import _
30
30
31
31
32 log = logging.getLogger(__name__)
32 log = logging.getLogger(__name__)
33
33
34 NavListEntry = collections.namedtuple('NavListEntry', ['key', 'name', 'url'])
34 NavListEntry = collections.namedtuple(
35 'NavListEntry', ['key', 'name', 'url', 'active_list'])
35
36
36
37
37 class NavEntry(object):
38 class NavEntry(object):
@@ -41,77 +42,69 b' class NavEntry(object):'
41 :param key: Unique identifier used to store reference in an OrderedDict.
42 :param key: Unique identifier used to store reference in an OrderedDict.
42 :param name: Display name, usually a translation string.
43 :param name: Display name, usually a translation string.
43 :param view_name: Name of the view, used generate the URL.
44 :param view_name: Name of the view, used generate the URL.
44 :param pyramid: Indicator to use pyramid for URL generation. This should
45 :param active_list: list of urls that we select active for this element
45 be removed as soon as we are fully migrated to pyramid.
46 """
46 """
47
47
48 def __init__(self, key, name, view_name, pyramid=False):
48 def __init__(self, key, name, view_name, active_list=None):
49 self.key = key
49 self.key = key
50 self.name = name
50 self.name = name
51 self.view_name = view_name
51 self.view_name = view_name
52 self.pyramid = pyramid
52 self._active_list = active_list or []
53
53
54 def generate_url(self, request):
54 def generate_url(self, request):
55 if self.pyramid:
55 return request.route_path(self.view_name)
56 if hasattr(request, 'route_path'):
57 return request.route_path(self.view_name)
58 else:
59 # TODO: johbo: Remove this after migrating to pyramid.
60 # We need the pyramid request here to generate URLs to pyramid
61 # views from within pylons views.
62 from pyramid.threadlocal import get_current_request
63 pyramid_request = get_current_request()
64 return pyramid_request.route_path(self.view_name)
65 else:
66 from pylons import url
67 return url(self.view_name)
68
56
69 def get_localized_name(self, request):
57 def get_localized_name(self, request):
70 if hasattr(request, 'translate'):
58 return request.translate(self.name)
71 return request.translate(self.name)
59
72 else:
60 @property
73 # TODO(marcink): Remove this after migrating to pyramid
61 def active_list(self):
74 from pyramid.threadlocal import get_current_request
62 active_list = [self.key]
75 pyramid_request = get_current_request()
63 if self._active_list:
76 return pyramid_request.translate(self.name)
64 active_list = self._active_list
65 return active_list
77
66
78
67
79 @implementer(IAdminNavigationRegistry)
68 @implementer(IAdminNavigationRegistry)
80 class NavigationRegistry(object):
69 class NavigationRegistry(object):
81
70
82 _base_entries = [
71 _base_entries = [
83 NavEntry('global', _('Global'), 'admin_settings_global'),
72 NavEntry('global', _('Global'),
84 NavEntry('vcs', _('VCS'), 'admin_settings_vcs'),
73 'admin_settings_global'),
85 NavEntry('visual', _('Visual'), 'admin_settings_visual'),
74 NavEntry('vcs', _('VCS'),
86 NavEntry('mapping', _('Remap and Rescan'), 'admin_settings_mapping'),
75 'admin_settings_vcs'),
76 NavEntry('visual', _('Visual'),
77 'admin_settings_visual'),
78 NavEntry('mapping', _('Remap and Rescan'),
79 'admin_settings_mapping'),
87 NavEntry('issuetracker', _('Issue Tracker'),
80 NavEntry('issuetracker', _('Issue Tracker'),
88 'admin_settings_issuetracker'),
81 'admin_settings_issuetracker'),
89 NavEntry('email', _('Email'), 'admin_settings_email'),
82 NavEntry('email', _('Email'),
90 NavEntry('hooks', _('Hooks'), 'admin_settings_hooks'),
83 'admin_settings_email'),
91 NavEntry('search', _('Full Text Search'), 'admin_settings_search'),
84 NavEntry('hooks', _('Hooks'),
92
85 'admin_settings_hooks'),
86 NavEntry('search', _('Full Text Search'),
87 'admin_settings_search'),
93 NavEntry('integrations', _('Integrations'),
88 NavEntry('integrations', _('Integrations'),
94 'global_integrations_home', pyramid=True),
89 'global_integrations_home'),
95 NavEntry('system', _('System Info'),
90 NavEntry('system', _('System Info'),
96 'admin_settings_system', pyramid=True),
91 'admin_settings_system'),
97 NavEntry('process_management', _('Processes'),
92 NavEntry('process_management', _('Processes'),
98 'admin_settings_process_management', pyramid=True),
93 'admin_settings_process_management'),
99 NavEntry('sessions', _('User Sessions'),
94 NavEntry('sessions', _('User Sessions'),
100 'admin_settings_sessions', pyramid=True),
95 'admin_settings_sessions'),
101 NavEntry('open_source', _('Open Source Licenses'),
96 NavEntry('open_source', _('Open Source Licenses'),
102 'admin_settings_open_source', pyramid=True),
97 'admin_settings_open_source'),
103
98
104 # TODO: marcink: we disable supervisor now until the supervisor stats
105 # page is fixed in the nix configuration
106 # NavEntry('supervisor', _('Supervisor'), 'admin_settings_supervisor'),
107 ]
99 ]
108
100
109 _labs_entry = NavEntry('labs', _('Labs'), 'admin_settings_labs')
101 _labs_entry = NavEntry('labs', _('Labs'),
102 'admin_settings_labs')
110
103
111 def __init__(self, labs_active=False):
104 def __init__(self, labs_active=False):
112 self._registered_entries = collections.OrderedDict([
105 self._registered_entries = collections.OrderedDict()
113 (item.key, item) for item in self.__class__._base_entries
106 for item in self.__class__._base_entries:
114 ])
107 self._registered_entries[item.key] = item
115
108
116 if labs_active:
109 if labs_active:
117 self.add_entry(self._labs_entry)
110 self.add_entry(self._labs_entry)
@@ -121,16 +114,16 b' class NavigationRegistry(object):'
121
114
122 def get_navlist(self, request):
115 def get_navlist(self, request):
123 navlist = [NavListEntry(i.key, i.get_localized_name(request),
116 navlist = [NavListEntry(i.key, i.get_localized_name(request),
124 i.generate_url(request))
117 i.generate_url(request), i.active_list)
125 for i in self._registered_entries.values()]
118 for i in self._registered_entries.values()]
126 return navlist
119 return navlist
127
120
128
121
129 def navigation_registry(request):
122 def navigation_registry(request, registry=None):
130 """
123 """
131 Helper that returns the admin navigation registry.
124 Helper that returns the admin navigation registry.
132 """
125 """
133 pyramid_registry = get_registry(request)
126 pyramid_registry = registry or request.registry
134 nav_registry = pyramid_registry.queryUtility(IAdminNavigationRegistry)
127 nav_registry = pyramid_registry.queryUtility(IAdminNavigationRegistry)
135 return nav_registry
128 return nav_registry
136
129
@@ -140,3 +133,11 b' def navigation_list(request):'
140 Helper that returns the admin navigation as list of NavListEntry objects.
133 Helper that returns the admin navigation as list of NavListEntry objects.
141 """
134 """
142 return navigation_registry(request).get_navlist(request)
135 return navigation_registry(request).get_navlist(request)
136
137
138 def includeme(config):
139 # Create admin navigation registry and add it to the pyramid registry.
140 settings = config.get_settings()
141 labs_active = str2bool(settings.get('labs_settings_active', False))
142 navigation_registry = NavigationRegistry(labs_active=labs_active)
143 config.registry.registerUtility(navigation_registry) No newline at end of file
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -46,10 +46,11 b' def route_path(name, params=None, **kwar'
46 return base_url
46 return base_url
47
47
48
48
49 class TestAdminController(TestController):
49 @pytest.mark.usefixtures('app')
50 class TestAdminController(object):
50
51
51 @pytest.fixture(scope='class', autouse=True)
52 @pytest.fixture(scope='class', autouse=True)
52 def prepare(self, request, pylonsapp):
53 def prepare(self, request, baseapp):
53 UserLog.query().delete()
54 UserLog.query().delete()
54 Session().commit()
55 Session().commit()
55
56
@@ -84,104 +85,87 b' class TestAdminController(TestController'
84 UserLog.query().delete()
85 UserLog.query().delete()
85 Session().commit()
86 Session().commit()
86
87
87 def test_index(self):
88 def test_index(self, autologin_user):
88 self.log_user()
89 response = self.app.get(route_path('admin_audit_logs'))
89 response = self.app.get(route_path('admin_audit_logs'))
90 response.mustcontain('Admin audit logs')
90 response.mustcontain('Admin audit logs')
91
91
92 def test_filter_all_entries(self):
92 def test_filter_all_entries(self, autologin_user):
93 self.log_user()
94 response = self.app.get(route_path('admin_audit_logs'))
93 response = self.app.get(route_path('admin_audit_logs'))
95 all_count = UserLog.query().count()
94 all_count = UserLog.query().count()
96 response.mustcontain('%s entries' % all_count)
95 response.mustcontain('%s entries' % all_count)
97
96
98 def test_filter_journal_filter_exact_match_on_repository(self):
97 def test_filter_journal_filter_exact_match_on_repository(self, autologin_user):
99 self.log_user()
100 response = self.app.get(route_path('admin_audit_logs',
98 response = self.app.get(route_path('admin_audit_logs',
101 params=dict(filter='repository:rhodecode')))
99 params=dict(filter='repository:rhodecode')))
102 response.mustcontain('3 entries')
100 response.mustcontain('3 entries')
103
101
104 def test_filter_journal_filter_exact_match_on_repository_CamelCase(self):
102 def test_filter_journal_filter_exact_match_on_repository_CamelCase(self, autologin_user):
105 self.log_user()
106 response = self.app.get(route_path('admin_audit_logs',
103 response = self.app.get(route_path('admin_audit_logs',
107 params=dict(filter='repository:RhodeCode')))
104 params=dict(filter='repository:RhodeCode')))
108 response.mustcontain('3 entries')
105 response.mustcontain('3 entries')
109
106
110 def test_filter_journal_filter_wildcard_on_repository(self):
107 def test_filter_journal_filter_wildcard_on_repository(self, autologin_user):
111 self.log_user()
112 response = self.app.get(route_path('admin_audit_logs',
108 response = self.app.get(route_path('admin_audit_logs',
113 params=dict(filter='repository:*test*')))
109 params=dict(filter='repository:*test*')))
114 response.mustcontain('862 entries')
110 response.mustcontain('862 entries')
115
111
116 def test_filter_journal_filter_prefix_on_repository(self):
112 def test_filter_journal_filter_prefix_on_repository(self, autologin_user):
117 self.log_user()
118 response = self.app.get(route_path('admin_audit_logs',
113 response = self.app.get(route_path('admin_audit_logs',
119 params=dict(filter='repository:test*')))
114 params=dict(filter='repository:test*')))
120 response.mustcontain('257 entries')
115 response.mustcontain('257 entries')
121
116
122 def test_filter_journal_filter_prefix_on_repository_CamelCase(self):
117 def test_filter_journal_filter_prefix_on_repository_CamelCase(self, autologin_user):
123 self.log_user()
124 response = self.app.get(route_path('admin_audit_logs',
118 response = self.app.get(route_path('admin_audit_logs',
125 params=dict(filter='repository:Test*')))
119 params=dict(filter='repository:Test*')))
126 response.mustcontain('257 entries')
120 response.mustcontain('257 entries')
127
121
128 def test_filter_journal_filter_prefix_on_repository_and_user(self):
122 def test_filter_journal_filter_prefix_on_repository_and_user(self, autologin_user):
129 self.log_user()
130 response = self.app.get(route_path('admin_audit_logs',
123 response = self.app.get(route_path('admin_audit_logs',
131 params=dict(filter='repository:test* AND username:demo')))
124 params=dict(filter='repository:test* AND username:demo')))
132 response.mustcontain('130 entries')
125 response.mustcontain('130 entries')
133
126
134 def test_filter_journal_filter_prefix_on_repository_or_target_repo(self):
127 def test_filter_journal_filter_prefix_on_repository_or_target_repo(self, autologin_user):
135 self.log_user()
136 response = self.app.get(route_path('admin_audit_logs',
128 response = self.app.get(route_path('admin_audit_logs',
137 params=dict(filter='repository:test* OR repository:rhodecode')))
129 params=dict(filter='repository:test* OR repository:rhodecode')))
138 response.mustcontain('260 entries') # 257 + 3
130 response.mustcontain('260 entries') # 257 + 3
139
131
140 def test_filter_journal_filter_exact_match_on_username(self):
132 def test_filter_journal_filter_exact_match_on_username(self, autologin_user):
141 self.log_user()
142 response = self.app.get(route_path('admin_audit_logs',
133 response = self.app.get(route_path('admin_audit_logs',
143 params=dict(filter='username:demo')))
134 params=dict(filter='username:demo')))
144 response.mustcontain('1087 entries')
135 response.mustcontain('1087 entries')
145
136
146 def test_filter_journal_filter_exact_match_on_username_camelCase(self):
137 def test_filter_journal_filter_exact_match_on_username_camelCase(self, autologin_user):
147 self.log_user()
148 response = self.app.get(route_path('admin_audit_logs',
138 response = self.app.get(route_path('admin_audit_logs',
149 params=dict(filter='username:DemO')))
139 params=dict(filter='username:DemO')))
150 response.mustcontain('1087 entries')
140 response.mustcontain('1087 entries')
151
141
152 def test_filter_journal_filter_wildcard_on_username(self):
142 def test_filter_journal_filter_wildcard_on_username(self, autologin_user):
153 self.log_user()
154 response = self.app.get(route_path('admin_audit_logs',
143 response = self.app.get(route_path('admin_audit_logs',
155 params=dict(filter='username:*test*')))
144 params=dict(filter='username:*test*')))
156 entries_count = UserLog.query().filter(UserLog.username.ilike('%test%')).count()
145 entries_count = UserLog.query().filter(UserLog.username.ilike('%test%')).count()
157 response.mustcontain('{} entries'.format(entries_count))
146 response.mustcontain('{} entries'.format(entries_count))
158
147
159 def test_filter_journal_filter_prefix_on_username(self):
148 def test_filter_journal_filter_prefix_on_username(self, autologin_user):
160 self.log_user()
161 response = self.app.get(route_path('admin_audit_logs',
149 response = self.app.get(route_path('admin_audit_logs',
162 params=dict(filter='username:demo*')))
150 params=dict(filter='username:demo*')))
163 response.mustcontain('1101 entries')
151 response.mustcontain('1101 entries')
164
152
165 def test_filter_journal_filter_prefix_on_user_or_other_user(self):
153 def test_filter_journal_filter_prefix_on_user_or_other_user(self, autologin_user):
166 self.log_user()
167 response = self.app.get(route_path('admin_audit_logs',
154 response = self.app.get(route_path('admin_audit_logs',
168 params=dict(filter='username:demo OR username:volcan')))
155 params=dict(filter='username:demo OR username:volcan')))
169 response.mustcontain('1095 entries') # 1087 + 8
156 response.mustcontain('1095 entries') # 1087 + 8
170
157
171 def test_filter_journal_filter_wildcard_on_action(self):
158 def test_filter_journal_filter_wildcard_on_action(self, autologin_user):
172 self.log_user()
173 response = self.app.get(route_path('admin_audit_logs',
159 response = self.app.get(route_path('admin_audit_logs',
174 params=dict(filter='action:*pull_request*')))
160 params=dict(filter='action:*pull_request*')))
175 response.mustcontain('187 entries')
161 response.mustcontain('187 entries')
176
162
177 def test_filter_journal_filter_on_date(self):
163 def test_filter_journal_filter_on_date(self, autologin_user):
178 self.log_user()
179 response = self.app.get(route_path('admin_audit_logs',
164 response = self.app.get(route_path('admin_audit_logs',
180 params=dict(filter='date:20121010')))
165 params=dict(filter='date:20121010')))
181 response.mustcontain('47 entries')
166 response.mustcontain('47 entries')
182
167
183 def test_filter_journal_filter_on_date_2(self):
168 def test_filter_journal_filter_on_date_2(self, autologin_user):
184 self.log_user()
185 response = self.app.get(route_path('admin_audit_logs',
169 response = self.app.get(route_path('admin_audit_logs',
186 params=dict(filter='date:20121020')))
170 params=dict(filter='date:20121020')))
187 response.mustcontain('17 entries')
171 response.mustcontain('17 entries')
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -32,7 +32,7 b' def assert_auth_settings_updated(respons'
32
32
33
33
34 @pytest.mark.usefixtures("autologin_user", "app")
34 @pytest.mark.usefixtures("autologin_user", "app")
35 class TestAuthSettingsController(object):
35 class TestAuthSettingsView(object):
36
36
37 def _enable_plugins(self, plugins_list, csrf_token, override=None,
37 def _enable_plugins(self, plugins_list, csrf_token, override=None,
38 verify_response=False):
38 verify_response=False):
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -22,17 +22,88 b' import mock'
22 import pytest
22 import pytest
23
23
24 import rhodecode
24 import rhodecode
25 from rhodecode.config.routing import ADMIN_PREFIX
25 from rhodecode.apps._base import ADMIN_PREFIX
26 from rhodecode.lib.utils2 import md5
26 from rhodecode.lib.utils2 import md5
27 from rhodecode.model.db import RhodeCodeUi
27 from rhodecode.model.db import RhodeCodeUi
28 from rhodecode.model.meta import Session
28 from rhodecode.model.meta import Session
29 from rhodecode.model.settings import SettingsModel, IssueTrackerSettingsModel
29 from rhodecode.model.settings import SettingsModel, IssueTrackerSettingsModel
30 from rhodecode.tests import url, assert_session_flash
30 from rhodecode.tests import assert_session_flash
31 from rhodecode.tests.utils import AssertResponse
31 from rhodecode.tests.utils import AssertResponse
32
32
33
33
34 UPDATE_DATA_QUALNAME = (
34 UPDATE_DATA_QUALNAME = 'rhodecode.model.update.UpdateModel.get_update_data'
35 'rhodecode.apps.admin.views.system_info.AdminSystemInfoSettingsView.get_update_data')
35
36
37 def route_path(name, params=None, **kwargs):
38 import urllib
39 from rhodecode.apps._base import ADMIN_PREFIX
40
41 base_url = {
42
43 'admin_settings':
44 ADMIN_PREFIX +'/settings',
45 'admin_settings_update':
46 ADMIN_PREFIX + '/settings/update',
47 'admin_settings_global':
48 ADMIN_PREFIX + '/settings/global',
49 'admin_settings_global_update':
50 ADMIN_PREFIX + '/settings/global/update',
51 'admin_settings_vcs':
52 ADMIN_PREFIX + '/settings/vcs',
53 'admin_settings_vcs_update':
54 ADMIN_PREFIX + '/settings/vcs/update',
55 'admin_settings_vcs_svn_pattern_delete':
56 ADMIN_PREFIX + '/settings/vcs/svn_pattern_delete',
57 'admin_settings_mapping':
58 ADMIN_PREFIX + '/settings/mapping',
59 'admin_settings_mapping_update':
60 ADMIN_PREFIX + '/settings/mapping/update',
61 'admin_settings_visual':
62 ADMIN_PREFIX + '/settings/visual',
63 'admin_settings_visual_update':
64 ADMIN_PREFIX + '/settings/visual/update',
65 'admin_settings_issuetracker':
66 ADMIN_PREFIX + '/settings/issue-tracker',
67 'admin_settings_issuetracker_update':
68 ADMIN_PREFIX + '/settings/issue-tracker/update',
69 'admin_settings_issuetracker_test':
70 ADMIN_PREFIX + '/settings/issue-tracker/test',
71 'admin_settings_issuetracker_delete':
72 ADMIN_PREFIX + '/settings/issue-tracker/delete',
73 'admin_settings_email':
74 ADMIN_PREFIX + '/settings/email',
75 'admin_settings_email_update':
76 ADMIN_PREFIX + '/settings/email/update',
77 'admin_settings_hooks':
78 ADMIN_PREFIX + '/settings/hooks',
79 'admin_settings_hooks_update':
80 ADMIN_PREFIX + '/settings/hooks/update',
81 'admin_settings_hooks_delete':
82 ADMIN_PREFIX + '/settings/hooks/delete',
83 'admin_settings_search':
84 ADMIN_PREFIX + '/settings/search',
85 'admin_settings_labs':
86 ADMIN_PREFIX + '/settings/labs',
87 'admin_settings_labs_update':
88 ADMIN_PREFIX + '/settings/labs/update',
89
90 'admin_settings_sessions':
91 ADMIN_PREFIX + '/settings/sessions',
92 'admin_settings_sessions_cleanup':
93 ADMIN_PREFIX + '/settings/sessions/cleanup',
94 'admin_settings_system':
95 ADMIN_PREFIX + '/settings/system',
96 'admin_settings_system_update':
97 ADMIN_PREFIX + '/settings/system/updates',
98 'admin_settings_open_source':
99 ADMIN_PREFIX + '/settings/open_source',
100
101
102 }[name].format(**kwargs)
103
104 if params:
105 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
106 return base_url
36
107
37
108
38 @pytest.mark.usefixtures('autologin_user', 'app')
109 @pytest.mark.usefixtures('autologin_user', 'app')
@@ -47,12 +118,12 b' class TestAdminSettingsController(object'
47 'admin_settings_hooks',
118 'admin_settings_hooks',
48 'admin_settings_search',
119 'admin_settings_search',
49 ])
120 ])
50 def test_simple_get(self, urlname, app):
121 def test_simple_get(self, urlname):
51 app.get(url(urlname))
122 self.app.get(route_path(urlname))
52
123
53 def test_create_custom_hook(self, csrf_token):
124 def test_create_custom_hook(self, csrf_token):
54 response = self.app.post(
125 response = self.app.post(
55 url('admin_settings_hooks'),
126 route_path('admin_settings_hooks_update'),
56 params={
127 params={
57 'new_hook_ui_key': 'test_hooks_1',
128 'new_hook_ui_key': 'test_hooks_1',
58 'new_hook_ui_value': 'cd /tmp',
129 'new_hook_ui_value': 'cd /tmp',
@@ -64,7 +135,7 b' class TestAdminSettingsController(object'
64
135
65 def test_create_custom_hook_delete(self, csrf_token):
136 def test_create_custom_hook_delete(self, csrf_token):
66 response = self.app.post(
137 response = self.app.post(
67 url('admin_settings_hooks'),
138 route_path('admin_settings_hooks_update'),
68 params={
139 params={
69 'new_hook_ui_key': 'test_hooks_2',
140 'new_hook_ui_key': 'test_hooks_2',
70 'new_hook_ui_value': 'cd /tmp2',
141 'new_hook_ui_value': 'cd /tmp2',
@@ -78,9 +149,9 b' class TestAdminSettingsController(object'
78
149
79 # delete
150 # delete
80 self.app.post(
151 self.app.post(
81 url('admin_settings_hooks'),
152 route_path('admin_settings_hooks_delete'),
82 params={'hook_id': hook_id, 'csrf_token': csrf_token})
153 params={'hook_id': hook_id, 'csrf_token': csrf_token})
83 response = self.app.get(url('admin_settings_hooks'))
154 response = self.app.get(route_path('admin_settings_hooks'))
84 response.mustcontain(no=['test_hooks_2'])
155 response.mustcontain(no=['test_hooks_2'])
85 response.mustcontain(no=['cd /tmp2'])
156 response.mustcontain(no=['cd /tmp2'])
86
157
@@ -135,7 +206,6 b' class TestAdminSettingsGlobal(object):'
135
206
136 def test_title_change(self, csrf_token):
207 def test_title_change(self, csrf_token):
137 old_title = 'RhodeCode'
208 old_title = 'RhodeCode'
138 new_title = old_title + '_changed'
139
209
140 for new_title in ['Changed', 'Żółwik', old_title]:
210 for new_title in ['Changed', 'Żółwik', old_title]:
141 response = self.post_and_verify_settings({
211 response = self.post_and_verify_settings({
@@ -161,7 +231,8 b' class TestAdminSettingsGlobal(object):'
161 'rhodecode_personal_repo_group_pattern': '${username}',
231 'rhodecode_personal_repo_group_pattern': '${username}',
162 }
232 }
163 params.update(settings)
233 params.update(settings)
164 response = self.app.post(url('admin_settings_global'), params=params)
234 response = self.app.post(
235 route_path('admin_settings_global_update'), params=params)
165
236
166 assert_session_flash(response, 'Updated application settings')
237 assert_session_flash(response, 'Updated application settings')
167 app_settings = SettingsModel().get_all_settings()
238 app_settings = SettingsModel().get_all_settings()
@@ -175,8 +246,8 b' class TestAdminSettingsGlobal(object):'
175 @pytest.mark.usefixtures('autologin_user', 'app')
246 @pytest.mark.usefixtures('autologin_user', 'app')
176 class TestAdminSettingsVcs(object):
247 class TestAdminSettingsVcs(object):
177
248
178 def test_contains_svn_default_patterns(self, app):
249 def test_contains_svn_default_patterns(self):
179 response = app.get(url('admin_settings_vcs'))
250 response = self.app.get(route_path('admin_settings_vcs'))
180 expected_patterns = [
251 expected_patterns = [
181 '/trunk',
252 '/trunk',
182 '/branches/*',
253 '/branches/*',
@@ -186,7 +257,7 b' class TestAdminSettingsVcs(object):'
186 response.mustcontain(pattern)
257 response.mustcontain(pattern)
187
258
188 def test_add_new_svn_branch_and_tag_pattern(
259 def test_add_new_svn_branch_and_tag_pattern(
189 self, app, backend_svn, form_defaults, disable_sql_cache,
260 self, backend_svn, form_defaults, disable_sql_cache,
190 csrf_token):
261 csrf_token):
191 form_defaults.update({
262 form_defaults.update({
192 'new_svn_branch': '/exp/branches/*',
263 'new_svn_branch': '/exp/branches/*',
@@ -194,8 +265,9 b' class TestAdminSettingsVcs(object):'
194 'csrf_token': csrf_token,
265 'csrf_token': csrf_token,
195 })
266 })
196
267
197 response = app.post(
268 response = self.app.post(
198 url('admin_settings_vcs'), params=form_defaults, status=302)
269 route_path('admin_settings_vcs_update'),
270 params=form_defaults, status=302)
199 response = response.follow()
271 response = response.follow()
200
272
201 # Expect to find the new values on the page
273 # Expect to find the new values on the page
@@ -208,12 +280,12 b' class TestAdminSettingsVcs(object):'
208 assert 'important_tags/v0.5' in repo.tags
280 assert 'important_tags/v0.5' in repo.tags
209
281
210 def test_add_same_svn_value_twice_shows_an_error_message(
282 def test_add_same_svn_value_twice_shows_an_error_message(
211 self, app, form_defaults, csrf_token, settings_util):
283 self, form_defaults, csrf_token, settings_util):
212 settings_util.create_rhodecode_ui('vcs_svn_branch', '/test')
284 settings_util.create_rhodecode_ui('vcs_svn_branch', '/test')
213 settings_util.create_rhodecode_ui('vcs_svn_tag', '/test')
285 settings_util.create_rhodecode_ui('vcs_svn_tag', '/test')
214
286
215 response = app.post(
287 response = self.app.post(
216 url('admin_settings_vcs'),
288 route_path('admin_settings_vcs_update'),
217 params={
289 params={
218 'paths_root_path': form_defaults['paths_root_path'],
290 'paths_root_path': form_defaults['paths_root_path'],
219 'new_svn_branch': '/test',
291 'new_svn_branch': '/test',
@@ -230,14 +302,13 b' class TestAdminSettingsVcs(object):'
230 'vcs_svn_tag',
302 'vcs_svn_tag',
231 ])
303 ])
232 def test_delete_svn_patterns(
304 def test_delete_svn_patterns(
233 self, section, app, csrf_token, settings_util):
305 self, section, csrf_token, settings_util):
234 setting = settings_util.create_rhodecode_ui(
306 setting = settings_util.create_rhodecode_ui(
235 section, '/test_delete', cleanup=False)
307 section, '/test_delete', cleanup=False)
236
308
237 app.post(
309 self.app.post(
238 url('admin_settings_vcs'),
310 route_path('admin_settings_vcs_svn_pattern_delete'),
239 params={
311 params={
240 '_method': 'delete',
241 'delete_svn_pattern': setting.ui_id,
312 'delete_svn_pattern': setting.ui_id,
242 'csrf_token': csrf_token},
313 'csrf_token': csrf_token},
243 headers={'X-REQUESTED-WITH': 'XMLHttpRequest'})
314 headers={'X-REQUESTED-WITH': 'XMLHttpRequest'})
@@ -246,25 +317,24 b' class TestAdminSettingsVcs(object):'
246 'vcs_svn_branch',
317 'vcs_svn_branch',
247 'vcs_svn_tag',
318 'vcs_svn_tag',
248 ])
319 ])
249 def test_delete_svn_patterns_raises_400_when_no_xhr(
320 def test_delete_svn_patterns_raises_404_when_no_xhr(
250 self, section, app, csrf_token, settings_util):
321 self, section, csrf_token, settings_util):
251 setting = settings_util.create_rhodecode_ui(section, '/test_delete')
322 setting = settings_util.create_rhodecode_ui(section, '/test_delete')
252
323
253 app.post(
324 self.app.post(
254 url('admin_settings_vcs'),
325 route_path('admin_settings_vcs_svn_pattern_delete'),
255 params={
326 params={
256 '_method': 'delete',
257 'delete_svn_pattern': setting.ui_id,
327 'delete_svn_pattern': setting.ui_id,
258 'csrf_token': csrf_token},
328 'csrf_token': csrf_token},
259 status=400)
329 status=404)
260
330
261 def test_extensions_hgsubversion(self, app, form_defaults, csrf_token):
331 def test_extensions_hgsubversion(self, form_defaults, csrf_token):
262 form_defaults.update({
332 form_defaults.update({
263 'csrf_token': csrf_token,
333 'csrf_token': csrf_token,
264 'extensions_hgsubversion': 'True',
334 'extensions_hgsubversion': 'True',
265 })
335 })
266 response = app.post(
336 response = self.app.post(
267 url('admin_settings_vcs'),
337 route_path('admin_settings_vcs_update'),
268 params=form_defaults,
338 params=form_defaults,
269 status=302)
339 status=302)
270
340
@@ -275,13 +345,13 b' class TestAdminSettingsVcs(object):'
275 'value="True" checked="checked" />')
345 'value="True" checked="checked" />')
276 response.mustcontain(extensions_input)
346 response.mustcontain(extensions_input)
277
347
278 def test_extensions_hgevolve(self, app, form_defaults, csrf_token):
348 def test_extensions_hgevolve(self, form_defaults, csrf_token):
279 form_defaults.update({
349 form_defaults.update({
280 'csrf_token': csrf_token,
350 'csrf_token': csrf_token,
281 'extensions_evolve': 'True',
351 'extensions_evolve': 'True',
282 })
352 })
283 response = app.post(
353 response = self.app.post(
284 url('admin_settings_vcs'),
354 route_path('admin_settings_vcs_update'),
285 params=form_defaults,
355 params=form_defaults,
286 status=302)
356 status=302)
287
357
@@ -292,20 +362,19 b' class TestAdminSettingsVcs(object):'
292 'value="True" checked="checked" />')
362 'value="True" checked="checked" />')
293 response.mustcontain(extensions_input)
363 response.mustcontain(extensions_input)
294
364
295 def test_has_a_section_for_pull_request_settings(self, app):
365 def test_has_a_section_for_pull_request_settings(self):
296 response = app.get(url('admin_settings_vcs'))
366 response = self.app.get(route_path('admin_settings_vcs'))
297 response.mustcontain('Pull Request Settings')
367 response.mustcontain('Pull Request Settings')
298
368
299 def test_has_an_input_for_invalidation_of_inline_comments(
369 def test_has_an_input_for_invalidation_of_inline_comments(self):
300 self, app):
370 response = self.app.get(route_path('admin_settings_vcs'))
301 response = app.get(url('admin_settings_vcs'))
302 assert_response = AssertResponse(response)
371 assert_response = AssertResponse(response)
303 assert_response.one_element_exists(
372 assert_response.one_element_exists(
304 '[name=rhodecode_use_outdated_comments]')
373 '[name=rhodecode_use_outdated_comments]')
305
374
306 @pytest.mark.parametrize('new_value', [True, False])
375 @pytest.mark.parametrize('new_value', [True, False])
307 def test_allows_to_change_invalidation_of_inline_comments(
376 def test_allows_to_change_invalidation_of_inline_comments(
308 self, app, form_defaults, csrf_token, new_value):
377 self, form_defaults, csrf_token, new_value):
309 setting_key = 'use_outdated_comments'
378 setting_key = 'use_outdated_comments'
310 setting = SettingsModel().create_or_update_setting(
379 setting = SettingsModel().create_or_update_setting(
311 setting_key, not new_value, 'bool')
380 setting_key, not new_value, 'bool')
@@ -316,8 +385,8 b' class TestAdminSettingsVcs(object):'
316 'csrf_token': csrf_token,
385 'csrf_token': csrf_token,
317 'rhodecode_use_outdated_comments': str(new_value),
386 'rhodecode_use_outdated_comments': str(new_value),
318 })
387 })
319 response = app.post(
388 response = self.app.post(
320 url('admin_settings_vcs'),
389 route_path('admin_settings_vcs_update'),
321 params=form_defaults,
390 params=form_defaults,
322 status=302)
391 status=302)
323 response = response.follow()
392 response = response.follow()
@@ -326,7 +395,7 b' class TestAdminSettingsVcs(object):'
326
395
327 @pytest.mark.parametrize('new_value', [True, False])
396 @pytest.mark.parametrize('new_value', [True, False])
328 def test_allows_to_change_hg_rebase_merge_strategy(
397 def test_allows_to_change_hg_rebase_merge_strategy(
329 self, app, form_defaults, csrf_token, new_value):
398 self, form_defaults, csrf_token, new_value):
330 setting_key = 'hg_use_rebase_for_merging'
399 setting_key = 'hg_use_rebase_for_merging'
331
400
332 form_defaults.update({
401 form_defaults.update({
@@ -336,8 +405,8 b' class TestAdminSettingsVcs(object):'
336
405
337 with mock.patch.dict(
406 with mock.patch.dict(
338 rhodecode.CONFIG, {'labs_settings_active': 'true'}):
407 rhodecode.CONFIG, {'labs_settings_active': 'true'}):
339 app.post(
408 self.app.post(
340 url('admin_settings_vcs'),
409 route_path('admin_settings_vcs_update'),
341 params=form_defaults,
410 params=form_defaults,
342 status=302)
411 status=302)
343
412
@@ -353,14 +422,13 b' class TestAdminSettingsVcs(object):'
353
422
354 @pytest.fixture
423 @pytest.fixture
355 def form_defaults(self):
424 def form_defaults(self):
356 from rhodecode.controllers.admin.settings import SettingsController
425 from rhodecode.apps.admin.views.settings import AdminSettingsView
357 controller = SettingsController()
426 return AdminSettingsView._form_defaults()
358 return controller._form_defaults()
359
427
360 # TODO: johbo: What we really want is to checkpoint before a test run and
428 # TODO: johbo: What we really want is to checkpoint before a test run and
361 # reset the session afterwards.
429 # reset the session afterwards.
362 @pytest.fixture(scope='class', autouse=True)
430 @pytest.fixture(scope='class', autouse=True)
363 def cleanup_settings(self, request, pylonsapp):
431 def cleanup_settings(self, request, baseapp):
364 ui_id = RhodeCodeUi.ui_id
432 ui_id = RhodeCodeUi.ui_id
365 original_ids = list(
433 original_ids = list(
366 r.ui_id for r in RhodeCodeUi.query().values(ui_id))
434 r.ui_id for r in RhodeCodeUi.query().values(ui_id))
@@ -374,14 +442,16 b' class TestAdminSettingsVcs(object):'
374 @pytest.mark.usefixtures('autologin_user', 'app')
442 @pytest.mark.usefixtures('autologin_user', 'app')
375 class TestLabsSettings(object):
443 class TestLabsSettings(object):
376 def test_get_settings_page_disabled(self):
444 def test_get_settings_page_disabled(self):
377 with mock.patch.dict(rhodecode.CONFIG,
445 with mock.patch.dict(
378 {'labs_settings_active': 'false'}):
446 rhodecode.CONFIG, {'labs_settings_active': 'false'}):
379 response = self.app.get(url('admin_settings_labs'), status=302)
380
447
381 assert response.location.endswith(url('admin_settings'))
448 response = self.app.get(
449 route_path('admin_settings_labs'), status=302)
450
451 assert response.location.endswith(route_path('admin_settings'))
382
452
383 def test_get_settings_page_enabled(self):
453 def test_get_settings_page_enabled(self):
384 from rhodecode.controllers.admin import settings
454 from rhodecode.apps.admin.views import settings
385 lab_settings = [
455 lab_settings = [
386 settings.LabSetting(
456 settings.LabSetting(
387 key='rhodecode_bool',
457 key='rhodecode_bool',
@@ -401,7 +471,7 b' class TestLabsSettings(object):'
401 with mock.patch.dict(rhodecode.CONFIG,
471 with mock.patch.dict(rhodecode.CONFIG,
402 {'labs_settings_active': 'true'}):
472 {'labs_settings_active': 'true'}):
403 with mock.patch.object(settings, '_LAB_SETTINGS', lab_settings):
473 with mock.patch.object(settings, '_LAB_SETTINGS', lab_settings):
404 response = self.app.get(url('admin_settings_labs'))
474 response = self.app.get(route_path('admin_settings_labs'))
405
475
406 assert '<label>bool group:</label>' in response
476 assert '<label>bool group:</label>' in response
407 assert '<label for="rhodecode_bool">bool label</label>' in response
477 assert '<label for="rhodecode_bool">bool label</label>' in response
@@ -417,9 +487,6 b' class TestLabsSettings(object):'
417 @pytest.mark.usefixtures('app')
487 @pytest.mark.usefixtures('app')
418 class TestOpenSourceLicenses(object):
488 class TestOpenSourceLicenses(object):
419
489
420 def _get_url(self):
421 return ADMIN_PREFIX + '/settings/open_source'
422
423 def test_records_are_displayed(self, autologin_user):
490 def test_records_are_displayed(self, autologin_user):
424 sample_licenses = {
491 sample_licenses = {
425 "python2.7-pytest-2.7.1": {
492 "python2.7-pytest-2.7.1": {
@@ -433,7 +500,8 b' class TestOpenSourceLicenses(object):'
433 'rhodecode.apps.admin.views.open_source_licenses.read_opensource_licenses',
500 'rhodecode.apps.admin.views.open_source_licenses.read_opensource_licenses',
434 return_value=sample_licenses)
501 return_value=sample_licenses)
435 with read_licenses_patch:
502 with read_licenses_patch:
436 response = self.app.get(self._get_url(), status=200)
503 response = self.app.get(
504 route_path('admin_settings_open_source'), status=200)
437
505
438 assert_response = AssertResponse(response)
506 assert_response = AssertResponse(response)
439 assert_response.element_contains(
507 assert_response.element_contains(
@@ -444,29 +512,25 b' class TestOpenSourceLicenses(object):'
444 assert_response.element_contains('.panel-body', license)
512 assert_response.element_contains('.panel-body', license)
445
513
446 def test_records_can_be_read(self, autologin_user):
514 def test_records_can_be_read(self, autologin_user):
447 response = self.app.get(self._get_url(), status=200)
515 response = self.app.get(
516 route_path('admin_settings_open_source'), status=200)
448 assert_response = AssertResponse(response)
517 assert_response = AssertResponse(response)
449 assert_response.element_contains(
518 assert_response.element_contains(
450 '.panel-heading', 'Licenses of Third Party Packages')
519 '.panel-heading', 'Licenses of Third Party Packages')
451
520
452 def test_forbidden_when_normal_user(self, autologin_regular_user):
521 def test_forbidden_when_normal_user(self, autologin_regular_user):
453 self.app.get(self._get_url(), status=404)
522 self.app.get(
523 route_path('admin_settings_open_source'), status=404)
454
524
455
525
456 @pytest.mark.usefixtures('app')
526 @pytest.mark.usefixtures('app')
457 class TestUserSessions(object):
527 class TestUserSessions(object):
458
528
459 def _get_url(self, name='admin_settings_sessions'):
460 return {
461 'admin_settings_sessions': ADMIN_PREFIX + '/settings/sessions',
462 'admin_settings_sessions_cleanup': ADMIN_PREFIX + '/settings/sessions/cleanup'
463 }[name]
464
465 def test_forbidden_when_normal_user(self, autologin_regular_user):
529 def test_forbidden_when_normal_user(self, autologin_regular_user):
466 self.app.get(self._get_url(), status=404)
530 self.app.get(route_path('admin_settings_sessions'), status=404)
467
531
468 def test_show_sessions_page(self, autologin_user):
532 def test_show_sessions_page(self, autologin_user):
469 response = self.app.get(self._get_url(), status=200)
533 response = self.app.get(route_path('admin_settings_sessions'), status=200)
470 response.mustcontain('file')
534 response.mustcontain('file')
471
535
472 def test_cleanup_old_sessions(self, autologin_user, csrf_token):
536 def test_cleanup_old_sessions(self, autologin_user, csrf_token):
@@ -476,24 +540,19 b' class TestUserSessions(object):'
476 'expire_days': '60'
540 'expire_days': '60'
477 }
541 }
478 response = self.app.post(
542 response = self.app.post(
479 self._get_url('admin_settings_sessions_cleanup'), params=post_data,
543 route_path('admin_settings_sessions_cleanup'), params=post_data,
480 status=302)
544 status=302)
481 assert_session_flash(response, 'Cleaned up old sessions')
545 assert_session_flash(response, 'Cleaned up old sessions')
482
546
483
547
484 @pytest.mark.usefixtures('app')
548 @pytest.mark.usefixtures('app')
485 class TestAdminSystemInfo(object):
549 class TestAdminSystemInfo(object):
486 def _get_url(self, name='admin_settings_system'):
487 return {
488 'admin_settings_system': ADMIN_PREFIX + '/settings/system',
489 'admin_settings_system_update': ADMIN_PREFIX + '/settings/system/updates',
490 }[name]
491
550
492 def test_forbidden_when_normal_user(self, autologin_regular_user):
551 def test_forbidden_when_normal_user(self, autologin_regular_user):
493 self.app.get(self._get_url(), status=404)
552 self.app.get(route_path('admin_settings_system'), status=404)
494
553
495 def test_system_info_page(self, autologin_user):
554 def test_system_info_page(self, autologin_user):
496 response = self.app.get(self._get_url())
555 response = self.app.get(route_path('admin_settings_system'))
497 response.mustcontain('RhodeCode Community Edition, version {}'.format(
556 response.mustcontain('RhodeCode Community Edition, version {}'.format(
498 rhodecode.__version__))
557 rhodecode.__version__))
499
558
@@ -511,7 +570,7 b' class TestAdminSystemInfo(object):'
511 ]
570 ]
512 }
571 }
513 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
572 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
514 response = self.app.get(self._get_url('admin_settings_system_update'))
573 response = self.app.get(route_path('admin_settings_system_update'))
515 response.mustcontain('A <b>new version</b> is available')
574 response.mustcontain('A <b>new version</b> is available')
516
575
517 def test_system_update_nothing_new(self, autologin_user):
576 def test_system_update_nothing_new(self, autologin_user):
@@ -524,13 +583,13 b' class TestAdminSystemInfo(object):'
524 ]
583 ]
525 }
584 }
526 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
585 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
527 response = self.app.get(self._get_url('admin_settings_system_update'))
586 response = self.app.get(route_path('admin_settings_system_update'))
528 response.mustcontain(
587 response.mustcontain(
529 'You already have the <b>latest</b> stable version.')
588 'This instance is already running the <b>latest</b> stable version')
530
589
531 def test_system_update_bad_response(self, autologin_user):
590 def test_system_update_bad_response(self, autologin_user):
532 with mock.patch(UPDATE_DATA_QUALNAME, side_effect=ValueError('foo')):
591 with mock.patch(UPDATE_DATA_QUALNAME, side_effect=ValueError('foo')):
533 response = self.app.get(self._get_url('admin_settings_system_update'))
592 response = self.app.get(route_path('admin_settings_system_update'))
534 response.mustcontain(
593 response.mustcontain(
535 'Bad data sent from update server')
594 'Bad data sent from update server')
536
595
@@ -542,12 +601,12 b' class TestAdminSettingsIssueTracker(obje'
542 PATTERN_KEY = RC_PREFIX + SHORT_PATTERN_KEY
601 PATTERN_KEY = RC_PREFIX + SHORT_PATTERN_KEY
543
602
544 def test_issuetracker_index(self, autologin_user):
603 def test_issuetracker_index(self, autologin_user):
545 response = self.app.get(url('admin_settings_issuetracker'))
604 response = self.app.get(route_path('admin_settings_issuetracker'))
546 assert response.status_code == 200
605 assert response.status_code == 200
547
606
548 def test_add_empty_issuetracker_pattern(
607 def test_add_empty_issuetracker_pattern(
549 self, request, autologin_user, csrf_token):
608 self, request, autologin_user, csrf_token):
550 post_url = url('admin_settings_issuetracker_save')
609 post_url = route_path('admin_settings_issuetracker_update')
551 post_data = {
610 post_data = {
552 'csrf_token': csrf_token
611 'csrf_token': csrf_token
553 }
612 }
@@ -557,14 +616,14 b' class TestAdminSettingsIssueTracker(obje'
557 self, request, autologin_user, csrf_token):
616 self, request, autologin_user, csrf_token):
558 pattern = 'issuetracker_pat'
617 pattern = 'issuetracker_pat'
559 another_pattern = pattern+'1'
618 another_pattern = pattern+'1'
560 post_url = url('admin_settings_issuetracker_save')
619 post_url = route_path('admin_settings_issuetracker_update')
561 post_data = {
620 post_data = {
562 'new_pattern_pattern_0': pattern,
621 'new_pattern_pattern_0': pattern,
563 'new_pattern_url_0': 'url',
622 'new_pattern_url_0': 'http://url',
564 'new_pattern_prefix_0': 'prefix',
623 'new_pattern_prefix_0': 'prefix',
565 'new_pattern_description_0': 'description',
624 'new_pattern_description_0': 'description',
566 'new_pattern_pattern_1': another_pattern,
625 'new_pattern_pattern_1': another_pattern,
567 'new_pattern_url_1': 'url1',
626 'new_pattern_url_1': 'https://url1',
568 'new_pattern_prefix_1': 'prefix1',
627 'new_pattern_prefix_1': 'prefix1',
569 'new_pattern_description_1': 'description1',
628 'new_pattern_description_1': 'description1',
570 'csrf_token': csrf_token
629 'csrf_token': csrf_token
@@ -600,10 +659,10 b' class TestAdminSettingsIssueTracker(obje'
600 SettingsModel().create_or_update_setting(
659 SettingsModel().create_or_update_setting(
601 self.SHORT_PATTERN_KEY+old_uid, old_pattern, 'unicode')
660 self.SHORT_PATTERN_KEY+old_uid, old_pattern, 'unicode')
602
661
603 post_url = url('admin_settings_issuetracker_save')
662 post_url = route_path('admin_settings_issuetracker_update')
604 post_data = {
663 post_data = {
605 'new_pattern_pattern_0': pattern,
664 'new_pattern_pattern_0': pattern,
606 'new_pattern_url_0': 'url',
665 'new_pattern_url_0': 'https://url',
607 'new_pattern_prefix_0': 'prefix',
666 'new_pattern_prefix_0': 'prefix',
608 'new_pattern_description_0': 'description',
667 'new_pattern_description_0': 'description',
609 'uid': old_uid,
668 'uid': old_uid,
@@ -634,10 +693,10 b' class TestAdminSettingsIssueTracker(obje'
634 settings_util.create_rhodecode_setting(
693 settings_util.create_rhodecode_setting(
635 desc_key, 'old description', 'unicode', cleanup=False)
694 desc_key, 'old description', 'unicode', cleanup=False)
636
695
637 post_url = url('admin_settings_issuetracker_save')
696 post_url = route_path('admin_settings_issuetracker_update')
638 post_data = {
697 post_data = {
639 'new_pattern_pattern_0': pattern,
698 'new_pattern_pattern_0': pattern,
640 'new_pattern_url_0': 'url',
699 'new_pattern_url_0': 'https://url',
641 'new_pattern_prefix_0': 'prefix',
700 'new_pattern_prefix_0': 'prefix',
642 'new_pattern_description_0': new_description,
701 'new_pattern_description_0': new_description,
643 'uid': self.uid,
702 'uid': self.uid,
@@ -659,7 +718,7 b' class TestAdminSettingsIssueTracker(obje'
659 settings_util.create_rhodecode_setting(
718 settings_util.create_rhodecode_setting(
660 self.SHORT_PATTERN_KEY+uid, pattern, 'unicode', cleanup=False)
719 self.SHORT_PATTERN_KEY+uid, pattern, 'unicode', cleanup=False)
661
720
662 post_url = url('admin_issuetracker_delete')
721 post_url = route_path('admin_settings_issuetracker_delete')
663 post_data = {
722 post_data = {
664 '_method': 'delete',
723 '_method': 'delete',
665 'uid': uid,
724 'uid': uid,
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -23,7 +23,6 b' from sqlalchemy.orm.exc import NoResultF'
23
23
24 from rhodecode.lib import auth
24 from rhodecode.lib import auth
25 from rhodecode.lib import helpers as h
25 from rhodecode.lib import helpers as h
26 from rhodecode.model import validators
27 from rhodecode.model.db import User, UserApiKeys, UserEmailMap, Repository
26 from rhodecode.model.db import User, UserApiKeys, UserEmailMap, Repository
28 from rhodecode.model.meta import Session
27 from rhodecode.model.meta import Session
29 from rhodecode.model.user import UserModel
28 from rhodecode.model.user import UserModel
@@ -386,8 +385,7 b' class TestAdminUsersView(TestController)'
386 'csrf_token': self.csrf_token,
385 'csrf_token': self.csrf_token,
387 })
386 })
388
387
389 msg = validators.ValidUsername(
388 msg = u'Username "%(username)s" is forbidden'
390 False, {})._messages['system_invalid_username']
391 msg = h.html_escape(msg % {'username': 'new_user'})
389 msg = h.html_escape(msg % {'username': 'new_user'})
392 response.mustcontain('<span class="error-message">%s</span>' % msg)
390 response.mustcontain('<span class="error-message">%s</span>' % msg)
393 response.mustcontain(
391 response.mustcontain(
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -36,7 +36,6 b' log = logging.getLogger(__name__)'
36 class AdminAuditLogsView(BaseAppView):
36 class AdminAuditLogsView(BaseAppView):
37 def load_default_context(self):
37 def load_default_context(self):
38 c = self._get_local_tmpl_context()
38 c = self._get_local_tmpl_context()
39 self._register_global_c(c)
40 return c
39 return c
41
40
42 @LoginRequired()
41 @LoginRequired()
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -44,7 +44,7 b' class AdminDefaultSettingsView(BaseAppVi'
44 def load_default_context(self):
44 def load_default_context(self):
45 c = self._get_local_tmpl_context()
45 c = self._get_local_tmpl_context()
46
46
47 self._register_global_c(c)
47
48 return c
48 return c
49
49
50 @LoginRequired()
50 @LoginRequired()
@@ -79,7 +79,7 b' class AdminDefaultSettingsView(BaseAppVi'
79 _ = self.request.translate
79 _ = self.request.translate
80 c = self.load_default_context()
80 c = self.load_default_context()
81 c.active = 'repositories'
81 c.active = 'repositories'
82 form = DefaultsForm()()
82 form = DefaultsForm(self.request.translate)()
83
83
84 try:
84 try:
85 form_result = form.to_python(dict(self.request.POST))
85 form_result = form.to_python(dict(self.request.POST))
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -35,7 +35,7 b' class OpenSourceLicensesAdminSettingsVie'
35
35
36 def load_default_context(self):
36 def load_default_context(self):
37 c = self._get_local_tmpl_context()
37 c = self._get_local_tmpl_context()
38 self._register_global_c(c)
38
39 return c
39 return c
40
40
41 @LoginRequired()
41 @LoginRequired()
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -53,8 +53,6 b' log = logging.getLogger(__name__)'
53 class AdminPermissionsView(BaseAppView, DataGridAppView):
53 class AdminPermissionsView(BaseAppView, DataGridAppView):
54 def load_default_context(self):
54 def load_default_context(self):
55 c = self._get_local_tmpl_context()
55 c = self._get_local_tmpl_context()
56
57 self._register_global_c(c)
58 PermissionModel().set_global_permission_choices(
56 PermissionModel().set_global_permission_choices(
59 c, gettext_translator=self.request.translate)
57 c, gettext_translator=self.request.translate)
60 return c
58 return c
@@ -100,6 +98,7 b' class AdminPermissionsView(BaseAppView, '
100 c.active = 'application'
98 c.active = 'application'
101
99
102 _form = ApplicationPermissionsForm(
100 _form = ApplicationPermissionsForm(
101 self.request.translate,
103 [x[0] for x in c.register_choices],
102 [x[0] for x in c.register_choices],
104 [x[0] for x in c.password_reset_choices],
103 [x[0] for x in c.password_reset_choices],
105 [x[0] for x in c.extern_activate_choices])()
104 [x[0] for x in c.extern_activate_choices])()
@@ -180,6 +179,7 b' class AdminPermissionsView(BaseAppView, '
180 c.active = 'objects'
179 c.active = 'objects'
181
180
182 _form = ObjectPermissionsForm(
181 _form = ObjectPermissionsForm(
182 self.request.translate,
183 [x[0] for x in c.repo_perms_choices],
183 [x[0] for x in c.repo_perms_choices],
184 [x[0] for x in c.group_perms_choices],
184 [x[0] for x in c.group_perms_choices],
185 [x[0] for x in c.user_group_perms_choices])()
185 [x[0] for x in c.user_group_perms_choices])()
@@ -251,6 +251,7 b' class AdminPermissionsView(BaseAppView, '
251 c.active = 'global'
251 c.active = 'global'
252
252
253 _form = UserPermissionsForm(
253 _form = UserPermissionsForm(
254 self.request.translate,
254 [x[0] for x in c.repo_create_choices],
255 [x[0] for x in c.repo_create_choices],
255 [x[0] for x in c.repo_create_on_write_choices],
256 [x[0] for x in c.repo_create_on_write_choices],
256 [x[0] for x in c.repo_group_create_choices],
257 [x[0] for x in c.repo_group_create_choices],
@@ -395,6 +396,7 b' class AdminPermissionsView(BaseAppView, '
395 renderer='json_ext', xhr=True)
396 renderer='json_ext', xhr=True)
396 def ssh_keys_data(self):
397 def ssh_keys_data(self):
397 _ = self.request.translate
398 _ = self.request.translate
399 self.load_default_context()
398 column_map = {
400 column_map = {
399 'fingerprint': 'ssh_key_fingerprint',
401 'fingerprint': 'ssh_key_fingerprint',
400 'username': User.username
402 'username': User.username
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -21,6 +21,7 b''
21 import logging
21 import logging
22
22
23 import psutil
23 import psutil
24 import signal
24 from pyramid.view import view_config
25 from pyramid.view import view_config
25
26
26 from rhodecode.apps._base import BaseAppView
27 from rhodecode.apps._base import BaseAppView
@@ -35,7 +36,7 b' log = logging.getLogger(__name__)'
35 class AdminProcessManagementView(BaseAppView):
36 class AdminProcessManagementView(BaseAppView):
36 def load_default_context(self):
37 def load_default_context(self):
37 c = self._get_local_tmpl_context()
38 c = self._get_local_tmpl_context()
38 self._register_global_c(c)
39
39 return c
40 return c
40
41
41 @LoginRequired()
42 @LoginRequired()
@@ -55,6 +56,18 b' class AdminProcessManagementView(BaseApp'
55
56
56 @LoginRequired()
57 @LoginRequired()
57 @HasPermissionAllDecorator('hg.admin')
58 @HasPermissionAllDecorator('hg.admin')
59 @view_config(
60 route_name='admin_settings_process_management_data', request_method='GET',
61 renderer='rhodecode:templates/admin/settings/settings_process_management_data.mako')
62 def process_management_data(self):
63 _ = self.request.translate
64 c = self.load_default_context()
65 c.gunicorn_processes = (
66 p for p in psutil.process_iter() if 'gunicorn' in p.name())
67 return self._get_template_context(c)
68
69 @LoginRequired()
70 @HasPermissionAllDecorator('hg.admin')
58 @CSRFRequired()
71 @CSRFRequired()
59 @view_config(
72 @view_config(
60 route_name='admin_settings_process_management_signal',
73 route_name='admin_settings_process_management_signal',
@@ -89,3 +102,32 b' class AdminProcessManagementView(BaseApp'
89 p.kill()
102 p.kill()
90
103
91 return {'result': result}
104 return {'result': result}
105
106 @LoginRequired()
107 @HasPermissionAllDecorator('hg.admin')
108 @CSRFRequired()
109 @view_config(
110 route_name='admin_settings_process_management_master_signal',
111 request_method='POST', renderer='json_ext')
112 def process_management_master_signal(self):
113 pid_data = self.request.json.get('pid_data', {})
114 pid = safe_int(pid_data['pid'])
115 action = pid_data['action']
116 if pid:
117 try:
118 proc = psutil.Process(pid)
119 except psutil.NoSuchProcess:
120 return {'result': 'failure_no_such_process'}
121
122 children = proc.children(recursive=True)
123 if children:
124 # master process
125 if action == '+' and len(children) <= 20:
126 proc.send_signal(signal.SIGTTIN)
127 elif action == '-' and len(children) >= 2:
128 proc.send_signal(signal.SIGTTOU)
129 else:
130 return {'result': 'failure_wrong_action'}
131 return {'result': 'success'}
132
133 return {'result': 'failure_not_master'}
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -47,7 +47,7 b' class AdminRepoGroupsView(BaseAppView, D'
47
47
48 def load_default_context(self):
48 def load_default_context(self):
49 c = self._get_local_tmpl_context()
49 c = self._get_local_tmpl_context()
50 self._register_global_c(c)
50
51 return c
51 return c
52
52
53 def _load_form_data(self, c):
53 def _load_form_data(self, c):
@@ -150,8 +150,9 b' class AdminRepoGroupsView(BaseAppView, D'
150 # permissions for can create group based on parent_id are checked
150 # permissions for can create group based on parent_id are checked
151 # here in the Form
151 # here in the Form
152 available_groups = map(lambda k: safe_unicode(k[0]), c.repo_groups)
152 available_groups = map(lambda k: safe_unicode(k[0]), c.repo_groups)
153 repo_group_form = RepoGroupForm(available_groups=available_groups,
153 repo_group_form = RepoGroupForm(
154 can_create_in_root=can_create)()
154 self.request.translate, available_groups=available_groups,
155 can_create_in_root=can_create)()
155
156
156 repo_group_name = self.request.POST.get('group_name')
157 repo_group_name = self.request.POST.get('group_name')
157 try:
158 try:
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -28,6 +28,7 b' from pyramid.renderers import render'
28 from pyramid.response import Response
28 from pyramid.response import Response
29
29
30 from rhodecode.apps._base import BaseAppView, DataGridAppView
30 from rhodecode.apps._base import BaseAppView, DataGridAppView
31 from rhodecode.lib.celerylib.utils import get_task_id
31
32
32 from rhodecode.lib.ext_json import json
33 from rhodecode.lib.ext_json import json
33 from rhodecode.lib.auth import (
34 from rhodecode.lib.auth import (
@@ -49,7 +50,7 b' class AdminReposView(BaseAppView, DataGr'
49
50
50 def load_default_context(self):
51 def load_default_context(self):
51 c = self._get_local_tmpl_context()
52 c = self._get_local_tmpl_context()
52 self._register_global_c(c)
53
53 return c
54 return c
54
55
55 def _load_form_data(self, c):
56 def _load_form_data(self, c):
@@ -58,7 +59,7 b' class AdminReposView(BaseAppView, DataGr'
58 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
59 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
59 c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups)
60 c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups)
60 c.landing_revs_choices, c.landing_revs = \
61 c.landing_revs_choices, c.landing_revs = \
61 ScmModel().get_repo_landing_revs()
62 ScmModel().get_repo_landing_revs(self.request.translate)
62 c.personal_repo_group = self._rhodecode_user.personal_repo_group
63 c.personal_repo_group = self._rhodecode_user.personal_repo_group
63
64
64 @LoginRequired()
65 @LoginRequired()
@@ -143,21 +144,19 b' class AdminReposView(BaseAppView, DataGr'
143 c = self.load_default_context()
144 c = self.load_default_context()
144
145
145 form_result = {}
146 form_result = {}
147 self._load_form_data(c)
146 task_id = None
148 task_id = None
147 self._load_form_data(c)
148
149 try:
149 try:
150 # CanWriteToGroup validators checks permissions of this POST
150 # CanWriteToGroup validators checks permissions of this POST
151 form_result = RepoForm(repo_groups=c.repo_groups_choices,
151 form = RepoForm(
152 landing_revs=c.landing_revs_choices)()\
152 self.request.translate, repo_groups=c.repo_groups_choices,
153 .to_python(dict(self.request.POST))
153 landing_revs=c.landing_revs_choices)()
154 form_result = form.to_python(dict(self.request.POST))
154
155
155 # create is done sometimes async on celery, db transaction
156 # create is done sometimes async on celery, db transaction
156 # management is handled there.
157 # management is handled there.
157 task = RepoModel().create(form_result, self._rhodecode_user.user_id)
158 task = RepoModel().create(form_result, self._rhodecode_user.user_id)
158 from celery.result import BaseAsyncResult
159 task_id = get_task_id(task)
159 if isinstance(task, BaseAsyncResult):
160 task_id = task.task_id
161 except formencode.Invalid as errors:
160 except formencode.Invalid as errors:
162 data = render('rhodecode:templates/admin/repos/repo_add.mako',
161 data = render('rhodecode:templates/admin/repos/repo_add.mako',
163 self._get_template_context(c), self.request)
162 self._get_template_context(c), self.request)
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -30,6 +30,7 b' from rhodecode.lib.auth import ('
30 from rhodecode.lib.utils2 import safe_int
30 from rhodecode.lib.utils2 import safe_int
31 from rhodecode.lib import system_info
31 from rhodecode.lib import system_info
32 from rhodecode.lib import user_sessions
32 from rhodecode.lib import user_sessions
33 from rhodecode.lib import helpers as h
33
34
34
35
35 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
@@ -39,7 +40,7 b' class AdminSessionSettingsView(BaseAppVi'
39 def load_default_context(self):
40 def load_default_context(self):
40 c = self._get_local_tmpl_context()
41 c = self._get_local_tmpl_context()
41
42
42 self._register_global_c(c)
43
43 return c
44 return c
44
45
45 @LoginRequired()
46 @LoginRequired()
@@ -88,14 +89,12 b' class AdminSessionSettingsView(BaseAppVi'
88 try:
89 try:
89 session_model.clean_sessions(
90 session_model.clean_sessions(
90 older_than_seconds=older_than_seconds)
91 older_than_seconds=older_than_seconds)
91 self.request.session.flash(
92 h.flash(_('Cleaned up old sessions'), category='success')
92 _('Cleaned up old sessions'), queue='success')
93 except user_sessions.CleanupCommand as msg:
93 except user_sessions.CleanupCommand as msg:
94 self.request.session.flash(msg.message, queue='warning')
94 h.flash(msg.message, category='warning')
95 except Exception as e:
95 except Exception as e:
96 log.exception('Failed session cleanup')
96 log.exception('Failed session cleanup')
97 self.request.session.flash(
97 h.flash(_('Failed to cleanup up old sessions'), category='error')
98 _('Failed to cleanup up old sessions'), queue='error')
99
98
100 redirect_to = self.request.resource_path(
99 redirect_to = self.request.resource_path(
101 self.context, route_name='admin_settings_sessions')
100 self.context, route_name='admin_settings_sessions')
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -20,7 +20,6 b''
20
20
21 import logging
21 import logging
22 import urllib2
22 import urllib2
23 import packaging.version
24
23
25 from pyramid.view import view_config
24 from pyramid.view import view_config
26
25
@@ -31,8 +30,7 b' from rhodecode.lib import helpers as h'
31 from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
30 from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
32 from rhodecode.lib.utils2 import str2bool
31 from rhodecode.lib.utils2 import str2bool
33 from rhodecode.lib import system_info
32 from rhodecode.lib import system_info
34 from rhodecode.lib.ext_json import json
33 from rhodecode.model.update import UpdateModel
35 from rhodecode.model.settings import SettingsModel
36
34
37 log = logging.getLogger(__name__)
35 log = logging.getLogger(__name__)
38
36
@@ -40,26 +38,8 b' log = logging.getLogger(__name__)'
40 class AdminSystemInfoSettingsView(BaseAppView):
38 class AdminSystemInfoSettingsView(BaseAppView):
41 def load_default_context(self):
39 def load_default_context(self):
42 c = self._get_local_tmpl_context()
40 c = self._get_local_tmpl_context()
43 self._register_global_c(c)
44 return c
41 return c
45
42
46 @staticmethod
47 def get_update_data(update_url):
48 """Return the JSON update data."""
49 ver = rhodecode.__version__
50 log.debug('Checking for upgrade on `%s` server', update_url)
51 opener = urllib2.build_opener()
52 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
53 response = opener.open(update_url)
54 response_data = response.read()
55 data = json.loads(response_data)
56
57 return data
58
59 def get_update_url(self):
60 settings = SettingsModel().get_all_settings()
61 return settings.get('rhodecode_update_url')
62
63 @LoginRequired()
43 @LoginRequired()
64 @HasPermissionAllDecorator('hg.admin')
44 @HasPermissionAllDecorator('hg.admin')
65 @view_config(
45 @view_config(
@@ -77,7 +57,7 b' class AdminSystemInfoSettingsView(BaseAp'
77
57
78 snapshot = str2bool(self.request.params.get('snapshot'))
58 snapshot = str2bool(self.request.params.get('snapshot'))
79
59
80 c.rhodecode_update_url = self.get_update_url()
60 c.rhodecode_update_url = UpdateModel().get_update_url()
81 server_info = system_info.get_system_info(self.request.environ)
61 server_info = system_info.get_system_info(self.request.environ)
82
62
83 for key, val in server_info.items():
63 for key, val in server_info.items():
@@ -97,6 +77,14 b' class AdminSystemInfoSettingsView(BaseAp'
97 update_info_msg = _('Note: please make sure this server can '
77 update_info_msg = _('Note: please make sure this server can '
98 'access `${url}` for the update link to work',
78 'access `${url}` for the update link to work',
99 mapping=dict(url=c.rhodecode_update_url))
79 mapping=dict(url=c.rhodecode_update_url))
80 version = UpdateModel().get_stored_version()
81 is_outdated = UpdateModel().is_outdated(
82 rhodecode.__version__, version)
83 update_state = {
84 'type': 'warning',
85 'message': 'New version available: {}'.format(version)
86 } \
87 if is_outdated else {}
100 c.data_items = [
88 c.data_items = [
101 # update info
89 # update info
102 (_('Update info'), h.literal(
90 (_('Update info'), h.literal(
@@ -107,6 +95,7 b' class AdminSystemInfoSettingsView(BaseAp'
107
95
108 # RhodeCode specific
96 # RhodeCode specific
109 (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')),
97 (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')),
98 (_('Latest version'), version, update_state),
110 (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')),
99 (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')),
111 (_('RhodeCode Server ID'), val('server')['server_id'], state('server')),
100 (_('RhodeCode Server ID'), val('server')['server_id'], state('server')),
112 (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')),
101 (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')),
@@ -166,8 +155,7 b' class AdminSystemInfoSettingsView(BaseAp'
166 c.data_items.pop(0) # remove server info
155 c.data_items.pop(0) # remove server info
167 self.request.override_renderer = 'admin/settings/settings_system_snapshot.mako'
156 self.request.override_renderer = 'admin/settings/settings_system_snapshot.mako'
168 else:
157 else:
169 self.request.session.flash(
158 h.flash('You are not allowed to do this', category='warning')
170 'You are not allowed to do this', queue='warning')
171 return self._get_template_context(c)
159 return self._get_template_context(c)
172
160
173 @LoginRequired()
161 @LoginRequired()
@@ -179,11 +167,11 b' class AdminSystemInfoSettingsView(BaseAp'
179 _ = self.request.translate
167 _ = self.request.translate
180 c = self.load_default_context()
168 c = self.load_default_context()
181
169
182 update_url = self.get_update_url()
170 update_url = UpdateModel().get_update_url()
183
171
184 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">{}</div>'.format(s)
172 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">{}</div>'.format(s)
185 try:
173 try:
186 data = self.get_update_data(update_url)
174 data = UpdateModel().get_update_data(update_url)
187 except urllib2.URLError as e:
175 except urllib2.URLError as e:
188 log.exception("Exception contacting upgrade server")
176 log.exception("Exception contacting upgrade server")
189 self.request.override_renderer = 'string'
177 self.request.override_renderer = 'string'
@@ -201,9 +189,9 b' class AdminSystemInfoSettingsView(BaseAp'
201 c.cur_ver = rhodecode.__version__
189 c.cur_ver = rhodecode.__version__
202 c.should_upgrade = False
190 c.should_upgrade = False
203
191
204 if (packaging.version.Version(c.latest_ver) >
192 is_oudated = UpdateModel().is_outdated(c.cur_ver, c.latest_ver)
205 packaging.version.Version(c.cur_ver)):
193 if is_oudated:
206 c.should_upgrade = True
194 c.should_upgrade = True
207 c.important_notices = latest['general']
195 c.important_notices = latest['general']
208
196 UpdateModel().store_version(latest['version'])
209 return self._get_template_context(c)
197 return self._get_template_context(c)
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -53,7 +53,6 b' class AdminUserGroupsView(BaseAppView, D'
53 PermissionModel().set_global_permission_choices(
53 PermissionModel().set_global_permission_choices(
54 c, gettext_translator=self.request.translate)
54 c, gettext_translator=self.request.translate)
55
55
56 self._register_global_c(c)
57 return c
56 return c
58
57
59 # permission check in data loading of
58 # permission check in data loading of
@@ -74,6 +73,7 b' class AdminUserGroupsView(BaseAppView, D'
74 route_name='user_groups_data', request_method='GET',
73 route_name='user_groups_data', request_method='GET',
75 renderer='json_ext', xhr=True)
74 renderer='json_ext', xhr=True)
76 def user_groups_list_data(self):
75 def user_groups_list_data(self):
76 self.load_default_context()
77 column_map = {
77 column_map = {
78 'active': 'users_group_active',
78 'active': 'users_group_active',
79 'description': 'user_group_description',
79 'description': 'user_group_description',
@@ -86,7 +86,7 b' class AdminUserGroupsView(BaseAppView, D'
86 self.request, column_map=column_map)
86 self.request, column_map=column_map)
87
87
88 _render = self.request.get_partial_renderer(
88 _render = self.request.get_partial_renderer(
89 'data_table/_dt_elements.mako')
89 'rhodecode:templates/data_table/_dt_elements.mako')
90
90
91 def user_group_name(user_group_id, user_group_name):
91 def user_group_name(user_group_id, user_group_name):
92 return _render("user_group_name", user_group_id, user_group_name)
92 return _render("user_group_name", user_group_id, user_group_name)
@@ -195,7 +195,7 b' class AdminUserGroupsView(BaseAppView, D'
195 def user_groups_create(self):
195 def user_groups_create(self):
196 _ = self.request.translate
196 _ = self.request.translate
197 c = self.load_default_context()
197 c = self.load_default_context()
198 users_group_form = UserGroupForm()()
198 users_group_form = UserGroupForm(self.request.translate)()
199
199
200 user_group_name = self.request.POST.get('users_group_name')
200 user_group_name = self.request.POST.get('users_group_name')
201 try:
201 try:
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -44,7 +44,8 b' from rhodecode.lib import helpers as h'
44 from rhodecode.lib.utils2 import safe_int, safe_unicode, AttributeDict
44 from rhodecode.lib.utils2 import safe_int, safe_unicode, AttributeDict
45 from rhodecode.model.auth_token import AuthTokenModel
45 from rhodecode.model.auth_token import AuthTokenModel
46 from rhodecode.model.forms import (
46 from rhodecode.model.forms import (
47 UserForm, UserIndividualPermissionsForm, UserPermissionsForm)
47 UserForm, UserIndividualPermissionsForm, UserPermissionsForm,
48 UserExtraEmailForm, UserExtraIpForm)
48 from rhodecode.model.permission import PermissionModel
49 from rhodecode.model.permission import PermissionModel
49 from rhodecode.model.repo_group import RepoGroupModel
50 from rhodecode.model.repo_group import RepoGroupModel
50 from rhodecode.model.ssh_key import SshKeyModel
51 from rhodecode.model.ssh_key import SshKeyModel
@@ -62,7 +63,6 b' class AdminUsersView(BaseAppView, DataGr'
62
63
63 def load_default_context(self):
64 def load_default_context(self):
64 c = self._get_local_tmpl_context()
65 c = self._get_local_tmpl_context()
65 self._register_global_c(c)
66 return c
66 return c
67
67
68 @LoginRequired()
68 @LoginRequired()
@@ -81,6 +81,7 b' class AdminUsersView(BaseAppView, DataGr'
81 route_name='users_data', request_method='GET',
81 route_name='users_data', request_method='GET',
82 renderer='json_ext', xhr=True)
82 renderer='json_ext', xhr=True)
83 def users_list_data(self):
83 def users_list_data(self):
84 self.load_default_context()
84 column_map = {
85 column_map = {
85 'first_name': 'name',
86 'first_name': 'name',
86 'last_name': 'lastname',
87 'last_name': 'lastname',
@@ -90,7 +91,7 b' class AdminUsersView(BaseAppView, DataGr'
90 self.request, column_map=column_map)
91 self.request, column_map=column_map)
91
92
92 _render = self.request.get_partial_renderer(
93 _render = self.request.get_partial_renderer(
93 'data_table/_dt_elements.mako')
94 'rhodecode:templates/data_table/_dt_elements.mako')
94
95
95 def user_actions(user_id, username):
96 def user_actions(user_id, username):
96 return _render("user_actions", user_id, username)
97 return _render("user_actions", user_id, username)
@@ -190,7 +191,7 b' class AdminUsersView(BaseAppView, DataGr'
190 c = self.load_default_context()
191 c = self.load_default_context()
191 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name
192 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name
192 user_model = UserModel()
193 user_model = UserModel()
193 user_form = UserForm()()
194 user_form = UserForm(self.request.translate)()
194 try:
195 try:
195 form_result = user_form.to_python(dict(self.request.POST))
196 form_result = user_form.to_python(dict(self.request.POST))
196 user = user_model.create(form_result)
197 user = user_model.create(form_result)
@@ -258,7 +259,6 b' class UsersView(UserAppView):'
258 PermissionModel().set_global_permission_choices(
259 PermissionModel().set_global_permission_choices(
259 c, gettext_translator=req.translate)
260 c, gettext_translator=req.translate)
260
261
261 self._register_global_c(c)
262 return c
262 return c
263
263
264 @LoginRequired()
264 @LoginRequired()
@@ -279,7 +279,8 b' class UsersView(UserAppView):'
279 c.extern_name = c.user.extern_name
279 c.extern_name = c.user.extern_name
280 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
280 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
281 available_languages = [x[0] for x in c.allowed_languages]
281 available_languages = [x[0] for x in c.allowed_languages]
282 _form = UserForm(edit=True, available_languages=available_languages,
282 _form = UserForm(self.request.translate, edit=True,
283 available_languages=available_languages,
283 old_data={'user_id': user_id,
284 old_data={'user_id': user_id,
284 'email': c.user.email})()
285 'email': c.user.email})()
285 form_result = {}
286 form_result = {}
@@ -537,7 +538,7 b' class UsersView(UserAppView):'
537 c.active = 'global_perms'
538 c.active = 'global_perms'
538 try:
539 try:
539 # first stage that verifies the checkbox
540 # first stage that verifies the checkbox
540 _form = UserIndividualPermissionsForm()
541 _form = UserIndividualPermissionsForm(self.request.translate)
541 form_result = _form.to_python(dict(self.request.POST))
542 form_result = _form.to_python(dict(self.request.POST))
542 inherit_perms = form_result['inherit_default_permissions']
543 inherit_perms = form_result['inherit_default_permissions']
543 c.user.inherit_default_permissions = inherit_perms
544 c.user.inherit_default_permissions = inherit_perms
@@ -546,6 +547,7 b' class UsersView(UserAppView):'
546 if not inherit_perms:
547 if not inherit_perms:
547 # only update the individual ones if we un check the flag
548 # only update the individual ones if we un check the flag
548 _form = UserPermissionsForm(
549 _form = UserPermissionsForm(
550 self.request.translate,
549 [x[0] for x in c.repo_create_choices],
551 [x[0] for x in c.repo_create_choices],
550 [x[0] for x in c.repo_create_on_write_choices],
552 [x[0] for x in c.repo_create_on_write_choices],
551 [x[0] for x in c.repo_group_create_choices],
553 [x[0] for x in c.repo_group_create_choices],
@@ -913,6 +915,11 b' class UsersView(UserAppView):'
913 email = self.request.POST.get('new_email')
915 email = self.request.POST.get('new_email')
914 user_data = c.user.get_api_data()
916 user_data = c.user.get_api_data()
915 try:
917 try:
918
919 form = UserExtraEmailForm(self.request.translate)()
920 data = form.to_python({'email': email})
921 email = data['email']
922
916 UserModel().add_extra_email(c.user.user_id, email)
923 UserModel().add_extra_email(c.user.user_id, email)
917 audit_logger.store_web(
924 audit_logger.store_web(
918 'user.edit.email.add',
925 'user.edit.email.add',
@@ -1008,6 +1015,10 b' class UsersView(UserAppView):'
1008 user_data = c.user.get_api_data()
1015 user_data = c.user.get_api_data()
1009 for ip in ip_list:
1016 for ip in ip_list:
1010 try:
1017 try:
1018 form = UserExtraIpForm(self.request.translate)()
1019 data = form.to_python({'ip': ip})
1020 ip = data['ip']
1021
1011 user_model.add_extra_ip(c.user.user_id, ip, desc)
1022 user_model.add_extra_ip(c.user.user_id, ip, desc)
1012 audit_logger.store_web(
1023 audit_logger.store_web(
1013 'user.edit.ip.add',
1024 'user.edit.ip.add',
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -20,9 +20,10 b''
20
20
21 import os
21 import os
22
22
23 from pyramid.events import ApplicationCreated
23 from pyramid.settings import asbool
24 from pyramid.settings import asbool
24
25
25 from rhodecode.config.routing import ADMIN_PREFIX
26 from rhodecode.apps._base import ADMIN_PREFIX
26 from rhodecode.lib.ext_json import json
27 from rhodecode.lib.ext_json import json
27
28
28
29
@@ -57,6 +58,14 b' PLUGIN_DEFINITION = {'
57 }
58 }
58
59
59
60
61 def maybe_create_history_store(event):
62 # create plugin history location
63 settings = event.app.registry.settings
64 history_dir = settings.get('channelstream.history.location', '')
65 if history_dir and not os.path.exists(history_dir):
66 os.makedirs(history_dir, 0750)
67
68
60 def includeme(config):
69 def includeme(config):
61 settings = config.registry.settings
70 settings = config.registry.settings
62 PLUGIN_DEFINITION['config']['enabled'] = asbool(
71 PLUGIN_DEFINITION['config']['enabled'] = asbool(
@@ -71,10 +80,7 b' def includeme(config):'
71 PLUGIN_DEFINITION['name'],
80 PLUGIN_DEFINITION['name'],
72 PLUGIN_DEFINITION['config']
81 PLUGIN_DEFINITION['config']
73 )
82 )
74 # create plugin history location
83 config.add_subscriber(maybe_create_history_store, ApplicationCreated)
75 history_dir = PLUGIN_DEFINITION['config']['history.location']
76 if history_dir and not os.path.exists(history_dir):
77 os.makedirs(history_dir, 0750)
78
84
79 config.add_route(
85 config.add_route(
80 name='channelstream_connect',
86 name='channelstream_connect',
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -24,6 +24,7 b' import uuid'
24 from pyramid.view import view_config
24 from pyramid.view import view_config
25 from pyramid.httpexceptions import HTTPBadRequest, HTTPForbidden, HTTPBadGateway
25 from pyramid.httpexceptions import HTTPBadRequest, HTTPForbidden, HTTPBadGateway
26
26
27 from rhodecode.apps._base import BaseAppView
27 from rhodecode.lib.channelstream import (
28 from rhodecode.lib.channelstream import (
28 channelstream_request,
29 channelstream_request,
29 ChannelstreamConnectionException,
30 ChannelstreamConnectionException,
@@ -34,28 +35,28 b' from rhodecode.lib.channelstream import '
34 parse_channels_info,
35 parse_channels_info,
35 update_history_from_logs,
36 update_history_from_logs,
36 STATE_PUBLIC_KEYS)
37 STATE_PUBLIC_KEYS)
38
37 from rhodecode.lib.auth import NotAnonymous
39 from rhodecode.lib.auth import NotAnonymous
38
40
39 log = logging.getLogger(__name__)
41 log = logging.getLogger(__name__)
40
42
41
43
42 class ChannelstreamView(object):
44 class ChannelstreamView(BaseAppView):
43 def __init__(self, context, request):
44 self.context = context
45 self.request = request
46
45
47 # Some of the decorators rely on this attribute to be present
46 def load_default_context(self):
48 # on the class of the decorated method.
47 c = self._get_local_tmpl_context()
49 self._rhodecode_user = request.user
48 self.channelstream_config = \
50 registry = request.registry
49 self.request.registry.rhodecode_plugins['channelstream']
51 self.channelstream_config = registry.rhodecode_plugins['channelstream']
52 if not self.channelstream_config.get('enabled'):
50 if not self.channelstream_config.get('enabled'):
53 log.error('Channelstream plugin is disabled')
51 log.error('Channelstream plugin is disabled')
54 raise HTTPBadRequest()
52 raise HTTPBadRequest()
55
53
54 return c
55
56 @NotAnonymous()
56 @NotAnonymous()
57 @view_config(route_name='channelstream_connect', renderer='json')
57 @view_config(route_name='channelstream_connect', renderer='json_ext')
58 def connect(self):
58 def connect(self):
59 self.load_default_context()
59 """ handle authorization of users trying to connect """
60 """ handle authorization of users trying to connect """
60 try:
61 try:
61 json_body = self.request.json_body
62 json_body = self.request.json_body
@@ -122,9 +123,10 b' class ChannelstreamView(object):'
122 return connect_result
123 return connect_result
123
124
124 @NotAnonymous()
125 @NotAnonymous()
125 @view_config(route_name='channelstream_subscribe', renderer='json')
126 @view_config(route_name='channelstream_subscribe', renderer='json_ext')
126 def subscribe(self):
127 def subscribe(self):
127 """ can be used to subscribe specific connection to other channels """
128 """ can be used to subscribe specific connection to other channels """
129 self.load_default_context()
128 try:
130 try:
129 json_body = self.request.json_body
131 json_body = self.request.json_body
130 except Exception:
132 except Exception:
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -31,7 +31,7 b' log = logging.getLogger(__name__)'
31 class DebugStyleView(BaseAppView):
31 class DebugStyleView(BaseAppView):
32 def load_default_context(self):
32 def load_default_context(self):
33 c = self._get_local_tmpl_context()
33 c = self._get_local_tmpl_context()
34 self._register_global_c(c)
34
35 return c
35 return c
36
36
37 @view_config(
37 @view_config(
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2013-2017 RhodeCode GmbH
3 # Copyright (C) 2013-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -67,7 +67,7 b' class GistView(BaseAppView):'
67 (Gist.ACL_LEVEL_PUBLIC, _("Can be accessed by anonymous users"))
67 (Gist.ACL_LEVEL_PUBLIC, _("Can be accessed by anonymous users"))
68 ]
68 ]
69
69
70 self._register_global_c(c)
70
71 return c
71 return c
72
72
73 @LoginRequired()
73 @LoginRequired()
@@ -114,7 +114,7 b' class GistView(BaseAppView):'
114 c.active = 'public'
114 c.active = 'public'
115
115
116 _render = self.request.get_partial_renderer(
116 _render = self.request.get_partial_renderer(
117 'data_table/_dt_elements.mako')
117 'rhodecode:templates/data_table/_dt_elements.mako')
118
118
119 data = []
119 data = []
120
120
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -66,7 +66,7 b' class TestGotoSwitcherData(TestControlle'
66 ]
66 ]
67
67
68 @pytest.fixture(autouse=True, scope='class')
68 @pytest.fixture(autouse=True, scope='class')
69 def prepare(self, request, pylonsapp):
69 def prepare(self, request, baseapp):
70 for repo_and_group in self.required_repos_with_groups:
70 for repo_and_group in self.required_repos_with_groups:
71 # create structure of groups and return the last group
71 # create structure of groups and return the last group
72
72
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -19,7 +19,7 b''
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 # -*- coding: utf-8 -*-
20 # -*- coding: utf-8 -*-
21
21
22 # Copyright (C) 2016-2017 RhodeCode GmbH
22 # Copyright (C) 2016-2018 RhodeCode GmbH
23 #
23 #
24 # This program is free software: you can redistribute it and/or modify
24 # This program is free software: you can redistribute it and/or modify
25 # it under the terms of the GNU Affero General Public License, version 3
25 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -46,7 +46,7 b' class HomeView(BaseAppView):'
46 def load_default_context(self):
46 def load_default_context(self):
47 c = self._get_local_tmpl_context()
47 c = self._get_local_tmpl_context()
48 c.user = c.auth_user.get_instance()
48 c.user = c.auth_user.get_instance()
49 self._register_global_c(c)
49
50 return c
50 return c
51
51
52 @LoginRequired()
52 @LoginRequired()
@@ -54,6 +54,7 b' class HomeView(BaseAppView):'
54 route_name='user_autocomplete_data', request_method='GET',
54 route_name='user_autocomplete_data', request_method='GET',
55 renderer='json_ext', xhr=True)
55 renderer='json_ext', xhr=True)
56 def user_autocomplete_data(self):
56 def user_autocomplete_data(self):
57 self.load_default_context()
57 query = self.request.GET.get('query')
58 query = self.request.GET.get('query')
58 active = str2bool(self.request.GET.get('active') or True)
59 active = str2bool(self.request.GET.get('active') or True)
59 include_groups = str2bool(self.request.GET.get('user_groups'))
60 include_groups = str2bool(self.request.GET.get('user_groups'))
@@ -87,6 +88,7 b' class HomeView(BaseAppView):'
87 route_name='user_group_autocomplete_data', request_method='GET',
88 route_name='user_group_autocomplete_data', request_method='GET',
88 renderer='json_ext', xhr=True)
89 renderer='json_ext', xhr=True)
89 def user_group_autocomplete_data(self):
90 def user_group_autocomplete_data(self):
91 self.load_default_context()
90 query = self.request.GET.get('query')
92 query = self.request.GET.get('query')
91 active = str2bool(self.request.GET.get('active') or True)
93 active = str2bool(self.request.GET.get('active') or True)
92 expand_groups = str2bool(self.request.GET.get('user_groups_expand'))
94 expand_groups = str2bool(self.request.GET.get('user_groups_expand'))
@@ -202,6 +204,7 b' class HomeView(BaseAppView):'
202 renderer='json_ext', xhr=True)
204 renderer='json_ext', xhr=True)
203 def repo_list_data(self):
205 def repo_list_data(self):
204 _ = self.request.translate
206 _ = self.request.translate
207 self.load_default_context()
205
208
206 query = self.request.GET.get('query')
209 query = self.request.GET.get('query')
207 repo_type = self.request.GET.get('repo_type')
210 repo_type = self.request.GET.get('repo_type')
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -47,7 +47,7 b' class JournalView(BaseAppView):'
47
47
48 def load_default_context(self):
48 def load_default_context(self):
49 c = self._get_local_tmpl_context(include_app_defaults=True)
49 c = self._get_local_tmpl_context(include_app_defaults=True)
50 self._register_global_c(c)
50
51 self._load_defaults(c.rhodecode_name)
51 self._load_defaults(c.rhodecode_name)
52
52
53 # TODO(marcink): what is this, why we need a global register ?
53 # TODO(marcink): what is this, why we need a global register ?
@@ -146,7 +146,8 b' class JournalView(BaseAppView):'
146 user = AttributeDict({'short_contact': entry.username,
146 user = AttributeDict({'short_contact': entry.username,
147 'email': '',
147 'email': '',
148 'full_contact': ''})
148 'full_contact': ''})
149 action, action_extra, ico = h.action_parser(entry, feed=True)
149 action, action_extra, ico = h.action_parser(
150 self.request, entry, feed=True)
150 title = "%s - %s %s" % (user.short_contact, action(),
151 title = "%s - %s %s" % (user.short_contact, action(),
151 entry.repository.repo_name)
152 entry.repository.repo_name)
152 desc = action_extra()
153 desc = action_extra()
@@ -191,7 +192,8 b' class JournalView(BaseAppView):'
191 user = AttributeDict({'short_contact': entry.username,
192 user = AttributeDict({'short_contact': entry.username,
192 'email': '',
193 'email': '',
193 'full_contact': ''})
194 'full_contact': ''})
194 action, action_extra, ico = h.action_parser(entry, feed=True)
195 action, action_extra, ico = h.action_parser(
196 self.request, entry, feed=True)
195 title = "%s - %s %s" % (user.short_contact, action(),
197 title = "%s - %s %s" % (user.short_contact, action(),
196 entry.repository.repo_name)
198 entry.repository.repo_name)
197 desc = action_extra()
199 desc = action_extra()
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -19,7 +19,7 b''
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 from rhodecode.config.routing import ADMIN_PREFIX
22 from rhodecode.apps._base import ADMIN_PREFIX
23
23
24
24
25 def includeme(config):
25 def includeme(config):
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -30,7 +30,6 b' from rhodecode.tests.fixture import Fixt'
30 from rhodecode.lib.auth import check_password
30 from rhodecode.lib.auth import check_password
31 from rhodecode.lib import helpers as h
31 from rhodecode.lib import helpers as h
32 from rhodecode.model.auth_token import AuthTokenModel
32 from rhodecode.model.auth_token import AuthTokenModel
33 from rhodecode.model import validators
34 from rhodecode.model.db import User, Notification, UserApiKeys
33 from rhodecode.model.db import User, Notification, UserApiKeys
35 from rhodecode.model.meta import Session
34 from rhodecode.model.meta import Session
36
35
@@ -89,32 +88,31 b' class TestLoginController(object):'
89 def test_login_admin_ok(self):
88 def test_login_admin_ok(self):
90 response = self.app.post(route_path('login'),
89 response = self.app.post(route_path('login'),
91 {'username': 'test_admin',
90 {'username': 'test_admin',
92 'password': 'test12'})
91 'password': 'test12'}, status=302)
93 assert response.status == '302 Found'
92 response = response.follow()
94 session = response.get_session_from_response()
93 session = response.get_session_from_response()
95 username = session['rhodecode_user'].get('username')
94 username = session['rhodecode_user'].get('username')
96 assert username == 'test_admin'
95 assert username == 'test_admin'
97 response = response.follow()
98 response.mustcontain('/%s' % HG_REPO)
96 response.mustcontain('/%s' % HG_REPO)
99
97
100 def test_login_regular_ok(self):
98 def test_login_regular_ok(self):
101 response = self.app.post(route_path('login'),
99 response = self.app.post(route_path('login'),
102 {'username': 'test_regular',
100 {'username': 'test_regular',
103 'password': 'test12'})
101 'password': 'test12'}, status=302)
104
102
105 assert response.status == '302 Found'
103 response = response.follow()
106 session = response.get_session_from_response()
104 session = response.get_session_from_response()
107 username = session['rhodecode_user'].get('username')
105 username = session['rhodecode_user'].get('username')
108 assert username == 'test_regular'
106 assert username == 'test_regular'
109 response = response.follow()
107
110 response.mustcontain('/%s' % HG_REPO)
108 response.mustcontain('/%s' % HG_REPO)
111
109
112 def test_login_ok_came_from(self):
110 def test_login_ok_came_from(self):
113 test_came_from = '/_admin/users?branch=stable'
111 test_came_from = '/_admin/users?branch=stable'
114 _url = '{}?came_from={}'.format(route_path('login'), test_came_from)
112 _url = '{}?came_from={}'.format(route_path('login'), test_came_from)
115 response = self.app.post(
113 response = self.app.post(
116 _url, {'username': 'test_admin', 'password': 'test12'})
114 _url, {'username': 'test_admin', 'password': 'test12'}, status=302)
117 assert response.status == '302 Found'
115
118 assert 'branch=stable' in response.location
116 assert 'branch=stable' in response.location
119 response = response.follow()
117 response = response.follow()
120
118
@@ -125,8 +123,8 b' class TestLoginController(object):'
125 with fixture.anon_access(False):
123 with fixture.anon_access(False):
126 kwargs = {'branch': 'stable'}
124 kwargs = {'branch': 'stable'}
127 response = self.app.get(
125 response = self.app.get(
128 h.route_path('repo_summary', repo_name=HG_REPO, _query=kwargs))
126 h.route_path('repo_summary', repo_name=HG_REPO, _query=kwargs),
129 assert response.status == '302 Found'
127 status=302)
130
128
131 response_query = urlparse.parse_qsl(response.location)
129 response_query = urlparse.parse_qsl(response.location)
132 assert 'branch=stable' in response_query[0][1]
130 assert 'branch=stable' in response_query[0][1]
@@ -201,13 +199,12 b' class TestLoginController(object):'
201 self.destroy_users.add(temp_user)
199 self.destroy_users.add(temp_user)
202 response = self.app.post(route_path('login'),
200 response = self.app.post(route_path('login'),
203 {'username': temp_user,
201 {'username': temp_user,
204 'password': 'test123'})
202 'password': 'test123'}, status=302)
205
203
206 assert response.status == '302 Found'
204 response = response.follow()
207 session = response.get_session_from_response()
205 session = response.get_session_from_response()
208 username = session['rhodecode_user'].get('username')
206 username = session['rhodecode_user'].get('username')
209 assert username == temp_user
207 assert username == temp_user
210 response = response.follow()
211 response.mustcontain('/%s' % HG_REPO)
208 response.mustcontain('/%s' % HG_REPO)
212
209
213 # new password should be bcrypted, after log-in and transfer
210 # new password should be bcrypted, after log-in and transfer
@@ -234,7 +231,7 b' class TestLoginController(object):'
234 )
231 )
235
232
236 assertr = response.assert_response()
233 assertr = response.assert_response()
237 msg = validators.ValidUsername()._messages['username_exists']
234 msg = 'Username "%(username)s" already exists'
238 msg = msg % {'username': uname}
235 msg = msg % {'username': uname}
239 assertr.element_contains('#username+.error-message', msg)
236 assertr.element_contains('#username+.error-message', msg)
240
237
@@ -252,7 +249,7 b' class TestLoginController(object):'
252 )
249 )
253
250
254 assertr = response.assert_response()
251 assertr = response.assert_response()
255 msg = validators.UniqSystemEmail()()._messages['email_taken']
252 msg = u'This e-mail address is already taken'
256 assertr.element_contains('#email+.error-message', msg)
253 assertr.element_contains('#email+.error-message', msg)
257
254
258 def test_register_err_same_email_case_sensitive(self):
255 def test_register_err_same_email_case_sensitive(self):
@@ -268,7 +265,7 b' class TestLoginController(object):'
268 }
265 }
269 )
266 )
270 assertr = response.assert_response()
267 assertr = response.assert_response()
271 msg = validators.UniqSystemEmail()()._messages['email_taken']
268 msg = u'This e-mail address is already taken'
272 assertr.element_contains('#email+.error-message', msg)
269 assertr.element_contains('#email+.error-message', msg)
273
270
274 def test_register_err_wrong_data(self):
271 def test_register_err_wrong_data(self):
@@ -322,7 +319,7 b' class TestLoginController(object):'
322 )
319 )
323
320
324 assertr = response.assert_response()
321 assertr = response.assert_response()
325 msg = validators.ValidUsername()._messages['username_exists']
322 msg = u'Username "%(username)s" already exists'
326 msg = msg % {'username': usr}
323 msg = msg % {'username': usr}
327 assertr.element_contains('#username+.error-message', msg)
324 assertr.element_contains('#username+.error-message', msg)
328
325
@@ -339,7 +336,7 b' class TestLoginController(object):'
339 }
336 }
340 )
337 )
341
338
342 msg = validators.ValidPassword()._messages['invalid_password']
339 msg = u'Invalid characters (non-ascii) in password'
343 response.mustcontain(msg)
340 response.mustcontain(msg)
344
341
345 def test_register_password_mismatch(self):
342 def test_register_password_mismatch(self):
@@ -354,7 +351,7 b' class TestLoginController(object):'
354 'lastname': 'test'
351 'lastname': 'test'
355 }
352 }
356 )
353 )
357 msg = validators.ValidPasswordsMatch()._messages['password_mismatch']
354 msg = u'Passwords do not match'
358 response.mustcontain(msg)
355 response.mustcontain(msg)
359
356
360 def test_register_ok(self):
357 def test_register_ok(self):
@@ -364,6 +361,11 b' class TestLoginController(object):'
364 name = 'testname'
361 name = 'testname'
365 lastname = 'testlastname'
362 lastname = 'testlastname'
366
363
364 # this initializes a session
365 response = self.app.get(route_path('register'))
366 response.mustcontain('Create an Account')
367
368
367 response = self.app.post(
369 response = self.app.post(
368 route_path('register'),
370 route_path('register'),
369 {
371 {
@@ -374,9 +376,10 b' class TestLoginController(object):'
374 'firstname': name,
376 'firstname': name,
375 'lastname': lastname,
377 'lastname': lastname,
376 'admin': True
378 'admin': True
377 }
379 },
378 ) # This should be overriden
380 status=302
379 assert response.status == '302 Found'
381 ) # This should be overridden
382
380 assert_session_flash(
383 assert_session_flash(
381 response, 'You have successfully registered with RhodeCode')
384 response, 'You have successfully registered with RhodeCode')
382
385
@@ -392,6 +395,9 b' class TestLoginController(object):'
392
395
393 def test_forgot_password_wrong_mail(self):
396 def test_forgot_password_wrong_mail(self):
394 bad_email = 'marcin@wrongmail.org'
397 bad_email = 'marcin@wrongmail.org'
398 # this initializes a session
399 self.app.get(route_path('reset_password'))
400
395 response = self.app.post(
401 response = self.app.post(
396 route_path('reset_password'), {'email': bad_email, }
402 route_path('reset_password'), {'email': bad_email, }
397 )
403 )
@@ -399,8 +405,8 b' class TestLoginController(object):'
399 'If such email exists, a password reset link was sent to it.')
405 'If such email exists, a password reset link was sent to it.')
400
406
401 def test_forgot_password(self, user_util):
407 def test_forgot_password(self, user_util):
402 response = self.app.get(route_path('reset_password'))
408 # this initializes a session
403 assert response.status == '200 OK'
409 self.app.get(route_path('reset_password'))
404
410
405 user = user_util.create_user()
411 user = user_util.create_user()
406 user_id = user.user_id
412 user_id = user.user_id
@@ -413,8 +419,7 b' class TestLoginController(object):'
413
419
414 # BAD KEY
420 # BAD KEY
415 confirm_url = '{}?key={}'.format(route_path('reset_password_confirmation'), 'badkey')
421 confirm_url = '{}?key={}'.format(route_path('reset_password_confirmation'), 'badkey')
416 response = self.app.get(confirm_url)
422 response = self.app.get(confirm_url, status=302)
417 assert response.status == '302 Found'
418 assert response.location.endswith(route_path('reset_password'))
423 assert response.location.endswith(route_path('reset_password'))
419 assert_session_flash(response, 'Given reset token is invalid')
424 assert_session_flash(response, 'Given reset token is invalid')
420
425
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -22,10 +22,10 b''
22 import mock
22 import mock
23 import pytest
23 import pytest
24
24
25 from rhodecode.apps._base import ADMIN_PREFIX
25 from rhodecode.apps.login.views import LoginView, CaptchaData
26 from rhodecode.apps.login.views import LoginView, CaptchaData
26 from rhodecode.config.routing import ADMIN_PREFIX
27 from rhodecode.model.settings import SettingsModel
27 from rhodecode.lib.utils2 import AttributeDict
28 from rhodecode.lib.utils2 import AttributeDict
28 from rhodecode.model.settings import SettingsModel
29 from rhodecode.tests.utils import AssertResponse
29 from rhodecode.tests.utils import AssertResponse
30
30
31
31
@@ -58,7 +58,7 b' class TestRegisterCaptcha(object):'
58 ('privkey', '', CaptchaData(True, 'privkey', '')),
58 ('privkey', '', CaptchaData(True, 'privkey', '')),
59 ('privkey', 'pubkey', CaptchaData(True, 'privkey', 'pubkey')),
59 ('privkey', 'pubkey', CaptchaData(True, 'privkey', 'pubkey')),
60 ])
60 ])
61 def test_get_captcha_data(self, private_key, public_key, expected, db,
61 def test_get_captcha_data(self, private_key, public_key, expected,
62 request_stub, user_util):
62 request_stub, user_util):
63 request_stub.user = user_util.create_user().AuthUser()
63 request_stub.user = user_util.create_user().AuthUser()
64 request_stub.matched_route = AttributeDict({'name': 'login'})
64 request_stub.matched_route = AttributeDict({'name': 'login'})
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -32,7 +32,7 b' from recaptcha.client.captcha import sub'
32
32
33 from rhodecode.apps._base import BaseAppView
33 from rhodecode.apps._base import BaseAppView
34 from rhodecode.authentication.base import authenticate, HTTP_TYPE
34 from rhodecode.authentication.base import authenticate, HTTP_TYPE
35 from rhodecode.events import UserRegistered
35 from rhodecode.events import UserRegistered, trigger
36 from rhodecode.lib import helpers as h
36 from rhodecode.lib import helpers as h
37 from rhodecode.lib import audit_logger
37 from rhodecode.lib import audit_logger
38 from rhodecode.lib.auth import (
38 from rhodecode.lib.auth import (
@@ -113,7 +113,7 b' class LoginView(BaseAppView):'
113 def load_default_context(self):
113 def load_default_context(self):
114 c = self._get_local_tmpl_context()
114 c = self._get_local_tmpl_context()
115 c.came_from = get_came_from(self.request)
115 c.came_from = get_came_from(self.request)
116 self._register_global_c(c)
116
117 return c
117 return c
118
118
119 def _get_captcha_data(self):
119 def _get_captcha_data(self):
@@ -147,7 +147,7 b' class LoginView(BaseAppView):'
147 raise HTTPFound(c.came_from, headers=headers)
147 raise HTTPFound(c.came_from, headers=headers)
148 except UserCreationError as e:
148 except UserCreationError as e:
149 log.error(e)
149 log.error(e)
150 self.session.flash(e, queue='error')
150 h.flash(e, category='error')
151
151
152 return self._get_template_context(c)
152 return self._get_template_context(c)
153
153
@@ -157,7 +157,7 b' class LoginView(BaseAppView):'
157 def login_post(self):
157 def login_post(self):
158 c = self.load_default_context()
158 c = self.load_default_context()
159
159
160 login_form = LoginForm()()
160 login_form = LoginForm(self.request.translate)()
161
161
162 try:
162 try:
163 self.session.invalidate()
163 self.session.invalidate()
@@ -182,11 +182,10 b' class LoginView(BaseAppView):'
182 defaults = errors.value
182 defaults = errors.value
183 # remove password from filling in form again
183 # remove password from filling in form again
184 defaults.pop('password', None)
184 defaults.pop('password', None)
185 render_ctx = self._get_template_context(c)
185 render_ctx = {
186 render_ctx.update({
187 'errors': errors.error_dict,
186 'errors': errors.error_dict,
188 'defaults': defaults,
187 'defaults': defaults,
189 })
188 }
190
189
191 audit_user = audit_logger.UserWrap(
190 audit_user = audit_logger.UserWrap(
192 username=self.request.POST.get('username'),
191 username=self.request.POST.get('username'),
@@ -195,14 +194,14 b' class LoginView(BaseAppView):'
195 audit_logger.store_web(
194 audit_logger.store_web(
196 'user.login.failure', action_data=action_data,
195 'user.login.failure', action_data=action_data,
197 user=audit_user, commit=True)
196 user=audit_user, commit=True)
198 return render_ctx
197 return self._get_template_context(c, **render_ctx)
199
198
200 except UserCreationError as e:
199 except UserCreationError as e:
201 # headers auth or other auth functions that create users on
200 # headers auth or other auth functions that create users on
202 # the fly can throw this exception signaling that there's issue
201 # the fly can throw this exception signaling that there's issue
203 # with user creation, explanation should be provided in
202 # with user creation, explanation should be provided in
204 # Exception itself
203 # Exception itself
205 self.session.flash(e, queue='error')
204 h.flash(e, category='error')
206 return self._get_template_context(c)
205 return self._get_template_context(c)
207
206
208 @CSRFRequired()
207 @CSRFRequired()
@@ -251,11 +250,12 b' class LoginView(BaseAppView):'
251 route_name='register', request_method='POST',
250 route_name='register', request_method='POST',
252 renderer='rhodecode:templates/register.mako')
251 renderer='rhodecode:templates/register.mako')
253 def register_post(self):
252 def register_post(self):
253 self.load_default_context()
254 captcha = self._get_captcha_data()
254 captcha = self._get_captcha_data()
255 auto_active = 'hg.register.auto_activate' in User.get_default_user()\
255 auto_active = 'hg.register.auto_activate' in User.get_default_user()\
256 .AuthUser().permissions['global']
256 .AuthUser().permissions['global']
257
257
258 register_form = RegisterForm()()
258 register_form = RegisterForm(self.request.translate)()
259 try:
259 try:
260
260
261 form_result = register_form.to_python(self.request.POST)
261 form_result = register_form.to_python(self.request.POST)
@@ -275,11 +275,18 b' class LoginView(BaseAppView):'
275 error_dict=error_dict)
275 error_dict=error_dict)
276
276
277 new_user = UserModel().create_registration(form_result)
277 new_user = UserModel().create_registration(form_result)
278
279 action_data = {'data': new_user.get_api_data(),
280 'user_agent': self.request.user_agent}
281 audit_logger.store_web(
282 'user.register', action_data=action_data,
283 user=new_user)
284
278 event = UserRegistered(user=new_user, session=self.session)
285 event = UserRegistered(user=new_user, session=self.session)
279 self.request.registry.notify(event)
286 trigger(event)
280 self.session.flash(
287 h.flash(
281 _('You have successfully registered with RhodeCode'),
288 _('You have successfully registered with RhodeCode'),
282 queue='success')
289 category='success')
283 Session().commit()
290 Session().commit()
284
291
285 redirect_ro = self.request.route_path('login')
292 redirect_ro = self.request.route_path('login')
@@ -296,16 +303,17 b' class LoginView(BaseAppView):'
296 # the fly can throw this exception signaling that there's issue
303 # the fly can throw this exception signaling that there's issue
297 # with user creation, explanation should be provided in
304 # with user creation, explanation should be provided in
298 # Exception itself
305 # Exception itself
299 self.session.flash(e, queue='error')
306 h.flash(e, category='error')
300 return self.register()
307 return self.register()
301
308
302 @view_config(
309 @view_config(
303 route_name='reset_password', request_method=('GET', 'POST'),
310 route_name='reset_password', request_method=('GET', 'POST'),
304 renderer='rhodecode:templates/password_reset.mako')
311 renderer='rhodecode:templates/password_reset.mako')
305 def password_reset(self):
312 def password_reset(self):
313 c = self.load_default_context()
306 captcha = self._get_captcha_data()
314 captcha = self._get_captcha_data()
307
315
308 render_ctx = {
316 template_context = {
309 'captcha_active': captcha.active,
317 'captcha_active': captcha.active,
310 'captcha_public_key': captcha.public_key,
318 'captcha_public_key': captcha.public_key,
311 'defaults': {},
319 'defaults': {},
@@ -320,11 +328,11 b' class LoginView(BaseAppView):'
320 if h.HasPermissionAny('hg.password_reset.disabled')():
328 if h.HasPermissionAny('hg.password_reset.disabled')():
321 _email = self.request.POST.get('email', '')
329 _email = self.request.POST.get('email', '')
322 log.error('Failed attempt to reset password for `%s`.', _email)
330 log.error('Failed attempt to reset password for `%s`.', _email)
323 self.session.flash(_('Password reset has been disabled.'),
331 h.flash(_('Password reset has been disabled.'),
324 queue='error')
332 category='error')
325 return HTTPFound(self.request.route_path('reset_password'))
333 return HTTPFound(self.request.route_path('reset_password'))
326
334
327 password_reset_form = PasswordResetForm()()
335 password_reset_form = PasswordResetForm(self.request.translate)()
328 try:
336 try:
329 form_result = password_reset_form.to_python(
337 form_result = password_reset_form.to_python(
330 self.request.POST)
338 self.request.POST)
@@ -362,7 +370,7 b' class LoginView(BaseAppView):'
362 UserModel().reset_password_link(
370 UserModel().reset_password_link(
363 form_result, password_reset_url)
371 form_result, password_reset_url)
364 # Display success message and redirect.
372 # Display success message and redirect.
365 self.session.flash(msg, queue='success')
373 h.flash(msg, category='success')
366
374
367 action_data = {'email': user_email,
375 action_data = {'email': user_email,
368 'user_agent': self.request.user_agent}
376 'user_agent': self.request.user_agent}
@@ -372,30 +380,30 b' class LoginView(BaseAppView):'
372 return HTTPFound(self.request.route_path('reset_password'))
380 return HTTPFound(self.request.route_path('reset_password'))
373
381
374 except formencode.Invalid as errors:
382 except formencode.Invalid as errors:
375 render_ctx.update({
383 template_context.update({
376 'defaults': errors.value,
384 'defaults': errors.value,
377 'errors': errors.error_dict,
385 'errors': errors.error_dict,
378 })
386 })
379 if not self.request.POST.get('email'):
387 if not self.request.POST.get('email'):
380 # case of empty email, we want to report that
388 # case of empty email, we want to report that
381 return render_ctx
389 return self._get_template_context(c, **template_context)
382
390
383 if 'recaptcha_field' in errors.error_dict:
391 if 'recaptcha_field' in errors.error_dict:
384 # case of failed captcha
392 # case of failed captcha
385 return render_ctx
393 return self._get_template_context(c, **template_context)
386
394
387 log.debug('faking response on invalid password reset')
395 log.debug('faking response on invalid password reset')
388 # make this take 2s, to prevent brute forcing.
396 # make this take 2s, to prevent brute forcing.
389 time.sleep(2)
397 time.sleep(2)
390 self.session.flash(msg, queue='success')
398 h.flash(msg, category='success')
391 return HTTPFound(self.request.route_path('reset_password'))
399 return HTTPFound(self.request.route_path('reset_password'))
392
400
393 return render_ctx
401 return self._get_template_context(c, **template_context)
394
402
395 @view_config(route_name='reset_password_confirmation',
403 @view_config(route_name='reset_password_confirmation',
396 request_method='GET')
404 request_method='GET')
397 def password_reset_confirmation(self):
405 def password_reset_confirmation(self):
398
406 self.load_default_context()
399 if self.request.GET and self.request.GET.get('key'):
407 if self.request.GET and self.request.GET.get('key'):
400 # make this take 2s, to prevent brute forcing.
408 # make this take 2s, to prevent brute forcing.
401 time.sleep(2)
409 time.sleep(2)
@@ -408,18 +416,18 b' class LoginView(BaseAppView):'
408 log.debug('Got token with role:%s expected is %s',
416 log.debug('Got token with role:%s expected is %s',
409 getattr(token, 'role', 'EMPTY_TOKEN'),
417 getattr(token, 'role', 'EMPTY_TOKEN'),
410 UserApiKeys.ROLE_PASSWORD_RESET)
418 UserApiKeys.ROLE_PASSWORD_RESET)
411 self.session.flash(
419 h.flash(
412 _('Given reset token is invalid'), queue='error')
420 _('Given reset token is invalid'), category='error')
413 return HTTPFound(self.request.route_path('reset_password'))
421 return HTTPFound(self.request.route_path('reset_password'))
414
422
415 try:
423 try:
416 owner = token.user
424 owner = token.user
417 data = {'email': owner.email, 'token': token.api_key}
425 data = {'email': owner.email, 'token': token.api_key}
418 UserModel().reset_password(data)
426 UserModel().reset_password(data)
419 self.session.flash(
427 h.flash(
420 _('Your password reset was successful, '
428 _('Your password reset was successful, '
421 'a new password has been sent to your email'),
429 'a new password has been sent to your email'),
422 queue='success')
430 category='success')
423 except Exception as e:
431 except Exception as e:
424 log.error(e)
432 log.error(e)
425 return HTTPFound(self.request.route_path('reset_password'))
433 return HTTPFound(self.request.route_path('reset_password'))
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -70,6 +70,11 b' def includeme(config):'
70 name='my_account_ssh_keys_delete',
70 name='my_account_ssh_keys_delete',
71 pattern=ADMIN_PREFIX + '/my_account/ssh_keys/delete')
71 pattern=ADMIN_PREFIX + '/my_account/ssh_keys/delete')
72
72
73 # my account user group membership
74 config.add_route(
75 name='my_account_user_group_membership',
76 pattern=ADMIN_PREFIX + '/my_account/user_group_membership')
77
73 # my account emails
78 # my account emails
74 config.add_route(
79 config.add_route(
75 name='my_account_emails',
80 name='my_account_emails',
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -19,7 +19,7 b''
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 # -*- coding: utf-8 -*-
20 # -*- coding: utf-8 -*-
21
21
22 # Copyright (C) 2016-2017 RhodeCode GmbH
22 # Copyright (C) 2016-2018 RhodeCode GmbH
23 #
23 #
24 # This program is free software: you can redistribute it and/or modify
24 # This program is free software: you can redistribute it and/or modify
25 # it under the terms of the GNU Affero General Public License, version 3
25 # it under the terms of the GNU Affero General Public License, version 3
@@ -198,8 +198,6 b' class TestMyAccountEdit(TestController):'
198 params=params)
198 params=params)
199
199
200 response.mustcontain('An email address must contain a single @')
200 response.mustcontain('An email address must contain a single @')
201 from rhodecode.model import validators
201 msg = u'Username "%(username)s" already exists'
202 msg = validators.ValidUsername(
203 edit=False, old_data={})._messages['username_exists']
204 msg = h.html_escape(msg % {'username': 'test_admin'})
202 msg = h.html_escape(msg % {'username': 'test_admin'})
205 response.mustcontain(u"%s" % msg)
203 response.mustcontain(u"%s" % msg)
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -42,12 +42,13 b' from rhodecode.model.comment import Comm'
42 from rhodecode.model.db import (
42 from rhodecode.model.db import (
43 Repository, UserEmailMap, UserApiKeys, UserFollowing, joinedload,
43 Repository, UserEmailMap, UserApiKeys, UserFollowing, joinedload,
44 PullRequest)
44 PullRequest)
45 from rhodecode.model.forms import UserForm
45 from rhodecode.model.forms import UserForm, UserExtraEmailForm
46 from rhodecode.model.meta import Session
46 from rhodecode.model.meta import Session
47 from rhodecode.model.pull_request import PullRequestModel
47 from rhodecode.model.pull_request import PullRequestModel
48 from rhodecode.model.scm import RepoList
48 from rhodecode.model.scm import RepoList
49 from rhodecode.model.user import UserModel
49 from rhodecode.model.user import UserModel
50 from rhodecode.model.repo import RepoModel
50 from rhodecode.model.repo import RepoModel
51 from rhodecode.model.user_group import UserGroupModel
51 from rhodecode.model.validation_schema.schemas import user_schema
52 from rhodecode.model.validation_schema.schemas import user_schema
52
53
53 log = logging.getLogger(__name__)
54 log = logging.getLogger(__name__)
@@ -64,7 +65,7 b' class MyAccountView(BaseAppView, DataGri'
64 c = self._get_local_tmpl_context()
65 c = self._get_local_tmpl_context()
65 c.user = c.auth_user.get_instance()
66 c.user = c.auth_user.get_instance()
66 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
67 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
67 self._register_global_c(c)
68
68 return c
69 return c
69
70
70 @LoginRequired()
71 @LoginRequired()
@@ -245,6 +246,10 b' class MyAccountView(BaseAppView, DataGri'
245 email = self.request.POST.get('new_email')
246 email = self.request.POST.get('new_email')
246
247
247 try:
248 try:
249 form = UserExtraEmailForm(self.request.translate)()
250 data = form.to_python({'email': email})
251 email = data['email']
252
248 UserModel().add_extra_email(c.user.user_id, email)
253 UserModel().add_extra_email(c.user.user_id, email)
249 audit_logger.store_web(
254 audit_logger.store_web(
250 'user.edit.email.add', action_data={
255 'user.edit.email.add', action_data={
@@ -442,7 +447,7 b' class MyAccountView(BaseAppView, DataGri'
442 c.extern_type = c.user.extern_type
447 c.extern_type = c.user.extern_type
443 c.extern_name = c.user.extern_name
448 c.extern_name = c.user.extern_name
444
449
445 _form = UserForm(edit=True,
450 _form = UserForm(self.request.translate, edit=True,
446 old_data={'user_id': self._rhodecode_user.user_id,
451 old_data={'user_id': self._rhodecode_user.user_id,
447 'email': self._rhodecode_user.email})()
452 'email': self._rhodecode_user.email})()
448 form_result = {}
453 form_result = {}
@@ -492,7 +497,7 b' class MyAccountView(BaseAppView, DataGri'
492 draw, start, limit = self._extract_chunk(self.request)
497 draw, start, limit = self._extract_chunk(self.request)
493 search_q, order_by, order_dir = self._extract_ordering(self.request)
498 search_q, order_by, order_dir = self._extract_ordering(self.request)
494 _render = self.request.get_partial_renderer(
499 _render = self.request.get_partial_renderer(
495 'data_table/_dt_elements.mako')
500 'rhodecode:templates/data_table/_dt_elements.mako')
496
501
497 pull_requests = PullRequestModel().get_im_participating_in(
502 pull_requests = PullRequestModel().get_im_participating_in(
498 user_id=self._rhodecode_user.user_id,
503 user_id=self._rhodecode_user.user_id,
@@ -568,6 +573,7 b' class MyAccountView(BaseAppView, DataGri'
568 route_name='my_account_pullrequests_data',
573 route_name='my_account_pullrequests_data',
569 request_method='GET', renderer='json_ext')
574 request_method='GET', renderer='json_ext')
570 def my_account_pullrequests_data(self):
575 def my_account_pullrequests_data(self):
576 self.load_default_context()
571 req_get = self.request.GET
577 req_get = self.request.GET
572 closed = str2bool(req_get.get('closed'))
578 closed = str2bool(req_get.get('closed'))
573
579
@@ -578,3 +584,16 b' class MyAccountView(BaseAppView, DataGri'
578 data = self._get_pull_requests_list(statuses=statuses)
584 data = self._get_pull_requests_list(statuses=statuses)
579 return data
585 return data
580
586
587 @LoginRequired()
588 @NotAnonymous()
589 @view_config(
590 route_name='my_account_user_group_membership',
591 request_method='GET',
592 renderer='rhodecode:templates/admin/my_account/my_account.mako')
593 def my_account_user_group_membership(self):
594 c = self.load_default_context()
595 c.active = 'user_group_membership'
596 groups = [UserGroupModel.get_user_groups_as_dict(group.users_group)
597 for group in self._rhodecode_db_user.group_member]
598 c.user_groups = json.dumps(groups)
599 return self._get_template_context(c)
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -43,7 +43,7 b' class MyAccountNotificationsView(BaseApp'
43 def load_default_context(self):
43 def load_default_context(self):
44 c = self._get_local_tmpl_context()
44 c = self._get_local_tmpl_context()
45 c.user = c.auth_user.get_instance()
45 c.user = c.auth_user.get_instance()
46 self._register_global_c(c)
46
47 return c
47 return c
48
48
49 def _has_permissions(self, notification):
49 def _has_permissions(self, notification):
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -44,7 +44,7 b' class MyAccountSshKeysView(BaseAppView, '
44
44
45 c.ssh_enabled = self.request.registry.settings.get(
45 c.ssh_enabled = self.request.registry.settings.get(
46 'ssh.generate_authorized_keyfile')
46 'ssh.generate_authorized_keyfile')
47 self._register_global_c(c)
47
48 return c
48 return c
49
49
50 @LoginRequired()
50 @LoginRequired()
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -18,7 +18,7 b''
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 from rhodecode.config.routing import ADMIN_PREFIX
21 from rhodecode.apps._base import ADMIN_PREFIX
22
22
23
23
24 def admin_routes(config):
24 def admin_routes(config):
@@ -36,7 +36,7 b' def admin_routes(config):'
36 def includeme(config):
36 def includeme(config):
37
37
38 config.include(admin_routes, route_prefix=ADMIN_PREFIX + '/ops')
38 config.include(admin_routes, route_prefix=ADMIN_PREFIX + '/ops')
39 # make OLD entries from pylons work
39 # make OLD entries from <4.10.0 work
40 config.add_route(
40 config.add_route(
41 name='ops_ping_legacy', pattern=ADMIN_PREFIX + '/ping')
41 name='ops_ping_legacy', pattern=ADMIN_PREFIX + '/ping')
42 config.add_route(
42 config.add_route(
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -35,7 +35,7 b' class OpsView(BaseAppView):'
35 def load_default_context(self):
35 def load_default_context(self):
36 c = self._get_local_tmpl_context()
36 c = self._get_local_tmpl_context()
37 c.user = c.auth_user.get_instance()
37 c.user = c.auth_user.get_instance()
38 self._register_global_c(c)
38
39 return c
39 return c
40
40
41 @view_config(
41 @view_config(
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -37,7 +37,7 b' log = logging.getLogger(__name__)'
37 class RepoGroupSettingsView(RepoGroupAppView):
37 class RepoGroupSettingsView(RepoGroupAppView):
38 def load_default_context(self):
38 def load_default_context(self):
39 c = self._get_local_tmpl_context()
39 c = self._get_local_tmpl_context()
40 self._register_global_c(c)
40
41 return c
41 return c
42
42
43 @LoginRequired()
43 @LoginRequired()
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -38,7 +38,7 b' log = logging.getLogger(__name__)'
38 class RepoGroupPermissionsView(RepoGroupAppView):
38 class RepoGroupPermissionsView(RepoGroupAppView):
39 def load_default_context(self):
39 def load_default_context(self):
40 c = self._get_local_tmpl_context()
40 c = self._get_local_tmpl_context()
41 self._register_global_c(c)
41
42 return c
42 return c
43
43
44 @LoginRequired()
44 @LoginRequired()
@@ -65,7 +65,7 b' class RepoGroupPermissionsView(RepoGroup'
65 c.repo_group = self.db_repo_group
65 c.repo_group = self.db_repo_group
66
66
67 valid_recursive_choices = ['none', 'repos', 'groups', 'all']
67 valid_recursive_choices = ['none', 'repos', 'groups', 'all']
68 form = RepoGroupPermsForm(valid_recursive_choices)()\
68 form = RepoGroupPermsForm(self.request.translate, valid_recursive_choices)()\
69 .to_python(self.request.POST)
69 .to_python(self.request.POST)
70
70
71 if not c.rhodecode_user.is_admin:
71 if not c.rhodecode_user.is_admin:
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -73,7 +73,7 b' class RepoGroupSettingsView(RepoGroupApp'
73 c.repo_groups_choices.append(parent_group.group_id)
73 c.repo_groups_choices.append(parent_group.group_id)
74 c.repo_groups.append(RepoGroup._generate_choice(parent_group))
74 c.repo_groups.append(RepoGroup._generate_choice(parent_group))
75
75
76 self._register_global_c(c)
76
77 return c
77 return c
78
78
79 def _can_create_repo_group(self, parent_group_id=None):
79 def _can_create_repo_group(self, parent_group_id=None):
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -47,7 +47,7 b' def route_path(name, params=None, **kwar'
47 class TestRepoCommitCommentsView(TestController):
47 class TestRepoCommitCommentsView(TestController):
48
48
49 @pytest.fixture(autouse=True)
49 @pytest.fixture(autouse=True)
50 def prepare(self, request, pylonsapp):
50 def prepare(self, request, baseapp):
51 for x in ChangesetComment.query().all():
51 for x in ChangesetComment.query().all():
52 Session().delete(x)
52 Session().delete(x)
53 Session().commit()
53 Session().commit()
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -48,6 +48,7 b' def route_path(name, params=None, **kwar'
48 import urllib
48 import urllib
49
49
50 base_url = {
50 base_url = {
51 'repo_summary': '/{repo_name}',
51 'repo_archivefile': '/{repo_name}/archive/{fname}',
52 'repo_archivefile': '/{repo_name}/archive/{fname}',
52 'repo_files_diff': '/{repo_name}/diff/{f_path}',
53 'repo_files_diff': '/{repo_name}/diff/{f_path}',
53 'repo_files_diff_2way_redirect': '/{repo_name}/diff-2way/{f_path}',
54 'repo_files_diff_2way_redirect': '/{repo_name}/diff-2way/{f_path}',
@@ -999,8 +1000,11 b' class TestFilesViewOtherCases(object):'
999 .format(repo_file_add_url))
1000 .format(repo_file_add_url))
1000
1001
1001 def test_access_empty_repo_redirect_to_summary_with_alert_no_write_perms(
1002 def test_access_empty_repo_redirect_to_summary_with_alert_no_write_perms(
1002 self, backend_stub, user_util):
1003 self, backend_stub, autologin_regular_user):
1003 repo = backend_stub.create_repo()
1004 repo = backend_stub.create_repo()
1005 # init session for anon user
1006 route_path('repo_summary', repo_name=repo.repo_name)
1007
1004 repo_file_add_url = route_path(
1008 repo_file_add_url = route_path(
1005 'repo_files_add_file',
1009 'repo_files_add_file',
1006 repo_name=repo.repo_name,
1010 repo_name=repo.repo_name,
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -58,11 +58,11 b' class TestRepoIssueTracker(object):'
58 'edit_repo_issuetracker_update', repo_name=backend.repo.repo_name)
58 'edit_repo_issuetracker_update', repo_name=backend.repo.repo_name)
59 post_data = {
59 post_data = {
60 'new_pattern_pattern_0': pattern,
60 'new_pattern_pattern_0': pattern,
61 'new_pattern_url_0': 'url',
61 'new_pattern_url_0': 'http://url',
62 'new_pattern_prefix_0': 'prefix',
62 'new_pattern_prefix_0': 'prefix',
63 'new_pattern_description_0': 'description',
63 'new_pattern_description_0': 'description',
64 'new_pattern_pattern_1': another_pattern,
64 'new_pattern_pattern_1': another_pattern,
65 'new_pattern_url_1': 'url1',
65 'new_pattern_url_1': '/url1',
66 'new_pattern_prefix_1': 'prefix1',
66 'new_pattern_prefix_1': 'prefix1',
67 'new_pattern_description_1': 'description1',
67 'new_pattern_description_1': 'description1',
68 'csrf_token': csrf_token
68 'csrf_token': csrf_token
@@ -84,7 +84,7 b' class TestRepoIssueTracker(object):'
84 extra_environ=xhr_header, params=data)
84 extra_environ=xhr_header, params=data)
85
85
86 assert response.body == \
86 assert response.body == \
87 'example of <a class="issue-tracker-link" href="url">prefix</a> replacement'
87 'example of <a class="issue-tracker-link" href="http://url">prefix</a> replacement'
88
88
89 @request.addfinalizer
89 @request.addfinalizer
90 def cleanup():
90 def cleanup():
@@ -106,7 +106,7 b' class TestRepoIssueTracker(object):'
106 'edit_repo_issuetracker_update', repo_name=backend.repo.repo_name)
106 'edit_repo_issuetracker_update', repo_name=backend.repo.repo_name)
107 post_data = {
107 post_data = {
108 'new_pattern_pattern_0': pattern,
108 'new_pattern_pattern_0': pattern,
109 'new_pattern_url_0': 'url',
109 'new_pattern_url_0': '/url',
110 'new_pattern_prefix_0': 'prefix',
110 'new_pattern_prefix_0': 'prefix',
111 'new_pattern_description_0': 'description',
111 'new_pattern_description_0': 'description',
112 'uid': old_uid,
112 'uid': old_uid,
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -199,18 +199,17 b' class TestPullrequestsView(object):'
199 def test_edit_title_description_closed(self, pr_util, csrf_token):
199 def test_edit_title_description_closed(self, pr_util, csrf_token):
200 pull_request = pr_util.create_pull_request()
200 pull_request = pr_util.create_pull_request()
201 pull_request_id = pull_request.pull_request_id
201 pull_request_id = pull_request.pull_request_id
202 repo_name = pull_request.target_repo.repo_name
202 pr_util.close()
203 pr_util.close()
203
204
204 response = self.app.post(
205 response = self.app.post(
205 route_path('pullrequest_update',
206 route_path('pullrequest_update',
206 repo_name=pull_request.target_repo.repo_name,
207 repo_name=repo_name, pull_request_id=pull_request_id),
207 pull_request_id=pull_request_id),
208 params={
208 params={
209 'edit_pull_request': 'true',
209 'edit_pull_request': 'true',
210 'title': 'New title',
210 'title': 'New title',
211 'description': 'New description',
211 'description': 'New description',
212 'csrf_token': csrf_token})
212 'csrf_token': csrf_token}, status=200)
213
214 assert_session_flash(
213 assert_session_flash(
215 response, u'Cannot update closed pull requests.',
214 response, u'Cannot update closed pull requests.',
216 category='error')
215 category='error')
@@ -300,7 +299,7 b' class TestPullrequestsView(object):'
300 pull_request = pr_util.create_pull_request()
299 pull_request = pr_util.create_pull_request()
301 pull_request_id = pull_request.pull_request_id
300 pull_request_id = pull_request.pull_request_id
302 PullRequestModel().update_reviewers(
301 PullRequestModel().update_reviewers(
303 pull_request_id, [(1, ['reason'], False), (2, ['reason2'], False)],
302 pull_request_id, [(1, ['reason'], False, []), (2, ['reason2'], False, [])],
304 pull_request.author)
303 pull_request.author)
305 author = pull_request.user_id
304 author = pull_request.user_id
306 repo = pull_request.target_repo.repo_id
305 repo = pull_request.target_repo.repo_id
@@ -377,6 +376,8 b' class TestPullrequestsView(object):'
377 ('__start__', 'reasons:sequence'),
376 ('__start__', 'reasons:sequence'),
378 ('reason', 'Some reason'),
377 ('reason', 'Some reason'),
379 ('__end__', 'reasons:sequence'),
378 ('__end__', 'reasons:sequence'),
379 ('__start__', 'rules:sequence'),
380 ('__end__', 'rules:sequence'),
380 ('mandatory', 'False'),
381 ('mandatory', 'False'),
381 ('__end__', 'reviewer:mapping'),
382 ('__end__', 'reviewer:mapping'),
382 ('__end__', 'review_members:sequence'),
383 ('__end__', 'review_members:sequence'),
@@ -434,6 +435,8 b' class TestPullrequestsView(object):'
434 ('__start__', 'reasons:sequence'),
435 ('__start__', 'reasons:sequence'),
435 ('reason', 'Some reason'),
436 ('reason', 'Some reason'),
436 ('__end__', 'reasons:sequence'),
437 ('__end__', 'reasons:sequence'),
438 ('__start__', 'rules:sequence'),
439 ('__end__', 'rules:sequence'),
437 ('mandatory', 'False'),
440 ('mandatory', 'False'),
438 ('__end__', 'reviewer:mapping'),
441 ('__end__', 'reviewer:mapping'),
439 ('__end__', 'review_members:sequence'),
442 ('__end__', 'review_members:sequence'),
@@ -461,7 +464,7 b' class TestPullrequestsView(object):'
461
464
462 # Change reviewers and check that a notification was made
465 # Change reviewers and check that a notification was made
463 PullRequestModel().update_reviewers(
466 PullRequestModel().update_reviewers(
464 pull_request.pull_request_id, [(1, [], False)],
467 pull_request.pull_request_id, [(1, [], False, [])],
465 pull_request.author)
468 pull_request.author)
466 assert len(notifications.all()) == 2
469 assert len(notifications.all()) == 2
467
470
@@ -498,6 +501,8 b' class TestPullrequestsView(object):'
498 ('__start__', 'reasons:sequence'),
501 ('__start__', 'reasons:sequence'),
499 ('reason', 'Some reason'),
502 ('reason', 'Some reason'),
500 ('__end__', 'reasons:sequence'),
503 ('__end__', 'reasons:sequence'),
504 ('__start__', 'rules:sequence'),
505 ('__end__', 'rules:sequence'),
501 ('mandatory', 'False'),
506 ('mandatory', 'False'),
502 ('__end__', 'reviewer:mapping'),
507 ('__end__', 'reviewer:mapping'),
503 ('__end__', 'review_members:sequence'),
508 ('__end__', 'review_members:sequence'),
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -56,6 +56,16 b' def route_path(name, params=None, **kwar'
56 return base_url
56 return base_url
57
57
58
58
59 def assert_clone_url(response, server, repo, disabled=False):
60
61 response.mustcontain(
62 '<input type="text" class="input-monospace clone_url_input" '
63 '{disabled}readonly="readonly" '
64 'value="http://test_admin@{server}/{repo}"/>'.format(
65 server=server, repo=repo, disabled='disabled ' if disabled else ' ')
66 )
67
68
59 @pytest.mark.usefixtures('app')
69 @pytest.mark.usefixtures('app')
60 class TestSummaryView(object):
70 class TestSummaryView(object):
61 def test_index(self, autologin_user, backend, http_host_only_stub):
71 def test_index(self, autologin_user, backend, http_host_only_stub):
@@ -76,12 +86,8 b' class TestSummaryView(object):'
76 )
86 )
77
87
78 # clone url...
88 # clone url...
79 response.mustcontain(
89 assert_clone_url(response, http_host_only_stub, repo_name)
80 'id="clone_url" readonly="readonly"'
90 assert_clone_url(response, http_host_only_stub, '_{}'.format(repo_id))
81 ' value="http://test_admin@%s/%s"' % (http_host_only_stub, repo_name, ))
82 response.mustcontain(
83 'id="clone_url_id" readonly="readonly"'
84 ' value="http://test_admin@%s/_%s"' % (http_host_only_stub, repo_id, ))
85
91
86 def test_index_svn_without_proxy(
92 def test_index_svn_without_proxy(
87 self, autologin_user, backend_svn, http_host_only_stub):
93 self, autologin_user, backend_svn, http_host_only_stub):
@@ -89,12 +95,9 b' class TestSummaryView(object):'
89 repo_name = backend_svn.repo_name
95 repo_name = backend_svn.repo_name
90 response = self.app.get(route_path('repo_summary', repo_name=repo_name))
96 response = self.app.get(route_path('repo_summary', repo_name=repo_name))
91 # clone url...
97 # clone url...
92 response.mustcontain(
98
93 'id="clone_url" disabled'
99 assert_clone_url(response, http_host_only_stub, repo_name, disabled=True)
94 ' value="http://test_admin@%s/%s"' % (http_host_only_stub, repo_name, ))
100 assert_clone_url(response, http_host_only_stub, '_{}'.format(repo_id), disabled=True)
95 response.mustcontain(
96 'id="clone_url_id" disabled'
97 ' value="http://test_admin@%s/_%s"' % (http_host_only_stub, repo_id, ))
98
101
99 def test_index_with_trailing_slash(
102 def test_index_with_trailing_slash(
100 self, autologin_user, backend, http_host_only_stub):
103 self, autologin_user, backend, http_host_only_stub):
@@ -108,12 +111,8 b' class TestSummaryView(object):'
108 status=200)
111 status=200)
109
112
110 # clone url...
113 # clone url...
111 response.mustcontain(
114 assert_clone_url(response, http_host_only_stub, repo_name)
112 'id="clone_url" readonly="readonly"'
115 assert_clone_url(response, http_host_only_stub, '_{}'.format(repo_id))
113 ' value="http://test_admin@%s/%s"' % (http_host_only_stub, repo_name, ))
114 response.mustcontain(
115 'id="clone_url_id" readonly="readonly"'
116 ' value="http://test_admin@%s/_%s"' % (http_host_only_stub, repo_id, ))
117
116
118 def test_index_by_id(self, autologin_user, backend):
117 def test_index_by_id(self, autologin_user, backend):
119 repo_id = backend.repo.repo_id
118 repo_id = backend.repo.repo_id
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -22,7 +22,7 b' from rhodecode.lib import helpers as h'
22 from rhodecode.lib.utils2 import safe_int
22 from rhodecode.lib.utils2 import safe_int
23
23
24
24
25 def reviewer_as_json(user, reasons=None, mandatory=False):
25 def reviewer_as_json(user, reasons=None, mandatory=False, rules=None, user_group=None):
26 """
26 """
27 Returns json struct of a reviewer for frontend
27 Returns json struct of a reviewer for frontend
28
28
@@ -34,10 +34,13 b' def reviewer_as_json(user, reasons=None,'
34 return {
34 return {
35 'user_id': user.user_id,
35 'user_id': user.user_id,
36 'reasons': reasons or [],
36 'reasons': reasons or [],
37 'rules': rules or [],
37 'mandatory': mandatory,
38 'mandatory': mandatory,
39 'user_group': user_group,
38 'username': user.username,
40 'username': user.username,
39 'first_name': user.first_name,
41 'first_name': user.first_name,
40 'last_name': user.last_name,
42 'last_name': user.last_name,
43 'user_link': h.link_to_user(user),
41 'gravatar_link': h.gravatar_url(user.email, 14),
44 'gravatar_link': h.gravatar_url(user.email, 14),
42 }
45 }
43
46
@@ -68,7 +71,7 b' def validate_default_reviewers(review_me'
68 reviewer_by_id = {}
71 reviewer_by_id = {}
69 for r in review_members:
72 for r in review_members:
70 reviewer_user_id = safe_int(r['user_id'])
73 reviewer_user_id = safe_int(r['user_id'])
71 entry = (reviewer_user_id, r['reasons'], r['mandatory'])
74 entry = (reviewer_user_id, r['reasons'], r['mandatory'], r['rules'])
72
75
73 reviewer_by_id[reviewer_user_id] = entry
76 reviewer_by_id[reviewer_user_id] = entry
74 reviewers.append(entry)
77 reviewers.append(entry)
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -34,7 +34,7 b' class AuditLogsView(RepoAppView):'
34 def load_default_context(self):
34 def load_default_context(self):
35 c = self._get_local_tmpl_context()
35 c = self._get_local_tmpl_context()
36
36
37 self._register_global_c(c)
37
38 return c
38 return c
39
39
40 @LoginRequired()
40 @LoginRequired()
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -37,7 +37,7 b' class RepoCachesView(RepoAppView):'
37 def load_default_context(self):
37 def load_default_context(self):
38 c = self._get_local_tmpl_context()
38 c = self._get_local_tmpl_context()
39
39
40 self._register_global_c(c)
40
41 return c
41 return c
42
42
43 @LoginRequired()
43 @LoginRequired()
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -159,7 +159,7 b' class RepoChangelogView(RepoAppView):'
159 c = self._get_local_tmpl_context(include_app_defaults=True)
159 c = self._get_local_tmpl_context(include_app_defaults=True)
160
160
161 c.rhodecode_repo = self.rhodecode_vcs_repo
161 c.rhodecode_repo = self.rhodecode_vcs_repo
162 self._register_global_c(c)
162
163 return c
163 return c
164
164
165 def _get_preload_attrs(self):
165 def _get_preload_attrs(self):
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -34,7 +34,7 b' log = logging.getLogger(__name__)'
34 class RepoChecksView(BaseAppView):
34 class RepoChecksView(BaseAppView):
35 def load_default_context(self):
35 def load_default_context(self):
36 c = self._get_local_tmpl_context()
36 c = self._get_local_tmpl_context()
37 self._register_global_c(c)
37
38 return c
38 return c
39
39
40 @NotAnonymous()
40 @NotAnonymous()
@@ -78,10 +78,15 b' class RepoChecksView(BaseAppView):'
78
78
79 if task_id and task_id not in ['None']:
79 if task_id and task_id not in ['None']:
80 import rhodecode
80 import rhodecode
81 from celery.result import AsyncResult
81 from rhodecode.lib.celerylib.loader import celery_app, exceptions
82 if rhodecode.CELERY_ENABLED:
82 if rhodecode.CELERY_ENABLED:
83 task = AsyncResult(task_id)
83 log.debug('celery: checking result for task:%s', task_id)
84 if task.failed():
84 task = celery_app.AsyncResult(task_id)
85 try:
86 task.get(timeout=10)
87 except exceptions.TimeoutError:
88 task = None
89 if task and task.failed():
85 msg = self._log_creation_exception(task.result, repo_name)
90 msg = self._log_creation_exception(task.result, repo_name)
86 h.flash(msg, category='error')
91 h.flash(msg, category='error')
87 raise HTTPFound(h.route_path('home'), code=501)
92 raise HTTPFound(h.route_path('home'), code=501)
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -150,7 +150,6 b' class RepoCommitsView(RepoAppView):'
150 c = self._get_local_tmpl_context(include_app_defaults=True)
150 c = self._get_local_tmpl_context(include_app_defaults=True)
151 c.rhodecode_repo = self.rhodecode_vcs_repo
151 c.rhodecode_repo = self.rhodecode_vcs_repo
152
152
153 self._register_global_c(c)
154 return c
153 return c
155
154
156 def _commit(self, commit_id_range, method):
155 def _commit(self, commit_id_range, method):
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -47,7 +47,7 b' class RepoCompareView(RepoAppView):'
47
47
48 c.rhodecode_repo = self.rhodecode_vcs_repo
48 c.rhodecode_repo = self.rhodecode_vcs_repo
49
49
50 self._register_global_c(c)
50
51 return c
51 return c
52
52
53 def _get_commit_or_redirect(
53 def _get_commit_or_redirect(
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -42,7 +42,7 b' class RepoFeedView(RepoAppView):'
42 def load_default_context(self):
42 def load_default_context(self):
43 c = self._get_local_tmpl_context()
43 c = self._get_local_tmpl_context()
44
44
45 self._register_global_c(c)
45
46 self._load_defaults()
46 self._load_defaults()
47 return c
47 return c
48
48
@@ -81,21 +81,22 b' class RepoFeedView(RepoAppView):'
81 _parsed = diff_processor.prepare(inline_diff=False)
81 _parsed = diff_processor.prepare(inline_diff=False)
82 limited_diff = isinstance(_parsed, LimitedDiffContainer)
82 limited_diff = isinstance(_parsed, LimitedDiffContainer)
83
83
84 return _parsed, limited_diff
84 return diff_processor, _parsed, limited_diff
85
85
86 def _get_title(self, commit):
86 def _get_title(self, commit):
87 return h.shorter(commit.message, 160)
87 return h.shorter(commit.message, 160)
88
88
89 def _get_description(self, commit):
89 def _get_description(self, commit):
90 _renderer = self.request.get_partial_renderer(
90 _renderer = self.request.get_partial_renderer(
91 'feed/atom_feed_entry.mako')
91 'rhodecode:templates/feed/atom_feed_entry.mako')
92 parsed_diff, limited_diff = self._changes(commit)
92 diff_processor, parsed_diff, limited_diff = self._changes(commit)
93 return _renderer(
93 return _renderer(
94 'body',
94 'body',
95 commit=commit,
95 commit=commit,
96 parsed_diff=parsed_diff,
96 parsed_diff=parsed_diff,
97 limited_diff=limited_diff,
97 limited_diff=limited_diff,
98 feed_include_diff=self.feed_include_diff,
98 feed_include_diff=self.feed_include_diff,
99 diff_processor=diff_processor,
99 )
100 )
100
101
101 def _set_timezone(self, date, tzinfo=pytz.utc):
102 def _set_timezone(self, date, tzinfo=pytz.utc):
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -83,7 +83,7 b' class RepoFilesView(RepoAppView):'
83
83
84 c.rhodecode_repo = self.rhodecode_vcs_repo
84 c.rhodecode_repo = self.rhodecode_vcs_repo
85
85
86 self._register_global_c(c)
86
87 return c
87 return c
88
88
89 def _ensure_not_locked(self):
89 def _ensure_not_locked(self):
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -33,6 +33,7 b' from rhodecode.lib.auth import ('
33 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous,
33 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous,
34 HasRepoPermissionAny, HasPermissionAnyDecorator, CSRFRequired)
34 HasRepoPermissionAny, HasPermissionAnyDecorator, CSRFRequired)
35 import rhodecode.lib.helpers as h
35 import rhodecode.lib.helpers as h
36 from rhodecode.lib.celerylib.utils import get_task_id
36 from rhodecode.model.db import coalesce, or_, Repository, RepoGroup
37 from rhodecode.model.db import coalesce, or_, Repository, RepoGroup
37 from rhodecode.model.repo import RepoModel
38 from rhodecode.model.repo import RepoModel
38 from rhodecode.model.forms import RepoForkForm
39 from rhodecode.model.forms import RepoForkForm
@@ -53,11 +54,11 b' class RepoForksView(RepoAppView, DataGri'
53 perm_set=['group.write', 'group.admin'])
54 perm_set=['group.write', 'group.admin'])
54 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
55 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
55 c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups)
56 c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups)
56 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
57 choices, c.landing_revs = ScmModel().get_repo_landing_revs(
58 self.request.translate)
57 c.landing_revs_choices = choices
59 c.landing_revs_choices = choices
58 c.personal_repo_group = c.rhodecode_user.personal_repo_group
60 c.personal_repo_group = c.rhodecode_user.personal_repo_group
59
61
60 self._register_global_c(c)
61 return c
62 return c
62
63
63 @LoginRequired()
64 @LoginRequired()
@@ -78,6 +79,7 b' class RepoForksView(RepoAppView, DataGri'
78 renderer='json_ext', xhr=True)
79 renderer='json_ext', xhr=True)
79 def repo_forks_data(self):
80 def repo_forks_data(self):
80 _ = self.request.translate
81 _ = self.request.translate
82 self.load_default_context()
81 column_map = {
83 column_map = {
82 'fork_name': 'repo_name',
84 'fork_name': 'repo_name',
83 'fork_date': 'created_on',
85 'fork_date': 'created_on',
@@ -209,7 +211,7 b' class RepoForksView(RepoAppView, DataGri'
209 _ = self.request.translate
211 _ = self.request.translate
210 c = self.load_default_context()
212 c = self.load_default_context()
211
213
212 _form = RepoForkForm(old_data={'repo_type': self.db_repo.repo_type},
214 _form = RepoForkForm(self.request.translate, old_data={'repo_type': self.db_repo.repo_type},
213 repo_groups=c.repo_groups_choices,
215 repo_groups=c.repo_groups_choices,
214 landing_revs=c.landing_revs_choices)()
216 landing_revs=c.landing_revs_choices)()
215 post_data = dict(self.request.POST)
217 post_data = dict(self.request.POST)
@@ -225,9 +227,8 b' class RepoForksView(RepoAppView, DataGri'
225 # management is handled there.
227 # management is handled there.
226 task = RepoModel().create_fork(
228 task = RepoModel().create_fork(
227 form_result, c.rhodecode_user.user_id)
229 form_result, c.rhodecode_user.user_id)
228 from celery.result import BaseAsyncResult
230
229 if isinstance(task, BaseAsyncResult):
231 task_id = get_task_id(task)
230 task_id = task.task_id
231 except formencode.Invalid as errors:
232 except formencode.Invalid as errors:
232 c.rhodecode_db_repo = self.db_repo
233 c.rhodecode_db_repo = self.db_repo
233
234
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -33,7 +33,7 b' class RepoMaintenanceView(RepoAppView):'
33 def load_default_context(self):
33 def load_default_context(self):
34 c = self._get_local_tmpl_context()
34 c = self._get_local_tmpl_context()
35
35
36 self._register_global_c(c)
36
37 return c
37 return c
38
38
39 @LoginRequired()
39 @LoginRequired()
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -40,7 +40,7 b' class RepoSettingsPermissionsView(RepoAp'
40 def load_default_context(self):
40 def load_default_context(self):
41 c = self._get_local_tmpl_context()
41 c = self._get_local_tmpl_context()
42
42
43 self._register_global_c(c)
43
44 return c
44 return c
45
45
46 @LoginRequired()
46 @LoginRequired()
@@ -68,7 +68,7 b' class RepoSettingsPermissionsView(RepoAp'
68 # default user permissions, prevents submission of FAKE post data
68 # default user permissions, prevents submission of FAKE post data
69 # into the form for private repos
69 # into the form for private repos
70 data['repo_private'] = self.db_repo.private
70 data['repo_private'] = self.db_repo.private
71 form = RepoPermsForm()().to_python(data)
71 form = RepoPermsForm(self.request.translate)().to_python(data)
72 changes = RepoModel().update_permissions(
72 changes = RepoModel().update_permissions(
73 self.db_repo_name, form['perm_additions'], form['perm_updates'],
73 self.db_repo_name, form['perm_additions'], form['perm_updates'],
74 form['perm_deletions'])
74 form['perm_deletions'])
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -60,7 +60,7 b' class RepoPullRequestsView(RepoAppView, '
60 c = self._get_local_tmpl_context(include_app_defaults=True)
60 c = self._get_local_tmpl_context(include_app_defaults=True)
61 c.REVIEW_STATUS_APPROVED = ChangesetStatus.STATUS_APPROVED
61 c.REVIEW_STATUS_APPROVED = ChangesetStatus.STATUS_APPROVED
62 c.REVIEW_STATUS_REJECTED = ChangesetStatus.STATUS_REJECTED
62 c.REVIEW_STATUS_REJECTED = ChangesetStatus.STATUS_REJECTED
63 self._register_global_c(c)
63
64 return c
64 return c
65
65
66 def _get_pull_requests_list(
66 def _get_pull_requests_list(
@@ -69,7 +69,7 b' class RepoPullRequestsView(RepoAppView, '
69 draw, start, limit = self._extract_chunk(self.request)
69 draw, start, limit = self._extract_chunk(self.request)
70 search_q, order_by, order_dir = self._extract_ordering(self.request)
70 search_q, order_by, order_dir = self._extract_ordering(self.request)
71 _render = self.request.get_partial_renderer(
71 _render = self.request.get_partial_renderer(
72 'data_table/_dt_elements.mako')
72 'rhodecode:templates/data_table/_dt_elements.mako')
73
73
74 # pagination
74 # pagination
75
75
@@ -173,6 +173,7 b' class RepoPullRequestsView(RepoAppView, '
173 route_name='pullrequest_show_all_data', request_method='GET',
173 route_name='pullrequest_show_all_data', request_method='GET',
174 renderer='json_ext', xhr=True)
174 renderer='json_ext', xhr=True)
175 def pull_request_list_data(self):
175 def pull_request_list_data(self):
176 self.load_default_context()
176
177
177 # additional filters
178 # additional filters
178 req_get = self.request.GET
179 req_get = self.request.GET
@@ -200,29 +201,6 b' class RepoPullRequestsView(RepoAppView, '
200
201
201 return data
202 return data
202
203
203 def _get_pr_version(self, pull_request_id, version=None):
204 at_version = None
205
206 if version and version == 'latest':
207 pull_request_ver = PullRequest.get(pull_request_id)
208 pull_request_obj = pull_request_ver
209 _org_pull_request_obj = pull_request_obj
210 at_version = 'latest'
211 elif version:
212 pull_request_ver = PullRequestVersion.get_or_404(version)
213 pull_request_obj = pull_request_ver
214 _org_pull_request_obj = pull_request_ver.pull_request
215 at_version = pull_request_ver.pull_request_version_id
216 else:
217 _org_pull_request_obj = pull_request_obj = PullRequest.get_or_404(
218 pull_request_id)
219
220 pull_request_display_obj = PullRequest.get_pr_display_object(
221 pull_request_obj, _org_pull_request_obj)
222
223 return _org_pull_request_obj, pull_request_obj, \
224 pull_request_display_obj, at_version
225
226 def _get_diffset(self, source_repo_name, source_repo,
204 def _get_diffset(self, source_repo_name, source_repo,
227 source_ref_id, target_ref_id,
205 source_ref_id, target_ref_id,
228 target_commit, source_commit, diff_limit, fulldiff,
206 target_commit, source_commit, diff_limit, fulldiff,
@@ -277,7 +255,7 b' class RepoPullRequestsView(RepoAppView, '
277 (pull_request_latest,
255 (pull_request_latest,
278 pull_request_at_ver,
256 pull_request_at_ver,
279 pull_request_display_obj,
257 pull_request_display_obj,
280 at_version) = self._get_pr_version(
258 at_version) = PullRequestModel().get_pr_version(
281 pull_request_id, version=version)
259 pull_request_id, version=version)
282 pr_closed = pull_request_latest.is_closed()
260 pr_closed = pull_request_latest.is_closed()
283
261
@@ -299,7 +277,7 b' class RepoPullRequestsView(RepoAppView, '
299 (prev_pull_request_latest,
277 (prev_pull_request_latest,
300 prev_pull_request_at_ver,
278 prev_pull_request_at_ver,
301 prev_pull_request_display_obj,
279 prev_pull_request_display_obj,
302 prev_at_version) = self._get_pr_version(
280 prev_at_version) = PullRequestModel().get_pr_version(
303 pull_request_id, version=from_version)
281 pull_request_id, version=from_version)
304
282
305 c.from_version = prev_at_version
283 c.from_version = prev_at_version
@@ -630,7 +608,8 b' class RepoPullRequestsView(RepoAppView, '
630 try:
608 try:
631 source_repo_data = PullRequestModel().generate_repo_data(
609 source_repo_data = PullRequestModel().generate_repo_data(
632 source_repo, commit_id=commit_id,
610 source_repo, commit_id=commit_id,
633 branch=branch_ref, bookmark=bookmark_ref, translator=self.request.translate)
611 branch=branch_ref, bookmark=bookmark_ref,
612 translator=self.request.translate)
634 except CommitDoesNotExistError as e:
613 except CommitDoesNotExistError as e:
635 log.exception(e)
614 log.exception(e)
636 h.flash(_('Commit does not exist'), 'error')
615 h.flash(_('Commit does not exist'), 'error')
@@ -649,8 +628,9 b' class RepoPullRequestsView(RepoAppView, '
649 default_target_repo, translator=self.request.translate)
628 default_target_repo, translator=self.request.translate)
650
629
651 selected_source_ref = source_repo_data['refs']['selected_ref']
630 selected_source_ref = source_repo_data['refs']['selected_ref']
652
631 title_source_ref = ''
653 title_source_ref = selected_source_ref.split(':', 2)[1]
632 if selected_source_ref:
633 title_source_ref = selected_source_ref.split(':', 2)[1]
654 c.default_title = PullRequestModel().generate_pullrequest_title(
634 c.default_title = PullRequestModel().generate_pullrequest_title(
655 source=source_repo.repo_name,
635 source=source_repo.repo_name,
656 source_ref=title_source_ref,
636 source_ref=title_source_ref,
@@ -675,6 +655,7 b' class RepoPullRequestsView(RepoAppView, '
675 route_name='pullrequest_repo_refs', request_method='GET',
655 route_name='pullrequest_repo_refs', request_method='GET',
676 renderer='json_ext', xhr=True)
656 renderer='json_ext', xhr=True)
677 def pull_request_repo_refs(self):
657 def pull_request_repo_refs(self):
658 self.load_default_context()
678 target_repo_name = self.request.matchdict['target_repo_name']
659 target_repo_name = self.request.matchdict['target_repo_name']
679 repo = Repository.get_by_repo_name(target_repo_name)
660 repo = Repository.get_by_repo_name(target_repo_name)
680 if not repo:
661 if not repo:
@@ -752,16 +733,19 b' class RepoPullRequestsView(RepoAppView, '
752 def pull_request_create(self):
733 def pull_request_create(self):
753 _ = self.request.translate
734 _ = self.request.translate
754 self.assure_not_empty_repo()
735 self.assure_not_empty_repo()
736 self.load_default_context()
755
737
756 controls = peppercorn.parse(self.request.POST.items())
738 controls = peppercorn.parse(self.request.POST.items())
757
739
758 try:
740 try:
759 _form = PullRequestForm(self.db_repo.repo_id)().to_python(controls)
741 form = PullRequestForm(
742 self.request.translate, self.db_repo.repo_id)()
743 _form = form.to_python(controls)
760 except formencode.Invalid as errors:
744 except formencode.Invalid as errors:
761 if errors.error_dict.get('revisions'):
745 if errors.error_dict.get('revisions'):
762 msg = 'Revisions: %s' % errors.error_dict['revisions']
746 msg = 'Revisions: %s' % errors.error_dict['revisions']
763 elif errors.error_dict.get('pullrequest_title'):
747 elif errors.error_dict.get('pullrequest_title'):
764 msg = _('Pull request requires a title with min. 3 chars')
748 msg = errors.error_dict.get('pullrequest_title')
765 else:
749 else:
766 msg = _('Error creating pull request: {}').format(errors)
750 msg = _('Error creating pull request: {}').format(errors)
767 log.exception(msg)
751 log.exception(msg)
@@ -882,6 +866,15 b' class RepoPullRequestsView(RepoAppView, '
882 def pull_request_update(self):
866 def pull_request_update(self):
883 pull_request = PullRequest.get_or_404(
867 pull_request = PullRequest.get_or_404(
884 self.request.matchdict['pull_request_id'])
868 self.request.matchdict['pull_request_id'])
869 _ = self.request.translate
870
871 self.load_default_context()
872
873 if pull_request.is_closed():
874 log.debug('update: forbidden because pull request is closed')
875 msg = _(u'Cannot update closed pull requests.')
876 h.flash(msg, category='error')
877 return True
885
878
886 # only owner or admin can update it
879 # only owner or admin can update it
887 allowed_to_update = PullRequestModel().check_user_update(
880 allowed_to_update = PullRequestModel().check_user_update(
@@ -981,6 +974,7 b' class RepoPullRequestsView(RepoAppView, '
981 pull_request = PullRequest.get_or_404(
974 pull_request = PullRequest.get_or_404(
982 self.request.matchdict['pull_request_id'])
975 self.request.matchdict['pull_request_id'])
983
976
977 self.load_default_context()
984 check = MergeCheck.validate(pull_request, self._rhodecode_db_user,
978 check = MergeCheck.validate(pull_request, self._rhodecode_db_user,
985 translator=self.request.translate)
979 translator=self.request.translate)
986 merge_possible = not check.failed
980 merge_possible = not check.failed
@@ -1053,6 +1047,7 b' class RepoPullRequestsView(RepoAppView, '
1053
1047
1054 pull_request = PullRequest.get_or_404(
1048 pull_request = PullRequest.get_or_404(
1055 self.request.matchdict['pull_request_id'])
1049 self.request.matchdict['pull_request_id'])
1050 self.load_default_context()
1056
1051
1057 pr_closed = pull_request.is_closed()
1052 pr_closed = pull_request.is_closed()
1058 allowed_to_delete = PullRequestModel().check_user_delete(
1053 allowed_to_delete = PullRequestModel().check_user_delete(
@@ -1166,6 +1161,10 b' class RepoPullRequestsView(RepoAppView, '
1166 )
1161 )
1167
1162
1168 Session().flush()
1163 Session().flush()
1164 # this is somehow required to get access to some relationship
1165 # loaded on comment
1166 Session().refresh(comment)
1167
1169 events.trigger(
1168 events.trigger(
1170 events.PullRequestCommentEvent(pull_request, comment))
1169 events.PullRequestCommentEvent(pull_request, comment))
1171
1170
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -32,8 +32,6 b' log = logging.getLogger(__name__)'
32 class RepoReviewRulesView(RepoAppView):
32 class RepoReviewRulesView(RepoAppView):
33 def load_default_context(self):
33 def load_default_context(self):
34 c = self._get_local_tmpl_context()
34 c = self._get_local_tmpl_context()
35
36 self._register_global_c(c)
37 return c
35 return c
38
36
39 @LoginRequired()
37 @LoginRequired()
@@ -54,6 +52,7 b' class RepoReviewRulesView(RepoAppView):'
54 route_name='repo_default_reviewers_data', request_method='GET',
52 route_name='repo_default_reviewers_data', request_method='GET',
55 renderer='json_ext')
53 renderer='json_ext')
56 def repo_default_reviewers_data(self):
54 def repo_default_reviewers_data(self):
55 self.load_default_context()
57 review_data = get_default_reviewers_data(
56 review_data = get_default_reviewers_data(
58 self.db_repo.user, None, None, None, None)
57 self.db_repo.user, None, None, None, None)
59 return review_data
58 return review_data
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -62,16 +62,17 b' class RepoSettingsView(RepoAppView):'
62 # we might be in missing requirement state, so we load things
62 # we might be in missing requirement state, so we load things
63 # without touching scm_instance()
63 # without touching scm_instance()
64 c.landing_revs_choices, c.landing_revs = \
64 c.landing_revs_choices, c.landing_revs = \
65 ScmModel().get_repo_landing_revs()
65 ScmModel().get_repo_landing_revs(self.request.translate)
66 else:
66 else:
67 c.landing_revs_choices, c.landing_revs = \
67 c.landing_revs_choices, c.landing_revs = \
68 ScmModel().get_repo_landing_revs(self.db_repo)
68 ScmModel().get_repo_landing_revs(
69 self.request.translate, self.db_repo)
69
70
70 c.personal_repo_group = c.auth_user.personal_repo_group
71 c.personal_repo_group = c.auth_user.personal_repo_group
71 c.repo_fields = RepositoryField.query()\
72 c.repo_fields = RepositoryField.query()\
72 .filter(RepositoryField.repository == self.db_repo).all()
73 .filter(RepositoryField.repository == self.db_repo).all()
73
74
74 self._register_global_c(c)
75
75 return c
76 return c
76
77
77 def _get_schema(self, c, old_values=None):
78 def _get_schema(self, c, old_values=None):
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -44,7 +44,7 b' class RepoSettingsView(RepoAppView):'
44 def load_default_context(self):
44 def load_default_context(self):
45 c = self._get_local_tmpl_context()
45 c = self._get_local_tmpl_context()
46
46
47 self._register_global_c(c)
47
48 return c
48 return c
49
49
50 @LoginRequired()
50 @LoginRequired()
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -43,7 +43,7 b' class RepoSettingsFieldsView(RepoAppView'
43 def load_default_context(self):
43 def load_default_context(self):
44 c = self._get_local_tmpl_context()
44 c = self._get_local_tmpl_context()
45
45
46 self._register_global_c(c)
46
47 return c
47 return c
48
48
49 @LoginRequired()
49 @LoginRequired()
@@ -70,7 +70,8 b' class RepoSettingsFieldsView(RepoAppView'
70 _ = self.request.translate
70 _ = self.request.translate
71
71
72 try:
72 try:
73 form_result = RepoFieldForm()().to_python(dict(self.request.POST))
73 form = RepoFieldForm(self.request.translate)()
74 form_result = form.to_python(dict(self.request.POST))
74 RepoModel().add_repo_field(
75 RepoModel().add_repo_field(
75 self.db_repo_name,
76 self.db_repo_name,
76 form_result['new_field_key'],
77 form_result['new_field_key'],
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -22,6 +22,7 b' import logging'
22
22
23 from pyramid.httpexceptions import HTTPFound
23 from pyramid.httpexceptions import HTTPFound
24 from pyramid.view import view_config
24 from pyramid.view import view_config
25 import formencode
25
26
26 from rhodecode.apps._base import RepoAppView
27 from rhodecode.apps._base import RepoAppView
27 from rhodecode.lib import audit_logger
28 from rhodecode.lib import audit_logger
@@ -39,7 +40,7 b' class RepoSettingsIssueTrackersView(Repo'
39 def load_default_context(self):
40 def load_default_context(self):
40 c = self._get_local_tmpl_context()
41 c = self._get_local_tmpl_context()
41
42
42 self._register_global_c(c)
43
43 return c
44 return c
44
45
45 @LoginRequired()
46 @LoginRequired()
@@ -116,7 +117,17 b' class RepoSettingsIssueTrackersView(Repo'
116 repo_settings.inherit_global_settings = inherited
117 repo_settings.inherit_global_settings = inherited
117 Session().commit()
118 Session().commit()
118
119
119 form = IssueTrackerPatternsForm()().to_python(self.request.POST)
120 try:
121 form = IssueTrackerPatternsForm(self.request.translate)().to_python(self.request.POST)
122 except formencode.Invalid as errors:
123 log.exception('Failed to add new pattern')
124 error = errors
125 h.flash(_('Invalid issue tracker pattern: {}'.format(error)),
126 category='error')
127 raise HTTPFound(
128 h.route_path('edit_repo_issuetracker',
129 repo_name=self.db_repo_name))
130
120 if form:
131 if form:
121 self._update_patterns(form, repo_settings)
132 self._update_patterns(form, repo_settings)
122
133
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -36,7 +36,7 b' class RepoSettingsRemoteView(RepoAppView'
36 def load_default_context(self):
36 def load_default_context(self):
37 c = self._get_local_tmpl_context()
37 c = self._get_local_tmpl_context()
38
38
39 self._register_global_c(c)
39
40 return c
40 return c
41
41
42 @LoginRequired()
42 @LoginRequired()
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -43,7 +43,7 b' class RepoSettingsVcsView(RepoAppView):'
43 def load_default_context(self):
43 def load_default_context(self):
44 c = self._get_local_tmpl_context()
44 c = self._get_local_tmpl_context()
45
45
46 self._register_global_c(c)
46
47 return c
47 return c
48
48
49 def _vcs_form_defaults(self, repo_name):
49 def _vcs_form_defaults(self, repo_name):
@@ -117,7 +117,7 b' class RepoSettingsVcsView(RepoAppView):'
117 defaults = self._vcs_form_defaults(self.db_repo_name)
117 defaults = self._vcs_form_defaults(self.db_repo_name)
118 c.inherit_global_settings = defaults['inherit_global_settings']
118 c.inherit_global_settings = defaults['inherit_global_settings']
119
119
120 application_form = RepoVcsSettingsForm(self.db_repo_name)()
120 application_form = RepoVcsSettingsForm(self.request.translate, self.db_repo_name)()
121 try:
121 try:
122 form_result = application_form.to_python(dict(self.request.POST))
122 form_result = application_form.to_python(dict(self.request.POST))
123 except formencode.Invalid as errors:
123 except formencode.Invalid as errors:
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -35,7 +35,7 b' class StripView(RepoAppView):'
35 def load_default_context(self):
35 def load_default_context(self):
36 c = self._get_local_tmpl_context()
36 c = self._get_local_tmpl_context()
37
37
38 self._register_global_c(c)
38
39 return c
39 return c
40
40
41 @LoginRequired()
41 @LoginRequired()
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -48,12 +48,9 b' class RepoSummaryView(RepoAppView):'
48
48
49 def load_default_context(self):
49 def load_default_context(self):
50 c = self._get_local_tmpl_context(include_app_defaults=True)
50 c = self._get_local_tmpl_context(include_app_defaults=True)
51
52 c.rhodecode_repo = None
51 c.rhodecode_repo = None
53 if not c.repository_requirements_missing:
52 if not c.repository_requirements_missing:
54 c.rhodecode_repo = self.rhodecode_vcs_repo
53 c.rhodecode_repo = self.rhodecode_vcs_repo
55
56 self._register_global_c(c)
57 return c
54 return c
58
55
59 def _get_readme_data(self, db_repo, default_renderer):
56 def _get_readme_data(self, db_repo, default_renderer):
@@ -174,18 +171,22 b' class RepoSummaryView(RepoAppView):'
174 if self._rhodecode_user.username != User.DEFAULT_USER:
171 if self._rhodecode_user.username != User.DEFAULT_USER:
175 username = safe_str(self._rhodecode_user.username)
172 username = safe_str(self._rhodecode_user.username)
176
173
177 _def_clone_uri = _def_clone_uri_by_id = c.clone_uri_tmpl
174 _def_clone_uri = _def_clone_uri_id = c.clone_uri_tmpl
175 _def_clone_uri_ssh = c.clone_uri_ssh_tmpl
176
178 if '{repo}' in _def_clone_uri:
177 if '{repo}' in _def_clone_uri:
179 _def_clone_uri_by_id = _def_clone_uri.replace(
178 _def_clone_uri_id = _def_clone_uri.replace(
180 '{repo}', '_{repoid}')
179 '{repo}', '_{repoid}')
181 elif '{repoid}' in _def_clone_uri:
180 elif '{repoid}' in _def_clone_uri:
182 _def_clone_uri_by_id = _def_clone_uri.replace(
181 _def_clone_uri_id = _def_clone_uri.replace(
183 '_{repoid}', '{repo}')
182 '_{repoid}', '{repo}')
184
183
185 c.clone_repo_url = self.db_repo.clone_url(
184 c.clone_repo_url = self.db_repo.clone_url(
186 user=username, uri_tmpl=_def_clone_uri)
185 user=username, uri_tmpl=_def_clone_uri)
187 c.clone_repo_url_id = self.db_repo.clone_url(
186 c.clone_repo_url_id = self.db_repo.clone_url(
188 user=username, uri_tmpl=_def_clone_uri_by_id)
187 user=username, uri_tmpl=_def_clone_uri_id)
188 c.clone_repo_url_ssh = self.db_repo.clone_url(
189 uri_tmpl=_def_clone_uri_ssh, ssh=True)
189
190
190 # If enabled, get statistics data
191 # If enabled, get statistics data
191
192
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -25,7 +25,7 b' import pytest'
25 from whoosh import query
25 from whoosh import query
26
26
27 from rhodecode.tests import (
27 from rhodecode.tests import (
28 TestController, SkipTest, HG_REPO,
28 TestController, HG_REPO,
29 TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
29 TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
30 from rhodecode.tests.utils import AssertResponse
30 from rhodecode.tests.utils import AssertResponse
31
31
@@ -51,7 +51,7 b' class TestSearchController(TestControlle'
51
51
52 def test_search_files_empty_search(self):
52 def test_search_files_empty_search(self):
53 if os.path.isdir(self.index_location):
53 if os.path.isdir(self.index_location):
54 raise SkipTest('skipped due to existing index')
54 pytest.skip('skipped due to existing index')
55 else:
55 else:
56 self.log_user()
56 self.log_user()
57 response = self.app.get(route_path('search'),
57 response = self.app.get(route_path('search'),
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -103,7 +103,7 b' def search(request, tmpl_context, repo_n'
103 class SearchView(BaseAppView):
103 class SearchView(BaseAppView):
104 def load_default_context(self):
104 def load_default_context(self):
105 c = self._get_local_tmpl_context()
105 c = self._get_local_tmpl_context()
106 self._register_global_c(c)
106
107 return c
107 return c
108
108
109 @LoginRequired()
109 @LoginRequired()
@@ -119,7 +119,7 b' class SearchView(BaseAppView):'
119 class SearchRepoView(RepoAppView):
119 class SearchRepoView(RepoAppView):
120 def load_default_context(self):
120 def load_default_context(self):
121 c = self._get_local_tmpl_context()
121 c = self._get_local_tmpl_context()
122 self._register_global_c(c)
122
123 return c
123 return c
124
124
125 @LoginRequired()
125 @LoginRequired()
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,4 +1,4 b''
1 # Copyright (C) 2016-2017 RhodeCode GmbH
1 # Copyright (C) 2016-2018 RhodeCode GmbH
2 #
2 #
3 # This program is free software: you can redistribute it and/or modify
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
4 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -22,7 +22,7 b' import os'
22 import re
22 import re
23 import logging
23 import logging
24 import datetime
24 import datetime
25 import ConfigParser
25 from pyramid.compat import configparser
26
26
27 from rhodecode.model.db import Session, User, UserSshKeys
27 from rhodecode.model.db import Session, User, UserSshKeys
28 from rhodecode.model.scm import ScmModel
28 from rhodecode.model.scm import ScmModel
@@ -51,7 +51,7 b' class SshWrapper(object):'
51 self.server_impl = None
51 self.server_impl = None
52
52
53 def parse_config(self, config_path):
53 def parse_config(self, config_path):
54 parser = ConfigParser.ConfigParser()
54 parser = configparser.ConfigParser()
55 parser.read(config_path)
55 parser.read(config_path)
56 return parser
56 return parser
57
57
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -93,6 +93,7 b' class VcsServer(object):'
93 scm_data = {
93 scm_data = {
94 'ip': os.environ['SSH_CLIENT'].split()[0],
94 'ip': os.environ['SSH_CLIENT'].split()[0],
95 'username': self.user.username,
95 'username': self.user.username,
96 'user_id': self.user.user_id,
96 'action': action,
97 'action': action,
97 'repository': self.repo_name,
98 'repository': self.repo_name,
98 'scm': self.backend,
99 'scm': self.backend,
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -20,7 +20,7 b''
20
20
21 import os
21 import os
22 import pytest
22 import pytest
23 import ConfigParser
23 from pyramid.compat import configparser
24
24
25 from rhodecode.apps.ssh_support.lib.ssh_wrapper import SshWrapper
25 from rhodecode.apps.ssh_support.lib.ssh_wrapper import SshWrapper
26 from rhodecode.lib.utils2 import AttributeDict
26 from rhodecode.lib.utils2 import AttributeDict
@@ -28,7 +28,7 b' from rhodecode.lib.utils2 import Attribu'
28
28
29 @pytest.fixture
29 @pytest.fixture
30 def dummy_conf_file(tmpdir):
30 def dummy_conf_file(tmpdir):
31 conf = ConfigParser.ConfigParser()
31 conf = configparser.ConfigParser()
32 conf.add_section('app:main')
32 conf.add_section('app:main')
33 conf.set('app:main', 'ssh.executable.hg', '/usr/bin/hg')
33 conf.set('app:main', 'ssh.executable.hg', '/usr/bin/hg')
34 conf.set('app:main', 'ssh.executable.git', '/usr/bin/git')
34 conf.set('app:main', 'ssh.executable.git', '/usr/bin/git')
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -127,6 +127,7 b' class TestGitServer(object):'
127
127
128 expected_data = {
128 expected_data = {
129 'username': git_server.user.username,
129 'username': git_server.user.username,
130 'user_id': git_server.user.user_id,
130 'scm': 'git',
131 'scm': 'git',
131 'repository': git_server.repo_name,
132 'repository': git_server.repo_name,
132 'make_lock': None,
133 'make_lock': None,
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,4 +1,4 b''
1 # Copyright (C) 2016-2017 RhodeCode GmbH
1 # Copyright (C) 2016-2018 RhodeCode GmbH
2 #
2 #
3 # This program is free software: you can redistribute it and/or modify
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
4 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -23,19 +23,14 b' import os'
23 import mock
23 import mock
24 import pytest
24 import pytest
25
25
26 from pyramid import testing
27
28 from rhodecode.apps.svn_support import utils
26 from rhodecode.apps.svn_support import utils
29
27
30
28
29 @pytest.mark.usefixtures('config_stub')
31 class TestModDavSvnConfig(object):
30 class TestModDavSvnConfig(object):
32
31
33 @classmethod
32 @classmethod
34 def setup_class(cls):
33 def setup_class(cls):
35 # Make mako renderer available in tests.
36 config = testing.setUp()
37 config.include('pyramid_mako')
38
39 cls.location_root = u'/location/root/çµäö'
34 cls.location_root = u'/location/root/çµäö'
40 cls.parent_path_root = u'/parent/path/çµäö'
35 cls.parent_path_root = u'/parent/path/çµäö'
41 cls.realm = u'Dummy Realm (äöüçµ)'
36 cls.realm = u'Dummy Realm (äöüçµ)'
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -20,7 +20,7 b''
20
20
21
21
22 from rhodecode.apps.admin.navigation import NavigationRegistry
22 from rhodecode.apps.admin.navigation import NavigationRegistry
23 from rhodecode.config.routing import ADMIN_PREFIX
23 from rhodecode.apps._base import ADMIN_PREFIX
24 from rhodecode.lib.utils2 import str2bool
24 from rhodecode.lib.utils2 import str2bool
25
25
26
26
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -40,8 +40,7 b' from rhodecode.lib.auth import ('
40 LoginRequired, HasUserGroupPermissionAnyDecorator, CSRFRequired)
40 LoginRequired, HasUserGroupPermissionAnyDecorator, CSRFRequired)
41 from rhodecode.lib import helpers as h, audit_logger
41 from rhodecode.lib import helpers as h, audit_logger
42 from rhodecode.lib.utils2 import str2bool
42 from rhodecode.lib.utils2 import str2bool
43 from rhodecode.model.db import (
43 from rhodecode.model.db import User
44 joinedload, User, UserGroupRepoToPerm, UserGroupRepoGroupToPerm)
45 from rhodecode.model.meta import Session
44 from rhodecode.model.meta import Session
46 from rhodecode.model.user_group import UserGroupModel
45 from rhodecode.model.user_group import UserGroupModel
47
46
@@ -56,35 +55,8 b' class UserGroupsView(UserGroupAppView):'
56 PermissionModel().set_global_permission_choices(
55 PermissionModel().set_global_permission_choices(
57 c, gettext_translator=self.request.translate)
56 c, gettext_translator=self.request.translate)
58
57
59 self._register_global_c(c)
60 return c
58 return c
61
59
62 def _get_perms_summary(self, user_group_id):
63 permissions = {
64 'repositories': {},
65 'repositories_groups': {},
66 }
67 ugroup_repo_perms = UserGroupRepoToPerm.query()\
68 .options(joinedload(UserGroupRepoToPerm.permission))\
69 .options(joinedload(UserGroupRepoToPerm.repository))\
70 .filter(UserGroupRepoToPerm.users_group_id == user_group_id)\
71 .all()
72
73 for gr in ugroup_repo_perms:
74 permissions['repositories'][gr.repository.repo_name] \
75 = gr.permission.permission_name
76
77 ugroup_group_perms = UserGroupRepoGroupToPerm.query()\
78 .options(joinedload(UserGroupRepoGroupToPerm.permission))\
79 .options(joinedload(UserGroupRepoGroupToPerm.group))\
80 .filter(UserGroupRepoGroupToPerm.users_group_id == user_group_id)\
81 .all()
82
83 for gr in ugroup_group_perms:
84 permissions['repositories_groups'][gr.group.group_name] \
85 = gr.permission.permission_name
86 return permissions
87
88 @LoginRequired()
60 @LoginRequired()
89 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
61 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
90 @view_config(
62 @view_config(
@@ -94,6 +66,7 b' class UserGroupsView(UserGroupAppView):'
94 """
66 """
95 Return members of given user group
67 Return members of given user group
96 """
68 """
69 self.load_default_context()
97 user_group = self.db_user_group
70 user_group = self.db_user_group
98 group_members_obj = sorted((x.user for x in user_group.members),
71 group_members_obj = sorted((x.user for x in user_group.members),
99 key=lambda u: u.username.lower())
72 key=lambda u: u.username.lower())
@@ -126,7 +99,8 b' class UserGroupsView(UserGroupAppView):'
126 c = self.load_default_context()
99 c = self.load_default_context()
127 c.user_group = self.db_user_group
100 c.user_group = self.db_user_group
128 c.active = 'perms_summary'
101 c.active = 'perms_summary'
129 c.permissions = self._get_perms_summary(c.user_group.users_group_id)
102 c.permissions = UserGroupModel().get_perms_summary(
103 c.user_group.users_group_id)
130 return self._get_template_context(c)
104 return self._get_template_context(c)
131
105
132 @LoginRequired()
106 @LoginRequired()
@@ -137,7 +111,7 b' class UserGroupsView(UserGroupAppView):'
137 def user_group_perms_summary_json(self):
111 def user_group_perms_summary_json(self):
138 self.load_default_context()
112 self.load_default_context()
139 user_group = self.db_user_group
113 user_group = self.db_user_group
140 return self._get_perms_summary(user_group.users_group_id)
114 return UserGroupModel().get_perms_summary(user_group.users_group_id)
141
115
142 def _revoke_perms_on_yourself(self, form_result):
116 def _revoke_perms_on_yourself(self, form_result):
143 _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
117 _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
@@ -173,7 +147,8 b' class UserGroupsView(UserGroupAppView):'
173 c.active = 'settings'
147 c.active = 'settings'
174
148
175 users_group_form = UserGroupForm(
149 users_group_form = UserGroupForm(
176 edit=True, old_data=c.user_group.get_dict(), allow_disabled=True)()
150 self.request.translate, edit=True,
151 old_data=c.user_group.get_dict(), allow_disabled=True)()
177
152
178 old_values = c.user_group.get_api_data()
153 old_values = c.user_group.get_api_data()
179 user_group_name = self.request.POST.get('users_group_name')
154 user_group_name = self.request.POST.get('users_group_name')
@@ -346,7 +321,7 b' class UserGroupsView(UserGroupAppView):'
346 user_group_id = user_group.users_group_id
321 user_group_id = user_group.users_group_id
347 c = self.load_default_context()
322 c = self.load_default_context()
348 c.user_group = user_group
323 c.user_group = user_group
349 form = UserGroupPermsForm()().to_python(self.request.POST)
324 form = UserGroupPermsForm(self.request.translate)().to_python(self.request.POST)
350
325
351 if not self._rhodecode_user.is_admin:
326 if not self._rhodecode_user.is_admin:
352 if self._revoke_perms_on_yourself(form):
327 if self._revoke_perms_on_yourself(form):
@@ -426,7 +401,7 b' class UserGroupsView(UserGroupAppView):'
426
401
427 try:
402 try:
428 # first stage that verifies the checkbox
403 # first stage that verifies the checkbox
429 _form = UserIndividualPermissionsForm()
404 _form = UserIndividualPermissionsForm(self.request.translate)
430 form_result = _form.to_python(dict(self.request.POST))
405 form_result = _form.to_python(dict(self.request.POST))
431 inherit_perms = form_result['inherit_default_permissions']
406 inherit_perms = form_result['inherit_default_permissions']
432 user_group.inherit_default_permissions = inherit_perms
407 user_group.inherit_default_permissions = inherit_perms
@@ -435,6 +410,7 b' class UserGroupsView(UserGroupAppView):'
435 if not inherit_perms:
410 if not inherit_perms:
436 # only update the individual ones if we un check the flag
411 # only update the individual ones if we un check the flag
437 _form = UserPermissionsForm(
412 _form = UserPermissionsForm(
413 self.request.translate,
438 [x[0] for x in c.repo_create_choices],
414 [x[0] for x in c.repo_create_choices],
439 [x[0] for x in c.repo_create_on_write_choices],
415 [x[0] for x in c.repo_create_on_write_choices],
440 [x[0] for x in c.repo_group_create_choices],
416 [x[0] for x in c.repo_group_create_choices],
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -27,7 +27,7 b' from pyramid.authentication import Sessi'
27 from rhodecode.authentication.registry import AuthenticationPluginRegistry
27 from rhodecode.authentication.registry import AuthenticationPluginRegistry
28 from rhodecode.authentication.routes import root_factory
28 from rhodecode.authentication.routes import root_factory
29 from rhodecode.authentication.routes import AuthnRootResource
29 from rhodecode.authentication.routes import AuthnRootResource
30 from rhodecode.config.routing import ADMIN_PREFIX
30 from rhodecode.apps._base import ADMIN_PREFIX
31 from rhodecode.model.settings import SettingsModel
31 from rhodecode.model.settings import SettingsModel
32
32
33
33
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -77,7 +77,6 b' class hybrid_property(object):'
77 self.fdel(instance)
77 self.fdel(instance)
78
78
79
79
80
81 class LazyFormencode(object):
80 class LazyFormencode(object):
82 def __init__(self, formencode_obj, *args, **kwargs):
81 def __init__(self, formencode_obj, *args, **kwargs):
83 self.formencode_obj = formencode_obj
82 self.formencode_obj = formencode_obj
@@ -106,6 +105,8 b' class RhodeCodeAuthPluginBase(object):'
106 "lastname": "last name",
105 "lastname": "last name",
107 "email": "email address",
106 "email": "email address",
108 "groups": '["list", "of", "groups"]',
107 "groups": '["list", "of", "groups"]',
108 "user_group_sync":
109 'True|False defines if returned user groups should be synced',
109 "extern_name": "name in external source of record",
110 "extern_name": "name in external source of record",
110 "extern_type": "type of external source of record",
111 "extern_type": "type of external source of record",
111 "admin": 'True|False defines if user should be RhodeCode super admin',
112 "admin": 'True|False defines if user should be RhodeCode super admin',
@@ -114,6 +115,7 b' class RhodeCodeAuthPluginBase(object):'
114 "active_from_extern":
115 "active_from_extern":
115 "True|False\None, active state from the external auth, "
116 "True|False\None, active state from the external auth, "
116 "None means use definition from RhodeCode extern_type active value"
117 "None means use definition from RhodeCode extern_type active value"
118
117 }
119 }
118 # set on authenticate() method and via set_auth_type func.
120 # set on authenticate() method and via set_auth_type func.
119 auth_type = None
121 auth_type = None
@@ -252,29 +254,6 b' class RhodeCodeAuthPluginBase(object):'
252 del settings_copy[k]
254 del settings_copy[k]
253 return settings_copy
255 return settings_copy
254
256
255 @property
256 def validators(self):
257 """
258 Exposes RhodeCode validators modules
259 """
260 # this is a hack to overcome issues with pylons threadlocals and
261 # translator object _() not being registered properly.
262 class LazyCaller(object):
263 def __init__(self, name):
264 self.validator_name = name
265
266 def __call__(self, *args, **kwargs):
267 from rhodecode.model import validators as v
268 obj = getattr(v, self.validator_name)
269 # log.debug('Initializing lazy formencode object: %s', obj)
270 return LazyFormencode(obj, *args, **kwargs)
271
272 class ProxyGet(object):
273 def __getattribute__(self, name):
274 return LazyCaller(name)
275
276 return ProxyGet()
277
278 @hybrid_property
257 @hybrid_property
279 def name(self):
258 def name(self):
280 """
259 """
@@ -435,8 +414,9 b' class RhodeCodeAuthPluginBase(object):'
435 new_hash = auth.get('_hash_migrate')
414 new_hash = auth.get('_hash_migrate')
436 if new_hash:
415 if new_hash:
437 self._migrate_hash_to_bcrypt(username, passwd, new_hash)
416 self._migrate_hash_to_bcrypt(username, passwd, new_hash)
417 if 'user_group_sync' not in auth:
418 auth['user_group_sync'] = False
438 return self._validate_auth_return(auth)
419 return self._validate_auth_return(auth)
439
440 return auth
420 return auth
441
421
442 def _migrate_hash_to_bcrypt(self, username, password, new_hash):
422 def _migrate_hash_to_bcrypt(self, username, password, new_hash):
@@ -561,16 +541,19 b' class RhodeCodeExternalAuthPlugin(RhodeC'
561 # enforce user is just in given groups, all of them has to be ones
541 # enforce user is just in given groups, all of them has to be ones
562 # created from plugins. We store this info in _group_data JSON
542 # created from plugins. We store this info in _group_data JSON
563 # field
543 # field
564 try:
544
565 groups = auth['groups'] or []
545 if auth['user_group_sync']:
566 log.debug(
546 try:
567 'Performing user_group sync based on set `%s` '
547 groups = auth['groups'] or []
568 'returned by this plugin', groups)
548 log.debug(
569 UserGroupModel().enforce_groups(user, groups, self.name)
549 'Performing user_group sync based on set `%s` '
570 except Exception:
550 'returned by `%s` plugin', groups, self.name)
571 # for any reason group syncing fails, we should
551 UserGroupModel().enforce_groups(user, groups, self.name)
572 # proceed with login
552 except Exception:
573 log.error(traceback.format_exc())
553 # for any reason group syncing fails, we should
554 # proceed with login
555 log.error(traceback.format_exc())
556
574 Session().commit()
557 Session().commit()
575 return auth
558 return auth
576
559
@@ -694,7 +677,7 b' def authenticate(username, password, env'
694 environ=environ or {})
677 environ=environ or {})
695
678
696 if plugin_cache_active:
679 if plugin_cache_active:
697 log.debug('Trying to fetch cached auth by %s', _password_hash[:6])
680 log.debug('Trying to fetch cached auth by `...%s`', _password_hash[:6])
698 plugin_user = cache_manager.get(
681 plugin_user = cache_manager.get(
699 _password_hash, createfunc=auth_func)
682 _password_hash, createfunc=auth_func)
700 else:
683 else:
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -267,6 +267,7 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
267 'firstname': crowd_user["first-name"] or firstname,
267 'firstname': crowd_user["first-name"] or firstname,
268 'lastname': crowd_user["last-name"] or lastname,
268 'lastname': crowd_user["last-name"] or lastname,
269 'groups': crowd_user["groups"],
269 'groups': crowd_user["groups"],
270 'user_group_sync': True,
270 'email': crowd_user["email"] or email,
271 'email': crowd_user["email"] or email,
271 'admin': admin,
272 'admin': admin,
272 'active': active,
273 'active': active,
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -212,6 +212,7 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
212 'firstname': safe_unicode(firstname or username),
212 'firstname': safe_unicode(firstname or username),
213 'lastname': safe_unicode(lastname or ''),
213 'lastname': safe_unicode(lastname or ''),
214 'groups': [],
214 'groups': [],
215 'user_group_sync': False,
215 'email': email or '',
216 'email': email or '',
216 'admin': admin or False,
217 'admin': admin or False,
217 'active': active,
218 'active': active,
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -154,6 +154,7 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
154 'firstname': safe_unicode(firstname or username),
154 'firstname': safe_unicode(firstname or username),
155 'lastname': safe_unicode(lastname or ''),
155 'lastname': safe_unicode(lastname or ''),
156 'groups': [],
156 'groups': [],
157 'user_group_sync': False,
157 'email': email or '',
158 'email': email or '',
158 'admin': admin or False,
159 'admin': admin or False,
159 'active': active,
160 'active': active,
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -460,6 +460,7 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
460 'lastname': safe_unicode(
460 'lastname': safe_unicode(
461 get_ldap_attr('attr_lastname') or lastname),
461 get_ldap_attr('attr_lastname') or lastname),
462 'groups': groups,
462 'groups': groups,
463 'user_group_sync': False,
463 'email': get_ldap_attr('attr_email') or email,
464 'email': get_ldap_attr('attr_email') or email,
464 'admin': admin,
465 'admin': admin,
465 'active': active,
466 'active': active,
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -136,6 +136,7 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
136 'lastname': lastname,
136 'lastname': lastname,
137 'groups': [g.gr_name for g in grp.getgrall()
137 'groups': [g.gr_name for g in grp.getgrall()
138 if username in g.gr_mem],
138 if username in g.gr_mem],
139 'user_group_sync': True,
139 'email': email,
140 'email': email,
140 'admin': admin,
141 'admin': admin,
141 'active': active,
142 'active': active,
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -100,6 +100,7 b' class RhodeCodeAuthPlugin(RhodeCodeAuthP'
100 "firstname": userobj.firstname,
100 "firstname": userobj.firstname,
101 "lastname": userobj.lastname,
101 "lastname": userobj.lastname,
102 "groups": [],
102 "groups": [],
103 'user_group_sync': False,
103 "email": userobj.email,
104 "email": userobj.email,
104 "admin": userobj.admin,
105 "admin": userobj.admin,
105 "active": userobj.active,
106 "active": userobj.active,
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -111,6 +111,7 b' class RhodeCodeAuthPlugin(RhodeCodeAuthP'
111 "firstname": userobj.firstname,
111 "firstname": userobj.firstname,
112 "lastname": userobj.lastname,
112 "lastname": userobj.lastname,
113 "groups": [],
113 "groups": [],
114 'user_group_sync': False,
114 "email": userobj.email,
115 "email": userobj.email,
115 "admin": userobj.admin,
116 "admin": userobj.admin,
116 "active": userobj.active,
117 "active": userobj.active,
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -22,7 +22,7 b''
22 import pytest
22 import pytest
23
23
24
24
25 class EnabledAuthPlugin():
25 class EnabledAuthPlugin(object):
26 """
26 """
27 Context manager that updates the 'auth_plugins' setting in DB to enable
27 Context manager that updates the 'auth_plugins' setting in DB to enable
28 a plugin. Previous setting is restored on exit. The rhodecode auth plugin
28 a plugin. Previous setting is restored on exit. The rhodecode auth plugin
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -23,7 +23,7 b' import pytest'
23
23
24 from rhodecode.authentication.tests.conftest import (
24 from rhodecode.authentication.tests.conftest import (
25 EnabledAuthPlugin, DisabledAuthPlugin)
25 EnabledAuthPlugin, DisabledAuthPlugin)
26 from rhodecode.config.routing import ADMIN_PREFIX
26 from rhodecode.apps._base import ADMIN_PREFIX
27
27
28
28
29 @pytest.mark.usefixtures('autologin_user', 'app')
29 @pytest.mark.usefixtures('autologin_user', 'app')
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -26,25 +26,25 b' from pyramid.httpexceptions import HTTPF'
26 from pyramid.renderers import render
26 from pyramid.renderers import render
27 from pyramid.response import Response
27 from pyramid.response import Response
28
28
29 from rhodecode.apps._base import BaseAppView
29 from rhodecode.authentication.base import (
30 from rhodecode.authentication.base import (
30 get_auth_cache_manager, get_perms_cache_manager, get_authn_registry)
31 get_auth_cache_manager, get_perms_cache_manager, get_authn_registry)
31 from rhodecode.lib import auth
32 from rhodecode.lib import helpers as h
32 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
33 from rhodecode.lib.auth import (
34 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
33 from rhodecode.model.forms import AuthSettingsForm
35 from rhodecode.model.forms import AuthSettingsForm
34 from rhodecode.model.meta import Session
36 from rhodecode.model.meta import Session
35 from rhodecode.model.settings import SettingsModel
37 from rhodecode.model.settings import SettingsModel
36 from rhodecode.translation import _
37
38
38 log = logging.getLogger(__name__)
39 log = logging.getLogger(__name__)
39
40
40
41
41 class AuthnPluginViewBase(object):
42 class AuthnPluginViewBase(BaseAppView):
42
43
43 def __init__(self, context, request):
44 def load_default_context(self):
44 self.request = request
45 c = self._get_local_tmpl_context()
45 self.context = context
46 self.plugin = self.context.plugin
46 self.plugin = context.plugin
47 return c
47 self._rhodecode_user = request.user
48
48
49 @LoginRequired()
49 @LoginRequired()
50 @HasPermissionAllDecorator('hg.admin')
50 @HasPermissionAllDecorator('hg.admin')
@@ -52,6 +52,7 b' class AuthnPluginViewBase(object):'
52 """
52 """
53 View that displays the plugin settings as a form.
53 View that displays the plugin settings as a form.
54 """
54 """
55 c = self.load_default_context()
55 defaults = defaults or {}
56 defaults = defaults or {}
56 errors = errors or {}
57 errors = errors or {}
57 schema = self.plugin.get_settings_schema()
58 schema = self.plugin.get_settings_schema()
@@ -70,15 +71,17 b' class AuthnPluginViewBase(object):'
70 'resource': self.context,
71 'resource': self.context,
71 }
72 }
72
73
73 return template_context
74 return self._get_template_context(c, **template_context)
74
75
75 @LoginRequired()
76 @LoginRequired()
76 @HasPermissionAllDecorator('hg.admin')
77 @HasPermissionAllDecorator('hg.admin')
77 @auth.CSRFRequired()
78 @CSRFRequired()
78 def settings_post(self):
79 def settings_post(self):
79 """
80 """
80 View that validates and stores the plugin settings.
81 View that validates and stores the plugin settings.
81 """
82 """
83 _ = self.request.translate
84 self.load_default_context()
82 schema = self.plugin.get_settings_schema()
85 schema = self.plugin.get_settings_schema()
83 data = self.request.params
86 data = self.request.params
84
87
@@ -86,10 +89,10 b' class AuthnPluginViewBase(object):'
86 valid_data = schema.deserialize(data)
89 valid_data = schema.deserialize(data)
87 except colander.Invalid as e:
90 except colander.Invalid as e:
88 # Display error message and display form again.
91 # Display error message and display form again.
89 self.request.session.flash(
92 h.flash(
90 _('Errors exist when saving plugin settings. '
93 _('Errors exist when saving plugin settings. '
91 'Please check the form inputs.'),
94 'Please check the form inputs.'),
92 queue='error')
95 category='error')
93 defaults = {key: data[key] for key in data if key in schema}
96 defaults = {key: data[key] for key in data if key in schema}
94 return self.settings_get(errors=e.asdict(), defaults=defaults)
97 return self.settings_get(errors=e.asdict(), defaults=defaults)
95
98
@@ -99,31 +102,22 b' class AuthnPluginViewBase(object):'
99 Session().commit()
102 Session().commit()
100
103
101 # Display success message and redirect.
104 # Display success message and redirect.
102 self.request.session.flash(
105 h.flash(_('Auth settings updated successfully.'), category='success')
103 _('Auth settings updated successfully.'),
104 queue='success')
105 redirect_to = self.request.resource_path(
106 redirect_to = self.request.resource_path(
106 self.context, route_name='auth_home')
107 self.context, route_name='auth_home')
107 return HTTPFound(redirect_to)
108 return HTTPFound(redirect_to)
108
109
109
110
110 # TODO: Ongoing migration in these views.
111 class AuthSettingsView(BaseAppView):
111 # - Maybe we should also use a colander schema for these views.
112 def load_default_context(self):
112 class AuthSettingsView(object):
113 c = self._get_local_tmpl_context()
113 def __init__(self, context, request):
114 return c
114 self.context = context
115 self.request = request
116
117 # TODO: Move this into a utility function. It is needed in all view
118 # classes during migration. Maybe a mixin?
119
120 # Some of the decorators rely on this attribute to be present on the
121 # class of the decorated method.
122 self._rhodecode_user = request.user
123
115
124 @LoginRequired()
116 @LoginRequired()
125 @HasPermissionAllDecorator('hg.admin')
117 @HasPermissionAllDecorator('hg.admin')
126 def index(self, defaults=None, errors=None, prefix_error=False):
118 def index(self, defaults=None, errors=None, prefix_error=False):
119 c = self.load_default_context()
120
127 defaults = defaults or {}
121 defaults = defaults or {}
128 authn_registry = get_authn_registry(self.request.registry)
122 authn_registry = get_authn_registry(self.request.registry)
129 enabled_plugins = SettingsModel().get_auth_plugins()
123 enabled_plugins = SettingsModel().get_auth_plugins()
@@ -135,8 +129,8 b' class AuthSettingsView(object):'
135 'enabled_plugins': enabled_plugins,
129 'enabled_plugins': enabled_plugins,
136 }
130 }
137 html = render('rhodecode:templates/admin/auth/auth_settings.mako',
131 html = render('rhodecode:templates/admin/auth/auth_settings.mako',
138 template_context,
132 self._get_template_context(c, **template_context),
139 request=self.request)
133 self.request)
140
134
141 # Create form default values and fill the form.
135 # Create form default values and fill the form.
142 form_defaults = {
136 form_defaults = {
@@ -155,11 +149,12 b' class AuthSettingsView(object):'
155
149
156 @LoginRequired()
150 @LoginRequired()
157 @HasPermissionAllDecorator('hg.admin')
151 @HasPermissionAllDecorator('hg.admin')
158 @auth.CSRFRequired()
152 @CSRFRequired()
159 def auth_settings(self):
153 def auth_settings(self):
154 _ = self.request.translate
160 try:
155 try:
161 form = AuthSettingsForm()()
156 form = AuthSettingsForm(self.request.translate)()
162 form_result = form.to_python(self.request.params)
157 form_result = form.to_python(self.request.POST)
163 plugins = ','.join(form_result['auth_plugins'])
158 plugins = ','.join(form_result['auth_plugins'])
164 setting = SettingsModel().create_or_update_setting(
159 setting = SettingsModel().create_or_update_setting(
165 'auth_plugins', plugins)
160 'auth_plugins', plugins)
@@ -172,24 +167,19 b' class AuthSettingsView(object):'
172 cache_manager = get_perms_cache_manager()
167 cache_manager = get_perms_cache_manager()
173 cache_manager.clear()
168 cache_manager.clear()
174
169
175 self.request.session.flash(
170 h.flash(_('Auth settings updated successfully.'), category='success')
176 _('Auth settings updated successfully.'),
177 queue='success')
178 except formencode.Invalid as errors:
171 except formencode.Invalid as errors:
179 e = errors.error_dict or {}
172 e = errors.error_dict or {}
180 self.request.session.flash(
173 h.flash(_('Errors exist when saving plugin setting. '
181 _('Errors exist when saving plugin setting. '
174 'Please check the form inputs.'), category='error')
182 'Please check the form inputs.'),
183 queue='error')
184 return self.index(
175 return self.index(
185 defaults=errors.value,
176 defaults=errors.value,
186 errors=e,
177 errors=e,
187 prefix_error=False)
178 prefix_error=False)
188 except Exception:
179 except Exception:
189 log.exception('Exception in auth_settings')
180 log.exception('Exception in auth_settings')
190 self.request.session.flash(
181 h.flash(_('Error occurred during update of auth settings.'),
191 _('Error occurred during update of auth settings.'),
182 category='error')
192 queue='error')
193
183
194 redirect_to = self.request.resource_path(
184 redirect_to = self.request.resource_path(
195 self.context, route_name='auth_home')
185 self.context, route_name='auth_home')
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2013-2017 RhodeCode GmbH
3 # Copyright (C) 2013-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -18,121 +18,19 b''
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
22 Pylons environment configuration
23 """
24
21
25 import os
22 import os
26 import logging
23 import logging
27 import rhodecode
24 import rhodecode
28 import platform
29 import re
30 import io
31
32 from mako.lookup import TemplateLookup
33 from pylons.configuration import PylonsConfig
34 from pylons.error import handle_mako_error
35 from pyramid.settings import asbool
36
37 # ------------------------------------------------------------------------------
38 # CELERY magic until refactor - issue #4163 - import order matters here:
39 from rhodecode.lib import celerypylons # this must be first, celerypylons
40 # sets config settings upon import
41
42 import rhodecode.integrations # any modules using celery task
43 # decorators should be added afterwards:
44 # ------------------------------------------------------------------------------
45
46 from rhodecode.lib import app_globals
47 from rhodecode.config import utils
48 from rhodecode.config.routing import make_map
49 from rhodecode.config.jsroutes import generate_jsroutes_content
50
51 from rhodecode.lib import helpers
52 from rhodecode.lib.auth import set_available_permissions
53 from rhodecode.lib.utils import (
54 repo2db_mapper, make_db_config, set_rhodecode_config,
55 load_rcextensions)
56 from rhodecode.lib.utils2 import str2bool, aslist
57 from rhodecode.lib.vcs import connect_vcs, start_vcs_server
58 from rhodecode.model.scm import ScmModel
59
60 log = logging.getLogger(__name__)
61
62 def load_environment(global_conf, app_conf, initial=False,
63 test_env=None, test_index=None):
64 """
65 Configure the Pylons environment via the ``pylons.config``
66 object
67 """
68 config = PylonsConfig()
69
25
70
26
71 # Pylons paths
27 from rhodecode.config import utils
72 root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
73 paths = {
74 'root': root,
75 'controllers': os.path.join(root, 'controllers'),
76 'static_files': os.path.join(root, 'public'),
77 'templates': [os.path.join(root, 'templates')],
78 }
79
80 # Initialize config with the basic options
81 config.init_app(global_conf, app_conf, package='rhodecode', paths=paths)
82
83 # store some globals into rhodecode
84 rhodecode.CELERY_ENABLED = str2bool(config['app_conf'].get('use_celery'))
85 rhodecode.CELERY_EAGER = str2bool(
86 config['app_conf'].get('celery.always.eager'))
87
88 config['routes.map'] = make_map(config)
89
90 config['pylons.app_globals'] = app_globals.Globals(config)
91 config['pylons.h'] = helpers
92 rhodecode.CONFIG = config
93
94 load_rcextensions(root_path=config['here'])
95
96 # Setup cache object as early as possible
97 import pylons
98 pylons.cache._push_object(config['pylons.app_globals'].cache)
99
28
100 # Create the Mako TemplateLookup, with the default auto-escaping
29 from rhodecode.lib.utils import load_rcextensions
101 config['pylons.app_globals'].mako_lookup = TemplateLookup(
30 from rhodecode.lib.utils2 import str2bool
102 directories=paths['templates'],
31 from rhodecode.lib.vcs import connect_vcs
103 error_handler=handle_mako_error,
104 module_directory=os.path.join(app_conf['cache_dir'], 'templates'),
105 input_encoding='utf-8', default_filters=['escape'],
106 imports=['from webhelpers.html import escape'])
107
108 # sets the c attribute access when don't existing attribute are accessed
109 config['pylons.strict_tmpl_context'] = True
110
111 # configure channelstream
112 config['channelstream_config'] = {
113 'enabled': asbool(config.get('channelstream.enabled', False)),
114 'server': config.get('channelstream.server'),
115 'secret': config.get('channelstream.secret')
116 }
117
32
118 db_cfg = make_db_config(clear_session=True)
33 log = logging.getLogger(__name__)
119
120 repos_path = list(db_cfg.items('paths'))[0][1]
121 config['base_path'] = repos_path
122
123 # store db config also in main global CONFIG
124 set_rhodecode_config(config)
125
126 # configure instance id
127 utils.set_instance_id(config)
128
129 # CONFIGURATION OPTIONS HERE (note: all config options will override
130 # any Pylons config options)
131
132 # store config reference into our module to skip import magic of pylons
133 rhodecode.CONFIG.update(config)
134
135 return config
136
34
137
35
138 def load_pyramid_environment(global_config, settings):
36 def load_pyramid_environment(global_config, settings):
@@ -140,10 +38,13 b' def load_pyramid_environment(global_conf'
140 settings_merged = global_config.copy()
38 settings_merged = global_config.copy()
141 settings_merged.update(settings)
39 settings_merged.update(settings)
142
40
143 # Store the settings to make them available to other modules.
41 # TODO(marcink): probably not required anymore
144 rhodecode.PYRAMID_SETTINGS = settings_merged
42 # configure channelstream,
145 # NOTE(marcink): needs to be enabled after full port to pyramid
43 settings_merged['channelstream_config'] = {
146 # rhodecode.CONFIG = config
44 'enabled': str2bool(settings_merged.get('channelstream.enabled', False)),
45 'server': settings_merged.get('channelstream.server'),
46 'secret': settings_merged.get('channelstream.secret')
47 }
147
48
148 # If this is a test run we prepare the test environment like
49 # If this is a test run we prepare the test environment like
149 # creating a test database, test search index and test repositories.
50 # creating a test database, test search index and test repositories.
@@ -157,6 +58,8 b' def load_pyramid_environment(global_conf'
157 # Initialize the database connection.
58 # Initialize the database connection.
158 utils.initialize_database(settings_merged)
59 utils.initialize_database(settings_merged)
159
60
61 load_rcextensions(root_path=settings_merged['here'])
62
160 # Limit backends to `vcs.backends` from configuration
63 # Limit backends to `vcs.backends` from configuration
161 for alias in rhodecode.BACKENDS.keys():
64 for alias in rhodecode.BACKENDS.keys():
162 if alias not in settings['vcs.backends']:
65 if alias not in settings['vcs.backends']:
@@ -166,17 +69,13 b' def load_pyramid_environment(global_conf'
166 # initialize vcs client and optionally run the server if enabled
69 # initialize vcs client and optionally run the server if enabled
167 vcs_server_uri = settings['vcs.server']
70 vcs_server_uri = settings['vcs.server']
168 vcs_server_enabled = settings['vcs.server.enable']
71 vcs_server_enabled = settings['vcs.server.enable']
169 start_server = (
170 settings['vcs.start_server'] and
171 not int(os.environ.get('RC_VCSSERVER_TEST_DISABLE', '0')))
172
173 if vcs_server_enabled and start_server:
174 log.info("Starting vcsserver")
175 start_vcs_server(server_and_port=vcs_server_uri,
176 protocol=utils.get_vcs_server_protocol(settings),
177 log_level=settings['vcs.server.log_level'])
178
72
179 utils.configure_vcs(settings)
73 utils.configure_vcs(settings)
180
74
75 # Store the settings to make them available to other modules.
76
77 rhodecode.PYRAMID_SETTINGS = settings_merged
78 rhodecode.CONFIG = settings_merged
79
181 if vcs_server_enabled:
80 if vcs_server_enabled:
182 connect_vcs(vcs_server_uri, utils.get_vcs_server_protocol(settings))
81 connect_vcs(vcs_server_uri, utils.get_vcs_server_protocol(settings))
@@ -16,7 +16,7 b" RC_HOOK_VER = '_TMPL_'"
16
16
17 def main():
17 def main():
18 if hooks is None:
18 if hooks is None:
19 # exit with success if we cannot import rhodecode.lib.hooks !!
19 # exit with success if we cannot import vcsserver.hooks !!
20 # this allows simply push to this repo even without rhodecode
20 # this allows simply push to this repo even without rhodecode
21 sys.exit(0)
21 sys.exit(0)
22
22
@@ -16,7 +16,7 b" RC_HOOK_VER = '_TMPL_'"
16
16
17 def main():
17 def main():
18 if hooks is None:
18 if hooks is None:
19 # exit with success if we cannot import rhodecode.lib.hooks !!
19 # exit with success if we cannot import vcsserver.hooks !!
20 # this allows simply push to this repo even without rhodecode
20 # this allows simply push to this repo even without rhodecode
21 sys.exit(0)
21 sys.exit(0)
22
22
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -43,10 +43,7 b''
43 },
43 },
44 "python2.7-Pygments-2.2.0": {
44 "python2.7-Pygments-2.2.0": {
45 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
45 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
46 },
46 },
47 "python2.7-Pylons-1.0.2.rhodecode-patch1": {
48 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
49 },
50 "python2.7-Routes-1.13": {
47 "python2.7-Routes-1.13": {
51 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
48 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
52 },
49 },
@@ -77,13 +74,7 b''
77 },
74 },
78 "python2.7-alembic-0.8.4": {
75 "python2.7-alembic-0.8.4": {
79 "MIT License": "http://spdx.org/licenses/MIT"
76 "MIT License": "http://spdx.org/licenses/MIT"
80 },
77 },
81 "python2.7-amqplib-1.0.2": {
82 "GNU Lesser General Public License v3.0 only": "http://spdx.org/licenses/LGPL-3.0"
83 },
84 "python2.7-anyjson-0.3.3": {
85 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
86 },
87 "python2.7-appenlight-client-0.6.14": {
78 "python2.7-appenlight-client-0.6.14": {
88 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
79 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
89 },
80 },
@@ -195,7 +186,7 b''
195 "python2.7-jupyter-core-4.3.0": {
186 "python2.7-jupyter-core-4.3.0": {
196 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
187 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
197 },
188 },
198 "python2.7-kombu-1.5.1": {
189 "python2.7-kombu-4.1.0": {
199 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
190 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
200 },
191 },
201 "python2.7-mistune-0.7.4": {
192 "python2.7-mistune-0.7.4": {
@@ -327,7 +318,7 b''
327 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0",
318 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0",
328 "Zope Public License 2.0": "http://spdx.org/licenses/ZPL-2.0"
319 "Zope Public License 2.0": "http://spdx.org/licenses/ZPL-2.0"
329 },
320 },
330 "python2.7-setuptools-scm-1.15.0": {
321 "python2.7-setuptools-scm-1.15.6": {
331 "MIT License": "http://spdx.org/licenses/MIT"
322 "MIT License": "http://spdx.org/licenses/MIT"
332 },
323 },
333 "python2.7-simplegeneric-0.8.1": {
324 "python2.7-simplegeneric-0.8.1": {
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -18,41 +18,31 b''
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
22 Pylons middleware initialization
23 """
24 import logging
21 import logging
25 import traceback
22 import traceback
26 from collections import OrderedDict
23 import collections
27
24
28 from paste.registry import RegistryManager
29 from paste.gzipper import make_gzip_middleware
25 from paste.gzipper import make_gzip_middleware
30 from pylons.wsgiapp import PylonsApp
26 from pyramid.wsgi import wsgiapp
31 from pyramid.authorization import ACLAuthorizationPolicy
27 from pyramid.authorization import ACLAuthorizationPolicy
32 from pyramid.config import Configurator
28 from pyramid.config import Configurator
33 from pyramid.settings import asbool, aslist
29 from pyramid.settings import asbool, aslist
34 from pyramid.wsgi import wsgiapp
35 from pyramid.httpexceptions import (
30 from pyramid.httpexceptions import (
36 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound)
31 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound, HTTPNotFound)
37 from pyramid.events import ApplicationCreated
32 from pyramid.events import ApplicationCreated
38 from pyramid.renderers import render_to_response
33 from pyramid.renderers import render_to_response
39 from routes.middleware import RoutesMiddleware
40 import rhodecode
41
34
42 from rhodecode.model import meta
35 from rhodecode.model import meta
43 from rhodecode.config import patches
36 from rhodecode.config import patches
44 from rhodecode.config import utils as config_utils
37 from rhodecode.config import utils as config_utils
45 from rhodecode.config.routing import STATIC_FILE_PREFIX
38 from rhodecode.config.environment import load_pyramid_environment
46 from rhodecode.config.environment import (
47 load_environment, load_pyramid_environment)
48
39
40 from rhodecode.lib.middleware.vcs import VCSMiddleware
49 from rhodecode.lib.vcs import VCSCommunicationError
41 from rhodecode.lib.vcs import VCSCommunicationError
50 from rhodecode.lib.exceptions import VCSServerUnavailable
42 from rhodecode.lib.exceptions import VCSServerUnavailable
51 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
43 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
52 from rhodecode.lib.middleware.error_handling import (
53 PylonsErrorHandlingMiddleware)
54 from rhodecode.lib.middleware.https_fixup import HttpsFixup
44 from rhodecode.lib.middleware.https_fixup import HttpsFixup
55 from rhodecode.lib.middleware.vcs import VCSMiddleware
45 from rhodecode.lib.celerylib.loader import configure_celery
56 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
46 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
57 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
47 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
58 from rhodecode.subscribers import (
48 from rhodecode.subscribers import (
@@ -63,157 +53,67 b' from rhodecode.subscribers import ('
63 log = logging.getLogger(__name__)
53 log = logging.getLogger(__name__)
64
54
65
55
66 # this is used to avoid avoid the route lookup overhead in routesmiddleware
56 def is_http_error(response):
67 # for certain routes which won't go to pylons to - eg. static files, debugger
57 # error which should have traceback
68 # it is only needed for the pylons migration and can be removed once complete
58 return response.status_code > 499
69 class SkippableRoutesMiddleware(RoutesMiddleware):
70 """ Routes middleware that allows you to skip prefixes """
71
72 def __init__(self, *args, **kw):
73 self.skip_prefixes = kw.pop('skip_prefixes', [])
74 super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
75
76 def __call__(self, environ, start_response):
77 for prefix in self.skip_prefixes:
78 if environ['PATH_INFO'].startswith(prefix):
79 # added to avoid the case when a missing /_static route falls
80 # through to pylons and causes an exception as pylons is
81 # expecting wsgiorg.routingargs to be set in the environ
82 # by RoutesMiddleware.
83 if 'wsgiorg.routing_args' not in environ:
84 environ['wsgiorg.routing_args'] = (None, {})
85 return self.app(environ, start_response)
86
87 return super(SkippableRoutesMiddleware, self).__call__(
88 environ, start_response)
89
90
91 def make_app(global_conf, static_files=True, **app_conf):
92 """Create a Pylons WSGI application and return it
93
94 ``global_conf``
95 The inherited configuration for this application. Normally from
96 the [DEFAULT] section of the Paste ini file.
97
98 ``app_conf``
99 The application's local configuration. Normally specified in
100 the [app:<name>] section of the Paste ini file (where <name>
101 defaults to main).
102
103 """
104 # Apply compatibility patches
105 patches.kombu_1_5_1_python_2_7_11()
106 patches.inspect_getargspec()
107
108 # Configure the Pylons environment
109 config = load_environment(global_conf, app_conf)
110
111 # The Pylons WSGI app
112 app = PylonsApp(config=config)
113
114 # Establish the Registry for this application
115 app = RegistryManager(app)
116
117 app.config = config
118
119 return app
120
59
121
60
122 def make_pyramid_app(global_config, **settings):
61 def make_pyramid_app(global_config, **settings):
123 """
62 """
124 Constructs the WSGI application based on Pyramid and wraps the Pylons based
63 Constructs the WSGI application based on Pyramid.
125 application.
126
64
127 Specials:
65 Specials:
128
66
129 * We migrate from Pylons to Pyramid. While doing this, we keep both
130 frameworks functional. This involves moving some WSGI middlewares around
131 and providing access to some data internals, so that the old code is
132 still functional.
133
134 * The application can also be integrated like a plugin via the call to
67 * The application can also be integrated like a plugin via the call to
135 `includeme`. This is accompanied with the other utility functions which
68 `includeme`. This is accompanied with the other utility functions which
136 are called. Changing this should be done with great care to not break
69 are called. Changing this should be done with great care to not break
137 cases when these fragments are assembled from another place.
70 cases when these fragments are assembled from another place.
138
71
139 """
72 """
140 # The edition string should be available in pylons too, so we add it here
141 # before copying the settings.
142 settings.setdefault('rhodecode.edition', 'Community Edition')
143
144 # As long as our Pylons application does expect "unprepared" settings, make
145 # sure that we keep an unmodified copy. This avoids unintentional change of
146 # behavior in the old application.
147 settings_pylons = settings.copy()
148
149 sanitize_settings_and_apply_defaults(settings)
73 sanitize_settings_and_apply_defaults(settings)
150
74
151 config = Configurator(settings=settings)
75 config = Configurator(settings=settings)
76
77 # Apply compatibility patches
78 patches.inspect_getargspec()
79
152 load_pyramid_environment(global_config, settings)
80 load_pyramid_environment(global_config, settings)
153
81
154 add_pylons_compat_data(config.registry, global_config, settings_pylons)
82 # Static file view comes first
83 includeme_first(config)
155
84
156 includeme_first(config)
157 includeme(config)
85 includeme(config)
158
86
159 pyramid_app = config.make_wsgi_app()
87 pyramid_app = config.make_wsgi_app()
160 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
88 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
161 pyramid_app.config = config
89 pyramid_app.config = config
162
90
91 config.configure_celery(global_config['__file__'])
163 # creating the app uses a connection - return it after we are done
92 # creating the app uses a connection - return it after we are done
164 meta.Session.remove()
93 meta.Session.remove()
165
94
95 log.info('Pyramid app %s created and configured.', pyramid_app)
166 return pyramid_app
96 return pyramid_app
167
97
168
98
169 def make_not_found_view(config):
99 def not_found_view(request):
170 """
100 """
171 This creates the view which should be registered as not-found-view to
101 This creates the view which should be registered as not-found-view to
172 pyramid. Basically it contains of the old pylons app, converted to a view.
102 pyramid.
173 Additionally it is wrapped by some other middlewares.
174 """
103 """
175 settings = config.registry.settings
176 vcs_server_enabled = settings['vcs.server.enable']
177
104
178 # Make pylons app from unprepared settings.
105 if not getattr(request, 'vcs_call', None):
179 pylons_app = make_app(
106 # handle like regular case with our error_handler
180 config.registry._pylons_compat_global_config,
107 return error_handler(HTTPNotFound(), request)
181 **config.registry._pylons_compat_settings)
182 config.registry._pylons_compat_config = pylons_app.config
183
184 # Appenlight monitoring.
185 pylons_app, appenlight_client = wrap_in_appenlight_if_enabled(
186 pylons_app, settings)
187
108
188 # The pylons app is executed inside of the pyramid 404 exception handler.
109 # handle not found view as a vcs call
189 # Exceptions which are raised inside of it are not handled by pyramid
110 settings = request.registry.settings
190 # again. Therefore we add a middleware that invokes the error handler in
111 ae_client = getattr(request, 'ae_client', None)
191 # case of an exception or error response. This way we return proper error
112 vcs_app = VCSMiddleware(
192 # HTML pages in case of an error.
113 HTTPNotFound(), request.registry, settings,
193 reraise = (settings.get('debugtoolbar.enabled', False) or
114 appenlight_client=ae_client)
194 rhodecode.disable_error_handler)
195 pylons_app = PylonsErrorHandlingMiddleware(
196 pylons_app, error_handler, reraise)
197
115
198 # The VCSMiddleware shall operate like a fallback if pyramid doesn't find a
116 return wsgiapp(vcs_app)(None, request)
199 # view to handle the request. Therefore it is wrapped around the pylons
200 # app. It has to be outside of the error handling otherwise error responses
201 # from the vcsserver are converted to HTML error pages. This confuses the
202 # command line tools and the user won't get a meaningful error message.
203 if vcs_server_enabled:
204 pylons_app = VCSMiddleware(
205 pylons_app, settings, appenlight_client, registry=config.registry)
206
207 # Convert WSGI app to pyramid view and return it.
208 return wsgiapp(pylons_app)
209
210
211 def add_pylons_compat_data(registry, global_config, settings):
212 """
213 Attach data to the registry to support the Pylons integration.
214 """
215 registry._pylons_compat_global_config = global_config
216 registry._pylons_compat_settings = settings
217
117
218
118
219 def error_handler(exception, request):
119 def error_handler(exception, request):
@@ -229,10 +129,6 b' def error_handler(exception, request):'
229 elif isinstance(exception, VCSCommunicationError):
129 elif isinstance(exception, VCSCommunicationError):
230 base_response = VCSServerUnavailable()
130 base_response = VCSServerUnavailable()
231
131
232 def is_http_error(response):
233 # error which should have traceback
234 return response.status_code > 499
235
236 if is_http_error(base_response):
132 if is_http_error(base_response):
237 log.exception(
133 log.exception(
238 'error occurred handling this request for path: %s', request.path)
134 'error occurred handling this request for path: %s', request.path)
@@ -272,26 +168,46 b' def error_handler(exception, request):'
272 return response
168 return response
273
169
274
170
171 def includeme_first(config):
172 # redirect automatic browser favicon.ico requests to correct place
173 def favicon_redirect(context, request):
174 return HTTPFound(
175 request.static_path('rhodecode:public/images/favicon.ico'))
176
177 config.add_view(favicon_redirect, route_name='favicon')
178 config.add_route('favicon', '/favicon.ico')
179
180 def robots_redirect(context, request):
181 return HTTPFound(
182 request.static_path('rhodecode:public/robots.txt'))
183
184 config.add_view(robots_redirect, route_name='robots')
185 config.add_route('robots', '/robots.txt')
186
187 config.add_static_view(
188 '_static/deform', 'deform:static')
189 config.add_static_view(
190 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
191
192
275 def includeme(config):
193 def includeme(config):
276 settings = config.registry.settings
194 settings = config.registry.settings
277
195
278 # plugin information
196 # plugin information
279 config.registry.rhodecode_plugins = OrderedDict()
197 config.registry.rhodecode_plugins = collections.OrderedDict()
280
198
281 config.add_directive(
199 config.add_directive(
282 'register_rhodecode_plugin', register_rhodecode_plugin)
200 'register_rhodecode_plugin', register_rhodecode_plugin)
283
201
202 config.add_directive('configure_celery', configure_celery)
203
284 if asbool(settings.get('appenlight', 'false')):
204 if asbool(settings.get('appenlight', 'false')):
285 config.include('appenlight_client.ext.pyramid_tween')
205 config.include('appenlight_client.ext.pyramid_tween')
286
206
287 if 'mako.default_filters' not in settings:
288 # set custom default filters if we don't have it defined
289 settings['mako.imports'] = 'from rhodecode.lib.base import h_filter'
290 settings['mako.default_filters'] = 'h_filter'
291
292 # Includes which are required. The application would fail without them.
207 # Includes which are required. The application would fail without them.
293 config.include('pyramid_mako')
208 config.include('pyramid_mako')
294 config.include('pyramid_beaker')
209 config.include('pyramid_beaker')
210 config.include('rhodecode.lib.caches')
295
211
296 config.include('rhodecode.authentication')
212 config.include('rhodecode.authentication')
297 config.include('rhodecode.integrations')
213 config.include('rhodecode.integrations')
@@ -331,16 +247,17 b' def includeme(config):'
331 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
247 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
332 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
248 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
333
249
334 config.add_request_method(
335 'rhodecode.lib.partial_renderer.get_partial_renderer',
336 'get_partial_renderer')
337
338 # events
250 # events
339 # TODO(marcink): this should be done when pyramid migration is finished
251 # TODO(marcink): this should be done when pyramid migration is finished
340 # config.add_subscriber(
252 # config.add_subscriber(
341 # 'rhodecode.integrations.integrations_event_handler',
253 # 'rhodecode.integrations.integrations_event_handler',
342 # 'rhodecode.events.RhodecodeEvent')
254 # 'rhodecode.events.RhodecodeEvent')
343
255
256 # request custom methods
257 config.add_request_method(
258 'rhodecode.lib.partial_renderer.get_partial_renderer',
259 'get_partial_renderer')
260
344 # Set the authorization policy.
261 # Set the authorization policy.
345 authz_policy = ACLAuthorizationPolicy()
262 authz_policy = ACLAuthorizationPolicy()
346 config.set_authorization_policy(authz_policy)
263 config.set_authorization_policy(authz_policy)
@@ -357,65 +274,29 b' def includeme(config):'
357 for inc in includes:
274 for inc in includes:
358 config.include(inc)
275 config.include(inc)
359
276
360 # This is the glue which allows us to migrate in chunks. By registering the
277 # custom not found view, if our pyramid app doesn't know how to handle
361 # pylons based application as the "Not Found" view in Pyramid, we will
278 # the request pass it to potential VCS handling ap
362 # fallback to the old application each time the new one does not yet know
279 config.add_notfound_view(not_found_view)
363 # how to handle a request.
364 config.add_notfound_view(make_not_found_view(config))
365
366 if not settings.get('debugtoolbar.enabled', False):
280 if not settings.get('debugtoolbar.enabled', False):
367 # disabled debugtoolbar handle all exceptions via the error_handlers
281 # disabled debugtoolbar handle all exceptions via the error_handlers
368 config.add_view(error_handler, context=Exception)
282 config.add_view(error_handler, context=Exception)
369
283
284 # all errors including 403/404/50X
370 config.add_view(error_handler, context=HTTPError)
285 config.add_view(error_handler, context=HTTPError)
371
286
372
287
373 def includeme_first(config):
374 # redirect automatic browser favicon.ico requests to correct place
375 def favicon_redirect(context, request):
376 return HTTPFound(
377 request.static_path('rhodecode:public/images/favicon.ico'))
378
379 config.add_view(favicon_redirect, route_name='favicon')
380 config.add_route('favicon', '/favicon.ico')
381
382 def robots_redirect(context, request):
383 return HTTPFound(
384 request.static_path('rhodecode:public/robots.txt'))
385
386 config.add_view(robots_redirect, route_name='robots')
387 config.add_route('robots', '/robots.txt')
388
389 config.add_static_view(
390 '_static/deform', 'deform:static')
391 config.add_static_view(
392 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
393
394
395 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
288 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
396 """
289 """
397 Apply outer WSGI middlewares around the application.
290 Apply outer WSGI middlewares around the application.
398
399 Part of this has been moved up from the Pylons layer, so that the
400 data is also available if old Pylons code is hit through an already ported
401 view.
402 """
291 """
403 settings = config.registry.settings
292 settings = config.registry.settings
404
293
405 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
294 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
406 pyramid_app = HttpsFixup(pyramid_app, settings)
295 pyramid_app = HttpsFixup(pyramid_app, settings)
407
296
408 # Add RoutesMiddleware to support the pylons compatibility tween during
297 pyramid_app, _ae_client = wrap_in_appenlight_if_enabled(
409 # migration to pyramid.
298 pyramid_app, settings)
410
299 config.registry.ae_client = _ae_client
411 # TODO(marcink): remove after migration to pyramid
412 if hasattr(config.registry, '_pylons_compat_config'):
413 routes_map = config.registry._pylons_compat_config['routes.map']
414 pyramid_app = SkippableRoutesMiddleware(
415 pyramid_app, routes_map,
416 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
417
418 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
419
300
420 if settings['gzip_responses']:
301 if settings['gzip_responses']:
421 pyramid_app = make_gzip_middleware(
302 pyramid_app = make_gzip_middleware(
@@ -452,16 +333,21 b' def sanitize_settings_and_apply_defaults'
452 function.
333 function.
453 """
334 """
454
335
455 # Pyramid's mako renderer has to search in the templates folder so that the
336 settings.setdefault('rhodecode.edition', 'Community Edition')
456 # old templates still work. Ported and new templates are expected to use
337
457 # real asset specifications for the includes.
338 if 'mako.default_filters' not in settings:
458 mako_directories = settings.setdefault('mako.directories', [
339 # set custom default filters if we don't have it defined
459 # Base templates of the original Pylons application
340 settings['mako.imports'] = 'from rhodecode.lib.base import h_filter'
460 'rhodecode:templates',
341 settings['mako.default_filters'] = 'h_filter'
461 ])
342
462 log.debug(
343 if 'mako.directories' not in settings:
463 "Using the following Mako template directories: %s",
344 mako_directories = settings.setdefault('mako.directories', [
464 mako_directories)
345 # Base templates of the original application
346 'rhodecode:templates',
347 ])
348 log.debug(
349 "Using the following Mako template directories: %s",
350 mako_directories)
465
351
466 # Default includes, possible to change as a user
352 # Default includes, possible to change as a user
467 pyramid_includes = settings.setdefault('pyramid.includes', [
353 pyramid_includes = settings.setdefault('pyramid.includes', [
@@ -526,10 +412,10 b' def _int_setting(settings, name, default'
526
412
527
413
528 def _bool_setting(settings, name, default):
414 def _bool_setting(settings, name, default):
529 input = settings.get(name, default)
415 input_val = settings.get(name, default)
530 if isinstance(input, unicode):
416 if isinstance(input_val, unicode):
531 input = input.encode('utf8')
417 input_val = input_val.encode('utf8')
532 settings[name] = asbool(input)
418 settings[name] = asbool(input_val)
533
419
534
420
535 def _list_setting(settings, name, default):
421 def _list_setting(settings, name, default):
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -32,26 +32,10 b' Please keep the following principles in '
32 """
32 """
33
33
34
34
35 def kombu_1_5_1_python_2_7_11():
36 """
37 Kombu 1.5.1 relies on a private method which got removed in Python 2.7.11.
38
39 This patch adds the symbol to the module :mod:`uuid` and assigns the value
40 ``None`` to it. This causes kombu to fall back to the public API of
41 :mod:`uuid`.
42
43 This patch can most probably be removed once celery and kombu are updated
44 to more recent versions.
45 """
46 import uuid
47
48 if not hasattr(uuid, '_uuid_generate_random'):
49 uuid._uuid_generate_random = None
50
51
35
52 def inspect_getargspec():
36 def inspect_getargspec():
53 """
37 """
54 Pyramid and Pylons rely on inspect.getargspec to lookup the signature of
38 Pyramid rely on inspect.getargspec to lookup the signature of
55 view functions. This is not compatible with cython, therefore we replace
39 view functions. This is not compatible with cython, therefore we replace
56 getargspec with a custom version.
40 getargspec with a custom version.
57 Code is inspired by the inspect module from Python-3.4
41 Code is inspired by the inspect module from Python-3.4
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/lib/paster_commands/setup_rhodecode.py to rhodecode/lib/paster_commands/deprecated/setup_rhodecode.py
NO CONTENT: file renamed from rhodecode/lib/paster_commands/setup_rhodecode.py to rhodecode/lib/paster_commands/deprecated/setup_rhodecode.py
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/tests/other/vcs_operations/__init__.py to rhodecode/tests/vcs_operations/__init__.py
NO CONTENT: file renamed from rhodecode/tests/other/vcs_operations/__init__.py to rhodecode/tests/vcs_operations/__init__.py
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/tests/other/vcs_operations/conftest.py to rhodecode/tests/vcs_operations/conftest.py
NO CONTENT: file renamed from rhodecode/tests/other/vcs_operations/conftest.py to rhodecode/tests/vcs_operations/conftest.py
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/tests/other/vcs_operations/test_vcs_calls_custom_auth_code_403.py to rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_403.py
NO CONTENT: file renamed from rhodecode/tests/other/vcs_operations/test_vcs_calls_custom_auth_code_403.py to rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_403.py
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/tests/other/vcs_operations/test_vcs_calls_custom_auth_code_404.py to rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_404.py
NO CONTENT: file renamed from rhodecode/tests/other/vcs_operations/test_vcs_calls_custom_auth_code_404.py to rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_404.py
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/tests/other/vcs_operations/test_vcs_calls_custom_auth_code_bad_code.py to rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_bad_code.py
NO CONTENT: file renamed from rhodecode/tests/other/vcs_operations/test_vcs_calls_custom_auth_code_bad_code.py to rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_bad_code.py
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/tests/other/vcs_operations/test_vcs_operations.py to rhodecode/tests/vcs_operations/test_vcs_operations.py
NO CONTENT: file renamed from rhodecode/tests/other/vcs_operations/test_vcs_operations.py to rhodecode/tests/vcs_operations/test_vcs_operations.py
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/tests/other/vcs_operations/test_vcs_operations_locking.py to rhodecode/tests/vcs_operations/test_vcs_operations_locking.py
NO CONTENT: file renamed from rhodecode/tests/other/vcs_operations/test_vcs_operations_locking.py to rhodecode/tests/vcs_operations/test_vcs_operations_locking.py
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/tests/other/vcs_operations/test_vcs_operations_locking_custom_code.py to rhodecode/tests/vcs_operations/test_vcs_operations_locking_custom_code.py
NO CONTENT: file renamed from rhodecode/tests/other/vcs_operations/test_vcs_operations_locking_custom_code.py to rhodecode/tests/vcs_operations/test_vcs_operations_locking_custom_code.py
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now