##// 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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 1 [bumpversion]
2 current_version = 4.10.6
2 current_version = 4.11.0
3 3 message = release: Bump version {current_version} to {new_version}
4 4
5 5 [bumpversion:file:rhodecode/VERSION]
@@ -3,15 +3,11 b''
3 3 branch = True
4 4
5 5 include =
6 rhodecode/lib/*
7 rhodecode/model/*
8 rhodecode/controllers/*
6 rhodecode/*
9 7
10 8 omit =
11 rhodecode/lib/vcs/remote/*
12 9 rhodecode/lib/dbmigrate/*
13 10 rhodecode/lib/paster_commands/*
14 rhodecode/tests/*
15 11
16 12 [report]
17 13
@@ -21,7 +21,7 b' syntax: regexp'
21 21 ^\.rhodecode$
22 22
23 23 ^rcextensions
24 ^_dev
24 ^.dev
25 25 ^._dev
26 26 ^build/
27 27 ^bower_components/
@@ -5,25 +5,20 b' done = false'
5 5 done = true
6 6
7 7 [task:rc_tools_pinned]
8 done = true
9 8
10 9 [task:fixes_on_stable]
11 done = true
12 10
13 11 [task:pip2nix_generated]
14 done = true
15 12
16 13 [task:changelog_updated]
17 done = true
18 14
19 15 [task:generate_api_docs]
20 done = true
16
17 [task:updated_translation]
21 18
22 19 [release]
23 state = prepared
24 version = 4.10.6
25
26 [task:updated_translation]
20 state = in_progress
21 version = 4.11.0
27 22
28 23 [task:generate_js_routes]
29 24
@@ -79,7 +79,7 b' asyncore_use_poll = true'
79 79 #proc_name = rhodecode
80 80 ## type of worker class, one of sync, gevent
81 81 ## recommended for bigger setup is using of of other than sync one
82 #worker_class = sync
82 #worker_class = gevent
83 83 ## The maximum number of simultaneous clients. Valid only for Gevent
84 84 #worker_connections = 10
85 85 ## max number of requests that worker will handle before being gracefully
@@ -295,29 +295,21 b' labs_settings_active = true'
295 295 ####################################
296 296 ### CELERY CONFIG ####
297 297 ####################################
298 use_celery = false
299 broker.host = localhost
300 broker.vhost = rabbitmqhost
301 broker.port = 5672
302 broker.user = rabbitmq
303 broker.password = qweqwe
304
305 celery.imports = rhodecode.lib.celerylib.tasks
298 ## run: /path/to/celery worker \
299 ## -E --beat --app rhodecode.lib.celerylib.loader \
300 ## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \
301 ## --loglevel DEBUG --ini /path/to/rhodecode.ini
306 302
307 celery.result.backend = amqp
308 celery.result.dburi = amqp://
309 celery.result.serialier = json
303 use_celery = false
310 304
311 #celery.send.task.error.emails = true
312 #celery.amqp.task.result.expires = 18000
305 ## connection url to the message broker (default rabbitmq)
306 celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost
313 307
314 celeryd.concurrency = 2
315 #celeryd.log.file = celeryd.log
316 celeryd.log.level = debug
317 celeryd.max.tasks.per.child = 1
308 ## maximum tasks to execute before worker restart
309 celery.max_tasks_per_child = 100
318 310
319 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 315 ### BEAKER CACHE ####
@@ -567,7 +559,7 b' vcs.hooks.protocol = http'
567 559
568 560 vcs.server.log_level = debug
569 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 564 ## List of enabled VCS backends, available options are:
573 565 ## `hg` - mercurial
@@ -649,7 +641,7 b' custom.conf = 1'
649 641 ### LOGGING CONFIGURATION ####
650 642 ################################
651 643 [loggers]
652 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper
644 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper, celery
653 645
654 646 [handlers]
655 647 keys = console, console_sql
@@ -688,6 +680,11 b' handlers ='
688 680 qualname = ssh_wrapper
689 681 propagate = 1
690 682
683 [logger_celery]
684 level = DEBUG
685 handlers =
686 qualname = celery
687
691 688
692 689 ##############
693 690 ## HANDLERS ##
@@ -28,9 +28,30 b" accesslog = '-'"
28 28 loglevel = 'debug'
29 29
30 30 # SECURITY
31
32 # The maximum size of HTTP request line in bytes.
31 33 limit_request_line = 4094
32 limit_request_fields = 100
33 limit_request_field_size = 8190
34
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 56 # SERVER MECHANICS
36 57 # None == system temp dir
@@ -57,10 +78,18 b' def pre_exec(server):'
57 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 85 def when_ready(server):
61 86 server.log.info("Server is ready. Spawning workers")
62 87
63 88
89 def on_reload(server):
90 pass
91
92
64 93 def worker_int(worker):
65 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 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 121 def pre_request(worker, req):
85 122 return
86 123 worker.log.debug("[<%-10s>] PRE WORKER: %s %s",
@@ -93,6 +130,7 b' def post_request(worker, req, environ, r'
93 130 req.method, req.path, resp.status_code)
94 131
95 132
133
96 134 class RhodeCodeLogger(Logger):
97 135 """
98 136 Custom Logger that allows some customization that gunicorn doesn't allow
@@ -79,7 +79,7 b' workers = 2'
79 79 proc_name = rhodecode
80 80 ## type of worker class, one of sync, gevent
81 81 ## recommended for bigger setup is using of of other than sync one
82 worker_class = sync
82 worker_class = gevent
83 83 ## The maximum number of simultaneous clients. Valid only for Gevent
84 84 #worker_connections = 10
85 85 ## max number of requests that worker will handle before being gracefully
@@ -270,29 +270,21 b' labs_settings_active = true'
270 270 ####################################
271 271 ### CELERY CONFIG ####
272 272 ####################################
273 use_celery = false
274 broker.host = localhost
275 broker.vhost = rabbitmqhost
276 broker.port = 5672
277 broker.user = rabbitmq
278 broker.password = qweqwe
279
280 celery.imports = rhodecode.lib.celerylib.tasks
273 ## run: /path/to/celery worker \
274 ## -E --beat --app rhodecode.lib.celerylib.loader \
275 ## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \
276 ## --loglevel DEBUG --ini /path/to/rhodecode.ini
281 277
282 celery.result.backend = amqp
283 celery.result.dburi = amqp://
284 celery.result.serialier = json
278 use_celery = false
285 279
286 #celery.send.task.error.emails = true
287 #celery.amqp.task.result.expires = 18000
280 ## connection url to the message broker (default rabbitmq)
281 celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost
288 282
289 celeryd.concurrency = 2
290 #celeryd.log.file = celeryd.log
291 celeryd.log.level = debug
292 celeryd.max.tasks.per.child = 1
283 ## maximum tasks to execute before worker restart
284 celery.max_tasks_per_child = 100
293 285
294 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 290 ### BEAKER CACHE ####
@@ -619,7 +611,7 b' custom.conf = 1'
619 611 ### LOGGING CONFIGURATION ####
620 612 ################################
621 613 [loggers]
622 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper
614 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper, celery
623 615
624 616 [handlers]
625 617 keys = console, console_sql
@@ -658,6 +650,11 b' handlers ='
658 650 qualname = ssh_wrapper
659 651 propagate = 1
660 652
653 [logger_celery]
654 level = DEBUG
655 handlers =
656 qualname = celery
657
661 658
662 659 ##############
663 660 ## HANDLERS ##
@@ -185,6 +185,7 b' let'
185 185 ln -s ${self.supervisor}/bin/supervisor* $out/bin/
186 186 ln -s ${self.PasteScript}/bin/paster $out/bin/
187 187 ln -s ${self.channelstream}/bin/channelstream $out/bin/
188 ln -s ${self.celery}/bin/celery $out/bin/
188 189
189 190 # rhodecode-tools
190 191 ln -s ${self.rhodecode-tools}/bin/rhodecode-* $out/bin/
@@ -70,7 +70,7 b' backup location:'
70 70 $ mysql -u <uname> -p <pass> rhodecode_db_name < mysql-db-backup
71 71
72 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 74 # PosgreSQL restore
75 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 47 ### LOGGING CONFIGURATION ####
48 48 ################################
49 49 [loggers]
50 keys = root, routes, rhodecode, sqlalchemy, beaker, templates
50 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper
51 51
52 52 [handlers]
53 53 keys = console, console_sql, file, file_rotating
@@ -75,12 +75,6 b' the ``debug`` level.'
75 75 qualname = beaker.container
76 76 propagate = 1
77 77
78 [logger_templates]
79 level = INFO
80 handlers =
81 qualname = pylons.templating
82 propagate = 1
83
84 78 [logger_rhodecode]
85 79 level = DEBUG
86 80 handlers =
@@ -9,7 +9,7 b' timeout during large pushes.'
9 9 .. code-block:: nginx
10 10
11 11 proxy_redirect off;
12 proxy_set_header Host $host;
12 proxy_set_header Host $http_host;
13 13
14 14 ## needed for container auth
15 15 # proxy_set_header REMOTE_USER $remote_user;
@@ -13,3 +13,4 b' instances are configured in as secure a '
13 13 sec-x-frame
14 14 sec-instance-basics
15 15 sec-ip-white
16 sec-sophos-umc
@@ -38,13 +38,13 b' changeset_comment'
38 38
39 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 45 "result" : {
46 46 "msg": "Commented on commit `<revision>` for repository `<repoid>`",
47 "status_change": null or "<status>",
47 "status_change": null or <status>,
48 48 "success": true
49 49 },
50 50 "error" : null
@@ -6,7 +6,7 b' pull_request methods'
6 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 11 Close the pull request specified by `pullrequestid`.
12 12
@@ -39,7 +39,7 b' close_pull_request'
39 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 44 Comment on the pull request specified with the `pullrequestid`,
45 45 in the |repo| specified by the `repoid`, and optionally change the
@@ -47,7 +47,7 b' comment_pull_request'
47 47
48 48 :param apiuser: This is filled automatically from the |authtoken|.
49 49 :type apiuser: AuthUser
50 :param repoid: The repository name or repository ID.
50 :param repoid: Optional repository name or repository ID.
51 51 :type repoid: str or int
52 52 :param pullrequestid: The pull request ID.
53 53 :type pullrequestid: int
@@ -120,14 +120,14 b' create_pull_request'
120 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 125 Get a pull request based on the given ID.
126 126
127 127 :param apiuser: This is filled automatically from the |authtoken|.
128 128 :type apiuser: AuthUser
129 :param repoid: Repository name or repository ID from where the pull
130 request was opened.
129 :param repoid: Optional, repository name or repository ID from where
130 the pull request was opened.
131 131 :type repoid: str or int
132 132 :param pullrequestid: ID of the requested pull request.
133 133 :type pullrequestid: int
@@ -199,6 +199,48 b' get_pull_request'
199 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 244 get_pull_requests
203 245 -----------------
204 246
@@ -208,7 +250,7 b' get_pull_requests'
208 250
209 251 :param apiuser: This is filled automatically from the |authtoken|.
210 252 :type apiuser: AuthUser
211 :param repoid: Repository name or repository ID.
253 :param repoid: Optional repository name or repository ID.
212 254 :type repoid: str or int
213 255 :param status: Only return pull requests with the specified status.
214 256 Valid options are.
@@ -289,14 +331,14 b' get_pull_requests'
289 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 336 Merge the pull request specified by `pullrequestid` into its target
295 337 repository.
296 338
297 339 :param apiuser: This is filled automatically from the |authtoken|.
298 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 342 target repository to which the |pr| is to be merged.
301 343 :type repoid: str or int
302 344 :param pullrequestid: ID of the pull request which shall be merged.
@@ -326,13 +368,13 b' merge_pull_request'
326 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 373 Updates a pull request.
332 374
333 375 :param apiuser: This is filled automatically from the |authtoken|.
334 376 :type apiuser: AuthUser
335 :param repoid: The repository name or repository ID.
377 :param repoid: Optional repository name or repository ID.
336 378 :type repoid: str or int
337 379 :param pullrequestid: The pull request ID.
338 380 :type pullrequestid: int
@@ -115,7 +115,7 b' get_repo_group'
115 115 "group_description": "repo group description",
116 116 "group_id": 14,
117 117 "group_name": "group name",
118 "members": [
118 "permissions": [
119 119 {
120 120 "name": "super-admin-username",
121 121 "origin": "super-admin",
@@ -306,26 +306,6 b' get_repo'
306 306 "lock_reason": null,
307 307 "locked_by": null,
308 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 309 "owner": "owner-name",
330 310 "permissions": [
331 311 {
@@ -533,9 +513,6 b' get_repo_settings'
533 513 "hooks_outgoing_pull_logger": true,
534 514 "phases_publish": "True",
535 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 516 "rhodecode_pr_merge_enabled": true,
540 517 "rhodecode_use_outdated_comments": true
541 518 }
@@ -162,7 +162,7 b' get_user_group'
162 162 "active": true,
163 163 "group_description": "group description",
164 164 "group_name": "group name",
165 "members": [
165 "permissions": [
166 166 {
167 167 "name": "owner-name",
168 168 "origin": "owner",
@@ -183,6 +183,12 b' get_user_group'
183 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 192 "owner": "owner name",
187 193 "users": [],
188 194 "users_group_id": 2
@@ -160,7 +160,8 b' get_user'
160 160 "last_login": "Timestamp",
161 161 "last_activity": "Timestamp",
162 162 "lastname": "surnae",
163 "permissions": {
163 "permissions": <deprecated>,
164 "permissions_summary": {
164 165 "global": [
165 166 "hg.inherit_default_perms.true",
166 167 "usergroup.read",
@@ -178,7 +179,7 b' get_user'
178 179 "repositories": { "username/example": "repository.write"},
179 180 "repositories_groups": { "user-group/repo": "group.none" },
180 181 "user_groups": { "user_group_name": "usergroup.read" }
181 },
182 }
182 183 "user_id": 32,
183 184 "username": "username"
184 185 }
@@ -64,7 +64,7 b' 2. Enable the SSH module on instance.'
64 64 ssh.wrapper_cmd_allow_shell = false
65 65
66 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 68 ssh.enable_debug_logging = false
69 69
70 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 111 Then add, remove your SSH key and try connecting again.
112 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 119 For SVN:
118 120
119 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 125 For GIT:
124 126
125 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 131 For Mercurial:
130 132
@@ -133,6 +135,6 b' 4. Add the public key to your user accou'
133 135 Add to hgrc:
134 136
135 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 140 hg clone ssh://rhodecode@rc-server/repo_name
@@ -11,128 +11,253 b' let'
11 11 python = pkgs.python27Packages.python;
12 12
13 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 18 src = fetchurl {
16 url = "http://pypi.python.org/packages/source/J/Jinja2/${name}.tar.gz";
17 md5 = "b9dffd2f3b43d673802fe857c8445b1a";
19 url = "https://pypi.python.org/packages/90/61/f820ff0076a2599dd39406dcb858ecb239438c02ce706c8e91131ab9c7f1/Jinja2-2.9.6.tar.gz";
20 md5 = "6411537324b4dba0956aaa8109f3c77b";
18 21 };
19 propagatedBuildInputs = [ MarkupSafe ];
20 22 };
21 23
22 24 MarkupSafe = buildPythonPackage rec {
23 name = "MarkupSafe-0.23";
25 name = "MarkupSafe-1.0";
26 buildInputs = [];
27 doCheck = false;
28 propagatedBuildInputs = [];
24 29 src = fetchurl {
25 url = "https://pypi.python.org/packages/source/M/MarkupSafe/${name}.tar.gz";
26 md5 = "f5ab3deee4c37cd6a922fb81e730da6e";
30 url = "https://pypi.python.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz";
31 md5 = "2fcedc9284d50e577b5192e8e3578355";
27 32 };
28 33 };
29 34
30 Pygments = buildPythonPackage rec {
31 name = "Pygments-2.1.3";
35 Pygments = buildPythonPackage {
36 name = "Pygments-2.2.0";
37 buildInputs = [];
32 38 doCheck = false;
39 propagatedBuildInputs = [];
33 40 src = fetchurl {
34 url = "https://pypi.python.org/packages/b8/67/ab177979be1c81bc99c8d0592ef22d547e70bb4c6815c383286ed5dec504/Pygments-2.1.3.tar.gz";
35 md5 = "ed3fba2467c8afcda4d317e4ef2c6150";
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";
41 url = "https://pypi.python.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz";
42 md5 = "13037baca42f16917cbd5ad2fab50844";
44 43 };
45 44 };
46 45
47 six = buildPythonPackage rec {
48 name = "six-1.9.0";
46 Sphinx = buildPythonPackage (rec {
47 name = "Sphinx-1.6.5";
49 48 src = fetchurl {
50 url = "https://pypi.python.org/packages/source/s/six/${name}.tar.gz";
51 md5 = "476881ef4012262dfc8adc645ee786c4";
49 url = "https://pypi.python.org/packages/8b/7e/b188d9a3b9c938e736e02a74c1363c2888e095d770df2c72b4c312f9fdcb/Sphinx-1.6.5.tar.gz";
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 {
56 name = "snowballstemmer-1.2.0";
84 babel = buildPythonPackage {
85 name = "babel-2.5.1";
86 buildInputs = [];
87 doCheck = false;
88 propagatedBuildInputs = [pytz];
57 89 src = fetchurl {
58 url = "https://pypi.python.org/packages/source/s/snowballstemmer/${name}.tar.gz";
59 md5 = "51f2ef829db8129dd0f2354f0b209970";
90 url = "https://pypi.python.org/packages/5a/22/63f1dbb8514bb7e0d0c8a85cc9b14506599a075e231985f98afd70430e1f/Babel-2.5.1.tar.gz";
91 md5 = "60228b3ce93a203357158b909afe8ae1";
60 92 };
61 93 };
62 94
63 pytz = buildPythonPackage rec {
64 name = "pytz-2015.2";
95 certifi = buildPythonPackage {
96 name = "certifi-2017.11.5";
97 buildInputs = [];
98 doCheck = false;
99 propagatedBuildInputs = [];
65 100 src = fetchurl {
66 url = "https://pypi.python.org/packages/source/p/pytz/${name}.tar.gz";
67 md5 = "08440d994cfbbf13d3343362cc3173f7";
101 url = "https://pypi.python.org/packages/23/3f/8be01c50ed24a4bd6b8da799839066ce0288f66f5e11f0367323467f0cbc/certifi-2017.11.5.tar.gz";
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 {
72 name = "Babel-1.3";
117 docutils = buildPythonPackage {
118 name = "docutils-0.14";
119 buildInputs = [];
120 doCheck = false;
121 propagatedBuildInputs = [];
73 122 src = fetchurl {
74 url = "https://pypi.python.org/packages/source/B/Babel/${name}.tar.gz";
75 md5 = "5264ceb02717843cbc9ffce8e6e06bdb";
123 url = "https://pypi.python.org/packages/84/f4/5771e41fdf52aabebbadecc9381d11dea0fa34e4759b4071244fa094804c/docutils-0.14.tar.gz";
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 140 name = "imagesize-0.7.1";
141 buildInputs = [];
142 doCheck = false;
143 propagatedBuildInputs = [];
84 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 146 md5 = "976148283286a6ba5f69b0f81aef8052";
87 147 };
88 148 };
89 149
90 Sphinx = buildPythonPackage (rec {
91 name = "Sphinx-1.4.8";
150 pytz = buildPythonPackage {
151 name = "pytz-2017.3";
152 buildInputs = [];
153 doCheck = false;
154 propagatedBuildInputs = [];
92 155 src = fetchurl {
93 url = "https://pypi.python.org/packages/1f/f6/e54a7aad73e35232356103771ae76306dadd8546b024c646fbe75135571c/${name}.tar.gz";
94 md5 = "5ec718a4855917e149498bba91b74e67";
156 url = "https://pypi.python.org/packages/60/88/d3152c234da4b2a1f7a989f89609ea488225eaea015bc16fbde2b3fdfefa/pytz-2017.3.zip";
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 = [
97 docutils
98 Jinja2
99 Pygments
100 alabaster
101 six
102 snowballstemmer
103 pytz
104 babel
105 imagesize
170 };
171
172 setuptools = buildPythonPackage {
173 name = "setuptools-36.6.0";
174 buildInputs = [];
175 doCheck = false;
176 propagatedBuildInputs = [];
177 src = fetchurl {
178 url = "https://pypi.python.org/packages/45/29/8814bf414e7cd1031e1a3c8a4169218376e284ea2553cc0822a6ea1c2d78/setuptools-36.6.0.zip";
179 md5 = "74663b15117d9a2cc5295d76011e6fd1";
180 };
181 };
106 182
107 # TODO: johbo: Had to include it here so that can be imported
108 sphinx_rtd_theme
109 ];
110 });
183 six = buildPythonPackage {
184 name = "six-1.11.0";
185 buildInputs = [];
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 {
113 name = "docutils-0.12";
194 snowballstemmer = buildPythonPackage {
195 name = "snowballstemmer-1.2.1";
196 buildInputs = [];
197 doCheck = false;
198 propagatedBuildInputs = [];
114 199 src = fetchurl {
115 url = "https://pypi.python.org/packages/source/d/docutils/${name}.tar.gz";
116 md5 = "4622263b62c5c771c03502afa3157768";
200 url = "https://pypi.python.org/packages/20/6b/d2a7cb176d4d664d94a6debf52cd8dbae1f7203c8e42426daa077051d59c/snowballstemmer-1.2.1.tar.gz";
201 md5 = "643b019667a708a922172e33a99bf2fa";
117 202 };
118 203 };
119 204
120 sphinx_rtd_theme = buildPythonPackage rec {
121 name = "sphinx_rtd_theme-0.1.9";
205 sphinx-rtd-theme = buildPythonPackage {
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 221 src = fetchurl {
123 url = "https://pypi.python.org/packages/source/s/sphinx_rtd_theme/${name}.tar.gz";
124 md5 = "86a25c8d47147c872e42dc84cc66f97b";
222 url = "https://pypi.python.org/packages/c5/6b/f0630436b931ad4f8331a9399ca18a7d447f0fcc0c7178fb56b1aee68d01/sphinxcontrib-websupport-1.0.1.tar.gz";
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 263 in python.buildEnv.override {
@@ -9,6 +9,7 b' Release Notes'
9 9 .. toctree::
10 10 :maxdepth: 1
11 11
12 release-notes-4.11.0.rst
12 13 release-notes-4.10.6.rst
13 14 release-notes-4.10.5.rst
14 15 release-notes-4.10.4.rst
@@ -42,6 +42,8 b''
42 42 "<%= dirs.js.src %>/bootstrap.js",
43 43 "<%= dirs.js.src %>/i18n_utils.js",
44 44 "<%= dirs.js.src %>/deform.js",
45 "<%= dirs.js.src %>/ejs.js",
46 "<%= dirs.js.src %>/ejs_templates/utils.js",
45 47 "<%= dirs.js.src %>/plugins/jquery.pjax.js",
46 48 "<%= dirs.js.src %>/plugins/jquery.dataTables.js",
47 49 "<%= dirs.js.src %>/plugins/flavoured_checkbox.js",
@@ -7,7 +7,7 b' buildEnv { name = "bower-env"; ignoreCol'
7 7 (fetchbower "paper-tooltip" "PolymerElements/paper-tooltip#1.1.3" "PolymerElements/paper-tooltip#^1.1.2" "0vmrm1n8k9sk9nvqy03q177axy22pia6i3j1gxbk72j3pqiqvg6k")
8 8 (fetchbower "paper-toast" "PolymerElements/paper-toast#1.3.0" "PolymerElements/paper-toast#^1.3.0" "0x9rqxsks5455s8pk4aikpp99ijdn6kxr9gvhwh99nbcqdzcxq1m")
9 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 11 (fetchbower "iron-autogrow-textarea" "PolymerElements/iron-autogrow-textarea#1.0.13" "PolymerElements/iron-autogrow-textarea#^1.0.13" "0zwhpl97vii1s8k0lgain8i9dnw29b0mxc5ixdscx9las13n2lqq")
12 12 (fetchbower "iron-a11y-keys" "PolymerElements/iron-a11y-keys#1.0.6" "PolymerElements/iron-a11y-keys#^1.0.6" "1xz3mgghfcxixq28sdb654iaxj4nyi1bzcwf77ydkms6fviqs9mv")
13 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 40 gnureadline = super.gnureadline.override (attrs: {
35 41 buildInputs = attrs.buildInputs ++ [
36 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 70 lxml = super.lxml.override (attrs: {
82 71 # johbo: On 16.09 we need this to compile on darwin, otherwise compilation
83 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 106 pycurl = super.pycurl.override (attrs: {
122 107 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
123 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 121 pyramid = super.pyramid.override (attrs: {
141 122 postFixup = ''
142 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 192 docutils = super.docutils.override (attrs: {
218 193 meta = {
219 194 license = pkgs.lib.licenses.bsd2;
@@ -68,13 +68,13 b''
68 68 };
69 69 };
70 70 Jinja2 = super.buildPythonPackage {
71 name = "Jinja2-2.7.3";
71 name = "Jinja2-2.9.6";
72 72 buildInputs = with self; [];
73 73 doCheck = false;
74 74 propagatedBuildInputs = with self; [MarkupSafe];
75 75 src = fetchurl {
76 url = "https://pypi.python.org/packages/b0/73/eab0bca302d6d6a0b5c402f47ad1760dc9cb2dd14bbc1873ad48db258e4d/Jinja2-2.7.3.tar.gz";
77 md5 = "b9dffd2f3b43d673802fe857c8445b1a";
76 url = "https://pypi.python.org/packages/90/61/f820ff0076a2599dd39406dcb858ecb239438c02ce706c8e91131ab9c7f1/Jinja2-2.9.6.tar.gz";
77 md5 = "6411537324b4dba0956aaa8109f3c77b";
78 78 };
79 79 meta = {
80 80 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -94,26 +94,26 b''
94 94 };
95 95 };
96 96 Markdown = super.buildPythonPackage {
97 name = "Markdown-2.6.8";
97 name = "Markdown-2.6.9";
98 98 buildInputs = with self; [];
99 99 doCheck = false;
100 100 propagatedBuildInputs = with self; [];
101 101 src = fetchurl {
102 url = "https://pypi.python.org/packages/1d/25/3f6d2cb31ec42ca5bd3bfbea99b63892b735d76e26f20dd2dcc34ffe4f0d/Markdown-2.6.8.tar.gz";
103 md5 = "d9ef057a5bd185f6f536400a31fc5d45";
102 url = "https://pypi.python.org/packages/29/82/dfe242bcfd9eec0e7bf93a80a8f8d8515a95b980c44f5c0b45606397a423/Markdown-2.6.9.tar.gz";
103 md5 = "56547d362a9abcf30955b8950b08b5e3";
104 104 };
105 105 meta = {
106 106 license = [ pkgs.lib.licenses.bsdOriginal ];
107 107 };
108 108 };
109 109 MarkupSafe = super.buildPythonPackage {
110 name = "MarkupSafe-0.23";
110 name = "MarkupSafe-1.0";
111 111 buildInputs = with self; [];
112 112 doCheck = false;
113 113 propagatedBuildInputs = with self; [];
114 114 src = fetchurl {
115 url = "https://pypi.python.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-0.23.tar.gz";
116 md5 = "f5ab3deee4c37cd6a922fb81e730da6e";
115 url = "https://pypi.python.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz";
116 md5 = "2fcedc9284d50e577b5192e8e3578355";
117 117 };
118 118 meta = {
119 119 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -159,13 +159,13 b''
159 159 };
160 160 };
161 161 PasteScript = super.buildPythonPackage {
162 name = "PasteScript-1.7.5";
162 name = "PasteScript-2.0.2";
163 163 buildInputs = with self; [];
164 164 doCheck = false;
165 propagatedBuildInputs = with self; [Paste PasteDeploy];
165 propagatedBuildInputs = with self; [Paste PasteDeploy six];
166 166 src = fetchurl {
167 url = "https://pypi.python.org/packages/a5/05/fc60efa7c2f17a1dbaeccb2a903a1e90902d92b9d00eebabe3095829d806/PasteScript-1.7.5.tar.gz";
168 md5 = "4c72d78dcb6bb993f30536842c16af4d";
167 url = "https://pypi.python.org/packages/e5/f0/78e766c3dcc61a4f3a6f71dd8c95168ae9c7a31722b5663d19c1fdf62cb6/PasteScript-2.0.2.tar.gz";
168 md5 = "ccb3045445097192ca71a13b746c77b2";
169 169 };
170 170 meta = {
171 171 license = [ pkgs.lib.licenses.mit ];
@@ -184,56 +184,30 b''
184 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 187 Routes = super.buildPythonPackage {
201 name = "Routes-1.13";
188 name = "Routes-2.4.1";
202 189 buildInputs = with self; [];
203 190 doCheck = false;
204 propagatedBuildInputs = with self; [repoze.lru];
191 propagatedBuildInputs = with self; [six repoze.lru];
205 192 src = fetchurl {
206 url = "https://pypi.python.org/packages/88/d3/259c3b3cde8837eb9441ab5f574a660e8a4acea8f54a078441d4d2acac1c/Routes-1.13.tar.gz";
207 md5 = "d527b0ab7dd9172b1275a41f97448783";
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";
193 url = "https://pypi.python.org/packages/33/38/ea827837e68d9c7dde4cff7ec122a93c319f0effc08ce92a17095576603f/Routes-2.4.1.tar.gz";
194 md5 = "c058dff6832941dec47e0d0052548ad8";
221 195 };
222 196 meta = {
223 197 license = [ pkgs.lib.licenses.mit ];
224 198 };
225 199 };
226 Sphinx = super.buildPythonPackage {
227 name = "Sphinx-1.2.2";
200 SQLAlchemy = super.buildPythonPackage {
201 name = "SQLAlchemy-1.1.15";
228 202 buildInputs = with self; [];
229 203 doCheck = false;
230 propagatedBuildInputs = with self; [Pygments docutils Jinja2];
204 propagatedBuildInputs = with self; [];
231 205 src = fetchurl {
232 url = "https://pypi.python.org/packages/0a/50/34017e6efcd372893a416aba14b84a1a149fc7074537b0e9cb6ca7b7abe9/Sphinx-1.2.2.tar.gz";
233 md5 = "3dc73ccaa8d0bfb2d62fb671b1f7e8a4";
206 url = "https://pypi.python.org/packages/c2/f6/11fcc1ce19a7cb81b1c9377f4e27ce3813265611922e355905e57c44d164/SQLAlchemy-1.1.15.tar.gz";
207 md5 = "077f9bd3339957f53068b5572a152674";
234 208 };
235 209 meta = {
236 license = [ pkgs.lib.licenses.bsdOriginal ];
210 license = [ pkgs.lib.licenses.mit ];
237 211 };
238 212 };
239 213 Tempita = super.buildPythonPackage {
@@ -315,13 +289,13 b''
315 289 };
316 290 };
317 291 WebTest = super.buildPythonPackage {
318 name = "WebTest-2.0.27";
292 name = "WebTest-2.0.29";
319 293 buildInputs = with self; [];
320 294 doCheck = false;
321 295 propagatedBuildInputs = with self; [six WebOb waitress beautifulsoup4];
322 296 src = fetchurl {
323 url = "https://pypi.python.org/packages/80/fa/ca3a759985c72e3a124cbca3e1f8a2e931a07ffd31fd45d8f7bf21cb95cf/WebTest-2.0.27.tar.gz";
324 md5 = "54e6515ac71c51b6fc90179483c749ad";
297 url = "https://pypi.python.org/packages/94/de/8f94738be649997da99c47b104aa3c3984ecec51a1d8153ed09638253d56/WebTest-2.0.29.tar.gz";
298 md5 = "30b4cf0d340b9a5335fac4389e6f84fc";
325 299 };
326 300 meta = {
327 301 license = [ pkgs.lib.licenses.mit ];
@@ -341,52 +315,39 b''
341 315 };
342 316 };
343 317 alembic = super.buildPythonPackage {
344 name = "alembic-0.9.2";
318 name = "alembic-0.9.6";
345 319 buildInputs = with self; [];
346 320 doCheck = false;
347 321 propagatedBuildInputs = with self; [SQLAlchemy Mako python-editor python-dateutil];
348 322 src = fetchurl {
349 url = "https://pypi.python.org/packages/78/48/b5b26e7218b415f40b60b92c53853d242e5456c0f19f6c66101d98ff5f2a/alembic-0.9.2.tar.gz";
350 md5 = "40daf8bae50969beea40efaaf0839ff4";
323 url = "https://pypi.python.org/packages/bf/b3/b28ea715824f8455635ece3c12f59d5d205f98cc378858e414e3aa6ebdbc/alembic-0.9.6.tar.gz";
324 md5 = "fcb096bccc87c8770bd07a04606cb989";
351 325 };
352 326 meta = {
353 327 license = [ pkgs.lib.licenses.mit ];
354 328 };
355 329 };
356 amqplib = super.buildPythonPackage {
357 name = "amqplib-1.0.2";
330 amqp = super.buildPythonPackage {
331 name = "amqp-2.2.2";
358 332 buildInputs = with self; [];
359 333 doCheck = false;
360 propagatedBuildInputs = with self; [];
334 propagatedBuildInputs = with self; [vine];
361 335 src = fetchurl {
362 url = "https://pypi.python.org/packages/75/b7/8c2429bf8d92354a0118614f9a4d15e53bc69ebedce534284111de5a0102/amqplib-1.0.2.tgz";
363 md5 = "5c92f17fbedd99b2b4a836d4352d1e2f";
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";
336 url = "https://pypi.python.org/packages/e0/70/9ab9ccd8247fb7d2adb717e9f6a0ed358c9e1ab2c349048b0352f9e80ee2/amqp-2.2.2.tar.gz";
337 md5 = "0971a3fd2d635ded45c349cfc17106bd";
377 338 };
378 339 meta = {
379 340 license = [ pkgs.lib.licenses.bsdOriginal ];
380 341 };
381 342 };
382 343 appenlight-client = super.buildPythonPackage {
383 name = "appenlight-client-0.6.21";
344 name = "appenlight-client-0.6.22";
384 345 buildInputs = with self; [];
385 346 doCheck = false;
386 347 propagatedBuildInputs = with self; [WebOb requests six];
387 348 src = fetchurl {
388 url = "https://pypi.python.org/packages/c9/23/91b66cfa0b963662c10b2a06ccaadf3f3a4848a7a2aa16255cb43d5160ec/appenlight_client-0.6.21.tar.gz";
389 md5 = "273999ac854fdaefa8d0fb61965a4ed9";
349 url = "https://pypi.python.org/packages/73/37/0a64460fa9670b17c061adc433bc8be5079cba21e8b3a92d824adccb12bc/appenlight_client-0.6.22.tar.gz";
350 md5 = "641afc114a9a3b3af4f75b11c70968ee";
390 351 };
391 352 meta = {
392 353 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -431,27 +392,40 b''
431 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 408 bleach = super.buildPythonPackage {
435 name = "bleach-1.5.0";
409 name = "bleach-2.1.1";
436 410 buildInputs = with self; [];
437 411 doCheck = false;
438 412 propagatedBuildInputs = with self; [six html5lib];
439 413 src = fetchurl {
440 url = "https://pypi.python.org/packages/99/00/25a8fce4de102bf6e3cc76bc4ea60685b2fee33bde1b34830c70cacc26a7/bleach-1.5.0.tar.gz";
441 md5 = "b663300efdf421b3b727b19d7be9c7e7";
414 url = "https://pypi.python.org/packages/d4/3f/d517089af35b01bb9bc4eac5ea04bae342b37a5e9abbb27b7c3ce0eae070/bleach-2.1.1.tar.gz";
415 md5 = "7c5dfb1d66ea979b5a465afb12c82ec4";
442 416 };
443 417 meta = {
444 418 license = [ pkgs.lib.licenses.asl20 ];
445 419 };
446 420 };
447 421 bottle = super.buildPythonPackage {
448 name = "bottle-0.12.8";
422 name = "bottle-0.12.13";
449 423 buildInputs = with self; [];
450 424 doCheck = false;
451 425 propagatedBuildInputs = with self; [];
452 426 src = fetchurl {
453 url = "https://pypi.python.org/packages/52/df/e4a408f3a7af396d186d4ecd3b389dd764f0f943b4fa8d257bfe7b49d343/bottle-0.12.8.tar.gz";
454 md5 = "13132c0a8f607bf860810a6ee9064c5b";
427 url = "https://pypi.python.org/packages/bd/99/04dc59ced52a8261ee0f965a8968717a255ea84a36013e527944dbf3468c/bottle-0.12.13.tar.gz";
428 md5 = "d2fe1b48c1d49217e78bf326b1cad437";
455 429 };
456 430 meta = {
457 431 license = [ pkgs.lib.licenses.mit ];
@@ -471,13 +445,13 b''
471 445 };
472 446 };
473 447 celery = super.buildPythonPackage {
474 name = "celery-2.2.10";
448 name = "celery-4.1.0";
475 449 buildInputs = with self; [];
476 450 doCheck = false;
477 propagatedBuildInputs = with self; [python-dateutil anyjson kombu pyparsing];
451 propagatedBuildInputs = with self; [pytz billiard kombu];
478 452 src = fetchurl {
479 url = "https://pypi.python.org/packages/b1/64/860fd50e45844c83442e7953effcddeff66b2851d90b2d784f7201c111b8/celery-2.2.10.tar.gz";
480 md5 = "898bc87e54f278055b561316ba73e222";
453 url = "https://pypi.python.org/packages/07/65/88a2a45fc80f487872c93121a701a53bbbc3d3d832016876fac84fc8d46a/celery-4.1.0.tar.gz";
454 md5 = "db91e1d26936381127f01e150fe3054a";
481 455 };
482 456 meta = {
483 457 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -497,26 +471,26 b''
497 471 };
498 472 };
499 473 click = super.buildPythonPackage {
500 name = "click-5.1";
474 name = "click-6.6";
501 475 buildInputs = with self; [];
502 476 doCheck = false;
503 477 propagatedBuildInputs = with self; [];
504 478 src = fetchurl {
505 url = "https://pypi.python.org/packages/b7/34/a496632c4fb6c1ee76efedf77bb8d28b29363d839953d95095b12defe791/click-5.1.tar.gz";
506 md5 = "9c5323008cccfe232a8b161fc8196d41";
479 url = "https://pypi.python.org/packages/7a/00/c14926d8232b36b08218067bcd5853caefb4737cda3f0a47437151344792/click-6.6.tar.gz";
480 md5 = "d0b09582123605220ad6977175f3e51d";
507 481 };
508 482 meta = {
509 483 license = [ pkgs.lib.licenses.bsdOriginal ];
510 484 };
511 485 };
512 486 colander = super.buildPythonPackage {
513 name = "colander-1.3.3";
487 name = "colander-1.4";
514 488 buildInputs = with self; [];
515 489 doCheck = false;
516 490 propagatedBuildInputs = with self; [translationstring iso8601];
517 491 src = fetchurl {
518 url = "https://pypi.python.org/packages/54/a9/9862a561e015b2c7b56404c0b13828a8bdc51e05ab3703bd792cec064487/colander-1.3.3.tar.gz";
519 md5 = "f5d783768c51d73695f49bbe95778ab4";
492 url = "https://pypi.python.org/packages/cc/e2/c4e716ac4a426d8ad4dfe306c34f0018a22275d2420815784005bf771c84/colander-1.4.tar.gz";
493 md5 = "cbb8e403c2ba05aeaa419d51fdb93736";
520 494 };
521 495 meta = {
522 496 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
@@ -588,13 +562,13 b''
588 562 };
589 563 };
590 564 decorator = super.buildPythonPackage {
591 name = "decorator-4.0.11";
565 name = "decorator-4.1.2";
592 566 buildInputs = with self; [];
593 567 doCheck = false;
594 568 propagatedBuildInputs = with self; [];
595 569 src = fetchurl {
596 url = "https://pypi.python.org/packages/cc/ac/5a16f1fc0506ff72fcc8fd4e858e3a1c231f224ab79bb7c4c9b2094cc570/decorator-4.0.11.tar.gz";
597 md5 = "73644c8f0bd4983d1b6a34b49adec0ae";
570 url = "https://pypi.python.org/packages/bb/e0/f6e41e9091e130bf16d4437dabbac3993908e4d6485ecbc985ef1352db94/decorator-4.1.2.tar.gz";
571 md5 = "a0f7f4fe00ae2dde93494d90c192cf8c";
598 572 };
599 573 meta = {
600 574 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "new BSD License"; } ];
@@ -614,13 +588,13 b''
614 588 };
615 589 };
616 590 docutils = super.buildPythonPackage {
617 name = "docutils-0.13.1";
591 name = "docutils-0.14";
618 592 buildInputs = with self; [];
619 593 doCheck = false;
620 594 propagatedBuildInputs = with self; [];
621 595 src = fetchurl {
622 url = "https://pypi.python.org/packages/05/25/7b5484aca5d46915493f1fd4ecb63c38c333bd32aa9ad6e19da8d08895ae/docutils-0.13.1.tar.gz";
623 md5 = "ea4a893c633c788be9b8078b6b305d53";
596 url = "https://pypi.python.org/packages/84/f4/5771e41fdf52aabebbadecc9381d11dea0fa34e4759b4071244fa094804c/docutils-0.14.tar.gz";
597 md5 = "c53768d63db3873b7d452833553469de";
624 598 };
625 599 meta = {
626 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 759 gnureadline = super.buildPythonPackage {
786 name = "gnureadline-6.3.3";
760 name = "gnureadline-6.3.8";
787 761 buildInputs = with self; [];
788 762 doCheck = false;
789 763 propagatedBuildInputs = with self; [];
790 764 src = fetchurl {
791 url = "https://pypi.python.org/packages/3a/ee/2c3f568b0a74974791ac590ec742ef6133e2fbd287a074ba72a53fa5e97c/gnureadline-6.3.3.tar.gz";
792 md5 = "c4af83c9a3fbeac8f2da9b5a7c60e51c";
765 url = "https://pypi.python.org/packages/50/64/86085c823cd78f9df9d8e33dce0baa71618016f8860460b82cf6610e1eb3/gnureadline-6.3.8.tar.gz";
766 md5 = "ba341f4b907250bd1f47dbc06290604f";
793 767 };
794 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 772 gprof2dot = super.buildPythonPackage {
799 name = "gprof2dot-2016.10.13";
773 name = "gprof2dot-2017.9.19";
800 774 buildInputs = with self; [];
801 775 doCheck = false;
802 776 propagatedBuildInputs = with self; [];
803 777 src = fetchurl {
804 url = "https://pypi.python.org/packages/a0/e0/73c71baed306f0402a00a94ffc7b2be94ad1296dfcb8b46912655b93154c/gprof2dot-2016.10.13.tar.gz";
805 md5 = "0125401f15fd2afe1df686a76c64a4fd";
778 url = "https://pypi.python.org/packages/9d/36/f977122502979f3dfb50704979c9ed70e6b620787942b089bf1af15f5aba/gprof2dot-2017.9.19.tar.gz";
779 md5 = "cda2d552bb0d0b9f16e6824a9aabd225";
806 780 };
807 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 785 graphviz = super.buildPythonPackage {
812 name = "graphviz-0.8";
786 name = "graphviz-0.8.1";
813 787 buildInputs = with self; [];
814 788 doCheck = false;
815 789 propagatedBuildInputs = with self; [];
816 790 src = fetchurl {
817 url = "https://pypi.python.org/packages/da/84/0e997520323d6b01124eb01c68d5c101814d0aab53083cd62bd75a90f70b/graphviz-0.8.zip";
818 md5 = "9486a885360a5ee54a81eb2950470c71";
791 url = "https://pypi.python.org/packages/a9/a6/ee6721349489a2da6eedd3dba124f2b5ac15ee1e0a7bd4d3cfdc4fff0327/graphviz-0.8.1.zip";
792 md5 = "88d8efa88c02a735b3659fe0feaf0b96";
819 793 };
820 794 meta = {
821 795 license = [ pkgs.lib.licenses.mit ];
@@ -848,13 +822,13 b''
848 822 };
849 823 };
850 824 html5lib = super.buildPythonPackage {
851 name = "html5lib-0.9999999";
825 name = "html5lib-1.0b10";
852 826 buildInputs = with self; [];
853 827 doCheck = false;
854 propagatedBuildInputs = with self; [six];
828 propagatedBuildInputs = with self; [six webencodings setuptools];
855 829 src = fetchurl {
856 url = "https://pypi.python.org/packages/ae/ae/bcb60402c60932b32dfaf19bb53870b29eda2cd17551ba5639219fb5ebf9/html5lib-0.9999999.tar.gz";
857 md5 = "ef43cb05e9e799f25d65d1135838a96f";
830 url = "https://pypi.python.org/packages/97/16/982214624095c1420c75f3bd295d9e658794aafb95fc075823de107e0ae4/html5lib-1.0b10.tar.gz";
831 md5 = "5ada1243b7a863624b2f35245b2186e9";
858 832 };
859 833 meta = {
860 834 license = [ pkgs.lib.licenses.mit ];
@@ -952,13 +926,13 b''
952 926 };
953 927 };
954 928 iso8601 = super.buildPythonPackage {
955 name = "iso8601-0.1.11";
929 name = "iso8601-0.1.12";
956 930 buildInputs = with self; [];
957 931 doCheck = false;
958 932 propagatedBuildInputs = with self; [];
959 933 src = fetchurl {
960 url = "https://pypi.python.org/packages/c0/75/c9209ee4d1b5975eb8c2cba4428bde6b61bd55664a98290dd015cdb18e98/iso8601-0.1.11.tar.gz";
961 md5 = "b06d11cd14a64096f907086044f0fe38";
934 url = "https://pypi.python.org/packages/45/13/3db24895497345fb44c4248c08b16da34a9eb02643cea2754b21b5ed08b0/iso8601-0.1.12.tar.gz";
935 md5 = "4de940f691c5ea759fb254384c8ddcf6";
962 936 };
963 937 meta = {
964 938 license = [ pkgs.lib.licenses.mit ];
@@ -1004,26 +978,26 b''
1004 978 };
1005 979 };
1006 980 jupyter-core = super.buildPythonPackage {
1007 name = "jupyter-core-4.3.0";
981 name = "jupyter-core-4.4.0";
1008 982 buildInputs = with self; [];
1009 983 doCheck = false;
1010 984 propagatedBuildInputs = with self; [traitlets];
1011 985 src = fetchurl {
1012 url = "https://pypi.python.org/packages/2f/39/5138f975100ce14d150938df48a83cd852a3fd8e24b1244f4113848e69e2/jupyter_core-4.3.0.tar.gz";
1013 md5 = "18819511a809afdeed9a995a9c27bcfb";
986 url = "https://pypi.python.org/packages/b6/2d/2804f4de3a95583f65e5dcb4d7c8c7183124882323758996e867f47e72af/jupyter_core-4.4.0.tar.gz";
987 md5 = "7829fc07884ed98459e170f217e2a5ba";
1014 988 };
1015 989 meta = {
1016 990 license = [ pkgs.lib.licenses.bsdOriginal ];
1017 991 };
1018 992 };
1019 993 kombu = super.buildPythonPackage {
1020 name = "kombu-1.5.1";
994 name = "kombu-4.1.0";
1021 995 buildInputs = with self; [];
1022 996 doCheck = false;
1023 propagatedBuildInputs = with self; [anyjson amqplib];
997 propagatedBuildInputs = with self; [amqp];
1024 998 src = fetchurl {
1025 url = "https://pypi.python.org/packages/19/53/74bf2a624644b45f0850a638752514fc10a8e1cbd738f10804951a6df3f5/kombu-1.5.1.tar.gz";
1026 md5 = "50662f3c7e9395b3d0721fb75d100b63";
999 url = "https://pypi.python.org/packages/03/5e/1a47d1e543d4943d65330af4e4406049f443878818fb65bfdc651bb93a96/kombu-4.1.0.tar.gz";
1000 md5 = "2fb2be9fec0e6514231bba23a3779439";
1027 1001 };
1028 1002 meta = {
1029 1003 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -1056,13 +1030,13 b''
1056 1030 };
1057 1031 };
1058 1032 mistune = super.buildPythonPackage {
1059 name = "mistune-0.7.4";
1033 name = "mistune-0.8.3";
1060 1034 buildInputs = with self; [];
1061 1035 doCheck = false;
1062 1036 propagatedBuildInputs = with self; [];
1063 1037 src = fetchurl {
1064 url = "https://pypi.python.org/packages/25/a4/12a584c0c59c9fed529f8b3c47ca8217c0cf8bcc5e1089d3256410cfbdbc/mistune-0.7.4.tar.gz";
1065 md5 = "92d01cb717e9e74429e9bde9d29ac43b";
1038 url = "https://pypi.python.org/packages/9d/be/e06d4346cc608a01dec6bf770d7d0303a4fd6db588b318ced18f5f257145/mistune-0.8.3.tar.gz";
1039 md5 = "a5e4043e93fb8f9082e27f29eeb5e054";
1066 1040 };
1067 1041 meta = {
1068 1042 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -1095,52 +1069,39 b''
1095 1069 };
1096 1070 };
1097 1071 nbconvert = super.buildPythonPackage {
1098 name = "nbconvert-5.1.1";
1072 name = "nbconvert-5.3.1";
1099 1073 buildInputs = with self; [];
1100 1074 doCheck = false;
1101 1075 propagatedBuildInputs = with self; [mistune Jinja2 Pygments traitlets jupyter-core nbformat entrypoints bleach pandocfilters testpath];
1102 1076 src = fetchurl {
1103 url = "https://pypi.python.org/packages/95/58/df1c91f1658ee5df19097f915a1e71c91fc824a708d82d2b2e35f8b80e9a/nbconvert-5.1.1.tar.gz";
1104 md5 = "d0263fb03a44db2f94eea09a608ed813";
1077 url = "https://pypi.python.org/packages/b9/a4/d0a0938ad6f5eeb4dea4e73d255c617ef94b0b2849d51194c9bbdb838412/nbconvert-5.3.1.tar.gz";
1078 md5 = "c128d0d93d02f70a85429a383dae96d2";
1105 1079 };
1106 1080 meta = {
1107 1081 license = [ pkgs.lib.licenses.bsdOriginal ];
1108 1082 };
1109 1083 };
1110 1084 nbformat = super.buildPythonPackage {
1111 name = "nbformat-4.3.0";
1085 name = "nbformat-4.4.0";
1112 1086 buildInputs = with self; [];
1113 1087 doCheck = false;
1114 1088 propagatedBuildInputs = with self; [ipython-genutils traitlets jsonschema jupyter-core];
1115 1089 src = fetchurl {
1116 url = "https://pypi.python.org/packages/f9/c5/89df4abf906f766727f976e170caa85b4f1c1d1feb1f45d716016e68e19f/nbformat-4.3.0.tar.gz";
1117 md5 = "9a00d20425914cd5ba5f97769d9963ca";
1090 url = "https://pypi.python.org/packages/6e/0e/160754f7ae3e984863f585a3743b0ed1702043a81245907c8fae2d537155/nbformat-4.4.0.tar.gz";
1091 md5 = "2d5f873138d9fbc2a3f9eaaebca3b8a1";
1118 1092 };
1119 1093 meta = {
1120 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 1097 objgraph = super.buildPythonPackage {
1137 name = "objgraph-3.1.0";
1098 name = "objgraph-3.1.1";
1138 1099 buildInputs = with self; [];
1139 1100 doCheck = false;
1140 1101 propagatedBuildInputs = with self; [graphviz];
1141 1102 src = fetchurl {
1142 url = "https://pypi.python.org/packages/f4/b3/082e54e62094cb2ec84f8d5a49e0142cef99016491cecba83309cff920ae/objgraph-3.1.0.tar.gz";
1143 md5 = "eddbd96039796bfbd13eee403701e64a";
1103 url = "https://pypi.python.org/packages/be/58/9ca81a20cc837054e94866df1475d899caaa94f3732b8a46006858b015f7/objgraph-3.1.1.tar.gz";
1104 md5 = "253af9944763377877c3678d8aaebb8b";
1144 1105 };
1145 1106 meta = {
1146 1107 license = [ pkgs.lib.licenses.mit ];
@@ -1199,13 +1160,13 b''
1199 1160 };
1200 1161 };
1201 1162 pexpect = super.buildPythonPackage {
1202 name = "pexpect-4.2.1";
1163 name = "pexpect-4.3.0";
1203 1164 buildInputs = with self; [];
1204 1165 doCheck = false;
1205 1166 propagatedBuildInputs = with self; [ptyprocess];
1206 1167 src = fetchurl {
1207 url = "https://pypi.python.org/packages/e8/13/d0b0599099d6cd23663043a2a0bb7c61e58c6ba359b2656e6fb000ef5b98/pexpect-4.2.1.tar.gz";
1208 md5 = "3694410001a99dff83f0b500a1ca1c95";
1168 url = "https://pypi.python.org/packages/f8/44/5466c30e49762bb92e442bbdf4472d6904608d211258eb3198a11f0309a4/pexpect-4.3.0.tar.gz";
1169 md5 = "047a486dcd26134b74f2e67046bb61a0";
1209 1170 };
1210 1171 meta = {
1211 1172 license = [ pkgs.lib.licenses.isc { fullName = "ISC License (ISCL)"; } ];
@@ -1225,26 +1186,26 b''
1225 1186 };
1226 1187 };
1227 1188 plaster = super.buildPythonPackage {
1228 name = "plaster-0.5";
1189 name = "plaster-1.0";
1229 1190 buildInputs = with self; [];
1230 1191 doCheck = false;
1231 1192 propagatedBuildInputs = with self; [setuptools];
1232 1193 src = fetchurl {
1233 url = "https://pypi.python.org/packages/99/b3/d7ca1fe31d2b56dba68a238721fda6820770f9c2a3de17a582d4b5b2edcc/plaster-0.5.tar.gz";
1234 md5 = "c59345a67a860cfcaa1bd6a81451399d";
1194 url = "https://pypi.python.org/packages/37/e1/56d04382d718d32751017d32f351214384e529b794084eee20bb52405563/plaster-1.0.tar.gz";
1195 md5 = "80e6beb4760c16fea31754babcc0576e";
1235 1196 };
1236 1197 meta = {
1237 1198 license = [ pkgs.lib.licenses.mit ];
1238 1199 };
1239 1200 };
1240 1201 plaster-pastedeploy = super.buildPythonPackage {
1241 name = "plaster-pastedeploy-0.4.1";
1202 name = "plaster-pastedeploy-0.4.2";
1242 1203 buildInputs = with self; [];
1243 1204 doCheck = false;
1244 1205 propagatedBuildInputs = with self; [PasteDeploy plaster];
1245 1206 src = fetchurl {
1246 url = "https://pypi.python.org/packages/9d/6e/f8be01ed41c94e6c54ac97cf2eb142a702aae0c8cce31c846f785e525b40/plaster_pastedeploy-0.4.1.tar.gz";
1247 md5 = "f48d5344b922e56c4978eebf1cd2e0d3";
1207 url = "https://pypi.python.org/packages/2c/62/0daf9c0be958e785023e583e51baac15863699e956bfb3d448898d80edd8/plaster_pastedeploy-0.4.2.tar.gz";
1208 md5 = "58fd7852002909378e818c9d5b71e90a";
1248 1209 };
1249 1210 meta = {
1250 1211 license = [ pkgs.lib.licenses.mit ];
@@ -1264,26 +1225,26 b''
1264 1225 };
1265 1226 };
1266 1227 psutil = super.buildPythonPackage {
1267 name = "psutil-4.3.1";
1228 name = "psutil-5.4.0";
1268 1229 buildInputs = with self; [];
1269 1230 doCheck = false;
1270 1231 propagatedBuildInputs = with self; [];
1271 1232 src = fetchurl {
1272 url = "https://pypi.python.org/packages/78/cc/f267a1371f229bf16db6a4e604428c3b032b823b83155bd33cef45e49a53/psutil-4.3.1.tar.gz";
1273 md5 = "199a366dba829c88bddaf5b41d19ddc0";
1233 url = "https://pypi.python.org/packages/8d/96/1fc6468be91521192861966c40bd73fdf8b065eae6d82dd0f870b9825a65/psutil-5.4.0.tar.gz";
1234 md5 = "01af6219b1e8fcfd53603023967713bf";
1274 1235 };
1275 1236 meta = {
1276 1237 license = [ pkgs.lib.licenses.bsdOriginal ];
1277 1238 };
1278 1239 };
1279 1240 psycopg2 = super.buildPythonPackage {
1280 name = "psycopg2-2.7.1";
1241 name = "psycopg2-2.7.3.2";
1281 1242 buildInputs = with self; [];
1282 1243 doCheck = false;
1283 1244 propagatedBuildInputs = with self; [];
1284 1245 src = fetchurl {
1285 url = "https://pypi.python.org/packages/f8/e9/5793369ce8a41bf5467623ded8d59a434dfef9c136351aca4e70c2657ba0/psycopg2-2.7.1.tar.gz";
1286 md5 = "67848ac33af88336046802f6ef7081f3";
1246 url = "https://pypi.python.org/packages/dd/47/000b405d73ca22980684fd7bd3318690cc03cfa3b2ae1c5b7fff8050b28a/psycopg2-2.7.3.2.tar.gz";
1247 md5 = "8114e672d5f23fa5329874a4314fbd6f";
1287 1248 };
1288 1249 meta = {
1289 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 1266 py = super.buildPythonPackage {
1306 name = "py-1.4.34";
1267 name = "py-1.5.2";
1307 1268 buildInputs = with self; [];
1308 1269 doCheck = false;
1309 1270 propagatedBuildInputs = with self; [];
1310 1271 src = fetchurl {
1311 url = "https://pypi.python.org/packages/68/35/58572278f1c097b403879c1e9369069633d1cbad5239b9057944bb764782/py-1.4.34.tar.gz";
1312 md5 = "d9c3d8f734b0819ff48e355d77bf1730";
1272 url = "https://pypi.python.org/packages/90/e3/e075127d39d35f09a500ebb4a90afd10f9ef0a1d28a6d09abeec0e444fdd/py-1.5.2.tar.gz";
1273 md5 = "279ca69c632069e1b71e11b14641ca28";
1313 1274 };
1314 1275 meta = {
1315 1276 license = [ pkgs.lib.licenses.mit ];
@@ -1334,8 +1295,8 b''
1334 1295 doCheck = false;
1335 1296 propagatedBuildInputs = with self; [setuptools Markdown];
1336 1297 src = fetchurl {
1337 url = "https://code.rhodecode.com/upstream/py-gfm/archive/0d66a19bc16e3d49de273c0f797d4e4781e8c0f2.tar.gz?md5=0d0d5385bfb629eea636a80b9c2bfd16";
1338 md5 = "0d0d5385bfb629eea636a80b9c2bfd16";
1298 url = "https://pypi.python.org/packages/12/e4/6b3d8678da04f97d7490d8264d8de51c2dc9fb91209ccee9c515c95e14c5/py-gfm-0.1.3.tar.gz";
1299 md5 = "e588d9e69640a241b97e2c59c22527a6";
1339 1300 };
1340 1301 meta = {
1341 1302 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -1433,26 +1394,26 b''
1433 1394 };
1434 1395 };
1435 1396 pyramid-debugtoolbar = super.buildPythonPackage {
1436 name = "pyramid-debugtoolbar-4.2.1";
1397 name = "pyramid-debugtoolbar-4.3";
1437 1398 buildInputs = with self; [];
1438 1399 doCheck = false;
1439 1400 propagatedBuildInputs = with self; [pyramid pyramid-mako repoze.lru Pygments ipaddress];
1440 1401 src = fetchurl {
1441 url = "https://pypi.python.org/packages/db/26/94620b7752936e2cd74838263ff366db9b454f7394bfb62d1eb2f84b29c1/pyramid_debugtoolbar-4.2.1.tar.gz";
1442 md5 = "3dfaced2fab1644ff5284017be9d92b9";
1402 url = "https://pypi.python.org/packages/a4/40/f09d8800bfc3c09bdb6c95f37bb61c890dc62c19c4e7caa304da7aa77403/pyramid_debugtoolbar-4.3.tar.gz";
1403 md5 = "9c49029e9f0695130499ef6416ffaaf8";
1443 1404 };
1444 1405 meta = {
1445 1406 license = [ { fullName = "Repoze Public License"; } pkgs.lib.licenses.bsdOriginal ];
1446 1407 };
1447 1408 };
1448 1409 pyramid-jinja2 = super.buildPythonPackage {
1449 name = "pyramid-jinja2-2.5";
1410 name = "pyramid-jinja2-2.7";
1450 1411 buildInputs = with self; [];
1451 1412 doCheck = false;
1452 1413 propagatedBuildInputs = with self; [pyramid zope.deprecation Jinja2 MarkupSafe];
1453 1414 src = fetchurl {
1454 url = "https://pypi.python.org/packages/a1/80/595e26ffab7deba7208676b6936b7e5a721875710f982e59899013cae1ed/pyramid_jinja2-2.5.tar.gz";
1455 md5 = "07cb6547204ac5e6f0b22a954ccee928";
1415 url = "https://pypi.python.org/packages/d8/80/d60a7233823de22ce77bd864a8a83736a1fe8b49884b08303a2e68b2c853/pyramid_jinja2-2.7.tar.gz";
1416 md5 = "c2f8b2cd7b73a6f1d9a311fcfaf4fb92";
1456 1417 };
1457 1418 meta = {
1458 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 1448 pytest = super.buildPythonPackage {
1488 name = "pytest-3.1.2";
1449 name = "pytest-3.2.5";
1489 1450 buildInputs = with self; [];
1490 1451 doCheck = false;
1491 1452 propagatedBuildInputs = with self; [py setuptools];
1492 1453 src = fetchurl {
1493 url = "https://pypi.python.org/packages/72/2b/2d3155e01f45a5a04427857352ee88220ee39550b2bc078f9db3190aea46/pytest-3.1.2.tar.gz";
1494 md5 = "c4d179f89043cc925e1c169d03128e02";
1454 url = "https://pypi.python.org/packages/1f/f8/8cd74c16952163ce0db0bd95fdd8810cbf093c08be00e6e665ebf0dc3138/pytest-3.2.5.tar.gz";
1455 md5 = "6dbe9bb093883f75394a689a1426ac6f";
1495 1456 };
1496 1457 meta = {
1497 1458 license = [ pkgs.lib.licenses.mit ];
@@ -1524,39 +1485,39 b''
1524 1485 };
1525 1486 };
1526 1487 pytest-profiling = super.buildPythonPackage {
1527 name = "pytest-profiling-1.2.6";
1488 name = "pytest-profiling-1.2.11";
1528 1489 buildInputs = with self; [];
1529 1490 doCheck = false;
1530 1491 propagatedBuildInputs = with self; [six pytest gprof2dot];
1531 1492 src = fetchurl {
1532 url = "https://pypi.python.org/packages/f9/0d/df67fb9ce16c2cef201693da956321b1bccfbf9a4ead39748b9f9d1d74cb/pytest-profiling-1.2.6.tar.gz";
1533 md5 = "50eb4c66c3762a2f1a49669bedc0b894";
1493 url = "https://pypi.python.org/packages/c0/4a/b4aa786e93c07a86f1f87c581a36bf355a9e06a9da7e00dbd05047626bd2/pytest-profiling-1.2.11.tar.gz";
1494 md5 = "9ef6b60248731be5d44477980408e8f7";
1534 1495 };
1535 1496 meta = {
1536 1497 license = [ pkgs.lib.licenses.mit ];
1537 1498 };
1538 1499 };
1539 1500 pytest-runner = super.buildPythonPackage {
1540 name = "pytest-runner-2.11.1";
1501 name = "pytest-runner-3.0";
1541 1502 buildInputs = with self; [];
1542 1503 doCheck = false;
1543 1504 propagatedBuildInputs = with self; [];
1544 1505 src = fetchurl {
1545 url = "https://pypi.python.org/packages/9e/4d/08889e5e27a9f5d6096b9ad257f4dea1faabb03c5ded8f665ead448f5d8a/pytest-runner-2.11.1.tar.gz";
1546 md5 = "bdb73eb18eca2727944a2dcf963c5a81";
1506 url = "https://pypi.python.org/packages/65/b4/ae89338cd2d81e2cc54bd6db2e962bfe948f612303610d68ab24539ac2d1/pytest-runner-3.0.tar.gz";
1507 md5 = "8f8363a52bbabc4cedd5e239beb2ba11";
1547 1508 };
1548 1509 meta = {
1549 1510 license = [ pkgs.lib.licenses.mit ];
1550 1511 };
1551 1512 };
1552 1513 pytest-sugar = super.buildPythonPackage {
1553 name = "pytest-sugar-0.8.0";
1514 name = "pytest-sugar-0.9.0";
1554 1515 buildInputs = with self; [];
1555 1516 doCheck = false;
1556 1517 propagatedBuildInputs = with self; [pytest termcolor];
1557 1518 src = fetchurl {
1558 url = "https://pypi.python.org/packages/a5/b0/b2773dee078f17773a5bf2dfad49b0be57b6354bbd84bbefe4313e509d87/pytest-sugar-0.8.0.tar.gz";
1559 md5 = "8cafbdad648068e0e44b8fc5f9faae42";
1519 url = "https://pypi.python.org/packages/49/d8/c5ff6cca3ce2ebd8b73eec89779bf6b4a7737456a70e8ea4d44c1ff90f71/pytest-sugar-0.9.0.tar.gz";
1520 md5 = "89fbff17277fa6a95a560a04b68cb9f9";
1560 1521 };
1561 1522 meta = {
1562 1523 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -1576,16 +1537,16 b''
1576 1537 };
1577 1538 };
1578 1539 python-dateutil = super.buildPythonPackage {
1579 name = "python-dateutil-2.1";
1540 name = "python-dateutil-2.6.1";
1580 1541 buildInputs = with self; [];
1581 1542 doCheck = false;
1582 1543 propagatedBuildInputs = with self; [six];
1583 1544 src = fetchurl {
1584 url = "https://pypi.python.org/packages/65/52/9c18dac21f174ad31b65e22d24297864a954e6fe65876eba3f5773d2da43/python-dateutil-2.1.tar.gz";
1585 md5 = "1534bb15cf311f07afaa3aacba1c028b";
1545 url = "https://pypi.python.org/packages/54/bb/f1db86504f7a49e1d9b9301531181b00a1c7325dc85a29160ee3eaa73a54/python-dateutil-2.6.1.tar.gz";
1546 md5 = "db38f6b4511cefd76014745bb0cc45a4";
1586 1547 };
1587 1548 meta = {
1588 license = [ { fullName = "Simplified BSD"; } ];
1549 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "Simplified BSD"; } ];
1589 1550 };
1590 1551 };
1591 1552 python-editor = super.buildPythonPackage {
@@ -1602,13 +1563,13 b''
1602 1563 };
1603 1564 };
1604 1565 python-ldap = super.buildPythonPackage {
1605 name = "python-ldap-2.4.40";
1566 name = "python-ldap-2.4.45";
1606 1567 buildInputs = with self; [];
1607 1568 doCheck = false;
1608 1569 propagatedBuildInputs = with self; [setuptools];
1609 1570 src = fetchurl {
1610 url = "https://pypi.python.org/packages/4a/d8/7d70a7469058a3987d224061a81d778951ac2b48220bdcc511e4b1b37176/python-ldap-2.4.40.tar.gz";
1611 md5 = "aea0233f7d39b0c7549fcd310deeb0e5";
1571 url = "https://pypi.python.org/packages/ce/52/6b5372d0166820f4a4b0a88ed73dc7504219355049fc1d266d8ccdb7942e/python-ldap-2.4.45.tar.gz";
1572 md5 = "6108e189a44eea8bc7d1cc281c222978";
1612 1573 };
1613 1574 meta = {
1614 1575 license = [ pkgs.lib.licenses.psfl ];
@@ -1641,13 +1602,13 b''
1641 1602 };
1642 1603 };
1643 1604 pytz = super.buildPythonPackage {
1644 name = "pytz-2015.4";
1605 name = "pytz-2017.3";
1645 1606 buildInputs = with self; [];
1646 1607 doCheck = false;
1647 1608 propagatedBuildInputs = with self; [];
1648 1609 src = fetchurl {
1649 url = "https://pypi.python.org/packages/7e/1a/f43b5c92df7b156822030fed151327ea096bcf417e45acc23bd1df43472f/pytz-2015.4.zip";
1650 md5 = "233f2a2b370d03f9b5911700cc9ebf3c";
1610 url = "https://pypi.python.org/packages/60/88/d3152c234da4b2a1f7a989f89609ea488225eaea015bc16fbde2b3fdfefa/pytz-2017.3.zip";
1611 md5 = "7006b56c0d68a162d9fe57d4249c3171";
1651 1612 };
1652 1613 meta = {
1653 1614 license = [ pkgs.lib.licenses.mit ];
@@ -1693,13 +1654,13 b''
1693 1654 };
1694 1655 };
1695 1656 repoze.lru = super.buildPythonPackage {
1696 name = "repoze.lru-0.6";
1657 name = "repoze.lru-0.7";
1697 1658 buildInputs = with self; [];
1698 1659 doCheck = false;
1699 1660 propagatedBuildInputs = with self; [];
1700 1661 src = fetchurl {
1701 url = "https://pypi.python.org/packages/6e/1e/aa15cc90217e086dc8769872c8778b409812ff036bf021b15795638939e4/repoze.lru-0.6.tar.gz";
1702 md5 = "2c3b64b17a8e18b405f55d46173e14dd";
1662 url = "https://pypi.python.org/packages/12/bc/595a77c4b5e204847fdf19268314ef59c85193a9dc9f83630fc459c0fee5/repoze.lru-0.7.tar.gz";
1663 md5 = "c08cc030387e0b1fc53c5c7d964b35e2";
1703 1664 };
1704 1665 meta = {
1705 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 1682 rhodecode-enterprise-ce = super.buildPythonPackage {
1722 name = "rhodecode-enterprise-ce-4.10.6";
1683 name = "rhodecode-enterprise-ce-4.11.0";
1723 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 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 1687 src = ./.;
1727 1688 meta = {
1728 1689 license = [ { fullName = "Affero GNU General Public License v3 or later (AGPLv3+)"; } { fullName = "AGPLv3, and Commercial License"; } ];
1729 1690 };
1730 1691 };
1731 1692 rhodecode-tools = super.buildPythonPackage {
1732 name = "rhodecode-tools-0.13.1";
1693 name = "rhodecode-tools-0.14.1";
1733 1694 buildInputs = with self; [];
1734 1695 doCheck = false;
1735 1696 propagatedBuildInputs = with self; [click future six Mako MarkupSafe requests elasticsearch elasticsearch-dsl urllib3 Whoosh];
1736 1697 src = fetchurl {
1737 url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.13.1.tar.gz?md5=f72add4690c9b341f87127a0a79573ae";
1738 md5 = "f72add4690c9b341f87127a0a79573ae";
1698 url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.14.1.tar.gz?md5=0b9c2caad160b68889f8172ea54af7b2";
1699 md5 = "0b9c2caad160b68889f8172ea54af7b2";
1739 1700 };
1740 1701 meta = {
1741 1702 license = [ { fullName = "AGPLv3 and Proprietary"; } ];
1742 1703 };
1743 1704 };
1744 1705 scandir = super.buildPythonPackage {
1745 name = "scandir-1.5";
1706 name = "scandir-1.6";
1746 1707 buildInputs = with self; [];
1747 1708 doCheck = false;
1748 1709 propagatedBuildInputs = with self; [];
1749 1710 src = fetchurl {
1750 url = "https://pypi.python.org/packages/bd/f4/3143e0289faf0883228017dbc6387a66d0b468df646645e29e1eb89ea10e/scandir-1.5.tar.gz";
1751 md5 = "a2713043de681bba6b084be42e7a8a44";
1711 url = "https://pypi.python.org/packages/77/3f/916f524f50ee65e3f465a280d2851bd63685250fddb3020c212b3977664d/scandir-1.6.tar.gz";
1712 md5 = "0180ddb97c96cbb2d4f25d2ae11c64ac";
1752 1713 };
1753 1714 meta = {
1754 1715 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "New BSD License"; } ];
1755 1716 };
1756 1717 };
1757 1718 setproctitle = super.buildPythonPackage {
1758 name = "setproctitle-1.1.8";
1719 name = "setproctitle-1.1.10";
1759 1720 buildInputs = with self; [];
1760 1721 doCheck = false;
1761 1722 propagatedBuildInputs = with self; [];
1762 1723 src = fetchurl {
1763 url = "https://pypi.python.org/packages/33/c3/ad367a4f4f1ca90468863ae727ac62f6edb558fc09a003d344a02cfc6ea6/setproctitle-1.1.8.tar.gz";
1764 md5 = "728f4c8c6031bbe56083a48594027edd";
1724 url = "https://pypi.python.org/packages/5a/0d/dc0d2234aacba6cf1a729964383e3452c52096dc695581248b548786f2b3/setproctitle-1.1.10.tar.gz";
1725 md5 = "2dcdd1b761700a5a13252fea3dfd1977";
1765 1726 };
1766 1727 meta = {
1767 1728 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -1781,13 +1742,13 b''
1781 1742 };
1782 1743 };
1783 1744 setuptools-scm = super.buildPythonPackage {
1784 name = "setuptools-scm-1.15.0";
1745 name = "setuptools-scm-1.15.6";
1785 1746 buildInputs = with self; [];
1786 1747 doCheck = false;
1787 1748 propagatedBuildInputs = with self; [];
1788 1749 src = fetchurl {
1789 url = "https://pypi.python.org/packages/80/b7/31b6ae5fcb188e37f7e31abe75f9be90490a5456a72860fa6e643f8a3cbc/setuptools_scm-1.15.0.tar.gz";
1790 md5 = "b6916c78ed6253d6602444fad4279c5b";
1750 url = "https://pypi.python.org/packages/03/6d/aafdd01edd227ee879b691455bf19895091872af7e48192bea1758c82032/setuptools_scm-1.15.6.tar.gz";
1751 md5 = "f17493d53f0d842bb0152f214775640b";
1791 1752 };
1792 1753 meta = {
1793 1754 license = [ pkgs.lib.licenses.mit ];
@@ -1820,13 +1781,13 b''
1820 1781 };
1821 1782 };
1822 1783 six = super.buildPythonPackage {
1823 name = "six-1.9.0";
1784 name = "six-1.11.0";
1824 1785 buildInputs = with self; [];
1825 1786 doCheck = false;
1826 1787 propagatedBuildInputs = with self; [];
1827 1788 src = fetchurl {
1828 url = "https://pypi.python.org/packages/16/64/1dc5e5976b17466fd7d712e59cbe9fb1e18bec153109e5ba3ed6c9102f1a/six-1.9.0.tar.gz";
1829 md5 = "476881ef4012262dfc8adc645ee786c4";
1789 url = "https://pypi.python.org/packages/16/d8/bc6316cf98419719bd59c91742194c111b6f2e85abac88e496adefaf7afe/six-1.11.0.tar.gz";
1790 md5 = "d12789f9baf7e9fb2524c0c64f1773f8";
1830 1791 };
1831 1792 meta = {
1832 1793 license = [ pkgs.lib.licenses.mit ];
@@ -1911,13 +1872,13 b''
1911 1872 };
1912 1873 };
1913 1874 transifex-client = super.buildPythonPackage {
1914 name = "transifex-client-0.10";
1875 name = "transifex-client-0.12.5";
1915 1876 buildInputs = with self; [];
1916 1877 doCheck = false;
1917 propagatedBuildInputs = with self; [];
1878 propagatedBuildInputs = with self; [urllib3 six];
1918 1879 src = fetchurl {
1919 url = "https://pypi.python.org/packages/f3/4e/7b925192aee656fb3e04fa6381c8b3dc40198047c3b4a356f6cfd642c809/transifex-client-0.10.tar.gz";
1920 md5 = "5549538d84b8eede6b254cd81ae024fa";
1880 url = "https://pypi.python.org/packages/7b/86/60f31a0c9b8d0b1266ce15b6c80b55f88522140c8acfc395d5aec5e23475/transifex-client-0.12.5.tar.gz";
1881 md5 = "e6e278117b23f60702c06e203b7e51ae";
1921 1882 };
1922 1883 meta = {
1923 1884 license = [ pkgs.lib.licenses.gpl2 ];
@@ -1988,14 +1949,27 b''
1988 1949 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1989 1950 };
1990 1951 };
1991 waitress = super.buildPythonPackage {
1992 name = "waitress-1.0.2";
1952 vine = super.buildPythonPackage {
1953 name = "vine-1.1.4";
1993 1954 buildInputs = with self; [];
1994 1955 doCheck = false;
1995 1956 propagatedBuildInputs = with self; [];
1996 1957 src = fetchurl {
1997 url = "https://pypi.python.org/packages/cd/f4/400d00863afa1e03618e31fd7e2092479a71b8c9718b00eb1eeb603746c6/waitress-1.0.2.tar.gz";
1998 md5 = "b968f39e95d609f6194c6e50425d4bb7";
1958 url = "https://pypi.python.org/packages/32/23/36284986e011f3c130d802c3c66abd8f1aef371eae110ddf80c5ae22e1ff/vine-1.1.4.tar.gz";
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 1974 meta = {
2001 1975 license = [ pkgs.lib.licenses.zpt21 ];
@@ -2014,14 +1988,27 b''
2014 1988 license = [ pkgs.lib.licenses.mit ];
2015 1989 };
2016 1990 };
2017 ws4py = super.buildPythonPackage {
2018 name = "ws4py-0.3.5";
1991 webencodings = super.buildPythonPackage {
1992 name = "webencodings-0.5.1";
2019 1993 buildInputs = with self; [];
2020 1994 doCheck = false;
2021 1995 propagatedBuildInputs = with self; [];
2022 1996 src = fetchurl {
2023 url = "https://pypi.python.org/packages/b6/4f/34af703be86939629479e74d6e650e39f3bd73b3b09212c34e5125764cbc/ws4py-0.3.5.zip";
2024 md5 = "a261b75c20b980e55ce7451a3576a867";
1997 url = "https://pypi.python.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz";
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 2013 meta = {
2027 2014 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -1,12 +1,12 b''
1 1 [pytest]
2 testpaths = ./rhodecode
3 pylons_config = rhodecode/tests/rhodecode.ini
2 testpaths = rhodecode
3 norecursedirs = rhodecode/public rhodecode/templates tests/scripts
4
5 pyramid_config = rhodecode/tests/rhodecode.ini
4 6 vcsserver_protocol = http
5 7 vcsserver_config_http = rhodecode/tests/vcsserver_http.ini
6 norecursedirs = tests/scripts
7 8
8 9 addopts =
9 -k "not _BaseTest"
10 10 --pdbcls=IPython.terminal.debugger:TerminalPdb
11 11
12 12 markers =
@@ -1,51 +1,49 b''
1 1 ## core
2 2 setuptools==30.1.0
3 setuptools-scm==1.15.0
3 setuptools-scm==1.15.6
4 4
5 amqplib==1.0.2
6 anyjson==0.3.3
5 amqp==2.2.2
7 6 authomatic==0.1.0.post1
8 7 Babel==1.3
9 8 Beaker==1.9.0
10 celery==2.2.10
9 celery==4.1.0
11 10 Chameleon==2.24
12 11 channelstream==0.5.2
13 click==5.1
14 colander==1.3.3
12 click==6.6
13 colander==1.4.0
15 14 configobj==5.0.6
16 15 cssselect==1.0.1
17 decorator==4.0.11
16 decorator==4.1.2
18 17 deform==2.0.4
19 docutils==0.13.1
18 docutils==0.14.0
20 19 dogpile.cache==0.6.4
21 20 dogpile.core==0.4.1
22 21 ecdsa==0.13
23 22 FormEncode==1.2.4
24 23 future==0.14.3
25 24 futures==3.0.2
26 gnureadline==6.3.3
25 gnureadline==6.3.8
27 26 infrae.cache==1.0.1
28 iso8601==0.1.11
27 iso8601==0.1.12
29 28 itsdangerous==0.24
30 Jinja2==2.7.3
31 kombu==1.5.1
29 Jinja2==2.9.6
30 billiard==3.5.0.3
31 kombu==4.1.0
32 32 lxml==3.7.3
33 33 Mako==1.0.7
34 Markdown==2.6.8
35 MarkupSafe==0.23
36 meld3==1.0.2
34 Markdown==2.6.9
35 MarkupSafe==1.0.0
37 36 msgpack-python==0.4.8
38 37 MySQL-python==1.2.5
39 nose==1.3.6
40 objgraph==3.1.0
38 objgraph==3.1.1
41 39 packaging==15.2
42 40 Paste==2.0.3
43 41 PasteDeploy==1.5.2
44 PasteScript==1.7.5
42 PasteScript==2.0.2
45 43 pathlib2==2.3.0
46 44 peppercorn==0.5
47 psutil==4.3.1
48 psycopg2==2.7.1
45 psutil==5.4.0
46 psycopg2==2.7.3.2
49 47 py-bcrypt==0.4
50 48 pycrypto==2.6.1
51 49 pycurl==7.19.5
@@ -54,27 +52,27 b' pygments-markdown-lexer==0.1.0.dev39'
54 52 Pygments==2.2.0
55 53 pyparsing==1.5.7
56 54 pyramid-beaker==0.8
57 pyramid-debugtoolbar==4.2.1
58 pyramid-jinja2==2.5
55 pyramid-debugtoolbar==4.3.0
56 pyramid-jinja2==2.7
59 57 pyramid-mako==1.0.2
60 58 pyramid==1.9.1
61 59 pysqlite==2.8.3
62 python-dateutil==2.1
63 python-ldap==2.4.40
60 python-dateutil
61 python-ldap==2.4.45
64 62 python-memcached==1.58
65 63 python-pam==1.8.2
66 pytz==2015.4
64 pytz==2017.3
67 65 pyzmq==14.6.0
66 py-gfm==0.1.3
68 67 recaptcha-client==1.0.6
69 68 redis==2.10.6
70 repoze.lru==0.6
69 repoze.lru==0.7
71 70 requests==2.9.1
72 Routes==1.13
73 setproctitle==1.1.8
71 Routes==2.4.1
72 setproctitle==1.1.10
74 73 simplejson==3.11.1
75 six==1.9.0
76 Sphinx==1.2.2
77 SQLAlchemy==1.1.11
74 six==1.11.0
75 SQLAlchemy==1.1.15
78 76 sshpubkeys==2.2.0
79 77 subprocess32==3.2.7
80 78 supervisor==3.3.3
@@ -95,44 +93,39 b' zope.deprecation==4.1.2'
95 93 zope.event==4.0.3
96 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 97 # IPYTHON RENDERING
105 98 # entrypoints backport, pypi version doesn't support egg installs
106 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
108 bleach==1.5.0
109 nbformat==4.3.0
100 nbconvert==5.3.1
101 bleach==2.1.1
102 nbformat==4.4.0
110 103 jupyter_client==5.0.0
111 104
112 105 ## cli tools
113 alembic==0.9.2
106 alembic==0.9.6
114 107 invoke==0.13.0
115 108 bumpversion==0.5.3
116 transifex-client==0.10
109 transifex-client==0.12.5
117 110
118 111 ## http servers
119 112 gevent==1.2.2
120 113 greenlet==0.4.12
121 114 gunicorn==19.7.1
122 waitress==1.0.2
115 waitress==1.1.0
123 116 uWSGI==2.0.15
124 117
125 118 ## debug
126 119 ipdb==0.10.3
127 120 ipython==5.1.0
128 121 CProfileV==1.0.7
129 bottle==0.12.8
122 bottle==0.12.13
130 123
131 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 127 ## appenlight
135 appenlight-client==0.6.21
128 appenlight-client==0.6.22
136 129
137 130 ## test related requirements
138 131 -r requirements_test.txt
@@ -1,15 +1,15 b''
1 1 # test related requirements
2 pytest==3.1.2
3 py==1.4.34
2 pytest==3.2.5
3 py==1.5.2
4 4 pytest-cov==2.5.1
5 pytest-sugar==0.8.0
6 pytest-runner==2.11.1
5 pytest-sugar==0.9.0
6 pytest-runner==3.0.0
7 7 pytest-catchlog==1.2.2
8 pytest-profiling==1.2.6
9 gprof2dot==2016.10.13
8 pytest-profiling==1.2.11
9 gprof2dot==2017.9.19
10 10 pytest-timeout==1.2.0
11 11
12 12 mock==1.0.1
13 WebTest==2.0.27
13 WebTest==2.0.29
14 14 cov-core==1.15.0
15 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 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -40,7 +40,7 b' BACKENDS = {'
40 40 CELERY_ENABLED = False
41 41 CELERY_EAGER = False
42 42
43 # link to config for pylons
43 # link to config for pyramid
44 44 CONFIG = {}
45 45
46 46 # Populated with the settings dictionary from application init in
@@ -51,7 +51,7 b' PYRAMID_SETTINGS = {}'
51 51 EXTENSIONS = {}
52 52
53 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 55 __platform__ = platform.system()
56 56 __license__ = 'AGPLv3, and Commercial License'
57 57 __author__ = 'RhodeCode GmbH'
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 29 @pytest.fixture(scope="class")
30 def testuser_api(request, pylonsapp):
30 def testuser_api(request, baseapp):
31 31 cls = request.cls
32 32
33 33 # ADMIN USER
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -86,7 +86,7 b' class TestApi(object):'
86 86 def test_api_non_existing_method_have_similar(self, request):
87 87 id_, params = build_data(self.apikey, 'comment', args='xx')
88 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 90 assert_error(id_, expected, given=response.body)
91 91
92 92 def test_api_disabled_user(self, request):
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -70,10 +70,11 b' class TestClosePullRequest(object):'
70 70 assert_error(id_, expected, given=response.body)
71 71
72 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 75 id_, params = build_data(
75 76 self.apikey, 'close_pull_request',
76 repoid=666, pullrequestid=1)
77 repoid=666, pullrequestid=pull_request.pull_request_id)
77 78 response = api_call(self.app, params)
78 79
79 80 expected = 'repository `666` does not exist'
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -170,10 +170,11 b' class TestCommentPullRequest(object):'
170 170 assert_error(id_, expected, given=response.body)
171 171
172 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 175 id_, params = build_data(
175 176 self.apikey, 'comment_pull_request',
176 repoid=666, pullrequestid=1)
177 repoid=666, pullrequestid=pull_request.pull_request_id)
177 178 response = api_call(self.app, params)
178 179
179 180 expected = 'repository `666` does not exist'
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -38,11 +38,12 b' class TestGetMethod(object):'
38 38 response = api_call(self.app, params)
39 39
40 40 expected = ['changeset_comment', 'comment_pull_request',
41 'comment_commit']
41 'get_pull_request_comments', 'comment_commit']
42 42 assert_ok(id_, expected, given=response.body)
43 43
44 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 47 response = api_call(self.app, params)
47 48
48 49 expected = ['comment_commit',
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -38,7 +38,6 b' class TestGetPullRequest(object):'
38 38 pull_request = pr_util.create_pull_request(mergeable=True)
39 39 id_, params = build_data(
40 40 self.apikey, 'get_pull_request',
41 repoid=pull_request.target_repo.repo_name,
42 41 pullrequestid=pull_request.pull_request_id)
43 42
44 43 response = api_call(self.app, params)
@@ -109,16 +108,17 b' class TestGetPullRequest(object):'
109 108 'reasons': reasons,
110 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 112 pull_request.reviewers_statuses()
114 113 ]
115 114 }
116 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 119 id_, params = build_data(
120 120 self.apikey, 'get_pull_request',
121 repoid=666, pullrequestid=1)
121 repoid=666, pullrequestid=pull_request.pull_request_id)
122 122 response = api_call(self.app, params)
123 123
124 124 expected = 'repository `666` does not exist'
@@ -126,9 +126,17 b' class TestGetPullRequest(object):'
126 126
127 127 def test_api_get_pull_request_pull_request_error(self):
128 128 id_, params = build_data(
129 self.apikey, 'get_pull_request',
130 repoid=1, pullrequestid=666)
129 self.apikey, 'get_pull_request', pullrequestid=666)
131 130 response = api_call(self.app, params)
132 131
133 132 expected = 'pull request `666` does not exist'
134 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 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -68,7 +68,6 b' class TestGetRepo(object):'
68 68 followers.append(user.user.get_api_data(
69 69 include_secrets=expect_secrets))
70 70
71 ret['members'] = permissions
72 71 ret['permissions'] = permissions
73 72 ret['followers'] = followers
74 73
@@ -106,7 +105,6 b' class TestGetRepo(object):'
106 105 for user in repo.followers:
107 106 followers.append(user.user.get_api_data())
108 107
109 ret['members'] = permissions
110 108 ret['permissions'] = permissions
111 109 ret['followers'] = followers
112 110
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 42 permissions = expected_permissions(repo_group)
43 43
44 ret['members'] = permissions
44 ret['permissions'] = permissions
45 45 expected = ret
46 46 assert_ok(id_, expected, given=response.body)
47 47
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 37 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
38 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 43 expected = ret
42 44 assert_ok(id_, expected, given=response.body)
@@ -54,7 +56,9 b' class TestGetUser(object):'
54 56
55 57 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
56 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 63 expected = ret
60 64 assert_ok(id_, expected, given=response.body)
@@ -65,7 +69,9 b' class TestGetUser(object):'
65 69
66 70 usr = UserModel().get_by_username(self.TEST_USER_LOGIN)
67 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 76 expected = ret
71 77 assert_ok(id_, expected, given=response.body)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 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 43 expected = ret
43 44 assert_ok(id_, expected, given=response.body)
44 45
@@ -54,7 +55,8 b' class TestGetUserGroups(object):'
54 55
55 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 60 expected = ret
59 61 assert_ok(id_, expected, given=response.body)
60 62
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -112,10 +112,11 b' class TestMergePullRequest(object):'
112 112 assert_error(id_, expected, given=response.body)
113 113
114 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 117 id_, params = build_data(
117 118 self.apikey, 'merge_pull_request',
118 repoid=666, pullrequestid=1)
119 repoid=666, pullrequestid=pull_request.pull_request_id)
119 120 response = api_call(self.app, params)
120 121
121 122 expected = 'repository `666` does not exist'
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -133,7 +133,7 b' class TestUpdatePullRequest(object):'
133 133 removed = [a.username]
134 134
135 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 138 id_, params = build_data(
139 139 self.apikey, 'update_pull_request',
@@ -168,10 +168,11 b' class TestUpdatePullRequest(object):'
168 168
169 169 @pytest.mark.backends("git", "hg")
170 170 def test_api_update_repo_error(self, pr_util):
171 pull_request = pr_util.create_pull_request()
171 172 id_, params = build_data(
172 173 self.apikey, 'update_pull_request',
173 174 repoid='fake',
174 pullrequestid='fake',
175 pullrequestid=pull_request.pull_request_id,
175 176 reviewers=[{'username': 'bad_name'}])
176 177 response = api_call(self.app, params)
177 178
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2014-2017 RhodeCode GmbH
3 # Copyright (C) 2014-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2015-2017 RhodeCode GmbH
3 # Copyright (C) 2015-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 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 48 Get a pull request based on the given ID.
49 49
50 50 :param apiuser: This is filled automatically from the |authtoken|.
51 51 :type apiuser: AuthUser
52 :param repoid: Repository name or repository ID from where the pull
53 request was opened.
52 :param repoid: Optional, repository name or repository ID from where
53 the pull request was opened.
54 54 :type repoid: str or int
55 55 :param pullrequestid: ID of the requested pull request.
56 56 :type pullrequestid: int
@@ -121,11 +121,17 b' def get_pull_request(request, apiuser, r'
121 121 },
122 122 "error": null
123 123 """
124 get_repo_or_error(repoid)
124
125 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 131 if not PullRequestModel().check_user_read(
127 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 135 data = pull_request.get_api_data()
130 136 return data
131 137
@@ -137,7 +143,7 b' def get_pull_requests(request, apiuser, '
137 143
138 144 :param apiuser: This is filled automatically from the |authtoken|.
139 145 :type apiuser: AuthUser
140 :param repoid: Repository name or repository ID.
146 :param repoid: Optional repository name or repository ID.
141 147 :type repoid: str or int
142 148 :param status: Only return pull requests with the specified status.
143 149 Valid options are.
@@ -229,7 +235,7 b' def get_pull_requests(request, apiuser, '
229 235
230 236 @jsonrpc_method()
231 237 def merge_pull_request(
232 request, apiuser, repoid, pullrequestid,
238 request, apiuser, pullrequestid, repoid=Optional(None),
233 239 userid=Optional(OAttr('apiuser'))):
234 240 """
235 241 Merge the pull request specified by `pullrequestid` into its target
@@ -237,7 +243,7 b' def merge_pull_request('
237 243
238 244 :param apiuser: This is filled automatically from the |authtoken|.
239 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 247 target repository to which the |pr| is to be merged.
242 248 :type repoid: str or int
243 249 :param pullrequestid: ID of the pull request which shall be merged.
@@ -263,7 +269,12 b' def merge_pull_request('
263 269 },
264 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 278 if not isinstance(userid, Optional):
268 279 if (has_superadmin_permission(apiuser) or
269 280 HasRepoPermissionAnyApi('repository.admin')(
@@ -272,8 +283,6 b' def merge_pull_request('
272 283 else:
273 284 raise JSONRPCError('userid is not the same as your user')
274 285
275 pull_request = get_pull_request_or_error(pullrequestid)
276
277 286 check = MergeCheck.validate(
278 287 pull_request, user=apiuser, translator=request.translate)
279 288 merge_possible = not check.failed
@@ -311,9 +320,112 b' def merge_pull_request('
311 320
312 321
313 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 426 def comment_pull_request(
315 request, apiuser, repoid, pullrequestid, message=Optional(None),
316 commit_id=Optional(None), status=Optional(None),
427 request, apiuser, pullrequestid, repoid=Optional(None),
428 message=Optional(None), commit_id=Optional(None), status=Optional(None),
317 429 comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
318 430 resolves_comment_id=Optional(None),
319 431 userid=Optional(OAttr('apiuser'))):
@@ -324,7 +436,7 b' def comment_pull_request('
324 436
325 437 :param apiuser: This is filled automatically from the |authtoken|.
326 438 :type apiuser: AuthUser
327 :param repoid: The repository name or repository ID.
439 :param repoid: Optional repository name or repository ID.
328 440 :type repoid: str or int
329 441 :param pullrequestid: The pull request ID.
330 442 :type pullrequestid: int
@@ -356,7 +468,12 b' def comment_pull_request('
356 468 },
357 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 477 if not isinstance(userid, Optional):
361 478 if (has_superadmin_permission(apiuser) or
362 479 HasRepoPermissionAnyApi('repository.admin')(
@@ -365,7 +482,6 b' def comment_pull_request('
365 482 else:
366 483 raise JSONRPCError('userid is not the same as your user')
367 484
368 pull_request = get_pull_request_or_error(pullrequestid)
369 485 if not PullRequestModel().check_user_read(
370 486 pull_request, apiuser, api=True):
371 487 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
@@ -573,15 +689,15 b' def create_pull_request('
573 689
574 690 @jsonrpc_method()
575 691 def update_pull_request(
576 request, apiuser, repoid, pullrequestid, title=Optional(''),
577 description=Optional(''), reviewers=Optional(None),
692 request, apiuser, pullrequestid, repoid=Optional(None),
693 title=Optional(''), description=Optional(''), reviewers=Optional(None),
578 694 update_commits=Optional(None)):
579 695 """
580 696 Updates a pull request.
581 697
582 698 :param apiuser: This is filled automatically from the |authtoken|.
583 699 :type apiuser: AuthUser
584 :param repoid: The repository name or repository ID.
700 :param repoid: Optional repository name or repository ID.
585 701 :type repoid: str or int
586 702 :param pullrequestid: The pull request ID.
587 703 :type pullrequestid: int
@@ -626,8 +742,12 b' def update_pull_request('
626 742 error : null
627 743 """
628 744
629 repo = get_repo_or_error(repoid)
630 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 751 if not PullRequestModel().check_user_update(
632 752 pull_request, apiuser, api=True):
633 753 raise JSONRPCError(
@@ -705,7 +825,7 b' def update_pull_request('
705 825
706 826 @jsonrpc_method()
707 827 def close_pull_request(
708 request, apiuser, repoid, pullrequestid,
828 request, apiuser, pullrequestid, repoid=Optional(None),
709 829 userid=Optional(OAttr('apiuser')), message=Optional('')):
710 830 """
711 831 Close the pull request specified by `pullrequestid`.
@@ -738,7 +858,12 b' def close_pull_request('
738 858 """
739 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 867 if not isinstance(userid, Optional):
743 868 if (has_superadmin_permission(apiuser) or
744 869 HasRepoPermissionAnyApi('repository.admin')(
@@ -747,8 +872,6 b' def close_pull_request('
747 872 else:
748 873 raise JSONRPCError('userid is not the same as your user')
749 874
750 pull_request = get_pull_request_or_error(pullrequestid)
751
752 875 if pull_request.is_closed():
753 876 raise JSONRPCError(
754 877 'pull request `%s` is already closed' % (pullrequestid,))
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 32 from rhodecode.lib import audit_logger
33 33 from rhodecode.lib import repo_maintenance
34 34 from rhodecode.lib.auth import HasPermissionAnyApi, HasUserGroupPermissionAnyApi
35 from rhodecode.lib.celerylib.utils import get_task_id
35 36 from rhodecode.lib.utils2 import str2bool, time_to_datetime
36 37 from rhodecode.lib.ext_json import json
37 38 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
@@ -126,26 +127,6 b' def get_repo(request, apiuser, repoid, c'
126 127 "lock_reason": null,
127 128 "locked_by": null,
128 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 130 "owner": "owner-name",
150 131 "permissions": [
151 132 {
@@ -213,7 +194,6 b' def get_repo(request, apiuser, repoid, c'
213 194 if not cache:
214 195 repo.update_commit_cache()
215 196 data = repo.get_api_data(include_secrets=include_secrets)
216 data['members'] = permissions # TODO: this should be deprecated soon
217 197 data['permissions'] = permissions
218 198 data['followers'] = following_users
219 199 return data
@@ -340,11 +320,7 b' def get_repo_changeset(request, apiuser,'
340 320 _cs_json = cs.__json__()
341 321 _cs_json['diff'] = build_commit_data(cs, changes_details)
342 322 if changes_details == 'full':
343 _cs_json['refs'] = {
344 'branches': [cs.branch],
345 'bookmarks': getattr(cs, 'bookmarks', []),
346 'tags': cs.tags
347 }
323 _cs_json['refs'] = cs._get_refs()
348 324 return _cs_json
349 325
350 326
@@ -716,10 +692,7 b' def create_repo('
716 692 }
717 693
718 694 task = RepoModel().create(form_data=data, cur_user=owner)
719 from celery.result import BaseAsyncResult
720 task_id = None
721 if isinstance(task, BaseAsyncResult):
722 task_id = task.task_id
695 task_id = get_task_id(task)
723 696 # no commit, it's done in RepoModel, or async via celery
724 697 return {
725 698 'msg': "Created new repository `%s`" % (schema_data['repo_name'],),
@@ -915,7 +888,8 b' def update_repo('
915 888 repo_enable_downloads=enable_downloads
916 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 894 old_values = repo.get_api_data()
921 895 schema = repo_schema.RepoSchema().bind(
@@ -1108,10 +1082,8 b' def fork_repo(request, apiuser, repoid, '
1108 1082
1109 1083 task = RepoModel().create_fork(data, cur_user=owner)
1110 1084 # no commit, it's done in RepoModel, or async via celery
1111 from celery.result import BaseAsyncResult
1112 task_id = None
1113 if isinstance(task, BaseAsyncResult):
1114 task_id = task.task_id
1085 task_id = get_task_id(task)
1086
1115 1087 return {
1116 1088 'msg': 'Created fork of `%s` as `%s`' % (
1117 1089 repo.repo_name, schema_data['repo_name']),
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 63 "group_description": "repo group description",
64 64 "group_id": 14,
65 65 "group_name": "group name",
66 "members": [
66 "permissions": [
67 67 {
68 68 "name": "super-admin-username",
69 69 "origin": "super-admin",
@@ -119,7 +119,7 b' def get_repo_group(request, apiuser, rep'
119 119 permissions.append(user_group_data)
120 120
121 121 data = repo_group.get_api_data()
122 data["members"] = permissions # TODO: this should be named permissions
122 data["permissions"] = permissions
123 123 return data
124 124
125 125
@@ -221,7 +221,7 b' def create_repo_group('
221 221 repo_group = RepoGroupModel().create(
222 222 owner=owner,
223 223 group_name=validated_group_name,
224 group_description=schema_data['repo_group_name'],
224 group_description=schema_data['repo_group_description'],
225 225 copy_permissions=schema_data['repo_group_copy_permissions'])
226 226 Session().flush()
227 227
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 79 "last_login": "Timestamp",
80 80 "last_activity": "Timestamp",
81 81 "lastname": "surnae",
82 "permissions": {
82 "permissions": <deprecated>,
83 "permissions_summary": {
83 84 "global": [
84 85 "hg.inherit_default_perms.true",
85 86 "usergroup.read",
@@ -97,7 +98,7 b' def get_user(request, apiuser, userid=Op'
97 98 "repositories": { "username/example": "repository.write"},
98 99 "repositories_groups": { "user-group/repo": "group.none" },
99 100 "user_groups": { "user_group_name": "usergroup.read" }
100 },
101 }
101 102 "user_id": 32,
102 103 "username": "username"
103 104 }
@@ -115,7 +116,9 b' def get_user(request, apiuser, userid=Op'
115 116
116 117 user = get_user_or_error(userid)
117 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 122 return data
120 123
121 124
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 61 "active": true,
62 62 "group_description": "group description",
63 63 "group_name": "group name",
64 "members": [
64 "permissions": [
65 65 {
66 66 "name": "owner-name",
67 67 "origin": "owner",
@@ -82,6 +82,12 b' def get_user_group(request, apiuser, use'
82 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 91 "owner": "owner name",
86 92 "users": [],
87 93 "users_group_id": 2
@@ -119,8 +125,9 b' def get_user_group(request, apiuser, use'
119 125 permissions.append(user_group_data)
120 126
121 127 data = user_group.get_api_data()
122 data['members'] = permissions
123
128 data["permissions"] = permissions
129 data["permissions_summary"] = UserGroupModel().get_perms_summary(
130 user_group.users_group_id)
124 131 return data
125 132
126 133
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -147,46 +147,26 b' class BaseAppView(object):'
147 147 % repo_name)
148 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 151 c = TemplateArgs()
152 152 c.auth_user = self.request.user
153 153 # TODO(marcink): migrate the usage of c.rhodecode_user to c.auth_user
154 154 c.rhodecode_user = self.request.user
155 155
156 156 if include_app_defaults:
157 # NOTE(marcink): after full pyramid migration include_app_defaults
158 # should be turned on by default
159 157 from rhodecode.lib.base import attach_context_attributes
160 158 attach_context_attributes(c, self.request, self.request.user.user_id)
161 159
162 160 return c
163 161
164 def _register_global_c(self, tmpl_args):
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)
162 def _get_template_context(self, tmpl_args, **kwargs):
180 163
181 164 local_tmpl_args = {
182 165 'defaults': {},
183 166 'errors': {},
184 # register a fake 'c' to be used in templates instead of global
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
167 'c': tmpl_args
188 168 }
189 local_tmpl_args.update(tmpl_args)
169 local_tmpl_args.update(kwargs)
190 170 return local_tmpl_args
191 171
192 172 def load_default_context(self):
@@ -196,7 +176,7 b' class BaseAppView(object):'
196 176 def load_default_context(self):
197 177 c = self._get_local_tmpl_context()
198 178 c.custom_var = 'foobar'
199 self._register_global_c(c)
179
200 180 return c
201 181 """
202 182 raise NotImplementedError('Needs implementation in view class')
@@ -215,7 +195,7 b' class RepoAppView(BaseAppView):'
215 195 'Requirements are missing for repository %s: %s',
216 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 199 _ = self.request.translate
220 200 c = super(RepoAppView, self)._get_local_tmpl_context(
221 201 include_app_defaults=include_app_defaults)
@@ -338,7 +318,7 b' class BaseReferencesView(RepoAppView):'
338 318 def load_default_context(self):
339 319 c = self._get_local_tmpl_context()
340 320
341 self._register_global_c(c)
321
342 322 return c
343 323
344 324 def load_refs_context(self, ref_items, partials_template):
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -19,9 +19,7 b''
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21
22 from rhodecode.apps.admin.navigation import NavigationRegistry
23 from rhodecode.config.routing import ADMIN_PREFIX
24 from rhodecode.lib.utils2 import str2bool
22 from rhodecode.apps._base import ADMIN_PREFIX
25 23
26 24
27 25 def admin_routes(config):
@@ -72,8 +70,14 b' def admin_routes(config):'
72 70 name='admin_settings_process_management',
73 71 pattern='/settings/process_management')
74 72 config.add_route(
73 name='admin_settings_process_management_data',
74 pattern='/settings/process_management/data')
75 config.add_route(
75 76 name='admin_settings_process_management_signal',
76 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 82 # default settings
79 83 config.add_route(
@@ -83,6 +87,88 b' def admin_routes(config):'
83 87 name='admin_defaults_repositories_update',
84 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 172 # global permissions
87 173
88 174 config.add_route(
@@ -237,7 +323,7 b' def admin_routes(config):'
237 323 config.add_route(
238 324 name='edit_user_ips_delete',
239 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 328 # user perms
243 329 config.add_route(
@@ -310,12 +396,10 b' def admin_routes(config):'
310 396
311 397
312 398 def includeme(config):
313 settings = config.get_settings()
399 from rhodecode.apps.admin.navigation import includeme as nav_includeme
314 400
315 401 # Create admin navigation registry and add it to the pyramid registry.
316 labs_active = str2bool(settings.get('labs_settings_active', False))
317 navigation_registry = NavigationRegistry(labs_active=labs_active)
318 config.registry.registerUtility(navigation_registry)
402 nav_includeme(config)
319 403
320 404 # main admin routes
321 405 config.add_route(name='admin_home', pattern=ADMIN_PREFIX)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -25,13 +25,14 b' import collections'
25 25 from zope.interface import implementer
26 26
27 27 from rhodecode.apps.admin.interfaces import IAdminNavigationRegistry
28 from rhodecode.lib.utils import get_registry
28 from rhodecode.lib.utils2 import str2bool
29 29 from rhodecode.translation import _
30 30
31 31
32 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 38 class NavEntry(object):
@@ -41,77 +42,69 b' class NavEntry(object):'
41 42 :param key: Unique identifier used to store reference in an OrderedDict.
42 43 :param name: Display name, usually a translation string.
43 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 be removed as soon as we are fully migrated to pyramid.
45 :param active_list: list of urls that we select active for this element
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 49 self.key = key
50 50 self.name = name
51 51 self.view_name = view_name
52 self.pyramid = pyramid
52 self._active_list = active_list or []
53 53
54 54 def generate_url(self, request):
55 if self.pyramid:
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)
55 return request.route_path(self.view_name)
68 56
69 57 def get_localized_name(self, request):
70 if hasattr(request, 'translate'):
71 return request.translate(self.name)
72 else:
73 # TODO(marcink): Remove this after migrating to pyramid
74 from pyramid.threadlocal import get_current_request
75 pyramid_request = get_current_request()
76 return pyramid_request.translate(self.name)
58 return request.translate(self.name)
59
60 @property
61 def active_list(self):
62 active_list = [self.key]
63 if self._active_list:
64 active_list = self._active_list
65 return active_list
77 66
78 67
79 68 @implementer(IAdminNavigationRegistry)
80 69 class NavigationRegistry(object):
81 70
82 71 _base_entries = [
83 NavEntry('global', _('Global'), 'admin_settings_global'),
84 NavEntry('vcs', _('VCS'), 'admin_settings_vcs'),
85 NavEntry('visual', _('Visual'), 'admin_settings_visual'),
86 NavEntry('mapping', _('Remap and Rescan'), 'admin_settings_mapping'),
72 NavEntry('global', _('Global'),
73 'admin_settings_global'),
74 NavEntry('vcs', _('VCS'),
75 'admin_settings_vcs'),
76 NavEntry('visual', _('Visual'),
77 'admin_settings_visual'),
78 NavEntry('mapping', _('Remap and Rescan'),
79 'admin_settings_mapping'),
87 80 NavEntry('issuetracker', _('Issue Tracker'),
88 81 'admin_settings_issuetracker'),
89 NavEntry('email', _('Email'), 'admin_settings_email'),
90 NavEntry('hooks', _('Hooks'), 'admin_settings_hooks'),
91 NavEntry('search', _('Full Text Search'), 'admin_settings_search'),
92
82 NavEntry('email', _('Email'),
83 'admin_settings_email'),
84 NavEntry('hooks', _('Hooks'),
85 'admin_settings_hooks'),
86 NavEntry('search', _('Full Text Search'),
87 'admin_settings_search'),
93 88 NavEntry('integrations', _('Integrations'),
94 'global_integrations_home', pyramid=True),
89 'global_integrations_home'),
95 90 NavEntry('system', _('System Info'),
96 'admin_settings_system', pyramid=True),
91 'admin_settings_system'),
97 92 NavEntry('process_management', _('Processes'),
98 'admin_settings_process_management', pyramid=True),
93 'admin_settings_process_management'),
99 94 NavEntry('sessions', _('User Sessions'),
100 'admin_settings_sessions', pyramid=True),
95 'admin_settings_sessions'),
101 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 104 def __init__(self, labs_active=False):
112 self._registered_entries = collections.OrderedDict([
113 (item.key, item) for item in self.__class__._base_entries
114 ])
105 self._registered_entries = collections.OrderedDict()
106 for item in self.__class__._base_entries:
107 self._registered_entries[item.key] = item
115 108
116 109 if labs_active:
117 110 self.add_entry(self._labs_entry)
@@ -121,16 +114,16 b' class NavigationRegistry(object):'
121 114
122 115 def get_navlist(self, request):
123 116 navlist = [NavListEntry(i.key, i.get_localized_name(request),
124 i.generate_url(request))
117 i.generate_url(request), i.active_list)
125 118 for i in self._registered_entries.values()]
126 119 return navlist
127 120
128 121
129 def navigation_registry(request):
122 def navigation_registry(request, registry=None):
130 123 """
131 124 Helper that returns the admin navigation registry.
132 125 """
133 pyramid_registry = get_registry(request)
126 pyramid_registry = registry or request.registry
134 127 nav_registry = pyramid_registry.queryUtility(IAdminNavigationRegistry)
135 128 return nav_registry
136 129
@@ -140,3 +133,11 b' def navigation_list(request):'
140 133 Helper that returns the admin navigation as list of NavListEntry objects.
141 134 """
142 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 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 46 return base_url
47 47
48 48
49 class TestAdminController(TestController):
49 @pytest.mark.usefixtures('app')
50 class TestAdminController(object):
50 51
51 52 @pytest.fixture(scope='class', autouse=True)
52 def prepare(self, request, pylonsapp):
53 def prepare(self, request, baseapp):
53 54 UserLog.query().delete()
54 55 Session().commit()
55 56
@@ -84,104 +85,87 b' class TestAdminController(TestController'
84 85 UserLog.query().delete()
85 86 Session().commit()
86 87
87 def test_index(self):
88 self.log_user()
88 def test_index(self, autologin_user):
89 89 response = self.app.get(route_path('admin_audit_logs'))
90 90 response.mustcontain('Admin audit logs')
91 91
92 def test_filter_all_entries(self):
93 self.log_user()
92 def test_filter_all_entries(self, autologin_user):
94 93 response = self.app.get(route_path('admin_audit_logs'))
95 94 all_count = UserLog.query().count()
96 95 response.mustcontain('%s entries' % all_count)
97 96
98 def test_filter_journal_filter_exact_match_on_repository(self):
99 self.log_user()
97 def test_filter_journal_filter_exact_match_on_repository(self, autologin_user):
100 98 response = self.app.get(route_path('admin_audit_logs',
101 99 params=dict(filter='repository:rhodecode')))
102 100 response.mustcontain('3 entries')
103 101
104 def test_filter_journal_filter_exact_match_on_repository_CamelCase(self):
105 self.log_user()
102 def test_filter_journal_filter_exact_match_on_repository_CamelCase(self, autologin_user):
106 103 response = self.app.get(route_path('admin_audit_logs',
107 104 params=dict(filter='repository:RhodeCode')))
108 105 response.mustcontain('3 entries')
109 106
110 def test_filter_journal_filter_wildcard_on_repository(self):
111 self.log_user()
107 def test_filter_journal_filter_wildcard_on_repository(self, autologin_user):
112 108 response = self.app.get(route_path('admin_audit_logs',
113 109 params=dict(filter='repository:*test*')))
114 110 response.mustcontain('862 entries')
115 111
116 def test_filter_journal_filter_prefix_on_repository(self):
117 self.log_user()
112 def test_filter_journal_filter_prefix_on_repository(self, autologin_user):
118 113 response = self.app.get(route_path('admin_audit_logs',
119 114 params=dict(filter='repository:test*')))
120 115 response.mustcontain('257 entries')
121 116
122 def test_filter_journal_filter_prefix_on_repository_CamelCase(self):
123 self.log_user()
117 def test_filter_journal_filter_prefix_on_repository_CamelCase(self, autologin_user):
124 118 response = self.app.get(route_path('admin_audit_logs',
125 119 params=dict(filter='repository:Test*')))
126 120 response.mustcontain('257 entries')
127 121
128 def test_filter_journal_filter_prefix_on_repository_and_user(self):
129 self.log_user()
122 def test_filter_journal_filter_prefix_on_repository_and_user(self, autologin_user):
130 123 response = self.app.get(route_path('admin_audit_logs',
131 124 params=dict(filter='repository:test* AND username:demo')))
132 125 response.mustcontain('130 entries')
133 126
134 def test_filter_journal_filter_prefix_on_repository_or_target_repo(self):
135 self.log_user()
127 def test_filter_journal_filter_prefix_on_repository_or_target_repo(self, autologin_user):
136 128 response = self.app.get(route_path('admin_audit_logs',
137 129 params=dict(filter='repository:test* OR repository:rhodecode')))
138 130 response.mustcontain('260 entries') # 257 + 3
139 131
140 def test_filter_journal_filter_exact_match_on_username(self):
141 self.log_user()
132 def test_filter_journal_filter_exact_match_on_username(self, autologin_user):
142 133 response = self.app.get(route_path('admin_audit_logs',
143 134 params=dict(filter='username:demo')))
144 135 response.mustcontain('1087 entries')
145 136
146 def test_filter_journal_filter_exact_match_on_username_camelCase(self):
147 self.log_user()
137 def test_filter_journal_filter_exact_match_on_username_camelCase(self, autologin_user):
148 138 response = self.app.get(route_path('admin_audit_logs',
149 139 params=dict(filter='username:DemO')))
150 140 response.mustcontain('1087 entries')
151 141
152 def test_filter_journal_filter_wildcard_on_username(self):
153 self.log_user()
142 def test_filter_journal_filter_wildcard_on_username(self, autologin_user):
154 143 response = self.app.get(route_path('admin_audit_logs',
155 144 params=dict(filter='username:*test*')))
156 145 entries_count = UserLog.query().filter(UserLog.username.ilike('%test%')).count()
157 146 response.mustcontain('{} entries'.format(entries_count))
158 147
159 def test_filter_journal_filter_prefix_on_username(self):
160 self.log_user()
148 def test_filter_journal_filter_prefix_on_username(self, autologin_user):
161 149 response = self.app.get(route_path('admin_audit_logs',
162 150 params=dict(filter='username:demo*')))
163 151 response.mustcontain('1101 entries')
164 152
165 def test_filter_journal_filter_prefix_on_user_or_other_user(self):
166 self.log_user()
153 def test_filter_journal_filter_prefix_on_user_or_other_user(self, autologin_user):
167 154 response = self.app.get(route_path('admin_audit_logs',
168 155 params=dict(filter='username:demo OR username:volcan')))
169 156 response.mustcontain('1095 entries') # 1087 + 8
170 157
171 def test_filter_journal_filter_wildcard_on_action(self):
172 self.log_user()
158 def test_filter_journal_filter_wildcard_on_action(self, autologin_user):
173 159 response = self.app.get(route_path('admin_audit_logs',
174 160 params=dict(filter='action:*pull_request*')))
175 161 response.mustcontain('187 entries')
176 162
177 def test_filter_journal_filter_on_date(self):
178 self.log_user()
163 def test_filter_journal_filter_on_date(self, autologin_user):
179 164 response = self.app.get(route_path('admin_audit_logs',
180 165 params=dict(filter='date:20121010')))
181 166 response.mustcontain('47 entries')
182 167
183 def test_filter_journal_filter_on_date_2(self):
184 self.log_user()
168 def test_filter_journal_filter_on_date_2(self, autologin_user):
185 169 response = self.app.get(route_path('admin_audit_logs',
186 170 params=dict(filter='date:20121020')))
187 171 response.mustcontain('17 entries')
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 34 @pytest.mark.usefixtures("autologin_user", "app")
35 class TestAuthSettingsController(object):
35 class TestAuthSettingsView(object):
36 36
37 37 def _enable_plugins(self, plugins_list, csrf_token, override=None,
38 38 verify_response=False):
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -22,17 +22,88 b' import mock'
22 22 import pytest
23 23
24 24 import rhodecode
25 from rhodecode.config.routing import ADMIN_PREFIX
25 from rhodecode.apps._base import ADMIN_PREFIX
26 26 from rhodecode.lib.utils2 import md5
27 27 from rhodecode.model.db import RhodeCodeUi
28 28 from rhodecode.model.meta import Session
29 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 31 from rhodecode.tests.utils import AssertResponse
32 32
33 33
34 UPDATE_DATA_QUALNAME = (
35 'rhodecode.apps.admin.views.system_info.AdminSystemInfoSettingsView.get_update_data')
34 UPDATE_DATA_QUALNAME = 'rhodecode.model.update.UpdateModel.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 109 @pytest.mark.usefixtures('autologin_user', 'app')
@@ -47,12 +118,12 b' class TestAdminSettingsController(object'
47 118 'admin_settings_hooks',
48 119 'admin_settings_search',
49 120 ])
50 def test_simple_get(self, urlname, app):
51 app.get(url(urlname))
121 def test_simple_get(self, urlname):
122 self.app.get(route_path(urlname))
52 123
53 124 def test_create_custom_hook(self, csrf_token):
54 125 response = self.app.post(
55 url('admin_settings_hooks'),
126 route_path('admin_settings_hooks_update'),
56 127 params={
57 128 'new_hook_ui_key': 'test_hooks_1',
58 129 'new_hook_ui_value': 'cd /tmp',
@@ -64,7 +135,7 b' class TestAdminSettingsController(object'
64 135
65 136 def test_create_custom_hook_delete(self, csrf_token):
66 137 response = self.app.post(
67 url('admin_settings_hooks'),
138 route_path('admin_settings_hooks_update'),
68 139 params={
69 140 'new_hook_ui_key': 'test_hooks_2',
70 141 'new_hook_ui_value': 'cd /tmp2',
@@ -78,9 +149,9 b' class TestAdminSettingsController(object'
78 149
79 150 # delete
80 151 self.app.post(
81 url('admin_settings_hooks'),
152 route_path('admin_settings_hooks_delete'),
82 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 155 response.mustcontain(no=['test_hooks_2'])
85 156 response.mustcontain(no=['cd /tmp2'])
86 157
@@ -135,7 +206,6 b' class TestAdminSettingsGlobal(object):'
135 206
136 207 def test_title_change(self, csrf_token):
137 208 old_title = 'RhodeCode'
138 new_title = old_title + '_changed'
139 209
140 210 for new_title in ['Changed', 'Żółwik', old_title]:
141 211 response = self.post_and_verify_settings({
@@ -161,7 +231,8 b' class TestAdminSettingsGlobal(object):'
161 231 'rhodecode_personal_repo_group_pattern': '${username}',
162 232 }
163 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 237 assert_session_flash(response, 'Updated application settings')
167 238 app_settings = SettingsModel().get_all_settings()
@@ -175,8 +246,8 b' class TestAdminSettingsGlobal(object):'
175 246 @pytest.mark.usefixtures('autologin_user', 'app')
176 247 class TestAdminSettingsVcs(object):
177 248
178 def test_contains_svn_default_patterns(self, app):
179 response = app.get(url('admin_settings_vcs'))
249 def test_contains_svn_default_patterns(self):
250 response = self.app.get(route_path('admin_settings_vcs'))
180 251 expected_patterns = [
181 252 '/trunk',
182 253 '/branches/*',
@@ -186,7 +257,7 b' class TestAdminSettingsVcs(object):'
186 257 response.mustcontain(pattern)
187 258
188 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 261 csrf_token):
191 262 form_defaults.update({
192 263 'new_svn_branch': '/exp/branches/*',
@@ -194,8 +265,9 b' class TestAdminSettingsVcs(object):'
194 265 'csrf_token': csrf_token,
195 266 })
196 267
197 response = app.post(
198 url('admin_settings_vcs'), params=form_defaults, status=302)
268 response = self.app.post(
269 route_path('admin_settings_vcs_update'),
270 params=form_defaults, status=302)
199 271 response = response.follow()
200 272
201 273 # Expect to find the new values on the page
@@ -208,12 +280,12 b' class TestAdminSettingsVcs(object):'
208 280 assert 'important_tags/v0.5' in repo.tags
209 281
210 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 284 settings_util.create_rhodecode_ui('vcs_svn_branch', '/test')
213 285 settings_util.create_rhodecode_ui('vcs_svn_tag', '/test')
214 286
215 response = app.post(
216 url('admin_settings_vcs'),
287 response = self.app.post(
288 route_path('admin_settings_vcs_update'),
217 289 params={
218 290 'paths_root_path': form_defaults['paths_root_path'],
219 291 'new_svn_branch': '/test',
@@ -230,14 +302,13 b' class TestAdminSettingsVcs(object):'
230 302 'vcs_svn_tag',
231 303 ])
232 304 def test_delete_svn_patterns(
233 self, section, app, csrf_token, settings_util):
305 self, section, csrf_token, settings_util):
234 306 setting = settings_util.create_rhodecode_ui(
235 307 section, '/test_delete', cleanup=False)
236 308
237 app.post(
238 url('admin_settings_vcs'),
309 self.app.post(
310 route_path('admin_settings_vcs_svn_pattern_delete'),
239 311 params={
240 '_method': 'delete',
241 312 'delete_svn_pattern': setting.ui_id,
242 313 'csrf_token': csrf_token},
243 314 headers={'X-REQUESTED-WITH': 'XMLHttpRequest'})
@@ -246,25 +317,24 b' class TestAdminSettingsVcs(object):'
246 317 'vcs_svn_branch',
247 318 'vcs_svn_tag',
248 319 ])
249 def test_delete_svn_patterns_raises_400_when_no_xhr(
250 self, section, app, csrf_token, settings_util):
320 def test_delete_svn_patterns_raises_404_when_no_xhr(
321 self, section, csrf_token, settings_util):
251 322 setting = settings_util.create_rhodecode_ui(section, '/test_delete')
252 323
253 app.post(
254 url('admin_settings_vcs'),
324 self.app.post(
325 route_path('admin_settings_vcs_svn_pattern_delete'),
255 326 params={
256 '_method': 'delete',
257 327 'delete_svn_pattern': setting.ui_id,
258 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 332 form_defaults.update({
263 333 'csrf_token': csrf_token,
264 334 'extensions_hgsubversion': 'True',
265 335 })
266 response = app.post(
267 url('admin_settings_vcs'),
336 response = self.app.post(
337 route_path('admin_settings_vcs_update'),
268 338 params=form_defaults,
269 339 status=302)
270 340
@@ -275,13 +345,13 b' class TestAdminSettingsVcs(object):'
275 345 'value="True" checked="checked" />')
276 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 349 form_defaults.update({
280 350 'csrf_token': csrf_token,
281 351 'extensions_evolve': 'True',
282 352 })
283 response = app.post(
284 url('admin_settings_vcs'),
353 response = self.app.post(
354 route_path('admin_settings_vcs_update'),
285 355 params=form_defaults,
286 356 status=302)
287 357
@@ -292,20 +362,19 b' class TestAdminSettingsVcs(object):'
292 362 'value="True" checked="checked" />')
293 363 response.mustcontain(extensions_input)
294 364
295 def test_has_a_section_for_pull_request_settings(self, app):
296 response = app.get(url('admin_settings_vcs'))
365 def test_has_a_section_for_pull_request_settings(self):
366 response = self.app.get(route_path('admin_settings_vcs'))
297 367 response.mustcontain('Pull Request Settings')
298 368
299 def test_has_an_input_for_invalidation_of_inline_comments(
300 self, app):
301 response = app.get(url('admin_settings_vcs'))
369 def test_has_an_input_for_invalidation_of_inline_comments(self):
370 response = self.app.get(route_path('admin_settings_vcs'))
302 371 assert_response = AssertResponse(response)
303 372 assert_response.one_element_exists(
304 373 '[name=rhodecode_use_outdated_comments]')
305 374
306 375 @pytest.mark.parametrize('new_value', [True, False])
307 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 378 setting_key = 'use_outdated_comments'
310 379 setting = SettingsModel().create_or_update_setting(
311 380 setting_key, not new_value, 'bool')
@@ -316,8 +385,8 b' class TestAdminSettingsVcs(object):'
316 385 'csrf_token': csrf_token,
317 386 'rhodecode_use_outdated_comments': str(new_value),
318 387 })
319 response = app.post(
320 url('admin_settings_vcs'),
388 response = self.app.post(
389 route_path('admin_settings_vcs_update'),
321 390 params=form_defaults,
322 391 status=302)
323 392 response = response.follow()
@@ -326,7 +395,7 b' class TestAdminSettingsVcs(object):'
326 395
327 396 @pytest.mark.parametrize('new_value', [True, False])
328 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 399 setting_key = 'hg_use_rebase_for_merging'
331 400
332 401 form_defaults.update({
@@ -336,8 +405,8 b' class TestAdminSettingsVcs(object):'
336 405
337 406 with mock.patch.dict(
338 407 rhodecode.CONFIG, {'labs_settings_active': 'true'}):
339 app.post(
340 url('admin_settings_vcs'),
408 self.app.post(
409 route_path('admin_settings_vcs_update'),
341 410 params=form_defaults,
342 411 status=302)
343 412
@@ -353,14 +422,13 b' class TestAdminSettingsVcs(object):'
353 422
354 423 @pytest.fixture
355 424 def form_defaults(self):
356 from rhodecode.controllers.admin.settings import SettingsController
357 controller = SettingsController()
358 return controller._form_defaults()
425 from rhodecode.apps.admin.views.settings import AdminSettingsView
426 return AdminSettingsView._form_defaults()
359 427
360 428 # TODO: johbo: What we really want is to checkpoint before a test run and
361 429 # reset the session afterwards.
362 430 @pytest.fixture(scope='class', autouse=True)
363 def cleanup_settings(self, request, pylonsapp):
431 def cleanup_settings(self, request, baseapp):
364 432 ui_id = RhodeCodeUi.ui_id
365 433 original_ids = list(
366 434 r.ui_id for r in RhodeCodeUi.query().values(ui_id))
@@ -374,14 +442,16 b' class TestAdminSettingsVcs(object):'
374 442 @pytest.mark.usefixtures('autologin_user', 'app')
375 443 class TestLabsSettings(object):
376 444 def test_get_settings_page_disabled(self):
377 with mock.patch.dict(rhodecode.CONFIG,
378 {'labs_settings_active': 'false'}):
379 response = self.app.get(url('admin_settings_labs'), status=302)
445 with mock.patch.dict(
446 rhodecode.CONFIG, {'labs_settings_active': 'false'}):
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 453 def test_get_settings_page_enabled(self):
384 from rhodecode.controllers.admin import settings
454 from rhodecode.apps.admin.views import settings
385 455 lab_settings = [
386 456 settings.LabSetting(
387 457 key='rhodecode_bool',
@@ -401,7 +471,7 b' class TestLabsSettings(object):'
401 471 with mock.patch.dict(rhodecode.CONFIG,
402 472 {'labs_settings_active': 'true'}):
403 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 476 assert '<label>bool group:</label>' in response
407 477 assert '<label for="rhodecode_bool">bool label</label>' in response
@@ -417,9 +487,6 b' class TestLabsSettings(object):'
417 487 @pytest.mark.usefixtures('app')
418 488 class TestOpenSourceLicenses(object):
419 489
420 def _get_url(self):
421 return ADMIN_PREFIX + '/settings/open_source'
422
423 490 def test_records_are_displayed(self, autologin_user):
424 491 sample_licenses = {
425 492 "python2.7-pytest-2.7.1": {
@@ -433,7 +500,8 b' class TestOpenSourceLicenses(object):'
433 500 'rhodecode.apps.admin.views.open_source_licenses.read_opensource_licenses',
434 501 return_value=sample_licenses)
435 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 506 assert_response = AssertResponse(response)
439 507 assert_response.element_contains(
@@ -444,29 +512,25 b' class TestOpenSourceLicenses(object):'
444 512 assert_response.element_contains('.panel-body', license)
445 513
446 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 517 assert_response = AssertResponse(response)
449 518 assert_response.element_contains(
450 519 '.panel-heading', 'Licenses of Third Party Packages')
451 520
452 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 526 @pytest.mark.usefixtures('app')
457 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 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 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 534 response.mustcontain('file')
471 535
472 536 def test_cleanup_old_sessions(self, autologin_user, csrf_token):
@@ -476,24 +540,19 b' class TestUserSessions(object):'
476 540 'expire_days': '60'
477 541 }
478 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 544 status=302)
481 545 assert_session_flash(response, 'Cleaned up old sessions')
482 546
483 547
484 548 @pytest.mark.usefixtures('app')
485 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 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 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 556 response.mustcontain('RhodeCode Community Edition, version {}'.format(
498 557 rhodecode.__version__))
499 558
@@ -511,7 +570,7 b' class TestAdminSystemInfo(object):'
511 570 ]
512 571 }
513 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 574 response.mustcontain('A <b>new version</b> is available')
516 575
517 576 def test_system_update_nothing_new(self, autologin_user):
@@ -524,13 +583,13 b' class TestAdminSystemInfo(object):'
524 583 ]
525 584 }
526 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 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 590 def test_system_update_bad_response(self, autologin_user):
532 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 593 response.mustcontain(
535 594 'Bad data sent from update server')
536 595
@@ -542,12 +601,12 b' class TestAdminSettingsIssueTracker(obje'
542 601 PATTERN_KEY = RC_PREFIX + SHORT_PATTERN_KEY
543 602
544 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 605 assert response.status_code == 200
547 606
548 607 def test_add_empty_issuetracker_pattern(
549 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 610 post_data = {
552 611 'csrf_token': csrf_token
553 612 }
@@ -557,14 +616,14 b' class TestAdminSettingsIssueTracker(obje'
557 616 self, request, autologin_user, csrf_token):
558 617 pattern = 'issuetracker_pat'
559 618 another_pattern = pattern+'1'
560 post_url = url('admin_settings_issuetracker_save')
619 post_url = route_path('admin_settings_issuetracker_update')
561 620 post_data = {
562 621 'new_pattern_pattern_0': pattern,
563 'new_pattern_url_0': 'url',
622 'new_pattern_url_0': 'http://url',
564 623 'new_pattern_prefix_0': 'prefix',
565 624 'new_pattern_description_0': 'description',
566 625 'new_pattern_pattern_1': another_pattern,
567 'new_pattern_url_1': 'url1',
626 'new_pattern_url_1': 'https://url1',
568 627 'new_pattern_prefix_1': 'prefix1',
569 628 'new_pattern_description_1': 'description1',
570 629 'csrf_token': csrf_token
@@ -600,10 +659,10 b' class TestAdminSettingsIssueTracker(obje'
600 659 SettingsModel().create_or_update_setting(
601 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 663 post_data = {
605 664 'new_pattern_pattern_0': pattern,
606 'new_pattern_url_0': 'url',
665 'new_pattern_url_0': 'https://url',
607 666 'new_pattern_prefix_0': 'prefix',
608 667 'new_pattern_description_0': 'description',
609 668 'uid': old_uid,
@@ -634,10 +693,10 b' class TestAdminSettingsIssueTracker(obje'
634 693 settings_util.create_rhodecode_setting(
635 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 697 post_data = {
639 698 'new_pattern_pattern_0': pattern,
640 'new_pattern_url_0': 'url',
699 'new_pattern_url_0': 'https://url',
641 700 'new_pattern_prefix_0': 'prefix',
642 701 'new_pattern_description_0': new_description,
643 702 'uid': self.uid,
@@ -659,7 +718,7 b' class TestAdminSettingsIssueTracker(obje'
659 718 settings_util.create_rhodecode_setting(
660 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 722 post_data = {
664 723 '_method': 'delete',
665 724 'uid': uid,
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 24 from rhodecode.lib import auth
25 25 from rhodecode.lib import helpers as h
26 from rhodecode.model import validators
27 26 from rhodecode.model.db import User, UserApiKeys, UserEmailMap, Repository
28 27 from rhodecode.model.meta import Session
29 28 from rhodecode.model.user import UserModel
@@ -386,8 +385,7 b' class TestAdminUsersView(TestController)'
386 385 'csrf_token': self.csrf_token,
387 386 })
388 387
389 msg = validators.ValidUsername(
390 False, {})._messages['system_invalid_username']
388 msg = u'Username "%(username)s" is forbidden'
391 389 msg = h.html_escape(msg % {'username': 'new_user'})
392 390 response.mustcontain('<span class="error-message">%s</span>' % msg)
393 391 response.mustcontain(
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -36,7 +36,6 b' log = logging.getLogger(__name__)'
36 36 class AdminAuditLogsView(BaseAppView):
37 37 def load_default_context(self):
38 38 c = self._get_local_tmpl_context()
39 self._register_global_c(c)
40 39 return c
41 40
42 41 @LoginRequired()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -44,7 +44,7 b' class AdminDefaultSettingsView(BaseAppVi'
44 44 def load_default_context(self):
45 45 c = self._get_local_tmpl_context()
46 46
47 self._register_global_c(c)
47
48 48 return c
49 49
50 50 @LoginRequired()
@@ -79,7 +79,7 b' class AdminDefaultSettingsView(BaseAppVi'
79 79 _ = self.request.translate
80 80 c = self.load_default_context()
81 81 c.active = 'repositories'
82 form = DefaultsForm()()
82 form = DefaultsForm(self.request.translate)()
83 83
84 84 try:
85 85 form_result = form.to_python(dict(self.request.POST))
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -35,7 +35,7 b' class OpenSourceLicensesAdminSettingsVie'
35 35
36 36 def load_default_context(self):
37 37 c = self._get_local_tmpl_context()
38 self._register_global_c(c)
38
39 39 return c
40 40
41 41 @LoginRequired()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -53,8 +53,6 b' log = logging.getLogger(__name__)'
53 53 class AdminPermissionsView(BaseAppView, DataGridAppView):
54 54 def load_default_context(self):
55 55 c = self._get_local_tmpl_context()
56
57 self._register_global_c(c)
58 56 PermissionModel().set_global_permission_choices(
59 57 c, gettext_translator=self.request.translate)
60 58 return c
@@ -100,6 +98,7 b' class AdminPermissionsView(BaseAppView, '
100 98 c.active = 'application'
101 99
102 100 _form = ApplicationPermissionsForm(
101 self.request.translate,
103 102 [x[0] for x in c.register_choices],
104 103 [x[0] for x in c.password_reset_choices],
105 104 [x[0] for x in c.extern_activate_choices])()
@@ -180,6 +179,7 b' class AdminPermissionsView(BaseAppView, '
180 179 c.active = 'objects'
181 180
182 181 _form = ObjectPermissionsForm(
182 self.request.translate,
183 183 [x[0] for x in c.repo_perms_choices],
184 184 [x[0] for x in c.group_perms_choices],
185 185 [x[0] for x in c.user_group_perms_choices])()
@@ -251,6 +251,7 b' class AdminPermissionsView(BaseAppView, '
251 251 c.active = 'global'
252 252
253 253 _form = UserPermissionsForm(
254 self.request.translate,
254 255 [x[0] for x in c.repo_create_choices],
255 256 [x[0] for x in c.repo_create_on_write_choices],
256 257 [x[0] for x in c.repo_group_create_choices],
@@ -395,6 +396,7 b' class AdminPermissionsView(BaseAppView, '
395 396 renderer='json_ext', xhr=True)
396 397 def ssh_keys_data(self):
397 398 _ = self.request.translate
399 self.load_default_context()
398 400 column_map = {
399 401 'fingerprint': 'ssh_key_fingerprint',
400 402 'username': User.username
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -21,6 +21,7 b''
21 21 import logging
22 22
23 23 import psutil
24 import signal
24 25 from pyramid.view import view_config
25 26
26 27 from rhodecode.apps._base import BaseAppView
@@ -35,7 +36,7 b' log = logging.getLogger(__name__)'
35 36 class AdminProcessManagementView(BaseAppView):
36 37 def load_default_context(self):
37 38 c = self._get_local_tmpl_context()
38 self._register_global_c(c)
39
39 40 return c
40 41
41 42 @LoginRequired()
@@ -55,6 +56,18 b' class AdminProcessManagementView(BaseApp'
55 56
56 57 @LoginRequired()
57 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 71 @CSRFRequired()
59 72 @view_config(
60 73 route_name='admin_settings_process_management_signal',
@@ -89,3 +102,32 b' class AdminProcessManagementView(BaseApp'
89 102 p.kill()
90 103
91 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 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 48 def load_default_context(self):
49 49 c = self._get_local_tmpl_context()
50 self._register_global_c(c)
50
51 51 return c
52 52
53 53 def _load_form_data(self, c):
@@ -150,8 +150,9 b' class AdminRepoGroupsView(BaseAppView, D'
150 150 # permissions for can create group based on parent_id are checked
151 151 # here in the Form
152 152 available_groups = map(lambda k: safe_unicode(k[0]), c.repo_groups)
153 repo_group_form = RepoGroupForm(available_groups=available_groups,
154 can_create_in_root=can_create)()
153 repo_group_form = RepoGroupForm(
154 self.request.translate, available_groups=available_groups,
155 can_create_in_root=can_create)()
155 156
156 157 repo_group_name = self.request.POST.get('group_name')
157 158 try:
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 28 from pyramid.response import Response
29 29
30 30 from rhodecode.apps._base import BaseAppView, DataGridAppView
31 from rhodecode.lib.celerylib.utils import get_task_id
31 32
32 33 from rhodecode.lib.ext_json import json
33 34 from rhodecode.lib.auth import (
@@ -49,7 +50,7 b' class AdminReposView(BaseAppView, DataGr'
49 50
50 51 def load_default_context(self):
51 52 c = self._get_local_tmpl_context()
52 self._register_global_c(c)
53
53 54 return c
54 55
55 56 def _load_form_data(self, c):
@@ -58,7 +59,7 b' class AdminReposView(BaseAppView, DataGr'
58 59 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
59 60 c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups)
60 61 c.landing_revs_choices, c.landing_revs = \
61 ScmModel().get_repo_landing_revs()
62 ScmModel().get_repo_landing_revs(self.request.translate)
62 63 c.personal_repo_group = self._rhodecode_user.personal_repo_group
63 64
64 65 @LoginRequired()
@@ -143,21 +144,19 b' class AdminReposView(BaseAppView, DataGr'
143 144 c = self.load_default_context()
144 145
145 146 form_result = {}
147 self._load_form_data(c)
146 148 task_id = None
147 self._load_form_data(c)
148
149 149 try:
150 150 # CanWriteToGroup validators checks permissions of this POST
151 form_result = RepoForm(repo_groups=c.repo_groups_choices,
152 landing_revs=c.landing_revs_choices)()\
153 .to_python(dict(self.request.POST))
151 form = RepoForm(
152 self.request.translate, repo_groups=c.repo_groups_choices,
153 landing_revs=c.landing_revs_choices)()
154 form_result = form.to_python(dict(self.request.POST))
154 155
155 156 # create is done sometimes async on celery, db transaction
156 157 # management is handled there.
157 158 task = RepoModel().create(form_result, self._rhodecode_user.user_id)
158 from celery.result import BaseAsyncResult
159 if isinstance(task, BaseAsyncResult):
160 task_id = task.task_id
159 task_id = get_task_id(task)
161 160 except formencode.Invalid as errors:
162 161 data = render('rhodecode:templates/admin/repos/repo_add.mako',
163 162 self._get_template_context(c), self.request)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 30 from rhodecode.lib.utils2 import safe_int
31 31 from rhodecode.lib import system_info
32 32 from rhodecode.lib import user_sessions
33 from rhodecode.lib import helpers as h
33 34
34 35
35 36 log = logging.getLogger(__name__)
@@ -39,7 +40,7 b' class AdminSessionSettingsView(BaseAppVi'
39 40 def load_default_context(self):
40 41 c = self._get_local_tmpl_context()
41 42
42 self._register_global_c(c)
43
43 44 return c
44 45
45 46 @LoginRequired()
@@ -88,14 +89,12 b' class AdminSessionSettingsView(BaseAppVi'
88 89 try:
89 90 session_model.clean_sessions(
90 91 older_than_seconds=older_than_seconds)
91 self.request.session.flash(
92 _('Cleaned up old sessions'), queue='success')
92 h.flash(_('Cleaned up old sessions'), category='success')
93 93 except user_sessions.CleanupCommand as msg:
94 self.request.session.flash(msg.message, queue='warning')
94 h.flash(msg.message, category='warning')
95 95 except Exception as e:
96 96 log.exception('Failed session cleanup')
97 self.request.session.flash(
98 _('Failed to cleanup up old sessions'), queue='error')
97 h.flash(_('Failed to cleanup up old sessions'), category='error')
99 98
100 99 redirect_to = self.request.resource_path(
101 100 self.context, route_name='admin_settings_sessions')
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -20,7 +20,6 b''
20 20
21 21 import logging
22 22 import urllib2
23 import packaging.version
24 23
25 24 from pyramid.view import view_config
26 25
@@ -31,8 +30,7 b' from rhodecode.lib import helpers as h'
31 30 from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
32 31 from rhodecode.lib.utils2 import str2bool
33 32 from rhodecode.lib import system_info
34 from rhodecode.lib.ext_json import json
35 from rhodecode.model.settings import SettingsModel
33 from rhodecode.model.update import UpdateModel
36 34
37 35 log = logging.getLogger(__name__)
38 36
@@ -40,26 +38,8 b' log = logging.getLogger(__name__)'
40 38 class AdminSystemInfoSettingsView(BaseAppView):
41 39 def load_default_context(self):
42 40 c = self._get_local_tmpl_context()
43 self._register_global_c(c)
44 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 43 @LoginRequired()
64 44 @HasPermissionAllDecorator('hg.admin')
65 45 @view_config(
@@ -77,7 +57,7 b' class AdminSystemInfoSettingsView(BaseAp'
77 57
78 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 61 server_info = system_info.get_system_info(self.request.environ)
82 62
83 63 for key, val in server_info.items():
@@ -97,6 +77,14 b' class AdminSystemInfoSettingsView(BaseAp'
97 77 update_info_msg = _('Note: please make sure this server can '
98 78 'access `${url}` for the update link to work',
99 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 88 c.data_items = [
101 89 # update info
102 90 (_('Update info'), h.literal(
@@ -107,6 +95,7 b' class AdminSystemInfoSettingsView(BaseAp'
107 95
108 96 # RhodeCode specific
109 97 (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')),
98 (_('Latest version'), version, update_state),
110 99 (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')),
111 100 (_('RhodeCode Server ID'), val('server')['server_id'], state('server')),
112 101 (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')),
@@ -166,8 +155,7 b' class AdminSystemInfoSettingsView(BaseAp'
166 155 c.data_items.pop(0) # remove server info
167 156 self.request.override_renderer = 'admin/settings/settings_system_snapshot.mako'
168 157 else:
169 self.request.session.flash(
170 'You are not allowed to do this', queue='warning')
158 h.flash('You are not allowed to do this', category='warning')
171 159 return self._get_template_context(c)
172 160
173 161 @LoginRequired()
@@ -179,11 +167,11 b' class AdminSystemInfoSettingsView(BaseAp'
179 167 _ = self.request.translate
180 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 172 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">{}</div>'.format(s)
185 173 try:
186 data = self.get_update_data(update_url)
174 data = UpdateModel().get_update_data(update_url)
187 175 except urllib2.URLError as e:
188 176 log.exception("Exception contacting upgrade server")
189 177 self.request.override_renderer = 'string'
@@ -201,9 +189,9 b' class AdminSystemInfoSettingsView(BaseAp'
201 189 c.cur_ver = rhodecode.__version__
202 190 c.should_upgrade = False
203 191
204 if (packaging.version.Version(c.latest_ver) >
205 packaging.version.Version(c.cur_ver)):
192 is_oudated = UpdateModel().is_outdated(c.cur_ver, c.latest_ver)
193 if is_oudated:
206 194 c.should_upgrade = True
207 195 c.important_notices = latest['general']
208
196 UpdateModel().store_version(latest['version'])
209 197 return self._get_template_context(c)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -53,7 +53,6 b' class AdminUserGroupsView(BaseAppView, D'
53 53 PermissionModel().set_global_permission_choices(
54 54 c, gettext_translator=self.request.translate)
55 55
56 self._register_global_c(c)
57 56 return c
58 57
59 58 # permission check in data loading of
@@ -74,6 +73,7 b' class AdminUserGroupsView(BaseAppView, D'
74 73 route_name='user_groups_data', request_method='GET',
75 74 renderer='json_ext', xhr=True)
76 75 def user_groups_list_data(self):
76 self.load_default_context()
77 77 column_map = {
78 78 'active': 'users_group_active',
79 79 'description': 'user_group_description',
@@ -86,7 +86,7 b' class AdminUserGroupsView(BaseAppView, D'
86 86 self.request, column_map=column_map)
87 87
88 88 _render = self.request.get_partial_renderer(
89 'data_table/_dt_elements.mako')
89 'rhodecode:templates/data_table/_dt_elements.mako')
90 90
91 91 def user_group_name(user_group_id, user_group_name):
92 92 return _render("user_group_name", user_group_id, user_group_name)
@@ -195,7 +195,7 b' class AdminUserGroupsView(BaseAppView, D'
195 195 def user_groups_create(self):
196 196 _ = self.request.translate
197 197 c = self.load_default_context()
198 users_group_form = UserGroupForm()()
198 users_group_form = UserGroupForm(self.request.translate)()
199 199
200 200 user_group_name = self.request.POST.get('users_group_name')
201 201 try:
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 44 from rhodecode.lib.utils2 import safe_int, safe_unicode, AttributeDict
45 45 from rhodecode.model.auth_token import AuthTokenModel
46 46 from rhodecode.model.forms import (
47 UserForm, UserIndividualPermissionsForm, UserPermissionsForm)
47 UserForm, UserIndividualPermissionsForm, UserPermissionsForm,
48 UserExtraEmailForm, UserExtraIpForm)
48 49 from rhodecode.model.permission import PermissionModel
49 50 from rhodecode.model.repo_group import RepoGroupModel
50 51 from rhodecode.model.ssh_key import SshKeyModel
@@ -62,7 +63,6 b' class AdminUsersView(BaseAppView, DataGr'
62 63
63 64 def load_default_context(self):
64 65 c = self._get_local_tmpl_context()
65 self._register_global_c(c)
66 66 return c
67 67
68 68 @LoginRequired()
@@ -81,6 +81,7 b' class AdminUsersView(BaseAppView, DataGr'
81 81 route_name='users_data', request_method='GET',
82 82 renderer='json_ext', xhr=True)
83 83 def users_list_data(self):
84 self.load_default_context()
84 85 column_map = {
85 86 'first_name': 'name',
86 87 'last_name': 'lastname',
@@ -90,7 +91,7 b' class AdminUsersView(BaseAppView, DataGr'
90 91 self.request, column_map=column_map)
91 92
92 93 _render = self.request.get_partial_renderer(
93 'data_table/_dt_elements.mako')
94 'rhodecode:templates/data_table/_dt_elements.mako')
94 95
95 96 def user_actions(user_id, username):
96 97 return _render("user_actions", user_id, username)
@@ -190,7 +191,7 b' class AdminUsersView(BaseAppView, DataGr'
190 191 c = self.load_default_context()
191 192 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name
192 193 user_model = UserModel()
193 user_form = UserForm()()
194 user_form = UserForm(self.request.translate)()
194 195 try:
195 196 form_result = user_form.to_python(dict(self.request.POST))
196 197 user = user_model.create(form_result)
@@ -258,7 +259,6 b' class UsersView(UserAppView):'
258 259 PermissionModel().set_global_permission_choices(
259 260 c, gettext_translator=req.translate)
260 261
261 self._register_global_c(c)
262 262 return c
263 263
264 264 @LoginRequired()
@@ -279,7 +279,8 b' class UsersView(UserAppView):'
279 279 c.extern_name = c.user.extern_name
280 280 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
281 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 284 old_data={'user_id': user_id,
284 285 'email': c.user.email})()
285 286 form_result = {}
@@ -537,7 +538,7 b' class UsersView(UserAppView):'
537 538 c.active = 'global_perms'
538 539 try:
539 540 # first stage that verifies the checkbox
540 _form = UserIndividualPermissionsForm()
541 _form = UserIndividualPermissionsForm(self.request.translate)
541 542 form_result = _form.to_python(dict(self.request.POST))
542 543 inherit_perms = form_result['inherit_default_permissions']
543 544 c.user.inherit_default_permissions = inherit_perms
@@ -546,6 +547,7 b' class UsersView(UserAppView):'
546 547 if not inherit_perms:
547 548 # only update the individual ones if we un check the flag
548 549 _form = UserPermissionsForm(
550 self.request.translate,
549 551 [x[0] for x in c.repo_create_choices],
550 552 [x[0] for x in c.repo_create_on_write_choices],
551 553 [x[0] for x in c.repo_group_create_choices],
@@ -913,6 +915,11 b' class UsersView(UserAppView):'
913 915 email = self.request.POST.get('new_email')
914 916 user_data = c.user.get_api_data()
915 917 try:
918
919 form = UserExtraEmailForm(self.request.translate)()
920 data = form.to_python({'email': email})
921 email = data['email']
922
916 923 UserModel().add_extra_email(c.user.user_id, email)
917 924 audit_logger.store_web(
918 925 'user.edit.email.add',
@@ -1008,6 +1015,10 b' class UsersView(UserAppView):'
1008 1015 user_data = c.user.get_api_data()
1009 1016 for ip in ip_list:
1010 1017 try:
1018 form = UserExtraIpForm(self.request.translate)()
1019 data = form.to_python({'ip': ip})
1020 ip = data['ip']
1021
1011 1022 user_model.add_extra_ip(c.user.user_id, ip, desc)
1012 1023 audit_logger.store_web(
1013 1024 'user.edit.ip.add',
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -20,9 +20,10 b''
20 20
21 21 import os
22 22
23 from pyramid.events import ApplicationCreated
23 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 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 69 def includeme(config):
61 70 settings = config.registry.settings
62 71 PLUGIN_DEFINITION['config']['enabled'] = asbool(
@@ -71,10 +80,7 b' def includeme(config):'
71 80 PLUGIN_DEFINITION['name'],
72 81 PLUGIN_DEFINITION['config']
73 82 )
74 # create plugin history location
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)
83 config.add_subscriber(maybe_create_history_store, ApplicationCreated)
78 84
79 85 config.add_route(
80 86 name='channelstream_connect',
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -24,6 +24,7 b' import uuid'
24 24 from pyramid.view import view_config
25 25 from pyramid.httpexceptions import HTTPBadRequest, HTTPForbidden, HTTPBadGateway
26 26
27 from rhodecode.apps._base import BaseAppView
27 28 from rhodecode.lib.channelstream import (
28 29 channelstream_request,
29 30 ChannelstreamConnectionException,
@@ -34,28 +35,28 b' from rhodecode.lib.channelstream import '
34 35 parse_channels_info,
35 36 update_history_from_logs,
36 37 STATE_PUBLIC_KEYS)
38
37 39 from rhodecode.lib.auth import NotAnonymous
38 40
39 41 log = logging.getLogger(__name__)
40 42
41 43
42 class ChannelstreamView(object):
43 def __init__(self, context, request):
44 self.context = context
45 self.request = request
44 class ChannelstreamView(BaseAppView):
46 45
47 # Some of the decorators rely on this attribute to be present
48 # on the class of the decorated method.
49 self._rhodecode_user = request.user
50 registry = request.registry
51 self.channelstream_config = registry.rhodecode_plugins['channelstream']
46 def load_default_context(self):
47 c = self._get_local_tmpl_context()
48 self.channelstream_config = \
49 self.request.registry.rhodecode_plugins['channelstream']
52 50 if not self.channelstream_config.get('enabled'):
53 51 log.error('Channelstream plugin is disabled')
54 52 raise HTTPBadRequest()
55 53
54 return c
55
56 56 @NotAnonymous()
57 @view_config(route_name='channelstream_connect', renderer='json')
57 @view_config(route_name='channelstream_connect', renderer='json_ext')
58 58 def connect(self):
59 self.load_default_context()
59 60 """ handle authorization of users trying to connect """
60 61 try:
61 62 json_body = self.request.json_body
@@ -122,9 +123,10 b' class ChannelstreamView(object):'
122 123 return connect_result
123 124
124 125 @NotAnonymous()
125 @view_config(route_name='channelstream_subscribe', renderer='json')
126 @view_config(route_name='channelstream_subscribe', renderer='json_ext')
126 127 def subscribe(self):
127 128 """ can be used to subscribe specific connection to other channels """
129 self.load_default_context()
128 130 try:
129 131 json_body = self.request.json_body
130 132 except Exception:
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -31,7 +31,7 b' log = logging.getLogger(__name__)'
31 31 class DebugStyleView(BaseAppView):
32 32 def load_default_context(self):
33 33 c = self._get_local_tmpl_context()
34 self._register_global_c(c)
34
35 35 return c
36 36
37 37 @view_config(
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2013-2017 RhodeCode GmbH
3 # Copyright (C) 2013-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -67,7 +67,7 b' class GistView(BaseAppView):'
67 67 (Gist.ACL_LEVEL_PUBLIC, _("Can be accessed by anonymous users"))
68 68 ]
69 69
70 self._register_global_c(c)
70
71 71 return c
72 72
73 73 @LoginRequired()
@@ -114,7 +114,7 b' class GistView(BaseAppView):'
114 114 c.active = 'public'
115 115
116 116 _render = self.request.get_partial_renderer(
117 'data_table/_dt_elements.mako')
117 'rhodecode:templates/data_table/_dt_elements.mako')
118 118
119 119 data = []
120 120
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 68 @pytest.fixture(autouse=True, scope='class')
69 def prepare(self, request, pylonsapp):
69 def prepare(self, request, baseapp):
70 70 for repo_and_group in self.required_repos_with_groups:
71 71 # create structure of groups and return the last group
72 72
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -19,7 +19,7 b''
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20 # -*- coding: utf-8 -*-
21 21
22 # Copyright (C) 2016-2017 RhodeCode GmbH
22 # Copyright (C) 2016-2018 RhodeCode GmbH
23 23 #
24 24 # This program is free software: you can redistribute it and/or modify
25 25 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -46,7 +46,7 b' class HomeView(BaseAppView):'
46 46 def load_default_context(self):
47 47 c = self._get_local_tmpl_context()
48 48 c.user = c.auth_user.get_instance()
49 self._register_global_c(c)
49
50 50 return c
51 51
52 52 @LoginRequired()
@@ -54,6 +54,7 b' class HomeView(BaseAppView):'
54 54 route_name='user_autocomplete_data', request_method='GET',
55 55 renderer='json_ext', xhr=True)
56 56 def user_autocomplete_data(self):
57 self.load_default_context()
57 58 query = self.request.GET.get('query')
58 59 active = str2bool(self.request.GET.get('active') or True)
59 60 include_groups = str2bool(self.request.GET.get('user_groups'))
@@ -87,6 +88,7 b' class HomeView(BaseAppView):'
87 88 route_name='user_group_autocomplete_data', request_method='GET',
88 89 renderer='json_ext', xhr=True)
89 90 def user_group_autocomplete_data(self):
91 self.load_default_context()
90 92 query = self.request.GET.get('query')
91 93 active = str2bool(self.request.GET.get('active') or True)
92 94 expand_groups = str2bool(self.request.GET.get('user_groups_expand'))
@@ -202,6 +204,7 b' class HomeView(BaseAppView):'
202 204 renderer='json_ext', xhr=True)
203 205 def repo_list_data(self):
204 206 _ = self.request.translate
207 self.load_default_context()
205 208
206 209 query = self.request.GET.get('query')
207 210 repo_type = self.request.GET.get('repo_type')
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 48 def load_default_context(self):
49 49 c = self._get_local_tmpl_context(include_app_defaults=True)
50 self._register_global_c(c)
50
51 51 self._load_defaults(c.rhodecode_name)
52 52
53 53 # TODO(marcink): what is this, why we need a global register ?
@@ -146,7 +146,8 b' class JournalView(BaseAppView):'
146 146 user = AttributeDict({'short_contact': entry.username,
147 147 'email': '',
148 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 151 title = "%s - %s %s" % (user.short_contact, action(),
151 152 entry.repository.repo_name)
152 153 desc = action_extra()
@@ -191,7 +192,8 b' class JournalView(BaseAppView):'
191 192 user = AttributeDict({'short_contact': entry.username,
192 193 'email': '',
193 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 197 title = "%s - %s %s" % (user.short_contact, action(),
196 198 entry.repository.repo_name)
197 199 desc = action_extra()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -19,7 +19,7 b''
19 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 25 def includeme(config):
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 30 from rhodecode.lib.auth import check_password
31 31 from rhodecode.lib import helpers as h
32 32 from rhodecode.model.auth_token import AuthTokenModel
33 from rhodecode.model import validators
34 33 from rhodecode.model.db import User, Notification, UserApiKeys
35 34 from rhodecode.model.meta import Session
36 35
@@ -89,32 +88,31 b' class TestLoginController(object):'
89 88 def test_login_admin_ok(self):
90 89 response = self.app.post(route_path('login'),
91 90 {'username': 'test_admin',
92 'password': 'test12'})
93 assert response.status == '302 Found'
91 'password': 'test12'}, status=302)
92 response = response.follow()
94 93 session = response.get_session_from_response()
95 94 username = session['rhodecode_user'].get('username')
96 95 assert username == 'test_admin'
97 response = response.follow()
98 96 response.mustcontain('/%s' % HG_REPO)
99 97
100 98 def test_login_regular_ok(self):
101 99 response = self.app.post(route_path('login'),
102 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 104 session = response.get_session_from_response()
107 105 username = session['rhodecode_user'].get('username')
108 106 assert username == 'test_regular'
109 response = response.follow()
107
110 108 response.mustcontain('/%s' % HG_REPO)
111 109
112 110 def test_login_ok_came_from(self):
113 111 test_came_from = '/_admin/users?branch=stable'
114 112 _url = '{}?came_from={}'.format(route_path('login'), test_came_from)
115 113 response = self.app.post(
116 _url, {'username': 'test_admin', 'password': 'test12'})
117 assert response.status == '302 Found'
114 _url, {'username': 'test_admin', 'password': 'test12'}, status=302)
115
118 116 assert 'branch=stable' in response.location
119 117 response = response.follow()
120 118
@@ -125,8 +123,8 b' class TestLoginController(object):'
125 123 with fixture.anon_access(False):
126 124 kwargs = {'branch': 'stable'}
127 125 response = self.app.get(
128 h.route_path('repo_summary', repo_name=HG_REPO, _query=kwargs))
129 assert response.status == '302 Found'
126 h.route_path('repo_summary', repo_name=HG_REPO, _query=kwargs),
127 status=302)
130 128
131 129 response_query = urlparse.parse_qsl(response.location)
132 130 assert 'branch=stable' in response_query[0][1]
@@ -201,13 +199,12 b' class TestLoginController(object):'
201 199 self.destroy_users.add(temp_user)
202 200 response = self.app.post(route_path('login'),
203 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 205 session = response.get_session_from_response()
208 206 username = session['rhodecode_user'].get('username')
209 207 assert username == temp_user
210 response = response.follow()
211 208 response.mustcontain('/%s' % HG_REPO)
212 209
213 210 # new password should be bcrypted, after log-in and transfer
@@ -234,7 +231,7 b' class TestLoginController(object):'
234 231 )
235 232
236 233 assertr = response.assert_response()
237 msg = validators.ValidUsername()._messages['username_exists']
234 msg = 'Username "%(username)s" already exists'
238 235 msg = msg % {'username': uname}
239 236 assertr.element_contains('#username+.error-message', msg)
240 237
@@ -252,7 +249,7 b' class TestLoginController(object):'
252 249 )
253 250
254 251 assertr = response.assert_response()
255 msg = validators.UniqSystemEmail()()._messages['email_taken']
252 msg = u'This e-mail address is already taken'
256 253 assertr.element_contains('#email+.error-message', msg)
257 254
258 255 def test_register_err_same_email_case_sensitive(self):
@@ -268,7 +265,7 b' class TestLoginController(object):'
268 265 }
269 266 )
270 267 assertr = response.assert_response()
271 msg = validators.UniqSystemEmail()()._messages['email_taken']
268 msg = u'This e-mail address is already taken'
272 269 assertr.element_contains('#email+.error-message', msg)
273 270
274 271 def test_register_err_wrong_data(self):
@@ -322,7 +319,7 b' class TestLoginController(object):'
322 319 )
323 320
324 321 assertr = response.assert_response()
325 msg = validators.ValidUsername()._messages['username_exists']
322 msg = u'Username "%(username)s" already exists'
326 323 msg = msg % {'username': usr}
327 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 340 response.mustcontain(msg)
344 341
345 342 def test_register_password_mismatch(self):
@@ -354,7 +351,7 b' class TestLoginController(object):'
354 351 'lastname': 'test'
355 352 }
356 353 )
357 msg = validators.ValidPasswordsMatch()._messages['password_mismatch']
354 msg = u'Passwords do not match'
358 355 response.mustcontain(msg)
359 356
360 357 def test_register_ok(self):
@@ -364,6 +361,11 b' class TestLoginController(object):'
364 361 name = 'testname'
365 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 369 response = self.app.post(
368 370 route_path('register'),
369 371 {
@@ -374,9 +376,10 b' class TestLoginController(object):'
374 376 'firstname': name,
375 377 'lastname': lastname,
376 378 'admin': True
377 }
378 ) # This should be overriden
379 assert response.status == '302 Found'
379 },
380 status=302
381 ) # This should be overridden
382
380 383 assert_session_flash(
381 384 response, 'You have successfully registered with RhodeCode')
382 385
@@ -392,6 +395,9 b' class TestLoginController(object):'
392 395
393 396 def test_forgot_password_wrong_mail(self):
394 397 bad_email = 'marcin@wrongmail.org'
398 # this initializes a session
399 self.app.get(route_path('reset_password'))
400
395 401 response = self.app.post(
396 402 route_path('reset_password'), {'email': bad_email, }
397 403 )
@@ -399,8 +405,8 b' class TestLoginController(object):'
399 405 'If such email exists, a password reset link was sent to it.')
400 406
401 407 def test_forgot_password(self, user_util):
402 response = self.app.get(route_path('reset_password'))
403 assert response.status == '200 OK'
408 # this initializes a session
409 self.app.get(route_path('reset_password'))
404 410
405 411 user = user_util.create_user()
406 412 user_id = user.user_id
@@ -413,8 +419,7 b' class TestLoginController(object):'
413 419
414 420 # BAD KEY
415 421 confirm_url = '{}?key={}'.format(route_path('reset_password_confirmation'), 'badkey')
416 response = self.app.get(confirm_url)
417 assert response.status == '302 Found'
422 response = self.app.get(confirm_url, status=302)
418 423 assert response.location.endswith(route_path('reset_password'))
419 424 assert_session_flash(response, 'Given reset token is invalid')
420 425
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -22,10 +22,10 b''
22 22 import mock
23 23 import pytest
24 24
25 from rhodecode.apps._base import ADMIN_PREFIX
25 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 28 from rhodecode.lib.utils2 import AttributeDict
28 from rhodecode.model.settings import SettingsModel
29 29 from rhodecode.tests.utils import AssertResponse
30 30
31 31
@@ -58,7 +58,7 b' class TestRegisterCaptcha(object):'
58 58 ('privkey', '', CaptchaData(True, 'privkey', '')),
59 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 62 request_stub, user_util):
63 63 request_stub.user = user_util.create_user().AuthUser()
64 64 request_stub.matched_route = AttributeDict({'name': 'login'})
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 33 from rhodecode.apps._base import BaseAppView
34 34 from rhodecode.authentication.base import authenticate, HTTP_TYPE
35 from rhodecode.events import UserRegistered
35 from rhodecode.events import UserRegistered, trigger
36 36 from rhodecode.lib import helpers as h
37 37 from rhodecode.lib import audit_logger
38 38 from rhodecode.lib.auth import (
@@ -113,7 +113,7 b' class LoginView(BaseAppView):'
113 113 def load_default_context(self):
114 114 c = self._get_local_tmpl_context()
115 115 c.came_from = get_came_from(self.request)
116 self._register_global_c(c)
116
117 117 return c
118 118
119 119 def _get_captcha_data(self):
@@ -147,7 +147,7 b' class LoginView(BaseAppView):'
147 147 raise HTTPFound(c.came_from, headers=headers)
148 148 except UserCreationError as e:
149 149 log.error(e)
150 self.session.flash(e, queue='error')
150 h.flash(e, category='error')
151 151
152 152 return self._get_template_context(c)
153 153
@@ -157,7 +157,7 b' class LoginView(BaseAppView):'
157 157 def login_post(self):
158 158 c = self.load_default_context()
159 159
160 login_form = LoginForm()()
160 login_form = LoginForm(self.request.translate)()
161 161
162 162 try:
163 163 self.session.invalidate()
@@ -182,11 +182,10 b' class LoginView(BaseAppView):'
182 182 defaults = errors.value
183 183 # remove password from filling in form again
184 184 defaults.pop('password', None)
185 render_ctx = self._get_template_context(c)
186 render_ctx.update({
185 render_ctx = {
187 186 'errors': errors.error_dict,
188 187 'defaults': defaults,
189 })
188 }
190 189
191 190 audit_user = audit_logger.UserWrap(
192 191 username=self.request.POST.get('username'),
@@ -195,14 +194,14 b' class LoginView(BaseAppView):'
195 194 audit_logger.store_web(
196 195 'user.login.failure', action_data=action_data,
197 196 user=audit_user, commit=True)
198 return render_ctx
197 return self._get_template_context(c, **render_ctx)
199 198
200 199 except UserCreationError as e:
201 200 # headers auth or other auth functions that create users on
202 201 # the fly can throw this exception signaling that there's issue
203 202 # with user creation, explanation should be provided in
204 203 # Exception itself
205 self.session.flash(e, queue='error')
204 h.flash(e, category='error')
206 205 return self._get_template_context(c)
207 206
208 207 @CSRFRequired()
@@ -251,11 +250,12 b' class LoginView(BaseAppView):'
251 250 route_name='register', request_method='POST',
252 251 renderer='rhodecode:templates/register.mako')
253 252 def register_post(self):
253 self.load_default_context()
254 254 captcha = self._get_captcha_data()
255 255 auto_active = 'hg.register.auto_activate' in User.get_default_user()\
256 256 .AuthUser().permissions['global']
257 257
258 register_form = RegisterForm()()
258 register_form = RegisterForm(self.request.translate)()
259 259 try:
260 260
261 261 form_result = register_form.to_python(self.request.POST)
@@ -275,11 +275,18 b' class LoginView(BaseAppView):'
275 275 error_dict=error_dict)
276 276
277 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 285 event = UserRegistered(user=new_user, session=self.session)
279 self.request.registry.notify(event)
280 self.session.flash(
286 trigger(event)
287 h.flash(
281 288 _('You have successfully registered with RhodeCode'),
282 queue='success')
289 category='success')
283 290 Session().commit()
284 291
285 292 redirect_ro = self.request.route_path('login')
@@ -296,16 +303,17 b' class LoginView(BaseAppView):'
296 303 # the fly can throw this exception signaling that there's issue
297 304 # with user creation, explanation should be provided in
298 305 # Exception itself
299 self.session.flash(e, queue='error')
306 h.flash(e, category='error')
300 307 return self.register()
301 308
302 309 @view_config(
303 310 route_name='reset_password', request_method=('GET', 'POST'),
304 311 renderer='rhodecode:templates/password_reset.mako')
305 312 def password_reset(self):
313 c = self.load_default_context()
306 314 captcha = self._get_captcha_data()
307 315
308 render_ctx = {
316 template_context = {
309 317 'captcha_active': captcha.active,
310 318 'captcha_public_key': captcha.public_key,
311 319 'defaults': {},
@@ -320,11 +328,11 b' class LoginView(BaseAppView):'
320 328 if h.HasPermissionAny('hg.password_reset.disabled')():
321 329 _email = self.request.POST.get('email', '')
322 330 log.error('Failed attempt to reset password for `%s`.', _email)
323 self.session.flash(_('Password reset has been disabled.'),
324 queue='error')
331 h.flash(_('Password reset has been disabled.'),
332 category='error')
325 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 336 try:
329 337 form_result = password_reset_form.to_python(
330 338 self.request.POST)
@@ -362,7 +370,7 b' class LoginView(BaseAppView):'
362 370 UserModel().reset_password_link(
363 371 form_result, password_reset_url)
364 372 # Display success message and redirect.
365 self.session.flash(msg, queue='success')
373 h.flash(msg, category='success')
366 374
367 375 action_data = {'email': user_email,
368 376 'user_agent': self.request.user_agent}
@@ -372,30 +380,30 b' class LoginView(BaseAppView):'
372 380 return HTTPFound(self.request.route_path('reset_password'))
373 381
374 382 except formencode.Invalid as errors:
375 render_ctx.update({
383 template_context.update({
376 384 'defaults': errors.value,
377 385 'errors': errors.error_dict,
378 386 })
379 387 if not self.request.POST.get('email'):
380 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 391 if 'recaptcha_field' in errors.error_dict:
384 392 # case of failed captcha
385 return render_ctx
393 return self._get_template_context(c, **template_context)
386 394
387 395 log.debug('faking response on invalid password reset')
388 396 # make this take 2s, to prevent brute forcing.
389 397 time.sleep(2)
390 self.session.flash(msg, queue='success')
398 h.flash(msg, category='success')
391 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 403 @view_config(route_name='reset_password_confirmation',
396 404 request_method='GET')
397 405 def password_reset_confirmation(self):
398
406 self.load_default_context()
399 407 if self.request.GET and self.request.GET.get('key'):
400 408 # make this take 2s, to prevent brute forcing.
401 409 time.sleep(2)
@@ -408,18 +416,18 b' class LoginView(BaseAppView):'
408 416 log.debug('Got token with role:%s expected is %s',
409 417 getattr(token, 'role', 'EMPTY_TOKEN'),
410 418 UserApiKeys.ROLE_PASSWORD_RESET)
411 self.session.flash(
412 _('Given reset token is invalid'), queue='error')
419 h.flash(
420 _('Given reset token is invalid'), category='error')
413 421 return HTTPFound(self.request.route_path('reset_password'))
414 422
415 423 try:
416 424 owner = token.user
417 425 data = {'email': owner.email, 'token': token.api_key}
418 426 UserModel().reset_password(data)
419 self.session.flash(
427 h.flash(
420 428 _('Your password reset was successful, '
421 429 'a new password has been sent to your email'),
422 queue='success')
430 category='success')
423 431 except Exception as e:
424 432 log.error(e)
425 433 return HTTPFound(self.request.route_path('reset_password'))
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -70,6 +70,11 b' def includeme(config):'
70 70 name='my_account_ssh_keys_delete',
71 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 78 # my account emails
74 79 config.add_route(
75 80 name='my_account_emails',
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -19,7 +19,7 b''
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20 # -*- coding: utf-8 -*-
21 21
22 # Copyright (C) 2016-2017 RhodeCode GmbH
22 # Copyright (C) 2016-2018 RhodeCode GmbH
23 23 #
24 24 # This program is free software: you can redistribute it and/or modify
25 25 # it under the terms of the GNU Affero General Public License, version 3
@@ -198,8 +198,6 b' class TestMyAccountEdit(TestController):'
198 198 params=params)
199 199
200 200 response.mustcontain('An email address must contain a single @')
201 from rhodecode.model import validators
202 msg = validators.ValidUsername(
203 edit=False, old_data={})._messages['username_exists']
201 msg = u'Username "%(username)s" already exists'
204 202 msg = h.html_escape(msg % {'username': 'test_admin'})
205 203 response.mustcontain(u"%s" % msg)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 42 from rhodecode.model.db import (
43 43 Repository, UserEmailMap, UserApiKeys, UserFollowing, joinedload,
44 44 PullRequest)
45 from rhodecode.model.forms import UserForm
45 from rhodecode.model.forms import UserForm, UserExtraEmailForm
46 46 from rhodecode.model.meta import Session
47 47 from rhodecode.model.pull_request import PullRequestModel
48 48 from rhodecode.model.scm import RepoList
49 49 from rhodecode.model.user import UserModel
50 50 from rhodecode.model.repo import RepoModel
51 from rhodecode.model.user_group import UserGroupModel
51 52 from rhodecode.model.validation_schema.schemas import user_schema
52 53
53 54 log = logging.getLogger(__name__)
@@ -64,7 +65,7 b' class MyAccountView(BaseAppView, DataGri'
64 65 c = self._get_local_tmpl_context()
65 66 c.user = c.auth_user.get_instance()
66 67 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
67 self._register_global_c(c)
68
68 69 return c
69 70
70 71 @LoginRequired()
@@ -245,6 +246,10 b' class MyAccountView(BaseAppView, DataGri'
245 246 email = self.request.POST.get('new_email')
246 247
247 248 try:
249 form = UserExtraEmailForm(self.request.translate)()
250 data = form.to_python({'email': email})
251 email = data['email']
252
248 253 UserModel().add_extra_email(c.user.user_id, email)
249 254 audit_logger.store_web(
250 255 'user.edit.email.add', action_data={
@@ -442,7 +447,7 b' class MyAccountView(BaseAppView, DataGri'
442 447 c.extern_type = c.user.extern_type
443 448 c.extern_name = c.user.extern_name
444 449
445 _form = UserForm(edit=True,
450 _form = UserForm(self.request.translate, edit=True,
446 451 old_data={'user_id': self._rhodecode_user.user_id,
447 452 'email': self._rhodecode_user.email})()
448 453 form_result = {}
@@ -492,7 +497,7 b' class MyAccountView(BaseAppView, DataGri'
492 497 draw, start, limit = self._extract_chunk(self.request)
493 498 search_q, order_by, order_dir = self._extract_ordering(self.request)
494 499 _render = self.request.get_partial_renderer(
495 'data_table/_dt_elements.mako')
500 'rhodecode:templates/data_table/_dt_elements.mako')
496 501
497 502 pull_requests = PullRequestModel().get_im_participating_in(
498 503 user_id=self._rhodecode_user.user_id,
@@ -568,6 +573,7 b' class MyAccountView(BaseAppView, DataGri'
568 573 route_name='my_account_pullrequests_data',
569 574 request_method='GET', renderer='json_ext')
570 575 def my_account_pullrequests_data(self):
576 self.load_default_context()
571 577 req_get = self.request.GET
572 578 closed = str2bool(req_get.get('closed'))
573 579
@@ -578,3 +584,16 b' class MyAccountView(BaseAppView, DataGri'
578 584 data = self._get_pull_requests_list(statuses=statuses)
579 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 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -43,7 +43,7 b' class MyAccountNotificationsView(BaseApp'
43 43 def load_default_context(self):
44 44 c = self._get_local_tmpl_context()
45 45 c.user = c.auth_user.get_instance()
46 self._register_global_c(c)
46
47 47 return c
48 48
49 49 def _has_permissions(self, notification):
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 45 c.ssh_enabled = self.request.registry.settings.get(
46 46 'ssh.generate_authorized_keyfile')
47 self._register_global_c(c)
47
48 48 return c
49 49
50 50 @LoginRequired()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -18,7 +18,7 b''
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 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 24 def admin_routes(config):
@@ -36,7 +36,7 b' def admin_routes(config):'
36 36 def includeme(config):
37 37
38 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 40 config.add_route(
41 41 name='ops_ping_legacy', pattern=ADMIN_PREFIX + '/ping')
42 42 config.add_route(
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -35,7 +35,7 b' class OpsView(BaseAppView):'
35 35 def load_default_context(self):
36 36 c = self._get_local_tmpl_context()
37 37 c.user = c.auth_user.get_instance()
38 self._register_global_c(c)
38
39 39 return c
40 40
41 41 @view_config(
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -37,7 +37,7 b' log = logging.getLogger(__name__)'
37 37 class RepoGroupSettingsView(RepoGroupAppView):
38 38 def load_default_context(self):
39 39 c = self._get_local_tmpl_context()
40 self._register_global_c(c)
40
41 41 return c
42 42
43 43 @LoginRequired()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -38,7 +38,7 b' log = logging.getLogger(__name__)'
38 38 class RepoGroupPermissionsView(RepoGroupAppView):
39 39 def load_default_context(self):
40 40 c = self._get_local_tmpl_context()
41 self._register_global_c(c)
41
42 42 return c
43 43
44 44 @LoginRequired()
@@ -65,7 +65,7 b' class RepoGroupPermissionsView(RepoGroup'
65 65 c.repo_group = self.db_repo_group
66 66
67 67 valid_recursive_choices = ['none', 'repos', 'groups', 'all']
68 form = RepoGroupPermsForm(valid_recursive_choices)()\
68 form = RepoGroupPermsForm(self.request.translate, valid_recursive_choices)()\
69 69 .to_python(self.request.POST)
70 70
71 71 if not c.rhodecode_user.is_admin:
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -73,7 +73,7 b' class RepoGroupSettingsView(RepoGroupApp'
73 73 c.repo_groups_choices.append(parent_group.group_id)
74 74 c.repo_groups.append(RepoGroup._generate_choice(parent_group))
75 75
76 self._register_global_c(c)
76
77 77 return c
78 78
79 79 def _can_create_repo_group(self, parent_group_id=None):
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 47 class TestRepoCommitCommentsView(TestController):
48 48
49 49 @pytest.fixture(autouse=True)
50 def prepare(self, request, pylonsapp):
50 def prepare(self, request, baseapp):
51 51 for x in ChangesetComment.query().all():
52 52 Session().delete(x)
53 53 Session().commit()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 48 import urllib
49 49
50 50 base_url = {
51 'repo_summary': '/{repo_name}',
51 52 'repo_archivefile': '/{repo_name}/archive/{fname}',
52 53 'repo_files_diff': '/{repo_name}/diff/{f_path}',
53 54 'repo_files_diff_2way_redirect': '/{repo_name}/diff-2way/{f_path}',
@@ -999,8 +1000,11 b' class TestFilesViewOtherCases(object):'
999 1000 .format(repo_file_add_url))
1000 1001
1001 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 1004 repo = backend_stub.create_repo()
1005 # init session for anon user
1006 route_path('repo_summary', repo_name=repo.repo_name)
1007
1004 1008 repo_file_add_url = route_path(
1005 1009 'repo_files_add_file',
1006 1010 repo_name=repo.repo_name,
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -58,11 +58,11 b' class TestRepoIssueTracker(object):'
58 58 'edit_repo_issuetracker_update', repo_name=backend.repo.repo_name)
59 59 post_data = {
60 60 'new_pattern_pattern_0': pattern,
61 'new_pattern_url_0': 'url',
61 'new_pattern_url_0': 'http://url',
62 62 'new_pattern_prefix_0': 'prefix',
63 63 'new_pattern_description_0': 'description',
64 64 'new_pattern_pattern_1': another_pattern,
65 'new_pattern_url_1': 'url1',
65 'new_pattern_url_1': '/url1',
66 66 'new_pattern_prefix_1': 'prefix1',
67 67 'new_pattern_description_1': 'description1',
68 68 'csrf_token': csrf_token
@@ -84,7 +84,7 b' class TestRepoIssueTracker(object):'
84 84 extra_environ=xhr_header, params=data)
85 85
86 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 89 @request.addfinalizer
90 90 def cleanup():
@@ -106,7 +106,7 b' class TestRepoIssueTracker(object):'
106 106 'edit_repo_issuetracker_update', repo_name=backend.repo.repo_name)
107 107 post_data = {
108 108 'new_pattern_pattern_0': pattern,
109 'new_pattern_url_0': 'url',
109 'new_pattern_url_0': '/url',
110 110 'new_pattern_prefix_0': 'prefix',
111 111 'new_pattern_description_0': 'description',
112 112 'uid': old_uid,
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -199,18 +199,17 b' class TestPullrequestsView(object):'
199 199 def test_edit_title_description_closed(self, pr_util, csrf_token):
200 200 pull_request = pr_util.create_pull_request()
201 201 pull_request_id = pull_request.pull_request_id
202 repo_name = pull_request.target_repo.repo_name
202 203 pr_util.close()
203 204
204 205 response = self.app.post(
205 206 route_path('pullrequest_update',
206 repo_name=pull_request.target_repo.repo_name,
207 pull_request_id=pull_request_id),
207 repo_name=repo_name, pull_request_id=pull_request_id),
208 208 params={
209 209 'edit_pull_request': 'true',
210 210 'title': 'New title',
211 211 'description': 'New description',
212 'csrf_token': csrf_token})
213
212 'csrf_token': csrf_token}, status=200)
214 213 assert_session_flash(
215 214 response, u'Cannot update closed pull requests.',
216 215 category='error')
@@ -300,7 +299,7 b' class TestPullrequestsView(object):'
300 299 pull_request = pr_util.create_pull_request()
301 300 pull_request_id = pull_request.pull_request_id
302 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 303 pull_request.author)
305 304 author = pull_request.user_id
306 305 repo = pull_request.target_repo.repo_id
@@ -377,6 +376,8 b' class TestPullrequestsView(object):'
377 376 ('__start__', 'reasons:sequence'),
378 377 ('reason', 'Some reason'),
379 378 ('__end__', 'reasons:sequence'),
379 ('__start__', 'rules:sequence'),
380 ('__end__', 'rules:sequence'),
380 381 ('mandatory', 'False'),
381 382 ('__end__', 'reviewer:mapping'),
382 383 ('__end__', 'review_members:sequence'),
@@ -434,6 +435,8 b' class TestPullrequestsView(object):'
434 435 ('__start__', 'reasons:sequence'),
435 436 ('reason', 'Some reason'),
436 437 ('__end__', 'reasons:sequence'),
438 ('__start__', 'rules:sequence'),
439 ('__end__', 'rules:sequence'),
437 440 ('mandatory', 'False'),
438 441 ('__end__', 'reviewer:mapping'),
439 442 ('__end__', 'review_members:sequence'),
@@ -461,7 +464,7 b' class TestPullrequestsView(object):'
461 464
462 465 # Change reviewers and check that a notification was made
463 466 PullRequestModel().update_reviewers(
464 pull_request.pull_request_id, [(1, [], False)],
467 pull_request.pull_request_id, [(1, [], False, [])],
465 468 pull_request.author)
466 469 assert len(notifications.all()) == 2
467 470
@@ -498,6 +501,8 b' class TestPullrequestsView(object):'
498 501 ('__start__', 'reasons:sequence'),
499 502 ('reason', 'Some reason'),
500 503 ('__end__', 'reasons:sequence'),
504 ('__start__', 'rules:sequence'),
505 ('__end__', 'rules:sequence'),
501 506 ('mandatory', 'False'),
502 507 ('__end__', 'reviewer:mapping'),
503 508 ('__end__', 'review_members:sequence'),
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 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 69 @pytest.mark.usefixtures('app')
60 70 class TestSummaryView(object):
61 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 88 # clone url...
79 response.mustcontain(
80 'id="clone_url" readonly="readonly"'
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, ))
89 assert_clone_url(response, http_host_only_stub, repo_name)
90 assert_clone_url(response, http_host_only_stub, '_{}'.format(repo_id))
85 91
86 92 def test_index_svn_without_proxy(
87 93 self, autologin_user, backend_svn, http_host_only_stub):
@@ -89,12 +95,9 b' class TestSummaryView(object):'
89 95 repo_name = backend_svn.repo_name
90 96 response = self.app.get(route_path('repo_summary', repo_name=repo_name))
91 97 # clone url...
92 response.mustcontain(
93 'id="clone_url" disabled'
94 ' value="http://test_admin@%s/%s"' % (http_host_only_stub, repo_name, ))
95 response.mustcontain(
96 'id="clone_url_id" disabled'
97 ' value="http://test_admin@%s/_%s"' % (http_host_only_stub, repo_id, ))
98
99 assert_clone_url(response, http_host_only_stub, repo_name, disabled=True)
100 assert_clone_url(response, http_host_only_stub, '_{}'.format(repo_id), disabled=True)
98 101
99 102 def test_index_with_trailing_slash(
100 103 self, autologin_user, backend, http_host_only_stub):
@@ -108,12 +111,8 b' class TestSummaryView(object):'
108 111 status=200)
109 112
110 113 # clone url...
111 response.mustcontain(
112 'id="clone_url" readonly="readonly"'
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, ))
114 assert_clone_url(response, http_host_only_stub, repo_name)
115 assert_clone_url(response, http_host_only_stub, '_{}'.format(repo_id))
117 116
118 117 def test_index_by_id(self, autologin_user, backend):
119 118 repo_id = backend.repo.repo_id
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 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 27 Returns json struct of a reviewer for frontend
28 28
@@ -34,10 +34,13 b' def reviewer_as_json(user, reasons=None,'
34 34 return {
35 35 'user_id': user.user_id,
36 36 'reasons': reasons or [],
37 'rules': rules or [],
37 38 'mandatory': mandatory,
39 'user_group': user_group,
38 40 'username': user.username,
39 41 'first_name': user.first_name,
40 42 'last_name': user.last_name,
43 'user_link': h.link_to_user(user),
41 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 71 reviewer_by_id = {}
69 72 for r in review_members:
70 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 76 reviewer_by_id[reviewer_user_id] = entry
74 77 reviewers.append(entry)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -34,7 +34,7 b' class AuditLogsView(RepoAppView):'
34 34 def load_default_context(self):
35 35 c = self._get_local_tmpl_context()
36 36
37 self._register_global_c(c)
37
38 38 return c
39 39
40 40 @LoginRequired()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -37,7 +37,7 b' class RepoCachesView(RepoAppView):'
37 37 def load_default_context(self):
38 38 c = self._get_local_tmpl_context()
39 39
40 self._register_global_c(c)
40
41 41 return c
42 42
43 43 @LoginRequired()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -159,7 +159,7 b' class RepoChangelogView(RepoAppView):'
159 159 c = self._get_local_tmpl_context(include_app_defaults=True)
160 160
161 161 c.rhodecode_repo = self.rhodecode_vcs_repo
162 self._register_global_c(c)
162
163 163 return c
164 164
165 165 def _get_preload_attrs(self):
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -34,7 +34,7 b' log = logging.getLogger(__name__)'
34 34 class RepoChecksView(BaseAppView):
35 35 def load_default_context(self):
36 36 c = self._get_local_tmpl_context()
37 self._register_global_c(c)
37
38 38 return c
39 39
40 40 @NotAnonymous()
@@ -78,10 +78,15 b' class RepoChecksView(BaseAppView):'
78 78
79 79 if task_id and task_id not in ['None']:
80 80 import rhodecode
81 from celery.result import AsyncResult
81 from rhodecode.lib.celerylib.loader import celery_app, exceptions
82 82 if rhodecode.CELERY_ENABLED:
83 task = AsyncResult(task_id)
84 if task.failed():
83 log.debug('celery: checking result for task:%s', task_id)
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 90 msg = self._log_creation_exception(task.result, repo_name)
86 91 h.flash(msg, category='error')
87 92 raise HTTPFound(h.route_path('home'), code=501)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -150,7 +150,6 b' class RepoCommitsView(RepoAppView):'
150 150 c = self._get_local_tmpl_context(include_app_defaults=True)
151 151 c.rhodecode_repo = self.rhodecode_vcs_repo
152 152
153 self._register_global_c(c)
154 153 return c
155 154
156 155 def _commit(self, commit_id_range, method):
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 48 c.rhodecode_repo = self.rhodecode_vcs_repo
49 49
50 self._register_global_c(c)
50
51 51 return c
52 52
53 53 def _get_commit_or_redirect(
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -42,7 +42,7 b' class RepoFeedView(RepoAppView):'
42 42 def load_default_context(self):
43 43 c = self._get_local_tmpl_context()
44 44
45 self._register_global_c(c)
45
46 46 self._load_defaults()
47 47 return c
48 48
@@ -81,21 +81,22 b' class RepoFeedView(RepoAppView):'
81 81 _parsed = diff_processor.prepare(inline_diff=False)
82 82 limited_diff = isinstance(_parsed, LimitedDiffContainer)
83 83
84 return _parsed, limited_diff
84 return diff_processor, _parsed, limited_diff
85 85
86 86 def _get_title(self, commit):
87 87 return h.shorter(commit.message, 160)
88 88
89 89 def _get_description(self, commit):
90 90 _renderer = self.request.get_partial_renderer(
91 'feed/atom_feed_entry.mako')
92 parsed_diff, limited_diff = self._changes(commit)
91 'rhodecode:templates/feed/atom_feed_entry.mako')
92 diff_processor, parsed_diff, limited_diff = self._changes(commit)
93 93 return _renderer(
94 94 'body',
95 95 commit=commit,
96 96 parsed_diff=parsed_diff,
97 97 limited_diff=limited_diff,
98 98 feed_include_diff=self.feed_include_diff,
99 diff_processor=diff_processor,
99 100 )
100 101
101 102 def _set_timezone(self, date, tzinfo=pytz.utc):
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 84 c.rhodecode_repo = self.rhodecode_vcs_repo
85 85
86 self._register_global_c(c)
86
87 87 return c
88 88
89 89 def _ensure_not_locked(self):
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 33 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous,
34 34 HasRepoPermissionAny, HasPermissionAnyDecorator, CSRFRequired)
35 35 import rhodecode.lib.helpers as h
36 from rhodecode.lib.celerylib.utils import get_task_id
36 37 from rhodecode.model.db import coalesce, or_, Repository, RepoGroup
37 38 from rhodecode.model.repo import RepoModel
38 39 from rhodecode.model.forms import RepoForkForm
@@ -53,11 +54,11 b' class RepoForksView(RepoAppView, DataGri'
53 54 perm_set=['group.write', 'group.admin'])
54 55 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
55 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 59 c.landing_revs_choices = choices
58 60 c.personal_repo_group = c.rhodecode_user.personal_repo_group
59 61
60 self._register_global_c(c)
61 62 return c
62 63
63 64 @LoginRequired()
@@ -78,6 +79,7 b' class RepoForksView(RepoAppView, DataGri'
78 79 renderer='json_ext', xhr=True)
79 80 def repo_forks_data(self):
80 81 _ = self.request.translate
82 self.load_default_context()
81 83 column_map = {
82 84 'fork_name': 'repo_name',
83 85 'fork_date': 'created_on',
@@ -209,7 +211,7 b' class RepoForksView(RepoAppView, DataGri'
209 211 _ = self.request.translate
210 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 215 repo_groups=c.repo_groups_choices,
214 216 landing_revs=c.landing_revs_choices)()
215 217 post_data = dict(self.request.POST)
@@ -225,9 +227,8 b' class RepoForksView(RepoAppView, DataGri'
225 227 # management is handled there.
226 228 task = RepoModel().create_fork(
227 229 form_result, c.rhodecode_user.user_id)
228 from celery.result import BaseAsyncResult
229 if isinstance(task, BaseAsyncResult):
230 task_id = task.task_id
230
231 task_id = get_task_id(task)
231 232 except formencode.Invalid as errors:
232 233 c.rhodecode_db_repo = self.db_repo
233 234
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -33,7 +33,7 b' class RepoMaintenanceView(RepoAppView):'
33 33 def load_default_context(self):
34 34 c = self._get_local_tmpl_context()
35 35
36 self._register_global_c(c)
36
37 37 return c
38 38
39 39 @LoginRequired()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -40,7 +40,7 b' class RepoSettingsPermissionsView(RepoAp'
40 40 def load_default_context(self):
41 41 c = self._get_local_tmpl_context()
42 42
43 self._register_global_c(c)
43
44 44 return c
45 45
46 46 @LoginRequired()
@@ -68,7 +68,7 b' class RepoSettingsPermissionsView(RepoAp'
68 68 # default user permissions, prevents submission of FAKE post data
69 69 # into the form for private repos
70 70 data['repo_private'] = self.db_repo.private
71 form = RepoPermsForm()().to_python(data)
71 form = RepoPermsForm(self.request.translate)().to_python(data)
72 72 changes = RepoModel().update_permissions(
73 73 self.db_repo_name, form['perm_additions'], form['perm_updates'],
74 74 form['perm_deletions'])
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -60,7 +60,7 b' class RepoPullRequestsView(RepoAppView, '
60 60 c = self._get_local_tmpl_context(include_app_defaults=True)
61 61 c.REVIEW_STATUS_APPROVED = ChangesetStatus.STATUS_APPROVED
62 62 c.REVIEW_STATUS_REJECTED = ChangesetStatus.STATUS_REJECTED
63 self._register_global_c(c)
63
64 64 return c
65 65
66 66 def _get_pull_requests_list(
@@ -69,7 +69,7 b' class RepoPullRequestsView(RepoAppView, '
69 69 draw, start, limit = self._extract_chunk(self.request)
70 70 search_q, order_by, order_dir = self._extract_ordering(self.request)
71 71 _render = self.request.get_partial_renderer(
72 'data_table/_dt_elements.mako')
72 'rhodecode:templates/data_table/_dt_elements.mako')
73 73
74 74 # pagination
75 75
@@ -173,6 +173,7 b' class RepoPullRequestsView(RepoAppView, '
173 173 route_name='pullrequest_show_all_data', request_method='GET',
174 174 renderer='json_ext', xhr=True)
175 175 def pull_request_list_data(self):
176 self.load_default_context()
176 177
177 178 # additional filters
178 179 req_get = self.request.GET
@@ -200,29 +201,6 b' class RepoPullRequestsView(RepoAppView, '
200 201
201 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 204 def _get_diffset(self, source_repo_name, source_repo,
227 205 source_ref_id, target_ref_id,
228 206 target_commit, source_commit, diff_limit, fulldiff,
@@ -277,7 +255,7 b' class RepoPullRequestsView(RepoAppView, '
277 255 (pull_request_latest,
278 256 pull_request_at_ver,
279 257 pull_request_display_obj,
280 at_version) = self._get_pr_version(
258 at_version) = PullRequestModel().get_pr_version(
281 259 pull_request_id, version=version)
282 260 pr_closed = pull_request_latest.is_closed()
283 261
@@ -299,7 +277,7 b' class RepoPullRequestsView(RepoAppView, '
299 277 (prev_pull_request_latest,
300 278 prev_pull_request_at_ver,
301 279 prev_pull_request_display_obj,
302 prev_at_version) = self._get_pr_version(
280 prev_at_version) = PullRequestModel().get_pr_version(
303 281 pull_request_id, version=from_version)
304 282
305 283 c.from_version = prev_at_version
@@ -630,7 +608,8 b' class RepoPullRequestsView(RepoAppView, '
630 608 try:
631 609 source_repo_data = PullRequestModel().generate_repo_data(
632 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 613 except CommitDoesNotExistError as e:
635 614 log.exception(e)
636 615 h.flash(_('Commit does not exist'), 'error')
@@ -649,8 +628,9 b' class RepoPullRequestsView(RepoAppView, '
649 628 default_target_repo, translator=self.request.translate)
650 629
651 630 selected_source_ref = source_repo_data['refs']['selected_ref']
652
653 title_source_ref = selected_source_ref.split(':', 2)[1]
631 title_source_ref = ''
632 if selected_source_ref:
633 title_source_ref = selected_source_ref.split(':', 2)[1]
654 634 c.default_title = PullRequestModel().generate_pullrequest_title(
655 635 source=source_repo.repo_name,
656 636 source_ref=title_source_ref,
@@ -675,6 +655,7 b' class RepoPullRequestsView(RepoAppView, '
675 655 route_name='pullrequest_repo_refs', request_method='GET',
676 656 renderer='json_ext', xhr=True)
677 657 def pull_request_repo_refs(self):
658 self.load_default_context()
678 659 target_repo_name = self.request.matchdict['target_repo_name']
679 660 repo = Repository.get_by_repo_name(target_repo_name)
680 661 if not repo:
@@ -752,16 +733,19 b' class RepoPullRequestsView(RepoAppView, '
752 733 def pull_request_create(self):
753 734 _ = self.request.translate
754 735 self.assure_not_empty_repo()
736 self.load_default_context()
755 737
756 738 controls = peppercorn.parse(self.request.POST.items())
757 739
758 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 744 except formencode.Invalid as errors:
761 745 if errors.error_dict.get('revisions'):
762 746 msg = 'Revisions: %s' % errors.error_dict['revisions']
763 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 749 else:
766 750 msg = _('Error creating pull request: {}').format(errors)
767 751 log.exception(msg)
@@ -882,6 +866,15 b' class RepoPullRequestsView(RepoAppView, '
882 866 def pull_request_update(self):
883 867 pull_request = PullRequest.get_or_404(
884 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 879 # only owner or admin can update it
887 880 allowed_to_update = PullRequestModel().check_user_update(
@@ -981,6 +974,7 b' class RepoPullRequestsView(RepoAppView, '
981 974 pull_request = PullRequest.get_or_404(
982 975 self.request.matchdict['pull_request_id'])
983 976
977 self.load_default_context()
984 978 check = MergeCheck.validate(pull_request, self._rhodecode_db_user,
985 979 translator=self.request.translate)
986 980 merge_possible = not check.failed
@@ -1053,6 +1047,7 b' class RepoPullRequestsView(RepoAppView, '
1053 1047
1054 1048 pull_request = PullRequest.get_or_404(
1055 1049 self.request.matchdict['pull_request_id'])
1050 self.load_default_context()
1056 1051
1057 1052 pr_closed = pull_request.is_closed()
1058 1053 allowed_to_delete = PullRequestModel().check_user_delete(
@@ -1166,6 +1161,10 b' class RepoPullRequestsView(RepoAppView, '
1166 1161 )
1167 1162
1168 1163 Session().flush()
1164 # this is somehow required to get access to some relationship
1165 # loaded on comment
1166 Session().refresh(comment)
1167
1169 1168 events.trigger(
1170 1169 events.PullRequestCommentEvent(pull_request, comment))
1171 1170
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -32,8 +32,6 b' log = logging.getLogger(__name__)'
32 32 class RepoReviewRulesView(RepoAppView):
33 33 def load_default_context(self):
34 34 c = self._get_local_tmpl_context()
35
36 self._register_global_c(c)
37 35 return c
38 36
39 37 @LoginRequired()
@@ -54,6 +52,7 b' class RepoReviewRulesView(RepoAppView):'
54 52 route_name='repo_default_reviewers_data', request_method='GET',
55 53 renderer='json_ext')
56 54 def repo_default_reviewers_data(self):
55 self.load_default_context()
57 56 review_data = get_default_reviewers_data(
58 57 self.db_repo.user, None, None, None, None)
59 58 return review_data
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -62,16 +62,17 b' class RepoSettingsView(RepoAppView):'
62 62 # we might be in missing requirement state, so we load things
63 63 # without touching scm_instance()
64 64 c.landing_revs_choices, c.landing_revs = \
65 ScmModel().get_repo_landing_revs()
65 ScmModel().get_repo_landing_revs(self.request.translate)
66 66 else:
67 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 71 c.personal_repo_group = c.auth_user.personal_repo_group
71 72 c.repo_fields = RepositoryField.query()\
72 73 .filter(RepositoryField.repository == self.db_repo).all()
73 74
74 self._register_global_c(c)
75
75 76 return c
76 77
77 78 def _get_schema(self, c, old_values=None):
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -44,7 +44,7 b' class RepoSettingsView(RepoAppView):'
44 44 def load_default_context(self):
45 45 c = self._get_local_tmpl_context()
46 46
47 self._register_global_c(c)
47
48 48 return c
49 49
50 50 @LoginRequired()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -43,7 +43,7 b' class RepoSettingsFieldsView(RepoAppView'
43 43 def load_default_context(self):
44 44 c = self._get_local_tmpl_context()
45 45
46 self._register_global_c(c)
46
47 47 return c
48 48
49 49 @LoginRequired()
@@ -70,7 +70,8 b' class RepoSettingsFieldsView(RepoAppView'
70 70 _ = self.request.translate
71 71
72 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 75 RepoModel().add_repo_field(
75 76 self.db_repo_name,
76 77 form_result['new_field_key'],
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -22,6 +22,7 b' import logging'
22 22
23 23 from pyramid.httpexceptions import HTTPFound
24 24 from pyramid.view import view_config
25 import formencode
25 26
26 27 from rhodecode.apps._base import RepoAppView
27 28 from rhodecode.lib import audit_logger
@@ -39,7 +40,7 b' class RepoSettingsIssueTrackersView(Repo'
39 40 def load_default_context(self):
40 41 c = self._get_local_tmpl_context()
41 42
42 self._register_global_c(c)
43
43 44 return c
44 45
45 46 @LoginRequired()
@@ -116,7 +117,17 b' class RepoSettingsIssueTrackersView(Repo'
116 117 repo_settings.inherit_global_settings = inherited
117 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 131 if form:
121 132 self._update_patterns(form, repo_settings)
122 133
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -36,7 +36,7 b' class RepoSettingsRemoteView(RepoAppView'
36 36 def load_default_context(self):
37 37 c = self._get_local_tmpl_context()
38 38
39 self._register_global_c(c)
39
40 40 return c
41 41
42 42 @LoginRequired()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -43,7 +43,7 b' class RepoSettingsVcsView(RepoAppView):'
43 43 def load_default_context(self):
44 44 c = self._get_local_tmpl_context()
45 45
46 self._register_global_c(c)
46
47 47 return c
48 48
49 49 def _vcs_form_defaults(self, repo_name):
@@ -117,7 +117,7 b' class RepoSettingsVcsView(RepoAppView):'
117 117 defaults = self._vcs_form_defaults(self.db_repo_name)
118 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 121 try:
122 122 form_result = application_form.to_python(dict(self.request.POST))
123 123 except formencode.Invalid as errors:
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -35,7 +35,7 b' class StripView(RepoAppView):'
35 35 def load_default_context(self):
36 36 c = self._get_local_tmpl_context()
37 37
38 self._register_global_c(c)
38
39 39 return c
40 40
41 41 @LoginRequired()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 49 def load_default_context(self):
50 50 c = self._get_local_tmpl_context(include_app_defaults=True)
51
52 51 c.rhodecode_repo = None
53 52 if not c.repository_requirements_missing:
54 53 c.rhodecode_repo = self.rhodecode_vcs_repo
55
56 self._register_global_c(c)
57 54 return c
58 55
59 56 def _get_readme_data(self, db_repo, default_renderer):
@@ -174,18 +171,22 b' class RepoSummaryView(RepoAppView):'
174 171 if self._rhodecode_user.username != User.DEFAULT_USER:
175 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 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 179 '{repo}', '_{repoid}')
181 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 182 '_{repoid}', '{repo}')
184 183
185 184 c.clone_repo_url = self.db_repo.clone_url(
186 185 user=username, uri_tmpl=_def_clone_uri)
187 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 191 # If enabled, get statistics data
191 192
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -25,7 +25,7 b' import pytest'
25 25 from whoosh import query
26 26
27 27 from rhodecode.tests import (
28 TestController, SkipTest, HG_REPO,
28 TestController, HG_REPO,
29 29 TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
30 30 from rhodecode.tests.utils import AssertResponse
31 31
@@ -51,7 +51,7 b' class TestSearchController(TestControlle'
51 51
52 52 def test_search_files_empty_search(self):
53 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 55 else:
56 56 self.log_user()
57 57 response = self.app.get(route_path('search'),
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 103 class SearchView(BaseAppView):
104 104 def load_default_context(self):
105 105 c = self._get_local_tmpl_context()
106 self._register_global_c(c)
106
107 107 return c
108 108
109 109 @LoginRequired()
@@ -119,7 +119,7 b' class SearchView(BaseAppView):'
119 119 class SearchRepoView(RepoAppView):
120 120 def load_default_context(self):
121 121 c = self._get_local_tmpl_context()
122 self._register_global_c(c)
122
123 123 return c
124 124
125 125 @LoginRequired()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 3 # This program is free software: you can redistribute it and/or modify
4 4 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -22,7 +22,7 b' import os'
22 22 import re
23 23 import logging
24 24 import datetime
25 import ConfigParser
25 from pyramid.compat import configparser
26 26
27 27 from rhodecode.model.db import Session, User, UserSshKeys
28 28 from rhodecode.model.scm import ScmModel
@@ -51,7 +51,7 b' class SshWrapper(object):'
51 51 self.server_impl = None
52 52
53 53 def parse_config(self, config_path):
54 parser = ConfigParser.ConfigParser()
54 parser = configparser.ConfigParser()
55 55 parser.read(config_path)
56 56 return parser
57 57
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -93,6 +93,7 b' class VcsServer(object):'
93 93 scm_data = {
94 94 'ip': os.environ['SSH_CLIENT'].split()[0],
95 95 'username': self.user.username,
96 'user_id': self.user.user_id,
96 97 'action': action,
97 98 'repository': self.repo_name,
98 99 'scm': self.backend,
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -20,7 +20,7 b''
20 20
21 21 import os
22 22 import pytest
23 import ConfigParser
23 from pyramid.compat import configparser
24 24
25 25 from rhodecode.apps.ssh_support.lib.ssh_wrapper import SshWrapper
26 26 from rhodecode.lib.utils2 import AttributeDict
@@ -28,7 +28,7 b' from rhodecode.lib.utils2 import Attribu'
28 28
29 29 @pytest.fixture
30 30 def dummy_conf_file(tmpdir):
31 conf = ConfigParser.ConfigParser()
31 conf = configparser.ConfigParser()
32 32 conf.add_section('app:main')
33 33 conf.set('app:main', 'ssh.executable.hg', '/usr/bin/hg')
34 34 conf.set('app:main', 'ssh.executable.git', '/usr/bin/git')
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 128 expected_data = {
129 129 'username': git_server.user.username,
130 'user_id': git_server.user.user_id,
130 131 'scm': 'git',
131 132 'repository': git_server.repo_name,
132 133 'make_lock': None,
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 3 # This program is free software: you can redistribute it and/or modify
4 4 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -23,19 +23,14 b' import os'
23 23 import mock
24 24 import pytest
25 25
26 from pyramid import testing
27
28 26 from rhodecode.apps.svn_support import utils
29 27
30 28
29 @pytest.mark.usefixtures('config_stub')
31 30 class TestModDavSvnConfig(object):
32 31
33 32 @classmethod
34 33 def setup_class(cls):
35 # Make mako renderer available in tests.
36 config = testing.setUp()
37 config.include('pyramid_mako')
38
39 34 cls.location_root = u'/location/root/çµäö'
40 35 cls.parent_path_root = u'/parent/path/çµäö'
41 36 cls.realm = u'Dummy Realm (äöüçµ)'
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -20,7 +20,7 b''
20 20
21 21
22 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 24 from rhodecode.lib.utils2 import str2bool
25 25
26 26
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 40 LoginRequired, HasUserGroupPermissionAnyDecorator, CSRFRequired)
41 41 from rhodecode.lib import helpers as h, audit_logger
42 42 from rhodecode.lib.utils2 import str2bool
43 from rhodecode.model.db import (
44 joinedload, User, UserGroupRepoToPerm, UserGroupRepoGroupToPerm)
43 from rhodecode.model.db import User
45 44 from rhodecode.model.meta import Session
46 45 from rhodecode.model.user_group import UserGroupModel
47 46
@@ -56,35 +55,8 b' class UserGroupsView(UserGroupAppView):'
56 55 PermissionModel().set_global_permission_choices(
57 56 c, gettext_translator=self.request.translate)
58 57
59 self._register_global_c(c)
60 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 60 @LoginRequired()
89 61 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
90 62 @view_config(
@@ -94,6 +66,7 b' class UserGroupsView(UserGroupAppView):'
94 66 """
95 67 Return members of given user group
96 68 """
69 self.load_default_context()
97 70 user_group = self.db_user_group
98 71 group_members_obj = sorted((x.user for x in user_group.members),
99 72 key=lambda u: u.username.lower())
@@ -126,7 +99,8 b' class UserGroupsView(UserGroupAppView):'
126 99 c = self.load_default_context()
127 100 c.user_group = self.db_user_group
128 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 104 return self._get_template_context(c)
131 105
132 106 @LoginRequired()
@@ -137,7 +111,7 b' class UserGroupsView(UserGroupAppView):'
137 111 def user_group_perms_summary_json(self):
138 112 self.load_default_context()
139 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 116 def _revoke_perms_on_yourself(self, form_result):
143 117 _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
@@ -173,7 +147,8 b' class UserGroupsView(UserGroupAppView):'
173 147 c.active = 'settings'
174 148
175 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 153 old_values = c.user_group.get_api_data()
179 154 user_group_name = self.request.POST.get('users_group_name')
@@ -346,7 +321,7 b' class UserGroupsView(UserGroupAppView):'
346 321 user_group_id = user_group.users_group_id
347 322 c = self.load_default_context()
348 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 326 if not self._rhodecode_user.is_admin:
352 327 if self._revoke_perms_on_yourself(form):
@@ -426,7 +401,7 b' class UserGroupsView(UserGroupAppView):'
426 401
427 402 try:
428 403 # first stage that verifies the checkbox
429 _form = UserIndividualPermissionsForm()
404 _form = UserIndividualPermissionsForm(self.request.translate)
430 405 form_result = _form.to_python(dict(self.request.POST))
431 406 inherit_perms = form_result['inherit_default_permissions']
432 407 user_group.inherit_default_permissions = inherit_perms
@@ -435,6 +410,7 b' class UserGroupsView(UserGroupAppView):'
435 410 if not inherit_perms:
436 411 # only update the individual ones if we un check the flag
437 412 _form = UserPermissionsForm(
413 self.request.translate,
438 414 [x[0] for x in c.repo_create_choices],
439 415 [x[0] for x in c.repo_create_on_write_choices],
440 416 [x[0] for x in c.repo_group_create_choices],
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 27 from rhodecode.authentication.registry import AuthenticationPluginRegistry
28 28 from rhodecode.authentication.routes import root_factory
29 29 from rhodecode.authentication.routes import AuthnRootResource
30 from rhodecode.config.routing import ADMIN_PREFIX
30 from rhodecode.apps._base import ADMIN_PREFIX
31 31 from rhodecode.model.settings import SettingsModel
32 32
33 33
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -77,7 +77,6 b' class hybrid_property(object):'
77 77 self.fdel(instance)
78 78
79 79
80
81 80 class LazyFormencode(object):
82 81 def __init__(self, formencode_obj, *args, **kwargs):
83 82 self.formencode_obj = formencode_obj
@@ -106,6 +105,8 b' class RhodeCodeAuthPluginBase(object):'
106 105 "lastname": "last name",
107 106 "email": "email address",
108 107 "groups": '["list", "of", "groups"]',
108 "user_group_sync":
109 'True|False defines if returned user groups should be synced',
109 110 "extern_name": "name in external source of record",
110 111 "extern_type": "type of external source of record",
111 112 "admin": 'True|False defines if user should be RhodeCode super admin',
@@ -114,6 +115,7 b' class RhodeCodeAuthPluginBase(object):'
114 115 "active_from_extern":
115 116 "True|False\None, active state from the external auth, "
116 117 "None means use definition from RhodeCode extern_type active value"
118
117 119 }
118 120 # set on authenticate() method and via set_auth_type func.
119 121 auth_type = None
@@ -252,29 +254,6 b' class RhodeCodeAuthPluginBase(object):'
252 254 del settings_copy[k]
253 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 257 @hybrid_property
279 258 def name(self):
280 259 """
@@ -435,8 +414,9 b' class RhodeCodeAuthPluginBase(object):'
435 414 new_hash = auth.get('_hash_migrate')
436 415 if new_hash:
437 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 419 return self._validate_auth_return(auth)
439
440 420 return auth
441 421
442 422 def _migrate_hash_to_bcrypt(self, username, password, new_hash):
@@ -561,16 +541,19 b' class RhodeCodeExternalAuthPlugin(RhodeC'
561 541 # enforce user is just in given groups, all of them has to be ones
562 542 # created from plugins. We store this info in _group_data JSON
563 543 # field
564 try:
565 groups = auth['groups'] or []
566 log.debug(
567 'Performing user_group sync based on set `%s` '
568 'returned by this plugin', groups)
569 UserGroupModel().enforce_groups(user, groups, self.name)
570 except Exception:
571 # for any reason group syncing fails, we should
572 # proceed with login
573 log.error(traceback.format_exc())
544
545 if auth['user_group_sync']:
546 try:
547 groups = auth['groups'] or []
548 log.debug(
549 'Performing user_group sync based on set `%s` '
550 'returned by `%s` plugin', groups, self.name)
551 UserGroupModel().enforce_groups(user, groups, self.name)
552 except Exception:
553 # for any reason group syncing fails, we should
554 # proceed with login
555 log.error(traceback.format_exc())
556
574 557 Session().commit()
575 558 return auth
576 559
@@ -694,7 +677,7 b' def authenticate(username, password, env'
694 677 environ=environ or {})
695 678
696 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 681 plugin_user = cache_manager.get(
699 682 _password_hash, createfunc=auth_func)
700 683 else:
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -267,6 +267,7 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
267 267 'firstname': crowd_user["first-name"] or firstname,
268 268 'lastname': crowd_user["last-name"] or lastname,
269 269 'groups': crowd_user["groups"],
270 'user_group_sync': True,
270 271 'email': crowd_user["email"] or email,
271 272 'admin': admin,
272 273 'active': active,
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -212,6 +212,7 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
212 212 'firstname': safe_unicode(firstname or username),
213 213 'lastname': safe_unicode(lastname or ''),
214 214 'groups': [],
215 'user_group_sync': False,
215 216 'email': email or '',
216 217 'admin': admin or False,
217 218 'active': active,
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -154,6 +154,7 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
154 154 'firstname': safe_unicode(firstname or username),
155 155 'lastname': safe_unicode(lastname or ''),
156 156 'groups': [],
157 'user_group_sync': False,
157 158 'email': email or '',
158 159 'admin': admin or False,
159 160 'active': active,
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -460,6 +460,7 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
460 460 'lastname': safe_unicode(
461 461 get_ldap_attr('attr_lastname') or lastname),
462 462 'groups': groups,
463 'user_group_sync': False,
463 464 'email': get_ldap_attr('attr_email') or email,
464 465 'admin': admin,
465 466 'active': active,
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -136,6 +136,7 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
136 136 'lastname': lastname,
137 137 'groups': [g.gr_name for g in grp.getgrall()
138 138 if username in g.gr_mem],
139 'user_group_sync': True,
139 140 'email': email,
140 141 'admin': admin,
141 142 'active': active,
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -100,6 +100,7 b' class RhodeCodeAuthPlugin(RhodeCodeAuthP'
100 100 "firstname": userobj.firstname,
101 101 "lastname": userobj.lastname,
102 102 "groups": [],
103 'user_group_sync': False,
103 104 "email": userobj.email,
104 105 "admin": userobj.admin,
105 106 "active": userobj.active,
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -111,6 +111,7 b' class RhodeCodeAuthPlugin(RhodeCodeAuthP'
111 111 "firstname": userobj.firstname,
112 112 "lastname": userobj.lastname,
113 113 "groups": [],
114 'user_group_sync': False,
114 115 "email": userobj.email,
115 116 "admin": userobj.admin,
116 117 "active": userobj.active,
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -22,7 +22,7 b''
22 22 import pytest
23 23
24 24
25 class EnabledAuthPlugin():
25 class EnabledAuthPlugin(object):
26 26 """
27 27 Context manager that updates the 'auth_plugins' setting in DB to enable
28 28 a plugin. Previous setting is restored on exit. The rhodecode auth plugin
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -23,7 +23,7 b' import pytest'
23 23
24 24 from rhodecode.authentication.tests.conftest import (
25 25 EnabledAuthPlugin, DisabledAuthPlugin)
26 from rhodecode.config.routing import ADMIN_PREFIX
26 from rhodecode.apps._base import ADMIN_PREFIX
27 27
28 28
29 29 @pytest.mark.usefixtures('autologin_user', 'app')
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2017 RhodeCode GmbH
3 # Copyright (C) 2012-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 26 from pyramid.renderers import render
27 27 from pyramid.response import Response
28 28
29 from rhodecode.apps._base import BaseAppView
29 30 from rhodecode.authentication.base import (
30 31 get_auth_cache_manager, get_perms_cache_manager, get_authn_registry)
31 from rhodecode.lib import auth
32 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
32 from rhodecode.lib import helpers as h
33 from rhodecode.lib.auth import (
34 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
33 35 from rhodecode.model.forms import AuthSettingsForm
34 36 from rhodecode.model.meta import Session
35 37 from rhodecode.model.settings import SettingsModel
36 from rhodecode.translation import _
37 38
38 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 self.request = request
45 self.context = context
46 self.plugin = context.plugin
47 self._rhodecode_user = request.user
44 def load_default_context(self):
45 c = self._get_local_tmpl_context()
46 self.plugin = self.context.plugin
47 return c
48 48
49 49 @LoginRequired()
50 50 @HasPermissionAllDecorator('hg.admin')
@@ -52,6 +52,7 b' class AuthnPluginViewBase(object):'
52 52 """
53 53 View that displays the plugin settings as a form.
54 54 """
55 c = self.load_default_context()
55 56 defaults = defaults or {}
56 57 errors = errors or {}
57 58 schema = self.plugin.get_settings_schema()
@@ -70,15 +71,17 b' class AuthnPluginViewBase(object):'
70 71 'resource': self.context,
71 72 }
72 73
73 return template_context
74 return self._get_template_context(c, **template_context)
74 75
75 76 @LoginRequired()
76 77 @HasPermissionAllDecorator('hg.admin')
77 @auth.CSRFRequired()
78 @CSRFRequired()
78 79 def settings_post(self):
79 80 """
80 81 View that validates and stores the plugin settings.
81 82 """
83 _ = self.request.translate
84 self.load_default_context()
82 85 schema = self.plugin.get_settings_schema()
83 86 data = self.request.params
84 87
@@ -86,10 +89,10 b' class AuthnPluginViewBase(object):'
86 89 valid_data = schema.deserialize(data)
87 90 except colander.Invalid as e:
88 91 # Display error message and display form again.
89 self.request.session.flash(
92 h.flash(
90 93 _('Errors exist when saving plugin settings. '
91 94 'Please check the form inputs.'),
92 queue='error')
95 category='error')
93 96 defaults = {key: data[key] for key in data if key in schema}
94 97 return self.settings_get(errors=e.asdict(), defaults=defaults)
95 98
@@ -99,31 +102,22 b' class AuthnPluginViewBase(object):'
99 102 Session().commit()
100 103
101 104 # Display success message and redirect.
102 self.request.session.flash(
103 _('Auth settings updated successfully.'),
104 queue='success')
105 h.flash(_('Auth settings updated successfully.'), category='success')
105 106 redirect_to = self.request.resource_path(
106 107 self.context, route_name='auth_home')
107 108 return HTTPFound(redirect_to)
108 109
109 110
110 # TODO: Ongoing migration in these views.
111 # - Maybe we should also use a colander schema for these views.
112 class AuthSettingsView(object):
113 def __init__(self, context, request):
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
111 class AuthSettingsView(BaseAppView):
112 def load_default_context(self):
113 c = self._get_local_tmpl_context()
114 return c
123 115
124 116 @LoginRequired()
125 117 @HasPermissionAllDecorator('hg.admin')
126 118 def index(self, defaults=None, errors=None, prefix_error=False):
119 c = self.load_default_context()
120
127 121 defaults = defaults or {}
128 122 authn_registry = get_authn_registry(self.request.registry)
129 123 enabled_plugins = SettingsModel().get_auth_plugins()
@@ -135,8 +129,8 b' class AuthSettingsView(object):'
135 129 'enabled_plugins': enabled_plugins,
136 130 }
137 131 html = render('rhodecode:templates/admin/auth/auth_settings.mako',
138 template_context,
139 request=self.request)
132 self._get_template_context(c, **template_context),
133 self.request)
140 134
141 135 # Create form default values and fill the form.
142 136 form_defaults = {
@@ -155,11 +149,12 b' class AuthSettingsView(object):'
155 149
156 150 @LoginRequired()
157 151 @HasPermissionAllDecorator('hg.admin')
158 @auth.CSRFRequired()
152 @CSRFRequired()
159 153 def auth_settings(self):
154 _ = self.request.translate
160 155 try:
161 form = AuthSettingsForm()()
162 form_result = form.to_python(self.request.params)
156 form = AuthSettingsForm(self.request.translate)()
157 form_result = form.to_python(self.request.POST)
163 158 plugins = ','.join(form_result['auth_plugins'])
164 159 setting = SettingsModel().create_or_update_setting(
165 160 'auth_plugins', plugins)
@@ -172,24 +167,19 b' class AuthSettingsView(object):'
172 167 cache_manager = get_perms_cache_manager()
173 168 cache_manager.clear()
174 169
175 self.request.session.flash(
176 _('Auth settings updated successfully.'),
177 queue='success')
170 h.flash(_('Auth settings updated successfully.'), category='success')
178 171 except formencode.Invalid as errors:
179 172 e = errors.error_dict or {}
180 self.request.session.flash(
181 _('Errors exist when saving plugin setting. '
182 'Please check the form inputs.'),
183 queue='error')
173 h.flash(_('Errors exist when saving plugin setting. '
174 'Please check the form inputs.'), category='error')
184 175 return self.index(
185 176 defaults=errors.value,
186 177 errors=e,
187 178 prefix_error=False)
188 179 except Exception:
189 180 log.exception('Exception in auth_settings')
190 self.request.session.flash(
191 _('Error occurred during update of auth settings.'),
192 queue='error')
181 h.flash(_('Error occurred during update of auth settings.'),
182 category='error')
193 183
194 184 redirect_to = self.request.resource_path(
195 185 self.context, route_name='auth_home')
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2013-2017 RhodeCode GmbH
3 # Copyright (C) 2013-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -18,121 +18,19 b''
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 """
22 Pylons environment configuration
23 """
24 21
25 22 import os
26 23 import logging
27 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
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)
27 from rhodecode.config import utils
99 28
100 # Create the Mako TemplateLookup, with the default auto-escaping
101 config['pylons.app_globals'].mako_lookup = TemplateLookup(
102 directories=paths['templates'],
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 }
29 from rhodecode.lib.utils import load_rcextensions
30 from rhodecode.lib.utils2 import str2bool
31 from rhodecode.lib.vcs import connect_vcs
117 32
118 db_cfg = make_db_config(clear_session=True)
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
33 log = logging.getLogger(__name__)
136 34
137 35
138 36 def load_pyramid_environment(global_config, settings):
@@ -140,10 +38,13 b' def load_pyramid_environment(global_conf'
140 38 settings_merged = global_config.copy()
141 39 settings_merged.update(settings)
142 40
143 # Store the settings to make them available to other modules.
144 rhodecode.PYRAMID_SETTINGS = settings_merged
145 # NOTE(marcink): needs to be enabled after full port to pyramid
146 # rhodecode.CONFIG = config
41 # TODO(marcink): probably not required anymore
42 # configure channelstream,
43 settings_merged['channelstream_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 49 # If this is a test run we prepare the test environment like
149 50 # creating a test database, test search index and test repositories.
@@ -157,6 +58,8 b' def load_pyramid_environment(global_conf'
157 58 # Initialize the database connection.
158 59 utils.initialize_database(settings_merged)
159 60
61 load_rcextensions(root_path=settings_merged['here'])
62
160 63 # Limit backends to `vcs.backends` from configuration
161 64 for alias in rhodecode.BACKENDS.keys():
162 65 if alias not in settings['vcs.backends']:
@@ -166,17 +69,13 b' def load_pyramid_environment(global_conf'
166 69 # initialize vcs client and optionally run the server if enabled
167 70 vcs_server_uri = settings['vcs.server']
168 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 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 80 if vcs_server_enabled:
182 81 connect_vcs(vcs_server_uri, utils.get_vcs_server_protocol(settings))
@@ -16,7 +16,7 b" RC_HOOK_VER = '_TMPL_'"
16 16
17 17 def main():
18 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 20 # this allows simply push to this repo even without rhodecode
21 21 sys.exit(0)
22 22
@@ -16,7 +16,7 b" RC_HOOK_VER = '_TMPL_'"
16 16
17 17 def main():
18 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 20 # this allows simply push to this repo even without rhodecode
21 21 sys.exit(0)
22 22
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -43,10 +43,7 b''
43 43 },
44 44 "python2.7-Pygments-2.2.0": {
45 45 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
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 },
46 },
50 47 "python2.7-Routes-1.13": {
51 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 75 "python2.7-alembic-0.8.4": {
79 76 "MIT License": "http://spdx.org/licenses/MIT"
80 },
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 },
77 },
87 78 "python2.7-appenlight-client-0.6.14": {
88 79 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
89 80 },
@@ -195,7 +186,7 b''
195 186 "python2.7-jupyter-core-4.3.0": {
196 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 190 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
200 191 },
201 192 "python2.7-mistune-0.7.4": {
@@ -327,7 +318,7 b''
327 318 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0",
328 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 322 "MIT License": "http://spdx.org/licenses/MIT"
332 323 },
333 324 "python2.7-simplegeneric-0.8.1": {
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -18,41 +18,31 b''
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 """
22 Pylons middleware initialization
23 """
24 21 import logging
25 22 import traceback
26 from collections import OrderedDict
23 import collections
27 24
28 from paste.registry import RegistryManager
29 25 from paste.gzipper import make_gzip_middleware
30 from pylons.wsgiapp import PylonsApp
26 from pyramid.wsgi import wsgiapp
31 27 from pyramid.authorization import ACLAuthorizationPolicy
32 28 from pyramid.config import Configurator
33 29 from pyramid.settings import asbool, aslist
34 from pyramid.wsgi import wsgiapp
35 30 from pyramid.httpexceptions import (
36 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound)
31 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound, HTTPNotFound)
37 32 from pyramid.events import ApplicationCreated
38 33 from pyramid.renderers import render_to_response
39 from routes.middleware import RoutesMiddleware
40 import rhodecode
41 34
42 35 from rhodecode.model import meta
43 36 from rhodecode.config import patches
44 37 from rhodecode.config import utils as config_utils
45 from rhodecode.config.routing import STATIC_FILE_PREFIX
46 from rhodecode.config.environment import (
47 load_environment, load_pyramid_environment)
38 from rhodecode.config.environment import load_pyramid_environment
48 39
40 from rhodecode.lib.middleware.vcs import VCSMiddleware
49 41 from rhodecode.lib.vcs import VCSCommunicationError
50 42 from rhodecode.lib.exceptions import VCSServerUnavailable
51 43 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
52 from rhodecode.lib.middleware.error_handling import (
53 PylonsErrorHandlingMiddleware)
54 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 46 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
57 47 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
58 48 from rhodecode.subscribers import (
@@ -63,157 +53,67 b' from rhodecode.subscribers import ('
63 53 log = logging.getLogger(__name__)
64 54
65 55
66 # this is used to avoid avoid the route lookup overhead in routesmiddleware
67 # for certain routes which won't go to pylons to - eg. static files, debugger
68 # it is only needed for the pylons migration and can be removed once complete
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
56 def is_http_error(response):
57 # error which should have traceback
58 return response.status_code > 499
120 59
121 60
122 61 def make_pyramid_app(global_config, **settings):
123 62 """
124 Constructs the WSGI application based on Pyramid and wraps the Pylons based
125 application.
63 Constructs the WSGI application based on Pyramid.
126 64
127 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 67 * The application can also be integrated like a plugin via the call to
135 68 `includeme`. This is accompanied with the other utility functions which
136 69 are called. Changing this should be done with great care to not break
137 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 73 sanitize_settings_and_apply_defaults(settings)
150 74
151 75 config = Configurator(settings=settings)
76
77 # Apply compatibility patches
78 patches.inspect_getargspec()
79
152 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 85 includeme(config)
158 86
159 87 pyramid_app = config.make_wsgi_app()
160 88 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
161 89 pyramid_app.config = config
162 90
91 config.configure_celery(global_config['__file__'])
163 92 # creating the app uses a connection - return it after we are done
164 93 meta.Session.remove()
165 94
95 log.info('Pyramid app %s created and configured.', pyramid_app)
166 96 return pyramid_app
167 97
168 98
169 def make_not_found_view(config):
99 def not_found_view(request):
170 100 """
171 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.
173 Additionally it is wrapped by some other middlewares.
102 pyramid.
174 103 """
175 settings = config.registry.settings
176 vcs_server_enabled = settings['vcs.server.enable']
177 104
178 # Make pylons app from unprepared settings.
179 pylons_app = make_app(
180 config.registry._pylons_compat_global_config,
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)
105 if not getattr(request, 'vcs_call', None):
106 # handle like regular case with our error_handler
107 return error_handler(HTTPNotFound(), request)
187 108
188 # The pylons app is executed inside of the pyramid 404 exception handler.
189 # Exceptions which are raised inside of it are not handled by pyramid
190 # again. Therefore we add a middleware that invokes the error handler in
191 # case of an exception or error response. This way we return proper error
192 # HTML pages in case of an error.
193 reraise = (settings.get('debugtoolbar.enabled', False) or
194 rhodecode.disable_error_handler)
195 pylons_app = PylonsErrorHandlingMiddleware(
196 pylons_app, error_handler, reraise)
109 # handle not found view as a vcs call
110 settings = request.registry.settings
111 ae_client = getattr(request, 'ae_client', None)
112 vcs_app = VCSMiddleware(
113 HTTPNotFound(), request.registry, settings,
114 appenlight_client=ae_client)
197 115
198 # The VCSMiddleware shall operate like a fallback if pyramid doesn't find a
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
116 return wsgiapp(vcs_app)(None, request)
217 117
218 118
219 119 def error_handler(exception, request):
@@ -229,10 +129,6 b' def error_handler(exception, request):'
229 129 elif isinstance(exception, VCSCommunicationError):
230 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 132 if is_http_error(base_response):
237 133 log.exception(
238 134 'error occurred handling this request for path: %s', request.path)
@@ -272,26 +168,46 b' def error_handler(exception, request):'
272 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 193 def includeme(config):
276 194 settings = config.registry.settings
277 195
278 196 # plugin information
279 config.registry.rhodecode_plugins = OrderedDict()
197 config.registry.rhodecode_plugins = collections.OrderedDict()
280 198
281 199 config.add_directive(
282 200 'register_rhodecode_plugin', register_rhodecode_plugin)
283 201
202 config.add_directive('configure_celery', configure_celery)
203
284 204 if asbool(settings.get('appenlight', 'false')):
285 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 207 # Includes which are required. The application would fail without them.
293 208 config.include('pyramid_mako')
294 209 config.include('pyramid_beaker')
210 config.include('rhodecode.lib.caches')
295 211
296 212 config.include('rhodecode.authentication')
297 213 config.include('rhodecode.integrations')
@@ -331,16 +247,17 b' def includeme(config):'
331 247 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
332 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 250 # events
339 251 # TODO(marcink): this should be done when pyramid migration is finished
340 252 # config.add_subscriber(
341 253 # 'rhodecode.integrations.integrations_event_handler',
342 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 261 # Set the authorization policy.
345 262 authz_policy = ACLAuthorizationPolicy()
346 263 config.set_authorization_policy(authz_policy)
@@ -357,65 +274,29 b' def includeme(config):'
357 274 for inc in includes:
358 275 config.include(inc)
359 276
360 # This is the glue which allows us to migrate in chunks. By registering the
361 # pylons based application as the "Not Found" view in Pyramid, we will
362 # fallback to the old application each time the new one does not yet know
363 # how to handle a request.
364 config.add_notfound_view(make_not_found_view(config))
365
277 # custom not found view, if our pyramid app doesn't know how to handle
278 # the request pass it to potential VCS handling ap
279 config.add_notfound_view(not_found_view)
366 280 if not settings.get('debugtoolbar.enabled', False):
367 281 # disabled debugtoolbar handle all exceptions via the error_handlers
368 282 config.add_view(error_handler, context=Exception)
369 283
284 # all errors including 403/404/50X
370 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 288 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
396 289 """
397 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 292 settings = config.registry.settings
404 293
405 294 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
406 295 pyramid_app = HttpsFixup(pyramid_app, settings)
407 296
408 # Add RoutesMiddleware to support the pylons compatibility tween during
409 # migration to pyramid.
410
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)
297 pyramid_app, _ae_client = wrap_in_appenlight_if_enabled(
298 pyramid_app, settings)
299 config.registry.ae_client = _ae_client
419 300
420 301 if settings['gzip_responses']:
421 302 pyramid_app = make_gzip_middleware(
@@ -452,16 +333,21 b' def sanitize_settings_and_apply_defaults'
452 333 function.
453 334 """
454 335
455 # Pyramid's mako renderer has to search in the templates folder so that the
456 # old templates still work. Ported and new templates are expected to use
457 # real asset specifications for the includes.
458 mako_directories = settings.setdefault('mako.directories', [
459 # Base templates of the original Pylons application
460 'rhodecode:templates',
461 ])
462 log.debug(
463 "Using the following Mako template directories: %s",
464 mako_directories)
336 settings.setdefault('rhodecode.edition', 'Community Edition')
337
338 if 'mako.default_filters' not in settings:
339 # set custom default filters if we don't have it defined
340 settings['mako.imports'] = 'from rhodecode.lib.base import h_filter'
341 settings['mako.default_filters'] = 'h_filter'
342
343 if 'mako.directories' not in settings:
344 mako_directories = settings.setdefault('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 352 # Default includes, possible to change as a user
467 353 pyramid_includes = settings.setdefault('pyramid.includes', [
@@ -526,10 +412,10 b' def _int_setting(settings, name, default'
526 412
527 413
528 414 def _bool_setting(settings, name, default):
529 input = settings.get(name, default)
530 if isinstance(input, unicode):
531 input = input.encode('utf8')
532 settings[name] = asbool(input)
415 input_val = settings.get(name, default)
416 if isinstance(input_val, unicode):
417 input_val = input_val.encode('utf8')
418 settings[name] = asbool(input_val)
533 419
534 420
535 421 def _list_setting(settings, name, default):
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 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 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 39 view functions. This is not compatible with cython, therefore we replace
56 40 getargspec with a custom version.
57 41 Code is inspired by the inspect module from Python-3.4
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 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
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
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
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
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
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
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
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
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 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
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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