Show More
@@ -1,554 +1,554 b'' | |||||
1 | # Copyright (C) 2016-2023 RhodeCode GmbH |
|
1 | # Copyright (C) 2016-2023 RhodeCode GmbH | |
2 | # |
|
2 | # | |
3 | # This program is free software: you can redistribute it and/or modify |
|
3 | # This program is free software: you can redistribute it and/or modify | |
4 | # it under the terms of the GNU Affero General Public License, version 3 |
|
4 | # it under the terms of the GNU Affero General Public License, version 3 | |
5 | # (only), as published by the Free Software Foundation. |
|
5 | # (only), as published by the Free Software Foundation. | |
6 | # |
|
6 | # | |
7 | # This program is distributed in the hope that it will be useful, |
|
7 | # This program is distributed in the hope that it will be useful, | |
8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | # GNU General Public License for more details. |
|
10 | # GNU General Public License for more details. | |
11 | # |
|
11 | # | |
12 | # You should have received a copy of the GNU Affero General Public License |
|
12 | # You should have received a copy of the GNU Affero General Public License | |
13 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
13 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
14 | # |
|
14 | # | |
15 | # This program is dual-licensed. If you wish to learn more about the |
|
15 | # This program is dual-licensed. If you wish to learn more about the | |
16 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
16 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
18 |
|
18 | |||
19 | import time |
|
19 | import time | |
20 | import json |
|
20 | import json | |
21 | import pyotp |
|
21 | import pyotp | |
22 | import qrcode |
|
22 | import qrcode | |
23 | import collections |
|
23 | import collections | |
24 | import datetime |
|
24 | import datetime | |
25 | import formencode |
|
25 | import formencode | |
26 | import formencode.htmlfill |
|
26 | import formencode.htmlfill | |
27 | import logging |
|
27 | import logging | |
28 | import urllib.parse |
|
28 | import urllib.parse | |
29 | import requests |
|
29 | import requests | |
30 | from io import BytesIO |
|
30 | from io import BytesIO | |
31 | from base64 import b64encode |
|
31 | from base64 import b64encode | |
32 |
|
32 | |||
33 | from pyramid.renderers import render |
|
33 | from pyramid.renderers import render | |
34 | from pyramid.response import Response |
|
34 | from pyramid.response import Response | |
35 | from pyramid.httpexceptions import HTTPFound |
|
35 | from pyramid.httpexceptions import HTTPFound | |
36 |
|
36 | |||
37 |
|
37 | |||
38 | from rhodecode.apps._base import BaseAppView |
|
38 | from rhodecode.apps._base import BaseAppView | |
39 | from rhodecode.authentication.base import authenticate, HTTP_TYPE |
|
39 | from rhodecode.authentication.base import authenticate, HTTP_TYPE | |
40 | from rhodecode.authentication.plugins import auth_rhodecode |
|
40 | from rhodecode.authentication.plugins import auth_rhodecode | |
41 | from rhodecode.events import UserRegistered, trigger |
|
41 | from rhodecode.events import UserRegistered, trigger | |
42 | from rhodecode.lib import helpers as h |
|
42 | from rhodecode.lib import helpers as h | |
43 | from rhodecode.lib import audit_logger |
|
43 | from rhodecode.lib import audit_logger | |
44 | from rhodecode.lib.auth import ( |
|
44 | from rhodecode.lib.auth import ( | |
45 | AuthUser, HasPermissionAnyDecorator, CSRFRequired, LoginRequired, NotAnonymous) |
|
45 | AuthUser, HasPermissionAnyDecorator, CSRFRequired, LoginRequired, NotAnonymous) | |
46 | from rhodecode.lib.base import get_ip_addr |
|
46 | from rhodecode.lib.base import get_ip_addr | |
47 | from rhodecode.lib.exceptions import UserCreationError |
|
47 | from rhodecode.lib.exceptions import UserCreationError | |
48 | from rhodecode.lib.utils2 import safe_str |
|
48 | from rhodecode.lib.utils2 import safe_str | |
49 | from rhodecode.model.db import User, UserApiKeys |
|
49 | from rhodecode.model.db import User, UserApiKeys | |
50 | from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm, TOTPForm |
|
50 | from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm, TOTPForm | |
51 | from rhodecode.model.meta import Session |
|
51 | from rhodecode.model.meta import Session | |
52 | from rhodecode.model.auth_token import AuthTokenModel |
|
52 | from rhodecode.model.auth_token import AuthTokenModel | |
53 | from rhodecode.model.settings import SettingsModel |
|
53 | from rhodecode.model.settings import SettingsModel | |
54 | from rhodecode.model.user import UserModel |
|
54 | from rhodecode.model.user import UserModel | |
55 | from rhodecode.translation import _ |
|
55 | from rhodecode.translation import _ | |
56 |
|
56 | |||
57 |
|
57 | |||
58 | log = logging.getLogger(__name__) |
|
58 | log = logging.getLogger(__name__) | |
59 |
|
59 | |||
60 | CaptchaData = collections.namedtuple( |
|
60 | CaptchaData = collections.namedtuple( | |
61 | 'CaptchaData', 'active, private_key, public_key') |
|
61 | 'CaptchaData', 'active, private_key, public_key') | |
62 |
|
62 | |||
63 |
|
63 | |||
64 | def store_user_in_session(session, user_identifier, remember=False): |
|
64 | def store_user_in_session(session, user_identifier, remember=False): | |
65 | user = User.get_by_username_or_primary_email(user_identifier) |
|
65 | user = User.get_by_username_or_primary_email(user_identifier) | |
66 | auth_user = AuthUser(user.user_id) |
|
66 | auth_user = AuthUser(user.user_id) | |
67 | auth_user.set_authenticated() |
|
67 | auth_user.set_authenticated() | |
68 | cs = auth_user.get_cookie_store() |
|
68 | cs = auth_user.get_cookie_store() | |
69 | session['rhodecode_user'] = cs |
|
69 | session['rhodecode_user'] = cs | |
70 | user.update_lastlogin() |
|
70 | user.update_lastlogin() | |
71 | Session().commit() |
|
71 | Session().commit() | |
72 |
|
72 | |||
73 | # If they want to be remembered, update the cookie |
|
73 | # If they want to be remembered, update the cookie | |
74 | if remember: |
|
74 | if remember: | |
75 | _year = (datetime.datetime.now() + |
|
75 | _year = (datetime.datetime.now() + | |
76 | datetime.timedelta(seconds=60 * 60 * 24 * 365)) |
|
76 | datetime.timedelta(seconds=60 * 60 * 24 * 365)) | |
77 | session._set_cookie_expires(_year) |
|
77 | session._set_cookie_expires(_year) | |
78 |
|
78 | |||
79 | session.save() |
|
79 | session.save() | |
80 |
|
80 | |||
81 | safe_cs = cs.copy() |
|
81 | safe_cs = cs.copy() | |
82 | safe_cs['password'] = '****' |
|
82 | safe_cs['password'] = '****' | |
83 | log.info('user %s is now authenticated and stored in ' |
|
83 | log.info('user %s is now authenticated and stored in ' | |
84 | 'session, session attrs %s', user_identifier, safe_cs) |
|
84 | 'session, session attrs %s', user_identifier, safe_cs) | |
85 |
|
85 | |||
86 | # dumps session attrs back to cookie |
|
86 | # dumps session attrs back to cookie | |
87 | session._update_cookie_out() |
|
87 | session._update_cookie_out() | |
88 | # we set new cookie |
|
88 | # we set new cookie | |
89 | headers = None |
|
89 | headers = None | |
90 | if session.request['set_cookie']: |
|
90 | if session.request['set_cookie']: | |
91 | # send set-cookie headers back to response to update cookie |
|
91 | # send set-cookie headers back to response to update cookie | |
92 | headers = [('Set-Cookie', session.request['cookie_out'])] |
|
92 | headers = [('Set-Cookie', session.request['cookie_out'])] | |
93 | return headers |
|
93 | return headers | |
94 |
|
94 | |||
95 |
|
95 | |||
96 | def get_came_from(request): |
|
96 | def get_came_from(request): | |
97 | came_from = safe_str(request.GET.get('came_from', '')) |
|
97 | came_from = safe_str(request.GET.get('came_from', '')) | |
98 | parsed = urllib.parse.urlparse(came_from) |
|
98 | parsed = urllib.parse.urlparse(came_from) | |
99 |
|
99 | |||
100 | allowed_schemes = ['http', 'https'] |
|
100 | allowed_schemes = ['http', 'https'] | |
101 | default_came_from = h.route_path('home') |
|
101 | default_came_from = h.route_path('home') | |
102 | if parsed.scheme and parsed.scheme not in allowed_schemes: |
|
102 | if parsed.scheme and parsed.scheme not in allowed_schemes: | |
103 | log.error('Suspicious URL scheme detected %s for url %s', |
|
103 | log.error('Suspicious URL scheme detected %s for url %s', | |
104 | parsed.scheme, parsed) |
|
104 | parsed.scheme, parsed) | |
105 | came_from = default_came_from |
|
105 | came_from = default_came_from | |
106 | elif parsed.netloc and request.host != parsed.netloc: |
|
106 | elif parsed.netloc and request.host != parsed.netloc: | |
107 | log.error('Suspicious NETLOC detected %s for url %s server url ' |
|
107 | log.error('Suspicious NETLOC detected %s for url %s server url ' | |
108 | 'is: %s', parsed.netloc, parsed, request.host) |
|
108 | 'is: %s', parsed.netloc, parsed, request.host) | |
109 | came_from = default_came_from |
|
109 | came_from = default_came_from | |
110 | elif any(bad_char in came_from for bad_char in ('\r', '\n')): |
|
110 | elif any(bad_char in came_from for bad_char in ('\r', '\n')): | |
111 | log.error('Header injection detected `%s` for url %s server url ', |
|
111 | log.error('Header injection detected `%s` for url %s server url ', | |
112 | parsed.path, parsed) |
|
112 | parsed.path, parsed) | |
113 | came_from = default_came_from |
|
113 | came_from = default_came_from | |
114 |
|
114 | |||
115 | return came_from or default_came_from |
|
115 | return came_from or default_came_from | |
116 |
|
116 | |||
117 |
|
117 | |||
118 | class LoginView(BaseAppView): |
|
118 | class LoginView(BaseAppView): | |
119 |
|
119 | |||
120 | def load_default_context(self): |
|
120 | def load_default_context(self): | |
121 | c = self._get_local_tmpl_context() |
|
121 | c = self._get_local_tmpl_context() | |
122 | c.came_from = get_came_from(self.request) |
|
122 | c.came_from = get_came_from(self.request) | |
123 | return c |
|
123 | return c | |
124 |
|
124 | |||
125 | def _get_captcha_data(self): |
|
125 | def _get_captcha_data(self): | |
126 | settings = SettingsModel().get_all_settings() |
|
126 | settings = SettingsModel().get_all_settings() | |
127 | private_key = settings.get('rhodecode_captcha_private_key') |
|
127 | private_key = settings.get('rhodecode_captcha_private_key') | |
128 | public_key = settings.get('rhodecode_captcha_public_key') |
|
128 | public_key = settings.get('rhodecode_captcha_public_key') | |
129 | active = bool(private_key) |
|
129 | active = bool(private_key) | |
130 | return CaptchaData( |
|
130 | return CaptchaData( | |
131 | active=active, private_key=private_key, public_key=public_key) |
|
131 | active=active, private_key=private_key, public_key=public_key) | |
132 |
|
132 | |||
133 | def validate_captcha(self, private_key): |
|
133 | def validate_captcha(self, private_key): | |
134 |
|
134 | |||
135 | captcha_rs = self.request.POST.get('g-recaptcha-response') |
|
135 | captcha_rs = self.request.POST.get('g-recaptcha-response') | |
136 | url = "https://www.google.com/recaptcha/api/siteverify" |
|
136 | url = "https://www.google.com/recaptcha/api/siteverify" | |
137 | params = { |
|
137 | params = { | |
138 | 'secret': private_key, |
|
138 | 'secret': private_key, | |
139 | 'response': captcha_rs, |
|
139 | 'response': captcha_rs, | |
140 | 'remoteip': get_ip_addr(self.request.environ) |
|
140 | 'remoteip': get_ip_addr(self.request.environ) | |
141 | } |
|
141 | } | |
142 | verify_rs = requests.get(url, params=params, verify=True, timeout=60) |
|
142 | verify_rs = requests.get(url, params=params, verify=True, timeout=60) | |
143 | verify_rs = verify_rs.json() |
|
143 | verify_rs = verify_rs.json() | |
144 | captcha_status = verify_rs.get('success', False) |
|
144 | captcha_status = verify_rs.get('success', False) | |
145 | captcha_errors = verify_rs.get('error-codes', []) |
|
145 | captcha_errors = verify_rs.get('error-codes', []) | |
146 | if not isinstance(captcha_errors, list): |
|
146 | if not isinstance(captcha_errors, list): | |
147 | captcha_errors = [captcha_errors] |
|
147 | captcha_errors = [captcha_errors] | |
148 | captcha_errors = ', '.join(captcha_errors) |
|
148 | captcha_errors = ', '.join(captcha_errors) | |
149 | captcha_message = '' |
|
149 | captcha_message = '' | |
150 | if captcha_status is False: |
|
150 | if captcha_status is False: | |
151 | captcha_message = "Bad captcha. Errors: {}".format( |
|
151 | captcha_message = "Bad captcha. Errors: {}".format( | |
152 | captcha_errors) |
|
152 | captcha_errors) | |
153 |
|
153 | |||
154 | return captcha_status, captcha_message |
|
154 | return captcha_status, captcha_message | |
155 |
|
155 | |||
156 | def login(self): |
|
156 | def login(self): | |
157 | c = self.load_default_context() |
|
157 | c = self.load_default_context() | |
158 | auth_user = self._rhodecode_user |
|
158 | auth_user = self._rhodecode_user | |
159 |
|
159 | |||
160 | # redirect if already logged in |
|
160 | # redirect if already logged in | |
161 | if (auth_user.is_authenticated and |
|
161 | if (auth_user.is_authenticated and | |
162 | not auth_user.is_default and auth_user.ip_allowed): |
|
162 | not auth_user.is_default and auth_user.ip_allowed): | |
163 | raise HTTPFound(c.came_from) |
|
163 | raise HTTPFound(c.came_from) | |
164 |
|
164 | |||
165 | # check if we use headers plugin, and try to login using it. |
|
165 | # check if we use headers plugin, and try to login using it. | |
166 | try: |
|
166 | try: | |
167 | log.debug('Running PRE-AUTH for headers based authentication') |
|
167 | log.debug('Running PRE-AUTH for headers based authentication') | |
168 | auth_info = authenticate( |
|
168 | auth_info = authenticate( | |
169 | '', '', self.request.environ, HTTP_TYPE, skip_missing=True) |
|
169 | '', '', self.request.environ, HTTP_TYPE, skip_missing=True) | |
170 | if auth_info: |
|
170 | if auth_info: | |
171 | headers = store_user_in_session( |
|
171 | headers = store_user_in_session( | |
172 | self.session, auth_info.get('username')) |
|
172 | self.session, auth_info.get('username')) | |
173 | raise HTTPFound(c.came_from, headers=headers) |
|
173 | raise HTTPFound(c.came_from, headers=headers) | |
174 | except UserCreationError as e: |
|
174 | except UserCreationError as e: | |
175 | log.error(e) |
|
175 | log.error(e) | |
176 | h.flash(e, category='error') |
|
176 | h.flash(e, category='error') | |
177 |
|
177 | |||
178 | return self._get_template_context(c) |
|
178 | return self._get_template_context(c) | |
179 |
|
179 | |||
180 | def login_post(self): |
|
180 | def login_post(self): | |
181 | c = self.load_default_context() |
|
181 | c = self.load_default_context() | |
182 |
|
182 | |||
183 | login_form = LoginForm(self.request.translate)() |
|
183 | login_form = LoginForm(self.request.translate)() | |
184 |
|
184 | |||
185 | try: |
|
185 | try: | |
186 | self.session.invalidate() |
|
186 | self.session.invalidate() | |
187 | form_result = login_form.to_python(self.request.POST) |
|
187 | form_result = login_form.to_python(self.request.POST) | |
188 | # form checks for username/password, now we're authenticated |
|
188 | # form checks for username/password, now we're authenticated | |
189 | username = form_result['username'] |
|
189 | username = form_result['username'] | |
190 | if (user := User.get_by_username_or_primary_email(username)).has_enabled_2fa: |
|
190 | if (user := User.get_by_username_or_primary_email(username)).has_enabled_2fa: | |
191 | user.has_check_2fa_flag = True |
|
191 | user.has_check_2fa_flag = True | |
192 |
|
192 | |||
193 | headers = store_user_in_session( |
|
193 | headers = store_user_in_session( | |
194 | self.session, |
|
194 | self.session, | |
195 | user_identifier=username, |
|
195 | user_identifier=username, | |
196 | remember=form_result['remember']) |
|
196 | remember=form_result['remember']) | |
197 | log.debug('Redirecting to "%s" after login.', c.came_from) |
|
197 | log.debug('Redirecting to "%s" after login.', c.came_from) | |
198 |
|
198 | |||
199 | audit_user = audit_logger.UserWrap( |
|
199 | audit_user = audit_logger.UserWrap( | |
200 | username=self.request.POST.get('username'), |
|
200 | username=self.request.POST.get('username'), | |
201 | ip_addr=self.request.remote_addr) |
|
201 | ip_addr=self.request.remote_addr) | |
202 | action_data = {'user_agent': self.request.user_agent} |
|
202 | action_data = {'user_agent': self.request.user_agent} | |
203 | audit_logger.store_web( |
|
203 | audit_logger.store_web( | |
204 | 'user.login.success', action_data=action_data, |
|
204 | 'user.login.success', action_data=action_data, | |
205 | user=audit_user, commit=True) |
|
205 | user=audit_user, commit=True) | |
206 |
|
206 | |||
207 | raise HTTPFound(c.came_from, headers=headers) |
|
207 | raise HTTPFound(c.came_from, headers=headers) | |
208 | except formencode.Invalid as errors: |
|
208 | except formencode.Invalid as errors: | |
209 | defaults = errors.value |
|
209 | defaults = errors.value | |
210 | # remove password from filling in form again |
|
210 | # remove password from filling in form again | |
211 | defaults.pop('password', None) |
|
211 | defaults.pop('password', None) | |
212 | render_ctx = { |
|
212 | render_ctx = { | |
213 | 'errors': errors.error_dict, |
|
213 | 'errors': errors.error_dict, | |
214 | 'defaults': defaults, |
|
214 | 'defaults': defaults, | |
215 | } |
|
215 | } | |
216 |
|
216 | |||
217 | audit_user = audit_logger.UserWrap( |
|
217 | audit_user = audit_logger.UserWrap( | |
218 | username=self.request.POST.get('username'), |
|
218 | username=self.request.POST.get('username'), | |
219 | ip_addr=self.request.remote_addr) |
|
219 | ip_addr=self.request.remote_addr) | |
220 | action_data = {'user_agent': self.request.user_agent} |
|
220 | action_data = {'user_agent': self.request.user_agent} | |
221 | audit_logger.store_web( |
|
221 | audit_logger.store_web( | |
222 | 'user.login.failure', action_data=action_data, |
|
222 | 'user.login.failure', action_data=action_data, | |
223 | user=audit_user, commit=True) |
|
223 | user=audit_user, commit=True) | |
224 | return self._get_template_context(c, **render_ctx) |
|
224 | return self._get_template_context(c, **render_ctx) | |
225 |
|
225 | |||
226 | except UserCreationError as e: |
|
226 | except UserCreationError as e: | |
227 | # headers auth or other auth functions that create users on |
|
227 | # headers auth or other auth functions that create users on | |
228 | # the fly can throw this exception signaling that there's issue |
|
228 | # the fly can throw this exception signaling that there's issue | |
229 | # with user creation, explanation should be provided in |
|
229 | # with user creation, explanation should be provided in | |
230 | # Exception itself |
|
230 | # Exception itself | |
231 | h.flash(e, category='error') |
|
231 | h.flash(e, category='error') | |
232 | return self._get_template_context(c) |
|
232 | return self._get_template_context(c) | |
233 |
|
233 | |||
234 | @CSRFRequired() |
|
234 | @CSRFRequired() | |
235 | def logout(self): |
|
235 | def logout(self): | |
236 | auth_user = self._rhodecode_user |
|
236 | auth_user = self._rhodecode_user | |
237 | log.info('Deleting session for user: `%s`', auth_user) |
|
237 | log.info('Deleting session for user: `%s`', auth_user) | |
238 |
|
238 | |||
239 | action_data = {'user_agent': self.request.user_agent} |
|
239 | action_data = {'user_agent': self.request.user_agent} | |
240 | audit_logger.store_web( |
|
240 | audit_logger.store_web( | |
241 | 'user.logout', action_data=action_data, |
|
241 | 'user.logout', action_data=action_data, | |
242 | user=auth_user, commit=True) |
|
242 | user=auth_user, commit=True) | |
243 | self.session.delete() |
|
243 | self.session.delete() | |
244 | return HTTPFound(h.route_path('home')) |
|
244 | return HTTPFound(h.route_path('home')) | |
245 |
|
245 | |||
246 | @HasPermissionAnyDecorator( |
|
246 | @HasPermissionAnyDecorator( | |
247 | 'hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate') |
|
247 | 'hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate') | |
248 | def register(self, defaults=None, errors=None): |
|
248 | def register(self, defaults=None, errors=None): | |
249 | c = self.load_default_context() |
|
249 | c = self.load_default_context() | |
250 | defaults = defaults or {} |
|
250 | defaults = defaults or {} | |
251 | errors = errors or {} |
|
251 | errors = errors or {} | |
252 |
|
252 | |||
253 | settings = SettingsModel().get_all_settings() |
|
253 | settings = SettingsModel().get_all_settings() | |
254 | register_message = settings.get('rhodecode_register_message') or '' |
|
254 | register_message = settings.get('rhodecode_register_message') or '' | |
255 | captcha = self._get_captcha_data() |
|
255 | captcha = self._get_captcha_data() | |
256 | auto_active = 'hg.register.auto_activate' in User.get_default_user()\ |
|
256 | auto_active = 'hg.register.auto_activate' in User.get_default_user()\ | |
257 | .AuthUser().permissions['global'] |
|
257 | .AuthUser().permissions['global'] | |
258 |
|
258 | |||
259 | render_ctx = self._get_template_context(c) |
|
259 | render_ctx = self._get_template_context(c) | |
260 | render_ctx.update({ |
|
260 | render_ctx.update({ | |
261 | 'defaults': defaults, |
|
261 | 'defaults': defaults, | |
262 | 'errors': errors, |
|
262 | 'errors': errors, | |
263 | 'auto_active': auto_active, |
|
263 | 'auto_active': auto_active, | |
264 | 'captcha_active': captcha.active, |
|
264 | 'captcha_active': captcha.active, | |
265 | 'captcha_public_key': captcha.public_key, |
|
265 | 'captcha_public_key': captcha.public_key, | |
266 | 'register_message': register_message, |
|
266 | 'register_message': register_message, | |
267 | }) |
|
267 | }) | |
268 | return render_ctx |
|
268 | return render_ctx | |
269 |
|
269 | |||
270 | @HasPermissionAnyDecorator( |
|
270 | @HasPermissionAnyDecorator( | |
271 | 'hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate') |
|
271 | 'hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate') | |
272 | def register_post(self): |
|
272 | def register_post(self): | |
273 | from rhodecode.authentication.plugins import auth_rhodecode |
|
273 | from rhodecode.authentication.plugins import auth_rhodecode | |
274 |
|
274 | |||
275 | self.load_default_context() |
|
275 | self.load_default_context() | |
276 | captcha = self._get_captcha_data() |
|
276 | captcha = self._get_captcha_data() | |
277 | auto_active = 'hg.register.auto_activate' in User.get_default_user()\ |
|
277 | auto_active = 'hg.register.auto_activate' in User.get_default_user()\ | |
278 | .AuthUser().permissions['global'] |
|
278 | .AuthUser().permissions['global'] | |
279 |
|
279 | |||
280 | extern_name = auth_rhodecode.RhodeCodeAuthPlugin.uid |
|
280 | extern_name = auth_rhodecode.RhodeCodeAuthPlugin.uid | |
281 | extern_type = auth_rhodecode.RhodeCodeAuthPlugin.uid |
|
281 | extern_type = auth_rhodecode.RhodeCodeAuthPlugin.uid | |
282 |
|
282 | |||
283 | register_form = RegisterForm(self.request.translate)() |
|
283 | register_form = RegisterForm(self.request.translate)() | |
284 | try: |
|
284 | try: | |
285 |
|
285 | |||
286 | form_result = register_form.to_python(self.request.POST) |
|
286 | form_result = register_form.to_python(self.request.POST) | |
287 | form_result['active'] = auto_active |
|
287 | form_result['active'] = auto_active | |
288 | external_identity = self.request.POST.get('external_identity') |
|
288 | external_identity = self.request.POST.get('external_identity') | |
289 |
|
289 | |||
290 | if external_identity: |
|
290 | if external_identity: | |
291 | extern_name = external_identity |
|
291 | extern_name = external_identity | |
292 | extern_type = external_identity |
|
292 | extern_type = external_identity | |
293 |
|
293 | |||
294 | if captcha.active: |
|
294 | if captcha.active: | |
295 | captcha_status, captcha_message = self.validate_captcha( |
|
295 | captcha_status, captcha_message = self.validate_captcha( | |
296 | captcha.private_key) |
|
296 | captcha.private_key) | |
297 |
|
297 | |||
298 | if not captcha_status: |
|
298 | if not captcha_status: | |
299 | _value = form_result |
|
299 | _value = form_result | |
300 | _msg = _('Bad captcha') |
|
300 | _msg = _('Bad captcha') | |
301 | error_dict = {'recaptcha_field': captcha_message} |
|
301 | error_dict = {'recaptcha_field': captcha_message} | |
302 | raise formencode.Invalid( |
|
302 | raise formencode.Invalid( | |
303 | _msg, _value, None, error_dict=error_dict) |
|
303 | _msg, _value, None, error_dict=error_dict) | |
304 |
|
304 | |||
305 | new_user = UserModel().create_registration( |
|
305 | new_user = UserModel().create_registration( | |
306 | form_result, extern_name=extern_name, extern_type=extern_type) |
|
306 | form_result, extern_name=extern_name, extern_type=extern_type) | |
307 |
|
307 | |||
308 | action_data = {'data': new_user.get_api_data(), |
|
308 | action_data = {'data': new_user.get_api_data(), | |
309 | 'user_agent': self.request.user_agent} |
|
309 | 'user_agent': self.request.user_agent} | |
310 |
|
310 | |||
311 | if external_identity: |
|
311 | if external_identity: | |
312 | action_data['external_identity'] = external_identity |
|
312 | action_data['external_identity'] = external_identity | |
313 |
|
313 | |||
314 | audit_user = audit_logger.UserWrap( |
|
314 | audit_user = audit_logger.UserWrap( | |
315 | username=new_user.username, |
|
315 | username=new_user.username, | |
316 | user_id=new_user.user_id, |
|
316 | user_id=new_user.user_id, | |
317 | ip_addr=self.request.remote_addr) |
|
317 | ip_addr=self.request.remote_addr) | |
318 |
|
318 | |||
319 | audit_logger.store_web( |
|
319 | audit_logger.store_web( | |
320 | 'user.register', action_data=action_data, |
|
320 | 'user.register', action_data=action_data, | |
321 | user=audit_user) |
|
321 | user=audit_user) | |
322 |
|
322 | |||
323 | event = UserRegistered(user=new_user, session=self.session) |
|
323 | event = UserRegistered(user=new_user, session=self.session) | |
324 | trigger(event) |
|
324 | trigger(event) | |
325 | h.flash( |
|
325 | h.flash( | |
326 | _('You have successfully registered with RhodeCode. You can log-in now.'), |
|
326 | _('You have successfully registered with RhodeCode. You can log-in now.'), | |
327 | category='success') |
|
327 | category='success') | |
328 | if external_identity: |
|
328 | if external_identity: | |
329 | h.flash( |
|
329 | h.flash( | |
330 | _('Please use the {identity} button to log-in').format( |
|
330 | _('Please use the {identity} button to log-in').format( | |
331 | identity=external_identity), |
|
331 | identity=external_identity), | |
332 | category='success') |
|
332 | category='success') | |
333 | Session().commit() |
|
333 | Session().commit() | |
334 |
|
334 | |||
335 | redirect_ro = self.request.route_path('login') |
|
335 | redirect_ro = self.request.route_path('login') | |
336 | raise HTTPFound(redirect_ro) |
|
336 | raise HTTPFound(redirect_ro) | |
337 |
|
337 | |||
338 | except formencode.Invalid as errors: |
|
338 | except formencode.Invalid as errors: | |
339 | errors.value.pop('password', None) |
|
339 | errors.value.pop('password', None) | |
340 | errors.value.pop('password_confirmation', None) |
|
340 | errors.value.pop('password_confirmation', None) | |
341 | return self.register( |
|
341 | return self.register( | |
342 | defaults=errors.value, errors=errors.error_dict) |
|
342 | defaults=errors.value, errors=errors.error_dict) | |
343 |
|
343 | |||
344 | except UserCreationError as e: |
|
344 | except UserCreationError as e: | |
345 | # container auth or other auth functions that create users on |
|
345 | # container auth or other auth functions that create users on | |
346 | # the fly can throw this exception signaling that there's issue |
|
346 | # the fly can throw this exception signaling that there's issue | |
347 | # with user creation, explanation should be provided in |
|
347 | # with user creation, explanation should be provided in | |
348 | # Exception itself |
|
348 | # Exception itself | |
349 | h.flash(e, category='error') |
|
349 | h.flash(e, category='error') | |
350 | return self.register() |
|
350 | return self.register() | |
351 |
|
351 | |||
352 | def password_reset(self): |
|
352 | def password_reset(self): | |
353 | c = self.load_default_context() |
|
353 | c = self.load_default_context() | |
354 | captcha = self._get_captcha_data() |
|
354 | captcha = self._get_captcha_data() | |
355 |
|
355 | |||
356 | template_context = { |
|
356 | template_context = { | |
357 | 'captcha_active': captcha.active, |
|
357 | 'captcha_active': captcha.active, | |
358 | 'captcha_public_key': captcha.public_key, |
|
358 | 'captcha_public_key': captcha.public_key, | |
359 | 'defaults': {}, |
|
359 | 'defaults': {}, | |
360 | 'errors': {}, |
|
360 | 'errors': {}, | |
361 | } |
|
361 | } | |
362 |
|
362 | |||
363 | # always send implicit message to prevent from discovery of |
|
363 | # always send implicit message to prevent from discovery of | |
364 | # matching emails |
|
364 | # matching emails | |
365 | msg = _('If such email exists, a password reset link was sent to it.') |
|
365 | msg = _('If such email exists, a password reset link was sent to it.') | |
366 |
|
366 | |||
367 | def default_response(): |
|
367 | def default_response(): | |
368 | log.debug('faking response on invalid password reset') |
|
368 | log.debug('faking response on invalid password reset') | |
369 | # make this take 2s, to prevent brute forcing. |
|
369 | # make this take 2s, to prevent brute forcing. | |
370 | time.sleep(2) |
|
370 | time.sleep(2) | |
371 | h.flash(msg, category='success') |
|
371 | h.flash(msg, category='success') | |
372 | return HTTPFound(self.request.route_path('reset_password')) |
|
372 | return HTTPFound(self.request.route_path('reset_password')) | |
373 |
|
373 | |||
374 | if self.request.POST: |
|
374 | if self.request.POST: | |
375 | if h.HasPermissionAny('hg.password_reset.disabled')(): |
|
375 | if h.HasPermissionAny('hg.password_reset.disabled')(): | |
376 | _email = self.request.POST.get('email', '') |
|
376 | _email = self.request.POST.get('email', '') | |
377 | log.error('Failed attempt to reset password for `%s`.', _email) |
|
377 | log.error('Failed attempt to reset password for `%s`.', _email) | |
378 | h.flash(_('Password reset has been disabled.'), category='error') |
|
378 | h.flash(_('Password reset has been disabled.'), category='error') | |
379 | return HTTPFound(self.request.route_path('reset_password')) |
|
379 | return HTTPFound(self.request.route_path('reset_password')) | |
380 |
|
380 | |||
381 | password_reset_form = PasswordResetForm(self.request.translate)() |
|
381 | password_reset_form = PasswordResetForm(self.request.translate)() | |
382 | description = 'Generated token for password reset from {}'.format( |
|
382 | description = 'Generated token for password reset from {}'.format( | |
383 | datetime.datetime.now().isoformat()) |
|
383 | datetime.datetime.now().isoformat()) | |
384 |
|
384 | |||
385 | try: |
|
385 | try: | |
386 | form_result = password_reset_form.to_python( |
|
386 | form_result = password_reset_form.to_python( | |
387 | self.request.POST) |
|
387 | self.request.POST) | |
388 | user_email = form_result['email'] |
|
388 | user_email = form_result['email'] | |
389 |
|
389 | |||
390 | if captcha.active: |
|
390 | if captcha.active: | |
391 | captcha_status, captcha_message = self.validate_captcha( |
|
391 | captcha_status, captcha_message = self.validate_captcha( | |
392 | captcha.private_key) |
|
392 | captcha.private_key) | |
393 |
|
393 | |||
394 | if not captcha_status: |
|
394 | if not captcha_status: | |
395 | _value = form_result |
|
395 | _value = form_result | |
396 | _msg = _('Bad captcha') |
|
396 | _msg = _('Bad captcha') | |
397 | error_dict = {'recaptcha_field': captcha_message} |
|
397 | error_dict = {'recaptcha_field': captcha_message} | |
398 | raise formencode.Invalid( |
|
398 | raise formencode.Invalid( | |
399 | _msg, _value, None, error_dict=error_dict) |
|
399 | _msg, _value, None, error_dict=error_dict) | |
400 |
|
400 | |||
401 | # Generate reset URL and send mail. |
|
401 | # Generate reset URL and send mail. | |
402 | user = User.get_by_email(user_email) |
|
402 | user = User.get_by_email(user_email) | |
403 |
|
403 | |||
404 | # only allow rhodecode based users to reset their password |
|
404 | # only allow rhodecode based users to reset their password | |
405 | # external auth shouldn't allow password reset |
|
405 | # external auth shouldn't allow password reset | |
406 | if user and user.extern_type != auth_rhodecode.RhodeCodeAuthPlugin.uid: |
|
406 | if user and user.extern_type != auth_rhodecode.RhodeCodeAuthPlugin.uid: | |
407 | log.warning('User %s with external type `%s` tried a password reset. ' |
|
407 | log.warning('User %s with external type `%s` tried a password reset. ' | |
408 | 'This try was rejected', user, user.extern_type) |
|
408 | 'This try was rejected', user, user.extern_type) | |
409 | return default_response() |
|
409 | return default_response() | |
410 |
|
410 | |||
411 | # generate password reset token that expires in 10 minutes |
|
411 | # generate password reset token that expires in 10 minutes | |
412 | reset_token = UserModel().add_auth_token( |
|
412 | reset_token = UserModel().add_auth_token( | |
413 | user=user, lifetime_minutes=10, |
|
413 | user=user, lifetime_minutes=10, | |
414 | role=UserModel.auth_token_role.ROLE_PASSWORD_RESET, |
|
414 | role=UserModel.auth_token_role.ROLE_PASSWORD_RESET, | |
415 | description=description) |
|
415 | description=description) | |
416 | Session().commit() |
|
416 | Session().commit() | |
417 |
|
417 | |||
418 | log.debug('Successfully created password recovery token') |
|
418 | log.debug('Successfully created password recovery token') | |
419 | password_reset_url = self.request.route_url( |
|
419 | password_reset_url = self.request.route_url( | |
420 | 'reset_password_confirmation', |
|
420 | 'reset_password_confirmation', | |
421 | _query={'key': reset_token.api_key}) |
|
421 | _query={'key': reset_token.api_key}) | |
422 | UserModel().reset_password_link( |
|
422 | UserModel().reset_password_link( | |
423 | form_result, password_reset_url) |
|
423 | form_result, password_reset_url) | |
424 |
|
424 | |||
425 | action_data = {'email': user_email, |
|
425 | action_data = {'email': user_email, | |
426 | 'user_agent': self.request.user_agent} |
|
426 | 'user_agent': self.request.user_agent} | |
427 | audit_logger.store_web( |
|
427 | audit_logger.store_web( | |
428 | 'user.password.reset_request', action_data=action_data, |
|
428 | 'user.password.reset_request', action_data=action_data, | |
429 | user=self._rhodecode_user, commit=True) |
|
429 | user=self._rhodecode_user, commit=True) | |
430 |
|
430 | |||
431 | return default_response() |
|
431 | return default_response() | |
432 |
|
432 | |||
433 | except formencode.Invalid as errors: |
|
433 | except formencode.Invalid as errors: | |
434 | template_context.update({ |
|
434 | template_context.update({ | |
435 | 'defaults': errors.value, |
|
435 | 'defaults': errors.value, | |
436 | 'errors': errors.error_dict, |
|
436 | 'errors': errors.error_dict, | |
437 | }) |
|
437 | }) | |
438 | if not self.request.POST.get('email'): |
|
438 | if not self.request.POST.get('email'): | |
439 | # case of empty email, we want to report that |
|
439 | # case of empty email, we want to report that | |
440 | return self._get_template_context(c, **template_context) |
|
440 | return self._get_template_context(c, **template_context) | |
441 |
|
441 | |||
442 | if 'recaptcha_field' in errors.error_dict: |
|
442 | if 'recaptcha_field' in errors.error_dict: | |
443 | # case of failed captcha |
|
443 | # case of failed captcha | |
444 | return self._get_template_context(c, **template_context) |
|
444 | return self._get_template_context(c, **template_context) | |
445 |
|
445 | |||
446 | return default_response() |
|
446 | return default_response() | |
447 |
|
447 | |||
448 | return self._get_template_context(c, **template_context) |
|
448 | return self._get_template_context(c, **template_context) | |
449 |
|
449 | |||
450 | @LoginRequired() |
|
450 | @LoginRequired() | |
451 | @NotAnonymous() |
|
451 | @NotAnonymous() | |
452 | def password_reset_confirmation(self): |
|
452 | def password_reset_confirmation(self): | |
453 | self.load_default_context() |
|
453 | self.load_default_context() | |
454 | if self.request.GET and self.request.GET.get('key'): |
|
454 | if self.request.GET and self.request.GET.get('key'): | |
455 | # make this take 2s, to prevent brute forcing. |
|
455 | # make this take 2s, to prevent brute forcing. | |
456 | time.sleep(2) |
|
456 | time.sleep(2) | |
457 |
|
457 | |||
458 | token = AuthTokenModel().get_auth_token( |
|
458 | token = AuthTokenModel().get_auth_token( | |
459 | self.request.GET.get('key')) |
|
459 | self.request.GET.get('key')) | |
460 |
|
460 | |||
461 | # verify token is the correct role |
|
461 | # verify token is the correct role | |
462 | if token is None or token.role != UserApiKeys.ROLE_PASSWORD_RESET: |
|
462 | if token is None or token.role != UserApiKeys.ROLE_PASSWORD_RESET: | |
463 | log.debug('Got token with role:%s expected is %s', |
|
463 | log.debug('Got token with role:%s expected is %s', | |
464 | getattr(token, 'role', 'EMPTY_TOKEN'), |
|
464 | getattr(token, 'role', 'EMPTY_TOKEN'), | |
465 | UserApiKeys.ROLE_PASSWORD_RESET) |
|
465 | UserApiKeys.ROLE_PASSWORD_RESET) | |
466 | h.flash( |
|
466 | h.flash( | |
467 | _('Given reset token is invalid'), category='error') |
|
467 | _('Given reset token is invalid'), category='error') | |
468 | return HTTPFound(self.request.route_path('reset_password')) |
|
468 | return HTTPFound(self.request.route_path('reset_password')) | |
469 |
|
469 | |||
470 | try: |
|
470 | try: | |
471 | owner = token.user |
|
471 | owner = token.user | |
472 | data = {'email': owner.email, 'token': token.api_key} |
|
472 | data = {'email': owner.email, 'token': token.api_key} | |
473 | UserModel().reset_password(data) |
|
473 | UserModel().reset_password(data) | |
474 | h.flash( |
|
474 | h.flash( | |
475 | _('Your password reset was successful, ' |
|
475 | _('Your password reset was successful, ' | |
476 | 'a new password has been sent to your email'), |
|
476 | 'a new password has been sent to your email'), | |
477 | category='success') |
|
477 | category='success') | |
478 | except Exception as e: |
|
478 | except Exception as e: | |
479 | log.error(e) |
|
479 | log.error(e) | |
480 | return HTTPFound(self.request.route_path('reset_password')) |
|
480 | return HTTPFound(self.request.route_path('reset_password')) | |
481 |
|
481 | |||
482 | return HTTPFound(self.request.route_path('login')) |
|
482 | return HTTPFound(self.request.route_path('login')) | |
483 |
|
483 | |||
484 | @LoginRequired() |
|
484 | @LoginRequired() | |
485 | @NotAnonymous() |
|
485 | @NotAnonymous() | |
486 | def setup_2fa(self): |
|
486 | def setup_2fa(self): | |
487 | _ = self.request.translate |
|
487 | _ = self.request.translate | |
488 | c = self.load_default_context() |
|
488 | c = self.load_default_context() | |
489 | user_instance = self._rhodecode_db_user |
|
489 | user_instance = self._rhodecode_db_user | |
490 | form = TOTPForm(_, user_instance)() |
|
490 | form = TOTPForm(_, user_instance)() | |
491 | render_ctx = {} |
|
491 | render_ctx = {} | |
492 | if self.request.method == 'POST': |
|
492 | if self.request.method == 'POST': | |
493 | post_items = dict(self.request.POST) |
|
493 | post_items = dict(self.request.POST) | |
494 |
|
494 | |||
495 | try: |
|
495 | try: | |
496 | form_details = form.to_python(post_items) |
|
496 | form_details = form.to_python(post_items) | |
497 | secret = form_details['secret_totp'] |
|
497 | secret = form_details['secret_totp'] | |
498 |
|
498 | |||
499 | user_instance.init_2fa_recovery_codes(persist=True, force=True) |
|
499 | user_instance.init_2fa_recovery_codes(persist=True, force=True) | |
500 | user_instance.set_2fa_secret(secret) |
|
500 | user_instance.set_2fa_secret(secret) | |
501 |
|
501 | |||
502 | Session().commit() |
|
502 | Session().commit() | |
503 |
raise HTTPFound(self.request.route_path('my_account_ |
|
503 | raise HTTPFound(self.request.route_path('my_account_configure_2fa', _query={'show-recovery-codes': 1})) | |
504 | except formencode.Invalid as errors: |
|
504 | except formencode.Invalid as errors: | |
505 | defaults = errors.value |
|
505 | defaults = errors.value | |
506 | render_ctx = { |
|
506 | render_ctx = { | |
507 | 'errors': errors.error_dict, |
|
507 | 'errors': errors.error_dict, | |
508 | 'defaults': defaults, |
|
508 | 'defaults': defaults, | |
509 | } |
|
509 | } | |
510 |
|
510 | |||
511 | # NOTE: here we DO NOT persist the secret 2FA, since this is only for setup, once a setup is completed |
|
511 | # NOTE: here we DO NOT persist the secret 2FA, since this is only for setup, once a setup is completed | |
512 | # only then we should persist it |
|
512 | # only then we should persist it | |
513 | secret = user_instance.init_secret_2fa(persist=False) |
|
513 | secret = user_instance.init_secret_2fa(persist=False) | |
514 |
|
514 | |||
515 | totp_name = f'RhodeCode token ({self.request.user.username})' |
|
515 | totp_name = f'RhodeCode token ({self.request.user.username})' | |
516 |
|
516 | |||
517 | qr = qrcode.QRCode(version=1, box_size=10, border=5) |
|
517 | qr = qrcode.QRCode(version=1, box_size=10, border=5) | |
518 | qr.add_data(pyotp.totp.TOTP(secret).provisioning_uri(name=totp_name)) |
|
518 | qr.add_data(pyotp.totp.TOTP(secret).provisioning_uri(name=totp_name)) | |
519 | qr.make(fit=True) |
|
519 | qr.make(fit=True) | |
520 | img = qr.make_image(fill_color='black', back_color='white') |
|
520 | img = qr.make_image(fill_color='black', back_color='white') | |
521 | buffered = BytesIO() |
|
521 | buffered = BytesIO() | |
522 | img.save(buffered) |
|
522 | img.save(buffered) | |
523 | return self._get_template_context( |
|
523 | return self._get_template_context( | |
524 | c, |
|
524 | c, | |
525 | qr=b64encode(buffered.getvalue()).decode("utf-8"), |
|
525 | qr=b64encode(buffered.getvalue()).decode("utf-8"), | |
526 | key=secret, |
|
526 | key=secret, | |
527 | totp_name=totp_name, |
|
527 | totp_name=totp_name, | |
528 | ** render_ctx |
|
528 | ** render_ctx | |
529 | ) |
|
529 | ) | |
530 |
|
530 | |||
531 | @LoginRequired() |
|
531 | @LoginRequired() | |
532 | @NotAnonymous() |
|
532 | @NotAnonymous() | |
533 | def verify_2fa(self): |
|
533 | def verify_2fa(self): | |
534 | _ = self.request.translate |
|
534 | _ = self.request.translate | |
535 | c = self.load_default_context() |
|
535 | c = self.load_default_context() | |
536 | render_ctx = {} |
|
536 | render_ctx = {} | |
537 | user_instance = self._rhodecode_db_user |
|
537 | user_instance = self._rhodecode_db_user | |
538 | totp_form = TOTPForm(_, user_instance, allow_recovery_code_use=True)() |
|
538 | totp_form = TOTPForm(_, user_instance, allow_recovery_code_use=True)() | |
539 | if self.request.method == 'POST': |
|
539 | if self.request.method == 'POST': | |
540 | post_items = dict(self.request.POST) |
|
540 | post_items = dict(self.request.POST) | |
541 | # NOTE: inject secret, as it's a post configured saved item. |
|
541 | # NOTE: inject secret, as it's a post configured saved item. | |
542 | post_items['secret_totp'] = user_instance.get_secret_2fa() |
|
542 | post_items['secret_totp'] = user_instance.get_secret_2fa() | |
543 | try: |
|
543 | try: | |
544 | totp_form.to_python(post_items) |
|
544 | totp_form.to_python(post_items) | |
545 | user_instance.has_check_2fa_flag = False |
|
545 | user_instance.has_check_2fa_flag = False | |
546 | Session().commit() |
|
546 | Session().commit() | |
547 | raise HTTPFound(c.came_from) |
|
547 | raise HTTPFound(c.came_from) | |
548 | except formencode.Invalid as errors: |
|
548 | except formencode.Invalid as errors: | |
549 | defaults = errors.value |
|
549 | defaults = errors.value | |
550 | render_ctx = { |
|
550 | render_ctx = { | |
551 | 'errors': errors.error_dict, |
|
551 | 'errors': errors.error_dict, | |
552 | 'defaults': defaults, |
|
552 | 'defaults': defaults, | |
553 | } |
|
553 | } | |
554 | return self._get_template_context(c, **render_ctx) |
|
554 | return self._get_template_context(c, **render_ctx) |
@@ -1,370 +1,370 b'' | |||||
1 | # Copyright (C) 2016-2023 RhodeCode GmbH |
|
1 | # Copyright (C) 2016-2023 RhodeCode GmbH | |
2 | # |
|
2 | # | |
3 | # This program is free software: you can redistribute it and/or modify |
|
3 | # This program is free software: you can redistribute it and/or modify | |
4 | # it under the terms of the GNU Affero General Public License, version 3 |
|
4 | # it under the terms of the GNU Affero General Public License, version 3 | |
5 | # (only), as published by the Free Software Foundation. |
|
5 | # (only), as published by the Free Software Foundation. | |
6 | # |
|
6 | # | |
7 | # This program is distributed in the hope that it will be useful, |
|
7 | # This program is distributed in the hope that it will be useful, | |
8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | # GNU General Public License for more details. |
|
10 | # GNU General Public License for more details. | |
11 | # |
|
11 | # | |
12 | # You should have received a copy of the GNU Affero General Public License |
|
12 | # You should have received a copy of the GNU Affero General Public License | |
13 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
13 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
14 | # |
|
14 | # | |
15 | # This program is dual-licensed. If you wish to learn more about the |
|
15 | # This program is dual-licensed. If you wish to learn more about the | |
16 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
16 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
18 |
|
18 | |||
19 |
|
19 | |||
20 | from rhodecode.apps._base import ADMIN_PREFIX |
|
20 | from rhodecode.apps._base import ADMIN_PREFIX | |
21 |
|
21 | |||
22 |
|
22 | |||
23 | def includeme(config): |
|
23 | def includeme(config): | |
24 | from rhodecode.apps.my_account.views.my_account import MyAccountView |
|
24 | from rhodecode.apps.my_account.views.my_account import MyAccountView | |
25 | from rhodecode.apps.my_account.views.my_account_notifications import MyAccountNotificationsView |
|
25 | from rhodecode.apps.my_account.views.my_account_notifications import MyAccountNotificationsView | |
26 | from rhodecode.apps.my_account.views.my_account_ssh_keys import MyAccountSshKeysView |
|
26 | from rhodecode.apps.my_account.views.my_account_ssh_keys import MyAccountSshKeysView | |
27 |
|
27 | |||
28 | config.add_route( |
|
28 | config.add_route( | |
29 | name='my_account_profile', |
|
29 | name='my_account_profile', | |
30 | pattern=ADMIN_PREFIX + '/my_account/profile') |
|
30 | pattern=ADMIN_PREFIX + '/my_account/profile') | |
31 | config.add_view( |
|
31 | config.add_view( | |
32 | MyAccountView, |
|
32 | MyAccountView, | |
33 | attr='my_account_profile', |
|
33 | attr='my_account_profile', | |
34 | route_name='my_account_profile', request_method='GET', |
|
34 | route_name='my_account_profile', request_method='GET', | |
35 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
35 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
36 |
|
36 | |||
37 | # my account edit details |
|
37 | # my account edit details | |
38 | config.add_route( |
|
38 | config.add_route( | |
39 | name='my_account_edit', |
|
39 | name='my_account_edit', | |
40 | pattern=ADMIN_PREFIX + '/my_account/edit') |
|
40 | pattern=ADMIN_PREFIX + '/my_account/edit') | |
41 | config.add_view( |
|
41 | config.add_view( | |
42 | MyAccountView, |
|
42 | MyAccountView, | |
43 | attr='my_account_edit', |
|
43 | attr='my_account_edit', | |
44 | route_name='my_account_edit', |
|
44 | route_name='my_account_edit', | |
45 | request_method='GET', |
|
45 | request_method='GET', | |
46 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
46 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
47 |
|
47 | |||
48 | config.add_route( |
|
48 | config.add_route( | |
49 | name='my_account_update', |
|
49 | name='my_account_update', | |
50 | pattern=ADMIN_PREFIX + '/my_account/update') |
|
50 | pattern=ADMIN_PREFIX + '/my_account/update') | |
51 | config.add_view( |
|
51 | config.add_view( | |
52 | MyAccountView, |
|
52 | MyAccountView, | |
53 | attr='my_account_update', |
|
53 | attr='my_account_update', | |
54 | route_name='my_account_update', |
|
54 | route_name='my_account_update', | |
55 | request_method='POST', |
|
55 | request_method='POST', | |
56 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
56 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
57 |
|
57 | |||
58 | # my account password |
|
58 | # my account password | |
59 | config.add_route( |
|
59 | config.add_route( | |
60 | name='my_account_password', |
|
60 | name='my_account_password', | |
61 | pattern=ADMIN_PREFIX + '/my_account/password') |
|
61 | pattern=ADMIN_PREFIX + '/my_account/password') | |
62 | config.add_view( |
|
62 | config.add_view( | |
63 | MyAccountView, |
|
63 | MyAccountView, | |
64 | attr='my_account_password', |
|
64 | attr='my_account_password', | |
65 | route_name='my_account_password', request_method='GET', |
|
65 | route_name='my_account_password', request_method='GET', | |
66 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
66 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
67 |
|
67 | |||
68 | config.add_route( |
|
68 | config.add_route( | |
69 | name='my_account_password_update', |
|
69 | name='my_account_password_update', | |
70 | pattern=ADMIN_PREFIX + '/my_account/password/update') |
|
70 | pattern=ADMIN_PREFIX + '/my_account/password/update') | |
71 | config.add_view( |
|
71 | config.add_view( | |
72 | MyAccountView, |
|
72 | MyAccountView, | |
73 | attr='my_account_password_update', |
|
73 | attr='my_account_password_update', | |
74 | route_name='my_account_password_update', request_method='POST', |
|
74 | route_name='my_account_password_update', request_method='POST', | |
75 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
75 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
76 |
|
76 | |||
77 | # my account 2fa |
|
77 | # my account 2fa | |
78 | config.add_route( |
|
78 | config.add_route( | |
79 |
name='my_account_ |
|
79 | name='my_account_configure_2fa', | |
80 |
pattern=ADMIN_PREFIX + '/my_account/ |
|
80 | pattern=ADMIN_PREFIX + '/my_account/configure_2fa') | |
81 | config.add_view( |
|
81 | config.add_view( | |
82 | MyAccountView, |
|
82 | MyAccountView, | |
83 | attr='my_account_2fa', |
|
83 | attr='my_account_2fa', | |
84 |
route_name='my_account_ |
|
84 | route_name='my_account_configure_2fa', request_method='GET', | |
85 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
85 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
86 | # my account 2fa save |
|
86 | # my account 2fa save | |
87 | config.add_route( |
|
87 | config.add_route( | |
88 |
name='my_account_ |
|
88 | name='my_account_configure_2fa_update', | |
89 |
pattern=ADMIN_PREFIX + '/my_account/ |
|
89 | pattern=ADMIN_PREFIX + '/my_account/configure_2fa_update') | |
90 | config.add_view( |
|
90 | config.add_view( | |
91 | MyAccountView, |
|
91 | MyAccountView, | |
92 | attr='my_account_2fa_update', |
|
92 | attr='my_account_2fa_update', | |
93 |
route_name='my_account_ |
|
93 | route_name='my_account_configure_2fa_update', request_method='POST', | |
94 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
94 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
95 |
|
95 | |||
96 | # my account 2fa recovery code-reset |
|
96 | # my account 2fa recovery code-reset | |
97 | config.add_route( |
|
97 | config.add_route( | |
98 | name='my_account_show_2fa_recovery_codes', |
|
98 | name='my_account_show_2fa_recovery_codes', | |
99 | pattern=ADMIN_PREFIX + '/my_account/recovery_codes') |
|
99 | pattern=ADMIN_PREFIX + '/my_account/recovery_codes') | |
100 | config.add_view( |
|
100 | config.add_view( | |
101 | MyAccountView, |
|
101 | MyAccountView, | |
102 | attr='my_account_2fa_show_recovery_codes', |
|
102 | attr='my_account_2fa_show_recovery_codes', | |
103 | route_name='my_account_show_2fa_recovery_codes', request_method='POST', xhr=True, |
|
103 | route_name='my_account_show_2fa_recovery_codes', request_method='POST', xhr=True, | |
104 | renderer='json_ext') |
|
104 | renderer='json_ext') | |
105 |
|
105 | |||
106 | # my account 2fa recovery code-reset |
|
106 | # my account 2fa recovery code-reset | |
107 | config.add_route( |
|
107 | config.add_route( | |
108 | name='my_account_regenerate_2fa_recovery_codes', |
|
108 | name='my_account_regenerate_2fa_recovery_codes', | |
109 | pattern=ADMIN_PREFIX + '/my_account/regenerate_recovery_codes') |
|
109 | pattern=ADMIN_PREFIX + '/my_account/regenerate_recovery_codes') | |
110 | config.add_view( |
|
110 | config.add_view( | |
111 | MyAccountView, |
|
111 | MyAccountView, | |
112 | attr='my_account_2fa_regenerate_recovery_codes', |
|
112 | attr='my_account_2fa_regenerate_recovery_codes', | |
113 | route_name='my_account_regenerate_2fa_recovery_codes', request_method='POST', |
|
113 | route_name='my_account_regenerate_2fa_recovery_codes', request_method='POST', | |
114 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
114 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
115 |
|
115 | |||
116 | # my account tokens |
|
116 | # my account tokens | |
117 | config.add_route( |
|
117 | config.add_route( | |
118 | name='my_account_auth_tokens', |
|
118 | name='my_account_auth_tokens', | |
119 | pattern=ADMIN_PREFIX + '/my_account/auth_tokens') |
|
119 | pattern=ADMIN_PREFIX + '/my_account/auth_tokens') | |
120 | config.add_view( |
|
120 | config.add_view( | |
121 | MyAccountView, |
|
121 | MyAccountView, | |
122 | attr='my_account_auth_tokens', |
|
122 | attr='my_account_auth_tokens', | |
123 | route_name='my_account_auth_tokens', request_method='GET', |
|
123 | route_name='my_account_auth_tokens', request_method='GET', | |
124 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
124 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
125 |
|
125 | |||
126 | config.add_route( |
|
126 | config.add_route( | |
127 | name='my_account_auth_tokens_view', |
|
127 | name='my_account_auth_tokens_view', | |
128 | pattern=ADMIN_PREFIX + '/my_account/auth_tokens/view') |
|
128 | pattern=ADMIN_PREFIX + '/my_account/auth_tokens/view') | |
129 | config.add_view( |
|
129 | config.add_view( | |
130 | MyAccountView, |
|
130 | MyAccountView, | |
131 | attr='my_account_auth_tokens_view', |
|
131 | attr='my_account_auth_tokens_view', | |
132 | route_name='my_account_auth_tokens_view', request_method='POST', xhr=True, |
|
132 | route_name='my_account_auth_tokens_view', request_method='POST', xhr=True, | |
133 | renderer='json_ext') |
|
133 | renderer='json_ext') | |
134 |
|
134 | |||
135 | config.add_route( |
|
135 | config.add_route( | |
136 | name='my_account_auth_tokens_add', |
|
136 | name='my_account_auth_tokens_add', | |
137 | pattern=ADMIN_PREFIX + '/my_account/auth_tokens/new') |
|
137 | pattern=ADMIN_PREFIX + '/my_account/auth_tokens/new') | |
138 | config.add_view( |
|
138 | config.add_view( | |
139 | MyAccountView, |
|
139 | MyAccountView, | |
140 | attr='my_account_auth_tokens_add', |
|
140 | attr='my_account_auth_tokens_add', | |
141 | route_name='my_account_auth_tokens_add', request_method='POST') |
|
141 | route_name='my_account_auth_tokens_add', request_method='POST') | |
142 |
|
142 | |||
143 | config.add_route( |
|
143 | config.add_route( | |
144 | name='my_account_auth_tokens_delete', |
|
144 | name='my_account_auth_tokens_delete', | |
145 | pattern=ADMIN_PREFIX + '/my_account/auth_tokens/delete') |
|
145 | pattern=ADMIN_PREFIX + '/my_account/auth_tokens/delete') | |
146 | config.add_view( |
|
146 | config.add_view( | |
147 | MyAccountView, |
|
147 | MyAccountView, | |
148 | attr='my_account_auth_tokens_delete', |
|
148 | attr='my_account_auth_tokens_delete', | |
149 | route_name='my_account_auth_tokens_delete', request_method='POST') |
|
149 | route_name='my_account_auth_tokens_delete', request_method='POST') | |
150 |
|
150 | |||
151 | # my account ssh keys |
|
151 | # my account ssh keys | |
152 | config.add_route( |
|
152 | config.add_route( | |
153 | name='my_account_ssh_keys', |
|
153 | name='my_account_ssh_keys', | |
154 | pattern=ADMIN_PREFIX + '/my_account/ssh_keys') |
|
154 | pattern=ADMIN_PREFIX + '/my_account/ssh_keys') | |
155 | config.add_view( |
|
155 | config.add_view( | |
156 | MyAccountSshKeysView, |
|
156 | MyAccountSshKeysView, | |
157 | attr='my_account_ssh_keys', |
|
157 | attr='my_account_ssh_keys', | |
158 | route_name='my_account_ssh_keys', request_method='GET', |
|
158 | route_name='my_account_ssh_keys', request_method='GET', | |
159 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
159 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
160 |
|
160 | |||
161 | config.add_route( |
|
161 | config.add_route( | |
162 | name='my_account_ssh_keys_generate', |
|
162 | name='my_account_ssh_keys_generate', | |
163 | pattern=ADMIN_PREFIX + '/my_account/ssh_keys/generate') |
|
163 | pattern=ADMIN_PREFIX + '/my_account/ssh_keys/generate') | |
164 | config.add_view( |
|
164 | config.add_view( | |
165 | MyAccountSshKeysView, |
|
165 | MyAccountSshKeysView, | |
166 | attr='ssh_keys_generate_keypair', |
|
166 | attr='ssh_keys_generate_keypair', | |
167 | route_name='my_account_ssh_keys_generate', request_method='GET', |
|
167 | route_name='my_account_ssh_keys_generate', request_method='GET', | |
168 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
168 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
169 |
|
169 | |||
170 | config.add_route( |
|
170 | config.add_route( | |
171 | name='my_account_ssh_keys_add', |
|
171 | name='my_account_ssh_keys_add', | |
172 | pattern=ADMIN_PREFIX + '/my_account/ssh_keys/new') |
|
172 | pattern=ADMIN_PREFIX + '/my_account/ssh_keys/new') | |
173 | config.add_view( |
|
173 | config.add_view( | |
174 | MyAccountSshKeysView, |
|
174 | MyAccountSshKeysView, | |
175 | attr='my_account_ssh_keys_add', |
|
175 | attr='my_account_ssh_keys_add', | |
176 | route_name='my_account_ssh_keys_add', request_method='POST',) |
|
176 | route_name='my_account_ssh_keys_add', request_method='POST',) | |
177 |
|
177 | |||
178 | config.add_route( |
|
178 | config.add_route( | |
179 | name='my_account_ssh_keys_delete', |
|
179 | name='my_account_ssh_keys_delete', | |
180 | pattern=ADMIN_PREFIX + '/my_account/ssh_keys/delete') |
|
180 | pattern=ADMIN_PREFIX + '/my_account/ssh_keys/delete') | |
181 | config.add_view( |
|
181 | config.add_view( | |
182 | MyAccountSshKeysView, |
|
182 | MyAccountSshKeysView, | |
183 | attr='my_account_ssh_keys_delete', |
|
183 | attr='my_account_ssh_keys_delete', | |
184 | route_name='my_account_ssh_keys_delete', request_method='POST') |
|
184 | route_name='my_account_ssh_keys_delete', request_method='POST') | |
185 |
|
185 | |||
186 | # my account user group membership |
|
186 | # my account user group membership | |
187 | config.add_route( |
|
187 | config.add_route( | |
188 | name='my_account_user_group_membership', |
|
188 | name='my_account_user_group_membership', | |
189 | pattern=ADMIN_PREFIX + '/my_account/user_group_membership') |
|
189 | pattern=ADMIN_PREFIX + '/my_account/user_group_membership') | |
190 | config.add_view( |
|
190 | config.add_view( | |
191 | MyAccountView, |
|
191 | MyAccountView, | |
192 | attr='my_account_user_group_membership', |
|
192 | attr='my_account_user_group_membership', | |
193 | route_name='my_account_user_group_membership', |
|
193 | route_name='my_account_user_group_membership', | |
194 | request_method='GET', |
|
194 | request_method='GET', | |
195 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
195 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
196 |
|
196 | |||
197 | # my account emails |
|
197 | # my account emails | |
198 | config.add_route( |
|
198 | config.add_route( | |
199 | name='my_account_emails', |
|
199 | name='my_account_emails', | |
200 | pattern=ADMIN_PREFIX + '/my_account/emails') |
|
200 | pattern=ADMIN_PREFIX + '/my_account/emails') | |
201 | config.add_view( |
|
201 | config.add_view( | |
202 | MyAccountView, |
|
202 | MyAccountView, | |
203 | attr='my_account_emails', |
|
203 | attr='my_account_emails', | |
204 | route_name='my_account_emails', request_method='GET', |
|
204 | route_name='my_account_emails', request_method='GET', | |
205 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
205 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
206 |
|
206 | |||
207 | config.add_route( |
|
207 | config.add_route( | |
208 | name='my_account_emails_add', |
|
208 | name='my_account_emails_add', | |
209 | pattern=ADMIN_PREFIX + '/my_account/emails/new') |
|
209 | pattern=ADMIN_PREFIX + '/my_account/emails/new') | |
210 | config.add_view( |
|
210 | config.add_view( | |
211 | MyAccountView, |
|
211 | MyAccountView, | |
212 | attr='my_account_emails_add', |
|
212 | attr='my_account_emails_add', | |
213 | route_name='my_account_emails_add', request_method='POST', |
|
213 | route_name='my_account_emails_add', request_method='POST', | |
214 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
214 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
215 |
|
215 | |||
216 | config.add_route( |
|
216 | config.add_route( | |
217 | name='my_account_emails_delete', |
|
217 | name='my_account_emails_delete', | |
218 | pattern=ADMIN_PREFIX + '/my_account/emails/delete') |
|
218 | pattern=ADMIN_PREFIX + '/my_account/emails/delete') | |
219 | config.add_view( |
|
219 | config.add_view( | |
220 | MyAccountView, |
|
220 | MyAccountView, | |
221 | attr='my_account_emails_delete', |
|
221 | attr='my_account_emails_delete', | |
222 | route_name='my_account_emails_delete', request_method='POST') |
|
222 | route_name='my_account_emails_delete', request_method='POST') | |
223 |
|
223 | |||
224 | config.add_route( |
|
224 | config.add_route( | |
225 | name='my_account_repos', |
|
225 | name='my_account_repos', | |
226 | pattern=ADMIN_PREFIX + '/my_account/repos') |
|
226 | pattern=ADMIN_PREFIX + '/my_account/repos') | |
227 | config.add_view( |
|
227 | config.add_view( | |
228 | MyAccountView, |
|
228 | MyAccountView, | |
229 | attr='my_account_repos', |
|
229 | attr='my_account_repos', | |
230 | route_name='my_account_repos', request_method='GET', |
|
230 | route_name='my_account_repos', request_method='GET', | |
231 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
231 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
232 |
|
232 | |||
233 | config.add_route( |
|
233 | config.add_route( | |
234 | name='my_account_watched', |
|
234 | name='my_account_watched', | |
235 | pattern=ADMIN_PREFIX + '/my_account/watched') |
|
235 | pattern=ADMIN_PREFIX + '/my_account/watched') | |
236 | config.add_view( |
|
236 | config.add_view( | |
237 | MyAccountView, |
|
237 | MyAccountView, | |
238 | attr='my_account_watched', |
|
238 | attr='my_account_watched', | |
239 | route_name='my_account_watched', request_method='GET', |
|
239 | route_name='my_account_watched', request_method='GET', | |
240 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
240 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
241 |
|
241 | |||
242 | config.add_route( |
|
242 | config.add_route( | |
243 | name='my_account_bookmarks', |
|
243 | name='my_account_bookmarks', | |
244 | pattern=ADMIN_PREFIX + '/my_account/bookmarks') |
|
244 | pattern=ADMIN_PREFIX + '/my_account/bookmarks') | |
245 | config.add_view( |
|
245 | config.add_view( | |
246 | MyAccountView, |
|
246 | MyAccountView, | |
247 | attr='my_account_bookmarks', |
|
247 | attr='my_account_bookmarks', | |
248 | route_name='my_account_bookmarks', request_method='GET', |
|
248 | route_name='my_account_bookmarks', request_method='GET', | |
249 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
249 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
250 |
|
250 | |||
251 | config.add_route( |
|
251 | config.add_route( | |
252 | name='my_account_bookmarks_update', |
|
252 | name='my_account_bookmarks_update', | |
253 | pattern=ADMIN_PREFIX + '/my_account/bookmarks/update') |
|
253 | pattern=ADMIN_PREFIX + '/my_account/bookmarks/update') | |
254 | config.add_view( |
|
254 | config.add_view( | |
255 | MyAccountView, |
|
255 | MyAccountView, | |
256 | attr='my_account_bookmarks_update', |
|
256 | attr='my_account_bookmarks_update', | |
257 | route_name='my_account_bookmarks_update', request_method='POST') |
|
257 | route_name='my_account_bookmarks_update', request_method='POST') | |
258 |
|
258 | |||
259 | config.add_route( |
|
259 | config.add_route( | |
260 | name='my_account_goto_bookmark', |
|
260 | name='my_account_goto_bookmark', | |
261 | pattern=ADMIN_PREFIX + '/my_account/bookmark/{bookmark_id}') |
|
261 | pattern=ADMIN_PREFIX + '/my_account/bookmark/{bookmark_id}') | |
262 | config.add_view( |
|
262 | config.add_view( | |
263 | MyAccountView, |
|
263 | MyAccountView, | |
264 | attr='my_account_goto_bookmark', |
|
264 | attr='my_account_goto_bookmark', | |
265 | route_name='my_account_goto_bookmark', request_method='GET', |
|
265 | route_name='my_account_goto_bookmark', request_method='GET', | |
266 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
266 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
267 |
|
267 | |||
268 | config.add_route( |
|
268 | config.add_route( | |
269 | name='my_account_perms', |
|
269 | name='my_account_perms', | |
270 | pattern=ADMIN_PREFIX + '/my_account/perms') |
|
270 | pattern=ADMIN_PREFIX + '/my_account/perms') | |
271 | config.add_view( |
|
271 | config.add_view( | |
272 | MyAccountView, |
|
272 | MyAccountView, | |
273 | attr='my_account_perms', |
|
273 | attr='my_account_perms', | |
274 | route_name='my_account_perms', request_method='GET', |
|
274 | route_name='my_account_perms', request_method='GET', | |
275 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
275 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
276 |
|
276 | |||
277 | config.add_route( |
|
277 | config.add_route( | |
278 | name='my_account_notifications', |
|
278 | name='my_account_notifications', | |
279 | pattern=ADMIN_PREFIX + '/my_account/notifications') |
|
279 | pattern=ADMIN_PREFIX + '/my_account/notifications') | |
280 | config.add_view( |
|
280 | config.add_view( | |
281 | MyAccountView, |
|
281 | MyAccountView, | |
282 | attr='my_notifications', |
|
282 | attr='my_notifications', | |
283 | route_name='my_account_notifications', request_method='GET', |
|
283 | route_name='my_account_notifications', request_method='GET', | |
284 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
284 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
285 |
|
285 | |||
286 | config.add_route( |
|
286 | config.add_route( | |
287 | name='my_account_notifications_toggle_visibility', |
|
287 | name='my_account_notifications_toggle_visibility', | |
288 | pattern=ADMIN_PREFIX + '/my_account/toggle_visibility') |
|
288 | pattern=ADMIN_PREFIX + '/my_account/toggle_visibility') | |
289 | config.add_view( |
|
289 | config.add_view( | |
290 | MyAccountView, |
|
290 | MyAccountView, | |
291 | attr='my_notifications_toggle_visibility', |
|
291 | attr='my_notifications_toggle_visibility', | |
292 | route_name='my_account_notifications_toggle_visibility', |
|
292 | route_name='my_account_notifications_toggle_visibility', | |
293 | request_method='POST', renderer='json_ext') |
|
293 | request_method='POST', renderer='json_ext') | |
294 |
|
294 | |||
295 | # my account pull requests |
|
295 | # my account pull requests | |
296 | config.add_route( |
|
296 | config.add_route( | |
297 | name='my_account_pullrequests', |
|
297 | name='my_account_pullrequests', | |
298 | pattern=ADMIN_PREFIX + '/my_account/pull_requests') |
|
298 | pattern=ADMIN_PREFIX + '/my_account/pull_requests') | |
299 | config.add_view( |
|
299 | config.add_view( | |
300 | MyAccountView, |
|
300 | MyAccountView, | |
301 | attr='my_account_pullrequests', |
|
301 | attr='my_account_pullrequests', | |
302 | route_name='my_account_pullrequests', |
|
302 | route_name='my_account_pullrequests', | |
303 | request_method='GET', |
|
303 | request_method='GET', | |
304 | renderer='rhodecode:templates/admin/my_account/my_account.mako') |
|
304 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
305 |
|
305 | |||
306 | config.add_route( |
|
306 | config.add_route( | |
307 | name='my_account_pullrequests_data', |
|
307 | name='my_account_pullrequests_data', | |
308 | pattern=ADMIN_PREFIX + '/my_account/pull_requests/data') |
|
308 | pattern=ADMIN_PREFIX + '/my_account/pull_requests/data') | |
309 | config.add_view( |
|
309 | config.add_view( | |
310 | MyAccountView, |
|
310 | MyAccountView, | |
311 | attr='my_account_pullrequests_data', |
|
311 | attr='my_account_pullrequests_data', | |
312 | route_name='my_account_pullrequests_data', |
|
312 | route_name='my_account_pullrequests_data', | |
313 | request_method='GET', renderer='json_ext') |
|
313 | request_method='GET', renderer='json_ext') | |
314 |
|
314 | |||
315 | # channelstream test |
|
315 | # channelstream test | |
316 | config.add_route( |
|
316 | config.add_route( | |
317 | name='my_account_notifications_test_channelstream', |
|
317 | name='my_account_notifications_test_channelstream', | |
318 | pattern=ADMIN_PREFIX + '/my_account/test_channelstream') |
|
318 | pattern=ADMIN_PREFIX + '/my_account/test_channelstream') | |
319 | config.add_view( |
|
319 | config.add_view( | |
320 | MyAccountView, |
|
320 | MyAccountView, | |
321 | attr='my_account_notifications_test_channelstream', |
|
321 | attr='my_account_notifications_test_channelstream', | |
322 | route_name='my_account_notifications_test_channelstream', |
|
322 | route_name='my_account_notifications_test_channelstream', | |
323 | request_method='POST', renderer='json_ext') |
|
323 | request_method='POST', renderer='json_ext') | |
324 |
|
324 | |||
325 | # notifications |
|
325 | # notifications | |
326 | config.add_route( |
|
326 | config.add_route( | |
327 | name='notifications_show_all', |
|
327 | name='notifications_show_all', | |
328 | pattern=ADMIN_PREFIX + '/notifications') |
|
328 | pattern=ADMIN_PREFIX + '/notifications') | |
329 | config.add_view( |
|
329 | config.add_view( | |
330 | MyAccountNotificationsView, |
|
330 | MyAccountNotificationsView, | |
331 | attr='notifications_show_all', |
|
331 | attr='notifications_show_all', | |
332 | route_name='notifications_show_all', request_method='GET', |
|
332 | route_name='notifications_show_all', request_method='GET', | |
333 | renderer='rhodecode:templates/admin/notifications/notifications_show_all.mako') |
|
333 | renderer='rhodecode:templates/admin/notifications/notifications_show_all.mako') | |
334 |
|
334 | |||
335 | # notifications |
|
335 | # notifications | |
336 | config.add_route( |
|
336 | config.add_route( | |
337 | name='notifications_mark_all_read', |
|
337 | name='notifications_mark_all_read', | |
338 | pattern=ADMIN_PREFIX + '/notifications_mark_all_read') |
|
338 | pattern=ADMIN_PREFIX + '/notifications_mark_all_read') | |
339 | config.add_view( |
|
339 | config.add_view( | |
340 | MyAccountNotificationsView, |
|
340 | MyAccountNotificationsView, | |
341 | attr='notifications_mark_all_read', |
|
341 | attr='notifications_mark_all_read', | |
342 | route_name='notifications_mark_all_read', request_method='POST', |
|
342 | route_name='notifications_mark_all_read', request_method='POST', | |
343 | renderer='rhodecode:templates/admin/notifications/notifications_show_all.mako') |
|
343 | renderer='rhodecode:templates/admin/notifications/notifications_show_all.mako') | |
344 |
|
344 | |||
345 | config.add_route( |
|
345 | config.add_route( | |
346 | name='notifications_show', |
|
346 | name='notifications_show', | |
347 | pattern=ADMIN_PREFIX + '/notifications/{notification_id}') |
|
347 | pattern=ADMIN_PREFIX + '/notifications/{notification_id}') | |
348 | config.add_view( |
|
348 | config.add_view( | |
349 | MyAccountNotificationsView, |
|
349 | MyAccountNotificationsView, | |
350 | attr='notifications_show', |
|
350 | attr='notifications_show', | |
351 | route_name='notifications_show', request_method='GET', |
|
351 | route_name='notifications_show', request_method='GET', | |
352 | renderer='rhodecode:templates/admin/notifications/notifications_show.mako') |
|
352 | renderer='rhodecode:templates/admin/notifications/notifications_show.mako') | |
353 |
|
353 | |||
354 | config.add_route( |
|
354 | config.add_route( | |
355 | name='notifications_update', |
|
355 | name='notifications_update', | |
356 | pattern=ADMIN_PREFIX + '/notifications/{notification_id}/update') |
|
356 | pattern=ADMIN_PREFIX + '/notifications/{notification_id}/update') | |
357 | config.add_view( |
|
357 | config.add_view( | |
358 | MyAccountNotificationsView, |
|
358 | MyAccountNotificationsView, | |
359 | attr='notification_update', |
|
359 | attr='notification_update', | |
360 | route_name='notifications_update', request_method='POST', |
|
360 | route_name='notifications_update', request_method='POST', | |
361 | renderer='json_ext') |
|
361 | renderer='json_ext') | |
362 |
|
362 | |||
363 | config.add_route( |
|
363 | config.add_route( | |
364 | name='notifications_delete', |
|
364 | name='notifications_delete', | |
365 | pattern=ADMIN_PREFIX + '/notifications/{notification_id}/delete') |
|
365 | pattern=ADMIN_PREFIX + '/notifications/{notification_id}/delete') | |
366 | config.add_view( |
|
366 | config.add_view( | |
367 | MyAccountNotificationsView, |
|
367 | MyAccountNotificationsView, | |
368 | attr='notification_delete', |
|
368 | attr='notification_delete', | |
369 | route_name='notifications_delete', request_method='POST', |
|
369 | route_name='notifications_delete', request_method='POST', | |
370 | renderer='json_ext') |
|
370 | renderer='json_ext') |
@@ -1,858 +1,858 b'' | |||||
1 | # Copyright (C) 2016-2023 RhodeCode GmbH |
|
1 | # Copyright (C) 2016-2023 RhodeCode GmbH | |
2 | # |
|
2 | # | |
3 | # This program is free software: you can redistribute it and/or modify |
|
3 | # This program is free software: you can redistribute it and/or modify | |
4 | # it under the terms of the GNU Affero General Public License, version 3 |
|
4 | # it under the terms of the GNU Affero General Public License, version 3 | |
5 | # (only), as published by the Free Software Foundation. |
|
5 | # (only), as published by the Free Software Foundation. | |
6 | # |
|
6 | # | |
7 | # This program is distributed in the hope that it will be useful, |
|
7 | # This program is distributed in the hope that it will be useful, | |
8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | # GNU General Public License for more details. |
|
10 | # GNU General Public License for more details. | |
11 | # |
|
11 | # | |
12 | # You should have received a copy of the GNU Affero General Public License |
|
12 | # You should have received a copy of the GNU Affero General Public License | |
13 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
13 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
14 | # |
|
14 | # | |
15 | # This program is dual-licensed. If you wish to learn more about the |
|
15 | # This program is dual-licensed. If you wish to learn more about the | |
16 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
16 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
18 |
|
18 | |||
19 | import time |
|
19 | import time | |
20 | import logging |
|
20 | import logging | |
21 | import datetime |
|
21 | import datetime | |
22 | import string |
|
22 | import string | |
23 |
|
23 | |||
24 | import formencode |
|
24 | import formencode | |
25 | import formencode.htmlfill |
|
25 | import formencode.htmlfill | |
26 | import peppercorn |
|
26 | import peppercorn | |
27 | from pyramid.httpexceptions import HTTPFound, HTTPNotFound |
|
27 | from pyramid.httpexceptions import HTTPFound, HTTPNotFound | |
28 |
|
28 | |||
29 | from rhodecode.apps._base import BaseAppView, DataGridAppView |
|
29 | from rhodecode.apps._base import BaseAppView, DataGridAppView | |
30 | from rhodecode import forms |
|
30 | from rhodecode import forms | |
31 | from rhodecode.lib import helpers as h |
|
31 | from rhodecode.lib import helpers as h | |
32 | from rhodecode.lib import audit_logger |
|
32 | from rhodecode.lib import audit_logger | |
33 | from rhodecode.lib import ext_json |
|
33 | from rhodecode.lib import ext_json | |
34 | from rhodecode.lib.auth import ( |
|
34 | from rhodecode.lib.auth import ( | |
35 | LoginRequired, NotAnonymous, CSRFRequired, |
|
35 | LoginRequired, NotAnonymous, CSRFRequired, | |
36 | HasRepoPermissionAny, HasRepoGroupPermissionAny, AuthUser) |
|
36 | HasRepoPermissionAny, HasRepoGroupPermissionAny, AuthUser) | |
37 | from rhodecode.lib.channelstream import ( |
|
37 | from rhodecode.lib.channelstream import ( | |
38 | channelstream_request, ChannelstreamException) |
|
38 | channelstream_request, ChannelstreamException) | |
39 | from rhodecode.lib.hash_utils import md5_safe |
|
39 | from rhodecode.lib.hash_utils import md5_safe | |
40 | from rhodecode.lib.utils2 import safe_int, md5, str2bool |
|
40 | from rhodecode.lib.utils2 import safe_int, md5, str2bool | |
41 | from rhodecode.model.auth_token import AuthTokenModel |
|
41 | from rhodecode.model.auth_token import AuthTokenModel | |
42 | from rhodecode.model.comment import CommentsModel |
|
42 | from rhodecode.model.comment import CommentsModel | |
43 | from rhodecode.model.db import ( |
|
43 | from rhodecode.model.db import ( | |
44 | IntegrityError, or_, in_filter_generator, select, |
|
44 | IntegrityError, or_, in_filter_generator, select, | |
45 | Repository, UserEmailMap, UserApiKeys, UserFollowing, |
|
45 | Repository, UserEmailMap, UserApiKeys, UserFollowing, | |
46 | PullRequest, UserBookmark, RepoGroup, ChangesetStatus) |
|
46 | PullRequest, UserBookmark, RepoGroup, ChangesetStatus) | |
47 | from rhodecode.model.forms import TOTPForm |
|
47 | from rhodecode.model.forms import TOTPForm | |
48 | from rhodecode.model.meta import Session |
|
48 | from rhodecode.model.meta import Session | |
49 | from rhodecode.model.pull_request import PullRequestModel |
|
49 | from rhodecode.model.pull_request import PullRequestModel | |
50 | from rhodecode.model.user import UserModel |
|
50 | from rhodecode.model.user import UserModel | |
51 | from rhodecode.model.user_group import UserGroupModel |
|
51 | from rhodecode.model.user_group import UserGroupModel | |
52 | from rhodecode.model.validation_schema.schemas import user_schema |
|
52 | from rhodecode.model.validation_schema.schemas import user_schema | |
53 |
|
53 | |||
54 | log = logging.getLogger(__name__) |
|
54 | log = logging.getLogger(__name__) | |
55 |
|
55 | |||
56 |
|
56 | |||
57 | class MyAccountView(BaseAppView, DataGridAppView): |
|
57 | class MyAccountView(BaseAppView, DataGridAppView): | |
58 | ALLOW_SCOPED_TOKENS = False |
|
58 | ALLOW_SCOPED_TOKENS = False | |
59 | """ |
|
59 | """ | |
60 | This view has alternative version inside EE, if modified please take a look |
|
60 | This view has alternative version inside EE, if modified please take a look | |
61 | in there as well. |
|
61 | in there as well. | |
62 | """ |
|
62 | """ | |
63 |
|
63 | |||
64 | def load_default_context(self): |
|
64 | def load_default_context(self): | |
65 | c = self._get_local_tmpl_context() |
|
65 | c = self._get_local_tmpl_context() | |
66 | c.user = c.auth_user.get_instance() |
|
66 | c.user = c.auth_user.get_instance() | |
67 | c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS |
|
67 | c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS | |
68 | return c |
|
68 | return c | |
69 |
|
69 | |||
70 | @LoginRequired() |
|
70 | @LoginRequired() | |
71 | @NotAnonymous() |
|
71 | @NotAnonymous() | |
72 | def my_account_profile(self): |
|
72 | def my_account_profile(self): | |
73 | c = self.load_default_context() |
|
73 | c = self.load_default_context() | |
74 | c.active = 'profile' |
|
74 | c.active = 'profile' | |
75 | c.extern_type = c.user.extern_type |
|
75 | c.extern_type = c.user.extern_type | |
76 | return self._get_template_context(c) |
|
76 | return self._get_template_context(c) | |
77 |
|
77 | |||
78 | @LoginRequired() |
|
78 | @LoginRequired() | |
79 | @NotAnonymous() |
|
79 | @NotAnonymous() | |
80 | def my_account_edit(self): |
|
80 | def my_account_edit(self): | |
81 | c = self.load_default_context() |
|
81 | c = self.load_default_context() | |
82 | c.active = 'profile_edit' |
|
82 | c.active = 'profile_edit' | |
83 | c.extern_type = c.user.extern_type |
|
83 | c.extern_type = c.user.extern_type | |
84 | c.extern_name = c.user.extern_name |
|
84 | c.extern_name = c.user.extern_name | |
85 |
|
85 | |||
86 | schema = user_schema.UserProfileSchema().bind( |
|
86 | schema = user_schema.UserProfileSchema().bind( | |
87 | username=c.user.username, user_emails=c.user.emails) |
|
87 | username=c.user.username, user_emails=c.user.emails) | |
88 | appstruct = { |
|
88 | appstruct = { | |
89 | 'username': c.user.username, |
|
89 | 'username': c.user.username, | |
90 | 'email': c.user.email, |
|
90 | 'email': c.user.email, | |
91 | 'firstname': c.user.firstname, |
|
91 | 'firstname': c.user.firstname, | |
92 | 'lastname': c.user.lastname, |
|
92 | 'lastname': c.user.lastname, | |
93 | 'description': c.user.description, |
|
93 | 'description': c.user.description, | |
94 | } |
|
94 | } | |
95 | c.form = forms.RcForm( |
|
95 | c.form = forms.RcForm( | |
96 | schema, appstruct=appstruct, |
|
96 | schema, appstruct=appstruct, | |
97 | action=h.route_path('my_account_update'), |
|
97 | action=h.route_path('my_account_update'), | |
98 | buttons=(forms.buttons.save, forms.buttons.reset)) |
|
98 | buttons=(forms.buttons.save, forms.buttons.reset)) | |
99 |
|
99 | |||
100 | return self._get_template_context(c) |
|
100 | return self._get_template_context(c) | |
101 |
|
101 | |||
102 | @LoginRequired() |
|
102 | @LoginRequired() | |
103 | @NotAnonymous() |
|
103 | @NotAnonymous() | |
104 | @CSRFRequired() |
|
104 | @CSRFRequired() | |
105 | def my_account_update(self): |
|
105 | def my_account_update(self): | |
106 | _ = self.request.translate |
|
106 | _ = self.request.translate | |
107 | c = self.load_default_context() |
|
107 | c = self.load_default_context() | |
108 | c.active = 'profile_edit' |
|
108 | c.active = 'profile_edit' | |
109 | c.perm_user = c.auth_user |
|
109 | c.perm_user = c.auth_user | |
110 | c.extern_type = c.user.extern_type |
|
110 | c.extern_type = c.user.extern_type | |
111 | c.extern_name = c.user.extern_name |
|
111 | c.extern_name = c.user.extern_name | |
112 |
|
112 | |||
113 | schema = user_schema.UserProfileSchema().bind( |
|
113 | schema = user_schema.UserProfileSchema().bind( | |
114 | username=c.user.username, user_emails=c.user.emails) |
|
114 | username=c.user.username, user_emails=c.user.emails) | |
115 | form = forms.RcForm( |
|
115 | form = forms.RcForm( | |
116 | schema, buttons=(forms.buttons.save, forms.buttons.reset)) |
|
116 | schema, buttons=(forms.buttons.save, forms.buttons.reset)) | |
117 |
|
117 | |||
118 | controls = list(self.request.POST.items()) |
|
118 | controls = list(self.request.POST.items()) | |
119 | try: |
|
119 | try: | |
120 | valid_data = form.validate(controls) |
|
120 | valid_data = form.validate(controls) | |
121 | skip_attrs = ['admin', 'active', 'extern_type', 'extern_name', |
|
121 | skip_attrs = ['admin', 'active', 'extern_type', 'extern_name', | |
122 | 'new_password', 'password_confirmation'] |
|
122 | 'new_password', 'password_confirmation'] | |
123 | if c.extern_type != "rhodecode": |
|
123 | if c.extern_type != "rhodecode": | |
124 | # forbid updating username for external accounts |
|
124 | # forbid updating username for external accounts | |
125 | skip_attrs.append('username') |
|
125 | skip_attrs.append('username') | |
126 | old_email = c.user.email |
|
126 | old_email = c.user.email | |
127 | UserModel().update_user( |
|
127 | UserModel().update_user( | |
128 | self._rhodecode_user.user_id, skip_attrs=skip_attrs, |
|
128 | self._rhodecode_user.user_id, skip_attrs=skip_attrs, | |
129 | **valid_data) |
|
129 | **valid_data) | |
130 | if old_email != valid_data['email']: |
|
130 | if old_email != valid_data['email']: | |
131 | old = UserEmailMap.query() \ |
|
131 | old = UserEmailMap.query() \ | |
132 | .filter(UserEmailMap.user == c.user)\ |
|
132 | .filter(UserEmailMap.user == c.user)\ | |
133 | .filter(UserEmailMap.email == valid_data['email'])\ |
|
133 | .filter(UserEmailMap.email == valid_data['email'])\ | |
134 | .first() |
|
134 | .first() | |
135 | old.email = old_email |
|
135 | old.email = old_email | |
136 | h.flash(_('Your account was updated successfully'), category='success') |
|
136 | h.flash(_('Your account was updated successfully'), category='success') | |
137 | Session().commit() |
|
137 | Session().commit() | |
138 | except forms.ValidationFailure as e: |
|
138 | except forms.ValidationFailure as e: | |
139 | c.form = e |
|
139 | c.form = e | |
140 | return self._get_template_context(c) |
|
140 | return self._get_template_context(c) | |
141 |
|
141 | |||
142 | except Exception: |
|
142 | except Exception: | |
143 | log.exception("Exception updating user") |
|
143 | log.exception("Exception updating user") | |
144 | h.flash(_('Error occurred during update of user'), |
|
144 | h.flash(_('Error occurred during update of user'), | |
145 | category='error') |
|
145 | category='error') | |
146 | raise HTTPFound(h.route_path('my_account_profile')) |
|
146 | raise HTTPFound(h.route_path('my_account_profile')) | |
147 |
|
147 | |||
148 | @LoginRequired() |
|
148 | @LoginRequired() | |
149 | @NotAnonymous() |
|
149 | @NotAnonymous() | |
150 | def my_account_password(self): |
|
150 | def my_account_password(self): | |
151 | c = self.load_default_context() |
|
151 | c = self.load_default_context() | |
152 | c.active = 'password' |
|
152 | c.active = 'password' | |
153 | c.extern_type = c.user.extern_type |
|
153 | c.extern_type = c.user.extern_type | |
154 |
|
154 | |||
155 | schema = user_schema.ChangePasswordSchema().bind( |
|
155 | schema = user_schema.ChangePasswordSchema().bind( | |
156 | username=c.user.username) |
|
156 | username=c.user.username) | |
157 |
|
157 | |||
158 | form = forms.Form( |
|
158 | form = forms.Form( | |
159 | schema, |
|
159 | schema, | |
160 | action=h.route_path('my_account_password_update'), |
|
160 | action=h.route_path('my_account_password_update'), | |
161 | buttons=(forms.buttons.save, forms.buttons.reset)) |
|
161 | buttons=(forms.buttons.save, forms.buttons.reset)) | |
162 |
|
162 | |||
163 | c.form = form |
|
163 | c.form = form | |
164 | return self._get_template_context(c) |
|
164 | return self._get_template_context(c) | |
165 |
|
165 | |||
166 | @LoginRequired() |
|
166 | @LoginRequired() | |
167 | @NotAnonymous() |
|
167 | @NotAnonymous() | |
168 | @CSRFRequired() |
|
168 | @CSRFRequired() | |
169 | def my_account_password_update(self): |
|
169 | def my_account_password_update(self): | |
170 | _ = self.request.translate |
|
170 | _ = self.request.translate | |
171 | c = self.load_default_context() |
|
171 | c = self.load_default_context() | |
172 | c.active = 'password' |
|
172 | c.active = 'password' | |
173 | c.extern_type = c.user.extern_type |
|
173 | c.extern_type = c.user.extern_type | |
174 |
|
174 | |||
175 | schema = user_schema.ChangePasswordSchema().bind( |
|
175 | schema = user_schema.ChangePasswordSchema().bind( | |
176 | username=c.user.username) |
|
176 | username=c.user.username) | |
177 |
|
177 | |||
178 | form = forms.Form( |
|
178 | form = forms.Form( | |
179 | schema, buttons=(forms.buttons.save, forms.buttons.reset)) |
|
179 | schema, buttons=(forms.buttons.save, forms.buttons.reset)) | |
180 |
|
180 | |||
181 | if c.extern_type != 'rhodecode': |
|
181 | if c.extern_type != 'rhodecode': | |
182 | raise HTTPFound(self.request.route_path('my_account_password')) |
|
182 | raise HTTPFound(self.request.route_path('my_account_password')) | |
183 |
|
183 | |||
184 | controls = list(self.request.POST.items()) |
|
184 | controls = list(self.request.POST.items()) | |
185 | try: |
|
185 | try: | |
186 | valid_data = form.validate(controls) |
|
186 | valid_data = form.validate(controls) | |
187 | UserModel().update_user(c.user.user_id, **valid_data) |
|
187 | UserModel().update_user(c.user.user_id, **valid_data) | |
188 | c.user.update_userdata(force_password_change=False) |
|
188 | c.user.update_userdata(force_password_change=False) | |
189 | Session().commit() |
|
189 | Session().commit() | |
190 | except forms.ValidationFailure as e: |
|
190 | except forms.ValidationFailure as e: | |
191 | c.form = e |
|
191 | c.form = e | |
192 | return self._get_template_context(c) |
|
192 | return self._get_template_context(c) | |
193 |
|
193 | |||
194 | except Exception: |
|
194 | except Exception: | |
195 | log.exception("Exception updating password") |
|
195 | log.exception("Exception updating password") | |
196 | h.flash(_('Error occurred during update of user password'), |
|
196 | h.flash(_('Error occurred during update of user password'), | |
197 | category='error') |
|
197 | category='error') | |
198 | else: |
|
198 | else: | |
199 | instance = c.auth_user.get_instance() |
|
199 | instance = c.auth_user.get_instance() | |
200 | self.session.setdefault('rhodecode_user', {}).update( |
|
200 | self.session.setdefault('rhodecode_user', {}).update( | |
201 | {'password': md5_safe(instance.password)}) |
|
201 | {'password': md5_safe(instance.password)}) | |
202 | self.session.save() |
|
202 | self.session.save() | |
203 | h.flash(_("Successfully updated password"), category='success') |
|
203 | h.flash(_("Successfully updated password"), category='success') | |
204 |
|
204 | |||
205 | raise HTTPFound(self.request.route_path('my_account_password')) |
|
205 | raise HTTPFound(self.request.route_path('my_account_password')) | |
206 |
|
206 | |||
207 | @LoginRequired() |
|
207 | @LoginRequired() | |
208 | @NotAnonymous() |
|
208 | @NotAnonymous() | |
209 | def my_account_2fa(self): |
|
209 | def my_account_2fa(self): | |
210 | _ = self.request.translate |
|
210 | _ = self.request.translate | |
211 | c = self.load_default_context() |
|
211 | c = self.load_default_context() | |
212 | c.active = '2FA' |
|
212 | c.active = '2FA' | |
213 | user_instance = c.auth_user.get_instance() |
|
213 | user_instance = c.auth_user.get_instance() | |
214 | locked_by_admin = user_instance.has_forced_2fa |
|
214 | locked_by_admin = user_instance.has_forced_2fa | |
215 | c.state_of_2fa = user_instance.has_enabled_2fa |
|
215 | c.state_of_2fa = user_instance.has_enabled_2fa | |
216 | c.user_seen_2fa_recovery_codes = user_instance.has_seen_2fa_codes |
|
216 | c.user_seen_2fa_recovery_codes = user_instance.has_seen_2fa_codes | |
217 | c.locked_2fa = str2bool(locked_by_admin) |
|
217 | c.locked_2fa = str2bool(locked_by_admin) | |
218 | return self._get_template_context(c) |
|
218 | return self._get_template_context(c) | |
219 |
|
219 | |||
220 | @LoginRequired() |
|
220 | @LoginRequired() | |
221 | @NotAnonymous() |
|
221 | @NotAnonymous() | |
222 | @CSRFRequired() |
|
222 | @CSRFRequired() | |
223 | def my_account_2fa_update(self): |
|
223 | def my_account_2fa_update(self): | |
224 | _ = self.request.translate |
|
224 | _ = self.request.translate | |
225 | c = self.load_default_context() |
|
225 | c = self.load_default_context() | |
226 | c.active = '2FA' |
|
226 | c.active = '2FA' | |
227 | user_instance = c.auth_user.get_instance() |
|
227 | user_instance = c.auth_user.get_instance() | |
228 |
|
228 | |||
229 | state = self.request.POST.get('2fa_status') == '1' |
|
229 | state = self.request.POST.get('2fa_status') == '1' | |
230 | user_instance.has_enabled_2fa = state |
|
230 | user_instance.has_enabled_2fa = state | |
231 | user_instance.update_userdata(update_2fa=time.time()) |
|
231 | user_instance.update_userdata(update_2fa=time.time()) | |
232 | Session().commit() |
|
232 | Session().commit() | |
233 | h.flash(_("Successfully saved 2FA settings"), category='success') |
|
233 | h.flash(_("Successfully saved 2FA settings"), category='success') | |
234 |
raise HTTPFound(self.request.route_path('my_account_ |
|
234 | raise HTTPFound(self.request.route_path('my_account_configure_2fa')) | |
235 |
|
235 | |||
236 | @LoginRequired() |
|
236 | @LoginRequired() | |
237 | @NotAnonymous() |
|
237 | @NotAnonymous() | |
238 | @CSRFRequired() |
|
238 | @CSRFRequired() | |
239 | def my_account_2fa_show_recovery_codes(self): |
|
239 | def my_account_2fa_show_recovery_codes(self): | |
240 | c = self.load_default_context() |
|
240 | c = self.load_default_context() | |
241 | user_instance = c.auth_user.get_instance() |
|
241 | user_instance = c.auth_user.get_instance() | |
242 | user_instance.has_seen_2fa_codes = True |
|
242 | user_instance.has_seen_2fa_codes = True | |
243 | Session().commit() |
|
243 | Session().commit() | |
244 | return {'recovery_codes': user_instance.get_2fa_recovery_codes()} |
|
244 | return {'recovery_codes': user_instance.get_2fa_recovery_codes()} | |
245 |
|
245 | |||
246 | @LoginRequired() |
|
246 | @LoginRequired() | |
247 | @NotAnonymous() |
|
247 | @NotAnonymous() | |
248 | @CSRFRequired() |
|
248 | @CSRFRequired() | |
249 | def my_account_2fa_regenerate_recovery_codes(self): |
|
249 | def my_account_2fa_regenerate_recovery_codes(self): | |
250 | _ = self.request.translate |
|
250 | _ = self.request.translate | |
251 | c = self.load_default_context() |
|
251 | c = self.load_default_context() | |
252 | user_instance = c.auth_user.get_instance() |
|
252 | user_instance = c.auth_user.get_instance() | |
253 |
|
253 | |||
254 | totp_form = TOTPForm(_, user_instance, allow_recovery_code_use=True)() |
|
254 | totp_form = TOTPForm(_, user_instance, allow_recovery_code_use=True)() | |
255 |
|
255 | |||
256 | post_items = dict(self.request.POST) |
|
256 | post_items = dict(self.request.POST) | |
257 | # NOTE: inject secret, as it's a post configured saved item. |
|
257 | # NOTE: inject secret, as it's a post configured saved item. | |
258 | post_items['secret_totp'] = user_instance.get_secret_2fa() |
|
258 | post_items['secret_totp'] = user_instance.get_secret_2fa() | |
259 | try: |
|
259 | try: | |
260 | totp_form.to_python(post_items) |
|
260 | totp_form.to_python(post_items) | |
261 | user_instance.regenerate_2fa_recovery_codes() |
|
261 | user_instance.regenerate_2fa_recovery_codes() | |
262 | Session().commit() |
|
262 | Session().commit() | |
263 | except formencode.Invalid as errors: |
|
263 | except formencode.Invalid as errors: | |
264 | h.flash(_("Failed to generate new recovery codes: {}").format(errors), category='error') |
|
264 | h.flash(_("Failed to generate new recovery codes: {}").format(errors), category='error') | |
265 |
raise HTTPFound(self.request.route_path('my_account_ |
|
265 | raise HTTPFound(self.request.route_path('my_account_configure_2fa')) | |
266 | except Exception as e: |
|
266 | except Exception as e: | |
267 | h.flash(_("Failed to generate new recovery codes: {}").format(e), category='error') |
|
267 | h.flash(_("Failed to generate new recovery codes: {}").format(e), category='error') | |
268 |
raise HTTPFound(self.request.route_path('my_account_ |
|
268 | raise HTTPFound(self.request.route_path('my_account_configure_2fa')) | |
269 |
|
269 | |||
270 |
raise HTTPFound(self.request.route_path('my_account_ |
|
270 | raise HTTPFound(self.request.route_path('my_account_configure_2fa', _query={'show-recovery-codes': 1})) | |
271 |
|
271 | |||
272 | @LoginRequired() |
|
272 | @LoginRequired() | |
273 | @NotAnonymous() |
|
273 | @NotAnonymous() | |
274 | def my_account_auth_tokens(self): |
|
274 | def my_account_auth_tokens(self): | |
275 | _ = self.request.translate |
|
275 | _ = self.request.translate | |
276 |
|
276 | |||
277 | c = self.load_default_context() |
|
277 | c = self.load_default_context() | |
278 | c.active = 'auth_tokens' |
|
278 | c.active = 'auth_tokens' | |
279 | c.lifetime_values = AuthTokenModel.get_lifetime_values(translator=_) |
|
279 | c.lifetime_values = AuthTokenModel.get_lifetime_values(translator=_) | |
280 | c.role_values = [ |
|
280 | c.role_values = [ | |
281 | (x, AuthTokenModel.cls._get_role_name(x)) |
|
281 | (x, AuthTokenModel.cls._get_role_name(x)) | |
282 | for x in AuthTokenModel.cls.ROLES] |
|
282 | for x in AuthTokenModel.cls.ROLES] | |
283 | c.role_options = [(c.role_values, _("Role"))] |
|
283 | c.role_options = [(c.role_values, _("Role"))] | |
284 | c.user_auth_tokens = AuthTokenModel().get_auth_tokens( |
|
284 | c.user_auth_tokens = AuthTokenModel().get_auth_tokens( | |
285 | c.user.user_id, show_expired=True) |
|
285 | c.user.user_id, show_expired=True) | |
286 | c.role_vcs = AuthTokenModel.cls.ROLE_VCS |
|
286 | c.role_vcs = AuthTokenModel.cls.ROLE_VCS | |
287 | return self._get_template_context(c) |
|
287 | return self._get_template_context(c) | |
288 |
|
288 | |||
289 | @LoginRequired() |
|
289 | @LoginRequired() | |
290 | @NotAnonymous() |
|
290 | @NotAnonymous() | |
291 | @CSRFRequired() |
|
291 | @CSRFRequired() | |
292 | def my_account_auth_tokens_view(self): |
|
292 | def my_account_auth_tokens_view(self): | |
293 | _ = self.request.translate |
|
293 | _ = self.request.translate | |
294 | c = self.load_default_context() |
|
294 | c = self.load_default_context() | |
295 |
|
295 | |||
296 | auth_token_id = self.request.POST.get('auth_token_id') |
|
296 | auth_token_id = self.request.POST.get('auth_token_id') | |
297 |
|
297 | |||
298 | if auth_token_id: |
|
298 | if auth_token_id: | |
299 | token = UserApiKeys.get_or_404(auth_token_id) |
|
299 | token = UserApiKeys.get_or_404(auth_token_id) | |
300 | if token.user.user_id != c.user.user_id: |
|
300 | if token.user.user_id != c.user.user_id: | |
301 | raise HTTPNotFound() |
|
301 | raise HTTPNotFound() | |
302 |
|
302 | |||
303 | return { |
|
303 | return { | |
304 | 'auth_token': token.api_key |
|
304 | 'auth_token': token.api_key | |
305 | } |
|
305 | } | |
306 |
|
306 | |||
307 | def maybe_attach_token_scope(self, token): |
|
307 | def maybe_attach_token_scope(self, token): | |
308 | # implemented in EE edition |
|
308 | # implemented in EE edition | |
309 | pass |
|
309 | pass | |
310 |
|
310 | |||
311 | @LoginRequired() |
|
311 | @LoginRequired() | |
312 | @NotAnonymous() |
|
312 | @NotAnonymous() | |
313 | @CSRFRequired() |
|
313 | @CSRFRequired() | |
314 | def my_account_auth_tokens_add(self): |
|
314 | def my_account_auth_tokens_add(self): | |
315 | _ = self.request.translate |
|
315 | _ = self.request.translate | |
316 | c = self.load_default_context() |
|
316 | c = self.load_default_context() | |
317 |
|
317 | |||
318 | lifetime = safe_int(self.request.POST.get('lifetime'), -1) |
|
318 | lifetime = safe_int(self.request.POST.get('lifetime'), -1) | |
319 | description = self.request.POST.get('description') |
|
319 | description = self.request.POST.get('description') | |
320 | role = self.request.POST.get('role') |
|
320 | role = self.request.POST.get('role') | |
321 |
|
321 | |||
322 | token = UserModel().add_auth_token( |
|
322 | token = UserModel().add_auth_token( | |
323 | user=c.user.user_id, |
|
323 | user=c.user.user_id, | |
324 | lifetime_minutes=lifetime, role=role, description=description, |
|
324 | lifetime_minutes=lifetime, role=role, description=description, | |
325 | scope_callback=self.maybe_attach_token_scope) |
|
325 | scope_callback=self.maybe_attach_token_scope) | |
326 | token_data = token.get_api_data() |
|
326 | token_data = token.get_api_data() | |
327 |
|
327 | |||
328 | audit_logger.store_web( |
|
328 | audit_logger.store_web( | |
329 | 'user.edit.token.add', action_data={ |
|
329 | 'user.edit.token.add', action_data={ | |
330 | 'data': {'token': token_data, 'user': 'self'}}, |
|
330 | 'data': {'token': token_data, 'user': 'self'}}, | |
331 | user=self._rhodecode_user, ) |
|
331 | user=self._rhodecode_user, ) | |
332 | Session().commit() |
|
332 | Session().commit() | |
333 |
|
333 | |||
334 | h.flash(_("Auth token successfully created"), category='success') |
|
334 | h.flash(_("Auth token successfully created"), category='success') | |
335 | return HTTPFound(h.route_path('my_account_auth_tokens')) |
|
335 | return HTTPFound(h.route_path('my_account_auth_tokens')) | |
336 |
|
336 | |||
337 | @LoginRequired() |
|
337 | @LoginRequired() | |
338 | @NotAnonymous() |
|
338 | @NotAnonymous() | |
339 | @CSRFRequired() |
|
339 | @CSRFRequired() | |
340 | def my_account_auth_tokens_delete(self): |
|
340 | def my_account_auth_tokens_delete(self): | |
341 | _ = self.request.translate |
|
341 | _ = self.request.translate | |
342 | c = self.load_default_context() |
|
342 | c = self.load_default_context() | |
343 |
|
343 | |||
344 | del_auth_token = self.request.POST.get('del_auth_token') |
|
344 | del_auth_token = self.request.POST.get('del_auth_token') | |
345 |
|
345 | |||
346 | if del_auth_token: |
|
346 | if del_auth_token: | |
347 | token = UserApiKeys.get_or_404(del_auth_token) |
|
347 | token = UserApiKeys.get_or_404(del_auth_token) | |
348 | token_data = token.get_api_data() |
|
348 | token_data = token.get_api_data() | |
349 |
|
349 | |||
350 | AuthTokenModel().delete(del_auth_token, c.user.user_id) |
|
350 | AuthTokenModel().delete(del_auth_token, c.user.user_id) | |
351 | audit_logger.store_web( |
|
351 | audit_logger.store_web( | |
352 | 'user.edit.token.delete', action_data={ |
|
352 | 'user.edit.token.delete', action_data={ | |
353 | 'data': {'token': token_data, 'user': 'self'}}, |
|
353 | 'data': {'token': token_data, 'user': 'self'}}, | |
354 | user=self._rhodecode_user,) |
|
354 | user=self._rhodecode_user,) | |
355 | Session().commit() |
|
355 | Session().commit() | |
356 | h.flash(_("Auth token successfully deleted"), category='success') |
|
356 | h.flash(_("Auth token successfully deleted"), category='success') | |
357 |
|
357 | |||
358 | return HTTPFound(h.route_path('my_account_auth_tokens')) |
|
358 | return HTTPFound(h.route_path('my_account_auth_tokens')) | |
359 |
|
359 | |||
360 | @LoginRequired() |
|
360 | @LoginRequired() | |
361 | @NotAnonymous() |
|
361 | @NotAnonymous() | |
362 | def my_account_emails(self): |
|
362 | def my_account_emails(self): | |
363 | _ = self.request.translate |
|
363 | _ = self.request.translate | |
364 |
|
364 | |||
365 | c = self.load_default_context() |
|
365 | c = self.load_default_context() | |
366 | c.active = 'emails' |
|
366 | c.active = 'emails' | |
367 |
|
367 | |||
368 | c.user_email_map = UserEmailMap.query()\ |
|
368 | c.user_email_map = UserEmailMap.query()\ | |
369 | .filter(UserEmailMap.user == c.user).all() |
|
369 | .filter(UserEmailMap.user == c.user).all() | |
370 |
|
370 | |||
371 | schema = user_schema.AddEmailSchema().bind( |
|
371 | schema = user_schema.AddEmailSchema().bind( | |
372 | username=c.user.username, user_emails=c.user.emails) |
|
372 | username=c.user.username, user_emails=c.user.emails) | |
373 |
|
373 | |||
374 | form = forms.RcForm(schema, |
|
374 | form = forms.RcForm(schema, | |
375 | action=h.route_path('my_account_emails_add'), |
|
375 | action=h.route_path('my_account_emails_add'), | |
376 | buttons=(forms.buttons.save, forms.buttons.reset)) |
|
376 | buttons=(forms.buttons.save, forms.buttons.reset)) | |
377 |
|
377 | |||
378 | c.form = form |
|
378 | c.form = form | |
379 | return self._get_template_context(c) |
|
379 | return self._get_template_context(c) | |
380 |
|
380 | |||
381 | @LoginRequired() |
|
381 | @LoginRequired() | |
382 | @NotAnonymous() |
|
382 | @NotAnonymous() | |
383 | @CSRFRequired() |
|
383 | @CSRFRequired() | |
384 | def my_account_emails_add(self): |
|
384 | def my_account_emails_add(self): | |
385 | _ = self.request.translate |
|
385 | _ = self.request.translate | |
386 | c = self.load_default_context() |
|
386 | c = self.load_default_context() | |
387 | c.active = 'emails' |
|
387 | c.active = 'emails' | |
388 |
|
388 | |||
389 | schema = user_schema.AddEmailSchema().bind( |
|
389 | schema = user_schema.AddEmailSchema().bind( | |
390 | username=c.user.username, user_emails=c.user.emails) |
|
390 | username=c.user.username, user_emails=c.user.emails) | |
391 |
|
391 | |||
392 | form = forms.RcForm( |
|
392 | form = forms.RcForm( | |
393 | schema, action=h.route_path('my_account_emails_add'), |
|
393 | schema, action=h.route_path('my_account_emails_add'), | |
394 | buttons=(forms.buttons.save, forms.buttons.reset)) |
|
394 | buttons=(forms.buttons.save, forms.buttons.reset)) | |
395 |
|
395 | |||
396 | controls = list(self.request.POST.items()) |
|
396 | controls = list(self.request.POST.items()) | |
397 | try: |
|
397 | try: | |
398 | valid_data = form.validate(controls) |
|
398 | valid_data = form.validate(controls) | |
399 | UserModel().add_extra_email(c.user.user_id, valid_data['email']) |
|
399 | UserModel().add_extra_email(c.user.user_id, valid_data['email']) | |
400 | audit_logger.store_web( |
|
400 | audit_logger.store_web( | |
401 | 'user.edit.email.add', action_data={ |
|
401 | 'user.edit.email.add', action_data={ | |
402 | 'data': {'email': valid_data['email'], 'user': 'self'}}, |
|
402 | 'data': {'email': valid_data['email'], 'user': 'self'}}, | |
403 | user=self._rhodecode_user,) |
|
403 | user=self._rhodecode_user,) | |
404 | Session().commit() |
|
404 | Session().commit() | |
405 | except formencode.Invalid as error: |
|
405 | except formencode.Invalid as error: | |
406 | h.flash(h.escape(error.error_dict['email']), category='error') |
|
406 | h.flash(h.escape(error.error_dict['email']), category='error') | |
407 | except forms.ValidationFailure as e: |
|
407 | except forms.ValidationFailure as e: | |
408 | c.user_email_map = UserEmailMap.query() \ |
|
408 | c.user_email_map = UserEmailMap.query() \ | |
409 | .filter(UserEmailMap.user == c.user).all() |
|
409 | .filter(UserEmailMap.user == c.user).all() | |
410 | c.form = e |
|
410 | c.form = e | |
411 | return self._get_template_context(c) |
|
411 | return self._get_template_context(c) | |
412 | except Exception: |
|
412 | except Exception: | |
413 | log.exception("Exception adding email") |
|
413 | log.exception("Exception adding email") | |
414 | h.flash(_('Error occurred during adding email'), |
|
414 | h.flash(_('Error occurred during adding email'), | |
415 | category='error') |
|
415 | category='error') | |
416 | else: |
|
416 | else: | |
417 | h.flash(_("Successfully added email"), category='success') |
|
417 | h.flash(_("Successfully added email"), category='success') | |
418 |
|
418 | |||
419 | raise HTTPFound(self.request.route_path('my_account_emails')) |
|
419 | raise HTTPFound(self.request.route_path('my_account_emails')) | |
420 |
|
420 | |||
421 | @LoginRequired() |
|
421 | @LoginRequired() | |
422 | @NotAnonymous() |
|
422 | @NotAnonymous() | |
423 | @CSRFRequired() |
|
423 | @CSRFRequired() | |
424 | def my_account_emails_delete(self): |
|
424 | def my_account_emails_delete(self): | |
425 | _ = self.request.translate |
|
425 | _ = self.request.translate | |
426 | c = self.load_default_context() |
|
426 | c = self.load_default_context() | |
427 |
|
427 | |||
428 | del_email_id = self.request.POST.get('del_email_id') |
|
428 | del_email_id = self.request.POST.get('del_email_id') | |
429 | if del_email_id: |
|
429 | if del_email_id: | |
430 | email = UserEmailMap.get_or_404(del_email_id).email |
|
430 | email = UserEmailMap.get_or_404(del_email_id).email | |
431 | UserModel().delete_extra_email(c.user.user_id, del_email_id) |
|
431 | UserModel().delete_extra_email(c.user.user_id, del_email_id) | |
432 | audit_logger.store_web( |
|
432 | audit_logger.store_web( | |
433 | 'user.edit.email.delete', action_data={ |
|
433 | 'user.edit.email.delete', action_data={ | |
434 | 'data': {'email': email, 'user': 'self'}}, |
|
434 | 'data': {'email': email, 'user': 'self'}}, | |
435 | user=self._rhodecode_user,) |
|
435 | user=self._rhodecode_user,) | |
436 | Session().commit() |
|
436 | Session().commit() | |
437 | h.flash(_("Email successfully deleted"), |
|
437 | h.flash(_("Email successfully deleted"), | |
438 | category='success') |
|
438 | category='success') | |
439 | return HTTPFound(h.route_path('my_account_emails')) |
|
439 | return HTTPFound(h.route_path('my_account_emails')) | |
440 |
|
440 | |||
441 | @LoginRequired() |
|
441 | @LoginRequired() | |
442 | @NotAnonymous() |
|
442 | @NotAnonymous() | |
443 | @CSRFRequired() |
|
443 | @CSRFRequired() | |
444 | def my_account_notifications_test_channelstream(self): |
|
444 | def my_account_notifications_test_channelstream(self): | |
445 | message = 'Test message sent via Channelstream by user: {}, on {}'.format( |
|
445 | message = 'Test message sent via Channelstream by user: {}, on {}'.format( | |
446 | self._rhodecode_user.username, datetime.datetime.now()) |
|
446 | self._rhodecode_user.username, datetime.datetime.now()) | |
447 | payload = { |
|
447 | payload = { | |
448 | # 'channel': 'broadcast', |
|
448 | # 'channel': 'broadcast', | |
449 | 'type': 'message', |
|
449 | 'type': 'message', | |
450 | 'timestamp': datetime.datetime.utcnow(), |
|
450 | 'timestamp': datetime.datetime.utcnow(), | |
451 | 'user': 'system', |
|
451 | 'user': 'system', | |
452 | 'pm_users': [self._rhodecode_user.username], |
|
452 | 'pm_users': [self._rhodecode_user.username], | |
453 | 'message': { |
|
453 | 'message': { | |
454 | 'message': message, |
|
454 | 'message': message, | |
455 | 'level': 'info', |
|
455 | 'level': 'info', | |
456 | 'topic': '/notifications' |
|
456 | 'topic': '/notifications' | |
457 | } |
|
457 | } | |
458 | } |
|
458 | } | |
459 |
|
459 | |||
460 | registry = self.request.registry |
|
460 | registry = self.request.registry | |
461 | rhodecode_plugins = getattr(registry, 'rhodecode_plugins', {}) |
|
461 | rhodecode_plugins = getattr(registry, 'rhodecode_plugins', {}) | |
462 | channelstream_config = rhodecode_plugins.get('channelstream', {}) |
|
462 | channelstream_config = rhodecode_plugins.get('channelstream', {}) | |
463 |
|
463 | |||
464 | try: |
|
464 | try: | |
465 | channelstream_request(channelstream_config, [payload], '/message') |
|
465 | channelstream_request(channelstream_config, [payload], '/message') | |
466 | except ChannelstreamException as e: |
|
466 | except ChannelstreamException as e: | |
467 | log.exception('Failed to send channelstream data') |
|
467 | log.exception('Failed to send channelstream data') | |
468 | return {"response": f'ERROR: {e.__class__.__name__}'} |
|
468 | return {"response": f'ERROR: {e.__class__.__name__}'} | |
469 | return {"response": 'Channelstream data sent. ' |
|
469 | return {"response": 'Channelstream data sent. ' | |
470 | 'You should see a new live message now.'} |
|
470 | 'You should see a new live message now.'} | |
471 |
|
471 | |||
472 | def _load_my_repos_data(self, watched=False): |
|
472 | def _load_my_repos_data(self, watched=False): | |
473 |
|
473 | |||
474 | allowed_ids = [-1] + self._rhodecode_user.repo_acl_ids_from_stack(AuthUser.repo_read_perms) |
|
474 | allowed_ids = [-1] + self._rhodecode_user.repo_acl_ids_from_stack(AuthUser.repo_read_perms) | |
475 |
|
475 | |||
476 | if watched: |
|
476 | if watched: | |
477 | # repos user watch |
|
477 | # repos user watch | |
478 | repo_list = Session().query( |
|
478 | repo_list = Session().query( | |
479 | Repository |
|
479 | Repository | |
480 | ) \ |
|
480 | ) \ | |
481 | .join( |
|
481 | .join( | |
482 | (UserFollowing, UserFollowing.follows_repo_id == Repository.repo_id) |
|
482 | (UserFollowing, UserFollowing.follows_repo_id == Repository.repo_id) | |
483 | ) \ |
|
483 | ) \ | |
484 | .filter( |
|
484 | .filter( | |
485 | UserFollowing.user_id == self._rhodecode_user.user_id |
|
485 | UserFollowing.user_id == self._rhodecode_user.user_id | |
486 | ) \ |
|
486 | ) \ | |
487 | .filter(or_( |
|
487 | .filter(or_( | |
488 | # generate multiple IN to fix limitation problems |
|
488 | # generate multiple IN to fix limitation problems | |
489 | *in_filter_generator(Repository.repo_id, allowed_ids)) |
|
489 | *in_filter_generator(Repository.repo_id, allowed_ids)) | |
490 | ) \ |
|
490 | ) \ | |
491 | .order_by(Repository.repo_name) \ |
|
491 | .order_by(Repository.repo_name) \ | |
492 | .all() |
|
492 | .all() | |
493 |
|
493 | |||
494 | else: |
|
494 | else: | |
495 | # repos user is owner of |
|
495 | # repos user is owner of | |
496 | repo_list = Session().query( |
|
496 | repo_list = Session().query( | |
497 | Repository |
|
497 | Repository | |
498 | ) \ |
|
498 | ) \ | |
499 | .filter( |
|
499 | .filter( | |
500 | Repository.user_id == self._rhodecode_user.user_id |
|
500 | Repository.user_id == self._rhodecode_user.user_id | |
501 | ) \ |
|
501 | ) \ | |
502 | .filter(or_( |
|
502 | .filter(or_( | |
503 | # generate multiple IN to fix limitation problems |
|
503 | # generate multiple IN to fix limitation problems | |
504 | *in_filter_generator(Repository.repo_id, allowed_ids)) |
|
504 | *in_filter_generator(Repository.repo_id, allowed_ids)) | |
505 | ) \ |
|
505 | ) \ | |
506 | .order_by(Repository.repo_name) \ |
|
506 | .order_by(Repository.repo_name) \ | |
507 | .all() |
|
507 | .all() | |
508 |
|
508 | |||
509 | _render = self.request.get_partial_renderer( |
|
509 | _render = self.request.get_partial_renderer( | |
510 | 'rhodecode:templates/data_table/_dt_elements.mako') |
|
510 | 'rhodecode:templates/data_table/_dt_elements.mako') | |
511 |
|
511 | |||
512 | def repo_lnk(name, rtype, rstate, private, archived, fork_of): |
|
512 | def repo_lnk(name, rtype, rstate, private, archived, fork_of): | |
513 | return _render('repo_name', name, rtype, rstate, private, archived, fork_of, |
|
513 | return _render('repo_name', name, rtype, rstate, private, archived, fork_of, | |
514 | short_name=False, admin=False) |
|
514 | short_name=False, admin=False) | |
515 |
|
515 | |||
516 | repos_data = [] |
|
516 | repos_data = [] | |
517 | for repo in repo_list: |
|
517 | for repo in repo_list: | |
518 | row = { |
|
518 | row = { | |
519 | "name": repo_lnk(repo.repo_name, repo.repo_type, repo.repo_state, |
|
519 | "name": repo_lnk(repo.repo_name, repo.repo_type, repo.repo_state, | |
520 | repo.private, repo.archived, repo.fork), |
|
520 | repo.private, repo.archived, repo.fork), | |
521 | "name_raw": repo.repo_name.lower(), |
|
521 | "name_raw": repo.repo_name.lower(), | |
522 | } |
|
522 | } | |
523 |
|
523 | |||
524 | repos_data.append(row) |
|
524 | repos_data.append(row) | |
525 |
|
525 | |||
526 | # json used to render the grid |
|
526 | # json used to render the grid | |
527 | return ext_json.str_json(repos_data) |
|
527 | return ext_json.str_json(repos_data) | |
528 |
|
528 | |||
529 | @LoginRequired() |
|
529 | @LoginRequired() | |
530 | @NotAnonymous() |
|
530 | @NotAnonymous() | |
531 | def my_account_repos(self): |
|
531 | def my_account_repos(self): | |
532 | c = self.load_default_context() |
|
532 | c = self.load_default_context() | |
533 | c.active = 'repos' |
|
533 | c.active = 'repos' | |
534 |
|
534 | |||
535 | # json used to render the grid |
|
535 | # json used to render the grid | |
536 | c.data = self._load_my_repos_data() |
|
536 | c.data = self._load_my_repos_data() | |
537 | return self._get_template_context(c) |
|
537 | return self._get_template_context(c) | |
538 |
|
538 | |||
539 | @LoginRequired() |
|
539 | @LoginRequired() | |
540 | @NotAnonymous() |
|
540 | @NotAnonymous() | |
541 | def my_account_watched(self): |
|
541 | def my_account_watched(self): | |
542 | c = self.load_default_context() |
|
542 | c = self.load_default_context() | |
543 | c.active = 'watched' |
|
543 | c.active = 'watched' | |
544 |
|
544 | |||
545 | # json used to render the grid |
|
545 | # json used to render the grid | |
546 | c.data = self._load_my_repos_data(watched=True) |
|
546 | c.data = self._load_my_repos_data(watched=True) | |
547 | return self._get_template_context(c) |
|
547 | return self._get_template_context(c) | |
548 |
|
548 | |||
549 | @LoginRequired() |
|
549 | @LoginRequired() | |
550 | @NotAnonymous() |
|
550 | @NotAnonymous() | |
551 | def my_account_bookmarks(self): |
|
551 | def my_account_bookmarks(self): | |
552 | c = self.load_default_context() |
|
552 | c = self.load_default_context() | |
553 | c.active = 'bookmarks' |
|
553 | c.active = 'bookmarks' | |
554 |
|
554 | |||
555 | user_bookmarks = \ |
|
555 | user_bookmarks = \ | |
556 | select(UserBookmark, Repository, RepoGroup) \ |
|
556 | select(UserBookmark, Repository, RepoGroup) \ | |
557 | .where(UserBookmark.user_id == self._rhodecode_user.user_id) \ |
|
557 | .where(UserBookmark.user_id == self._rhodecode_user.user_id) \ | |
558 | .outerjoin(Repository, Repository.repo_id == UserBookmark.bookmark_repo_id) \ |
|
558 | .outerjoin(Repository, Repository.repo_id == UserBookmark.bookmark_repo_id) \ | |
559 | .outerjoin(RepoGroup, RepoGroup.group_id == UserBookmark.bookmark_repo_group_id) \ |
|
559 | .outerjoin(RepoGroup, RepoGroup.group_id == UserBookmark.bookmark_repo_group_id) \ | |
560 | .order_by(UserBookmark.position.asc()) |
|
560 | .order_by(UserBookmark.position.asc()) | |
561 |
|
561 | |||
562 | c.user_bookmark_items = Session().execute(user_bookmarks).all() |
|
562 | c.user_bookmark_items = Session().execute(user_bookmarks).all() | |
563 | return self._get_template_context(c) |
|
563 | return self._get_template_context(c) | |
564 |
|
564 | |||
565 | def _process_bookmark_entry(self, entry, user_id): |
|
565 | def _process_bookmark_entry(self, entry, user_id): | |
566 | position = safe_int(entry.get('position')) |
|
566 | position = safe_int(entry.get('position')) | |
567 | cur_position = safe_int(entry.get('cur_position')) |
|
567 | cur_position = safe_int(entry.get('cur_position')) | |
568 | if position is None: |
|
568 | if position is None: | |
569 | return |
|
569 | return | |
570 |
|
570 | |||
571 | # check if this is an existing entry |
|
571 | # check if this is an existing entry | |
572 | is_new = False |
|
572 | is_new = False | |
573 | db_entry = UserBookmark().get_by_position_for_user(cur_position, user_id) |
|
573 | db_entry = UserBookmark().get_by_position_for_user(cur_position, user_id) | |
574 |
|
574 | |||
575 | if db_entry and str2bool(entry.get('remove')): |
|
575 | if db_entry and str2bool(entry.get('remove')): | |
576 | log.debug('Marked bookmark %s for deletion', db_entry) |
|
576 | log.debug('Marked bookmark %s for deletion', db_entry) | |
577 | Session().delete(db_entry) |
|
577 | Session().delete(db_entry) | |
578 | return |
|
578 | return | |
579 |
|
579 | |||
580 | if not db_entry: |
|
580 | if not db_entry: | |
581 | # new |
|
581 | # new | |
582 | db_entry = UserBookmark() |
|
582 | db_entry = UserBookmark() | |
583 | is_new = True |
|
583 | is_new = True | |
584 |
|
584 | |||
585 | should_save = False |
|
585 | should_save = False | |
586 | default_redirect_url = '' |
|
586 | default_redirect_url = '' | |
587 |
|
587 | |||
588 | # save repo |
|
588 | # save repo | |
589 | if entry.get('bookmark_repo') and safe_int(entry.get('bookmark_repo')): |
|
589 | if entry.get('bookmark_repo') and safe_int(entry.get('bookmark_repo')): | |
590 | repo = Repository.get(entry['bookmark_repo']) |
|
590 | repo = Repository.get(entry['bookmark_repo']) | |
591 | perm_check = HasRepoPermissionAny( |
|
591 | perm_check = HasRepoPermissionAny( | |
592 | 'repository.read', 'repository.write', 'repository.admin') |
|
592 | 'repository.read', 'repository.write', 'repository.admin') | |
593 | if repo and perm_check(repo_name=repo.repo_name): |
|
593 | if repo and perm_check(repo_name=repo.repo_name): | |
594 | db_entry.repository = repo |
|
594 | db_entry.repository = repo | |
595 | should_save = True |
|
595 | should_save = True | |
596 | default_redirect_url = '${repo_url}' |
|
596 | default_redirect_url = '${repo_url}' | |
597 | # save repo group |
|
597 | # save repo group | |
598 | elif entry.get('bookmark_repo_group') and safe_int(entry.get('bookmark_repo_group')): |
|
598 | elif entry.get('bookmark_repo_group') and safe_int(entry.get('bookmark_repo_group')): | |
599 | repo_group = RepoGroup.get(entry['bookmark_repo_group']) |
|
599 | repo_group = RepoGroup.get(entry['bookmark_repo_group']) | |
600 | perm_check = HasRepoGroupPermissionAny( |
|
600 | perm_check = HasRepoGroupPermissionAny( | |
601 | 'group.read', 'group.write', 'group.admin') |
|
601 | 'group.read', 'group.write', 'group.admin') | |
602 |
|
602 | |||
603 | if repo_group and perm_check(group_name=repo_group.group_name): |
|
603 | if repo_group and perm_check(group_name=repo_group.group_name): | |
604 | db_entry.repository_group = repo_group |
|
604 | db_entry.repository_group = repo_group | |
605 | should_save = True |
|
605 | should_save = True | |
606 | default_redirect_url = '${repo_group_url}' |
|
606 | default_redirect_url = '${repo_group_url}' | |
607 | # save generic info |
|
607 | # save generic info | |
608 | elif entry.get('title') and entry.get('redirect_url'): |
|
608 | elif entry.get('title') and entry.get('redirect_url'): | |
609 | should_save = True |
|
609 | should_save = True | |
610 |
|
610 | |||
611 | if should_save: |
|
611 | if should_save: | |
612 | # mark user and position |
|
612 | # mark user and position | |
613 | db_entry.user_id = user_id |
|
613 | db_entry.user_id = user_id | |
614 | db_entry.position = position |
|
614 | db_entry.position = position | |
615 | db_entry.title = entry.get('title') |
|
615 | db_entry.title = entry.get('title') | |
616 | db_entry.redirect_url = entry.get('redirect_url') or default_redirect_url |
|
616 | db_entry.redirect_url = entry.get('redirect_url') or default_redirect_url | |
617 | log.debug('Saving bookmark %s, new:%s', db_entry, is_new) |
|
617 | log.debug('Saving bookmark %s, new:%s', db_entry, is_new) | |
618 |
|
618 | |||
619 | Session().add(db_entry) |
|
619 | Session().add(db_entry) | |
620 |
|
620 | |||
621 | @LoginRequired() |
|
621 | @LoginRequired() | |
622 | @NotAnonymous() |
|
622 | @NotAnonymous() | |
623 | @CSRFRequired() |
|
623 | @CSRFRequired() | |
624 | def my_account_bookmarks_update(self): |
|
624 | def my_account_bookmarks_update(self): | |
625 | _ = self.request.translate |
|
625 | _ = self.request.translate | |
626 | c = self.load_default_context() |
|
626 | c = self.load_default_context() | |
627 | c.active = 'bookmarks' |
|
627 | c.active = 'bookmarks' | |
628 |
|
628 | |||
629 | controls = peppercorn.parse(self.request.POST.items()) |
|
629 | controls = peppercorn.parse(self.request.POST.items()) | |
630 | user_id = c.user.user_id |
|
630 | user_id = c.user.user_id | |
631 |
|
631 | |||
632 | # validate positions |
|
632 | # validate positions | |
633 | positions = {} |
|
633 | positions = {} | |
634 | for entry in controls.get('bookmarks', []): |
|
634 | for entry in controls.get('bookmarks', []): | |
635 | position = safe_int(entry['position']) |
|
635 | position = safe_int(entry['position']) | |
636 | if position is None: |
|
636 | if position is None: | |
637 | continue |
|
637 | continue | |
638 |
|
638 | |||
639 | if position in positions: |
|
639 | if position in positions: | |
640 | h.flash(_("Position {} is defined twice. " |
|
640 | h.flash(_("Position {} is defined twice. " | |
641 | "Please correct this error.").format(position), category='error') |
|
641 | "Please correct this error.").format(position), category='error') | |
642 | return HTTPFound(h.route_path('my_account_bookmarks')) |
|
642 | return HTTPFound(h.route_path('my_account_bookmarks')) | |
643 |
|
643 | |||
644 | entry['position'] = position |
|
644 | entry['position'] = position | |
645 | entry['cur_position'] = safe_int(entry.get('cur_position')) |
|
645 | entry['cur_position'] = safe_int(entry.get('cur_position')) | |
646 | positions[position] = entry |
|
646 | positions[position] = entry | |
647 |
|
647 | |||
648 | try: |
|
648 | try: | |
649 | for entry in positions.values(): |
|
649 | for entry in positions.values(): | |
650 | self._process_bookmark_entry(entry, user_id) |
|
650 | self._process_bookmark_entry(entry, user_id) | |
651 |
|
651 | |||
652 | Session().commit() |
|
652 | Session().commit() | |
653 | h.flash(_("Update Bookmarks"), category='success') |
|
653 | h.flash(_("Update Bookmarks"), category='success') | |
654 | except IntegrityError: |
|
654 | except IntegrityError: | |
655 | h.flash(_("Failed to update bookmarks. " |
|
655 | h.flash(_("Failed to update bookmarks. " | |
656 | "Make sure an unique position is used."), category='error') |
|
656 | "Make sure an unique position is used."), category='error') | |
657 |
|
657 | |||
658 | return HTTPFound(h.route_path('my_account_bookmarks')) |
|
658 | return HTTPFound(h.route_path('my_account_bookmarks')) | |
659 |
|
659 | |||
660 | @LoginRequired() |
|
660 | @LoginRequired() | |
661 | @NotAnonymous() |
|
661 | @NotAnonymous() | |
662 | def my_account_goto_bookmark(self): |
|
662 | def my_account_goto_bookmark(self): | |
663 |
|
663 | |||
664 | bookmark_id = self.request.matchdict['bookmark_id'] |
|
664 | bookmark_id = self.request.matchdict['bookmark_id'] | |
665 | user_bookmark = UserBookmark().query()\ |
|
665 | user_bookmark = UserBookmark().query()\ | |
666 | .filter(UserBookmark.user_id == self.request.user.user_id) \ |
|
666 | .filter(UserBookmark.user_id == self.request.user.user_id) \ | |
667 | .filter(UserBookmark.position == bookmark_id).scalar() |
|
667 | .filter(UserBookmark.position == bookmark_id).scalar() | |
668 |
|
668 | |||
669 | redirect_url = h.route_path('my_account_bookmarks') |
|
669 | redirect_url = h.route_path('my_account_bookmarks') | |
670 | if not user_bookmark: |
|
670 | if not user_bookmark: | |
671 | raise HTTPFound(redirect_url) |
|
671 | raise HTTPFound(redirect_url) | |
672 |
|
672 | |||
673 | # repository set |
|
673 | # repository set | |
674 | if user_bookmark.repository: |
|
674 | if user_bookmark.repository: | |
675 | repo_name = user_bookmark.repository.repo_name |
|
675 | repo_name = user_bookmark.repository.repo_name | |
676 | base_redirect_url = h.route_path( |
|
676 | base_redirect_url = h.route_path( | |
677 | 'repo_summary', repo_name=repo_name) |
|
677 | 'repo_summary', repo_name=repo_name) | |
678 | if user_bookmark.redirect_url and \ |
|
678 | if user_bookmark.redirect_url and \ | |
679 | '${repo_url}' in user_bookmark.redirect_url: |
|
679 | '${repo_url}' in user_bookmark.redirect_url: | |
680 | redirect_url = string.Template(user_bookmark.redirect_url)\ |
|
680 | redirect_url = string.Template(user_bookmark.redirect_url)\ | |
681 | .safe_substitute({'repo_url': base_redirect_url}) |
|
681 | .safe_substitute({'repo_url': base_redirect_url}) | |
682 | else: |
|
682 | else: | |
683 | redirect_url = base_redirect_url |
|
683 | redirect_url = base_redirect_url | |
684 | # repository group set |
|
684 | # repository group set | |
685 | elif user_bookmark.repository_group: |
|
685 | elif user_bookmark.repository_group: | |
686 | repo_group_name = user_bookmark.repository_group.group_name |
|
686 | repo_group_name = user_bookmark.repository_group.group_name | |
687 | base_redirect_url = h.route_path( |
|
687 | base_redirect_url = h.route_path( | |
688 | 'repo_group_home', repo_group_name=repo_group_name) |
|
688 | 'repo_group_home', repo_group_name=repo_group_name) | |
689 | if user_bookmark.redirect_url and \ |
|
689 | if user_bookmark.redirect_url and \ | |
690 | '${repo_group_url}' in user_bookmark.redirect_url: |
|
690 | '${repo_group_url}' in user_bookmark.redirect_url: | |
691 | redirect_url = string.Template(user_bookmark.redirect_url)\ |
|
691 | redirect_url = string.Template(user_bookmark.redirect_url)\ | |
692 | .safe_substitute({'repo_group_url': base_redirect_url}) |
|
692 | .safe_substitute({'repo_group_url': base_redirect_url}) | |
693 | else: |
|
693 | else: | |
694 | redirect_url = base_redirect_url |
|
694 | redirect_url = base_redirect_url | |
695 | # custom URL set |
|
695 | # custom URL set | |
696 | elif user_bookmark.redirect_url: |
|
696 | elif user_bookmark.redirect_url: | |
697 | server_url = h.route_url('home').rstrip('/') |
|
697 | server_url = h.route_url('home').rstrip('/') | |
698 | redirect_url = string.Template(user_bookmark.redirect_url) \ |
|
698 | redirect_url = string.Template(user_bookmark.redirect_url) \ | |
699 | .safe_substitute({'server_url': server_url}) |
|
699 | .safe_substitute({'server_url': server_url}) | |
700 |
|
700 | |||
701 | log.debug('Redirecting bookmark %s to %s', user_bookmark, redirect_url) |
|
701 | log.debug('Redirecting bookmark %s to %s', user_bookmark, redirect_url) | |
702 | raise HTTPFound(redirect_url) |
|
702 | raise HTTPFound(redirect_url) | |
703 |
|
703 | |||
704 | @LoginRequired() |
|
704 | @LoginRequired() | |
705 | @NotAnonymous() |
|
705 | @NotAnonymous() | |
706 | def my_account_perms(self): |
|
706 | def my_account_perms(self): | |
707 | c = self.load_default_context() |
|
707 | c = self.load_default_context() | |
708 | c.active = 'perms' |
|
708 | c.active = 'perms' | |
709 |
|
709 | |||
710 | c.perm_user = c.auth_user |
|
710 | c.perm_user = c.auth_user | |
711 | return self._get_template_context(c) |
|
711 | return self._get_template_context(c) | |
712 |
|
712 | |||
713 | @LoginRequired() |
|
713 | @LoginRequired() | |
714 | @NotAnonymous() |
|
714 | @NotAnonymous() | |
715 | def my_notifications(self): |
|
715 | def my_notifications(self): | |
716 | c = self.load_default_context() |
|
716 | c = self.load_default_context() | |
717 | c.active = 'notifications' |
|
717 | c.active = 'notifications' | |
718 |
|
718 | |||
719 | return self._get_template_context(c) |
|
719 | return self._get_template_context(c) | |
720 |
|
720 | |||
721 | @LoginRequired() |
|
721 | @LoginRequired() | |
722 | @NotAnonymous() |
|
722 | @NotAnonymous() | |
723 | @CSRFRequired() |
|
723 | @CSRFRequired() | |
724 | def my_notifications_toggle_visibility(self): |
|
724 | def my_notifications_toggle_visibility(self): | |
725 | user = self._rhodecode_db_user |
|
725 | user = self._rhodecode_db_user | |
726 | new_status = not user.user_data.get('notification_status', True) |
|
726 | new_status = not user.user_data.get('notification_status', True) | |
727 | user.update_userdata(notification_status=new_status) |
|
727 | user.update_userdata(notification_status=new_status) | |
728 | Session().commit() |
|
728 | Session().commit() | |
729 | return user.user_data['notification_status'] |
|
729 | return user.user_data['notification_status'] | |
730 |
|
730 | |||
731 | def _get_pull_requests_list(self, statuses, filter_type=None): |
|
731 | def _get_pull_requests_list(self, statuses, filter_type=None): | |
732 | draw, start, limit = self._extract_chunk(self.request) |
|
732 | draw, start, limit = self._extract_chunk(self.request) | |
733 | search_q, order_by, order_dir = self._extract_ordering(self.request) |
|
733 | search_q, order_by, order_dir = self._extract_ordering(self.request) | |
734 |
|
734 | |||
735 | _render = self.request.get_partial_renderer( |
|
735 | _render = self.request.get_partial_renderer( | |
736 | 'rhodecode:templates/data_table/_dt_elements.mako') |
|
736 | 'rhodecode:templates/data_table/_dt_elements.mako') | |
737 |
|
737 | |||
738 | if filter_type == 'awaiting_my_review': |
|
738 | if filter_type == 'awaiting_my_review': | |
739 | pull_requests = PullRequestModel().get_im_participating_in_for_review( |
|
739 | pull_requests = PullRequestModel().get_im_participating_in_for_review( | |
740 | user_id=self._rhodecode_user.user_id, |
|
740 | user_id=self._rhodecode_user.user_id, | |
741 | statuses=statuses, query=search_q, |
|
741 | statuses=statuses, query=search_q, | |
742 | offset=start, length=limit, order_by=order_by, |
|
742 | offset=start, length=limit, order_by=order_by, | |
743 | order_dir=order_dir) |
|
743 | order_dir=order_dir) | |
744 |
|
744 | |||
745 | pull_requests_total_count = PullRequestModel().count_im_participating_in_for_review( |
|
745 | pull_requests_total_count = PullRequestModel().count_im_participating_in_for_review( | |
746 | user_id=self._rhodecode_user.user_id, statuses=statuses, query=search_q) |
|
746 | user_id=self._rhodecode_user.user_id, statuses=statuses, query=search_q) | |
747 | else: |
|
747 | else: | |
748 | pull_requests = PullRequestModel().get_im_participating_in( |
|
748 | pull_requests = PullRequestModel().get_im_participating_in( | |
749 | user_id=self._rhodecode_user.user_id, |
|
749 | user_id=self._rhodecode_user.user_id, | |
750 | statuses=statuses, query=search_q, |
|
750 | statuses=statuses, query=search_q, | |
751 | offset=start, length=limit, order_by=order_by, |
|
751 | offset=start, length=limit, order_by=order_by, | |
752 | order_dir=order_dir) |
|
752 | order_dir=order_dir) | |
753 |
|
753 | |||
754 | pull_requests_total_count = PullRequestModel().count_im_participating_in( |
|
754 | pull_requests_total_count = PullRequestModel().count_im_participating_in( | |
755 | user_id=self._rhodecode_user.user_id, statuses=statuses, query=search_q) |
|
755 | user_id=self._rhodecode_user.user_id, statuses=statuses, query=search_q) | |
756 |
|
756 | |||
757 | data = [] |
|
757 | data = [] | |
758 | comments_model = CommentsModel() |
|
758 | comments_model = CommentsModel() | |
759 | for pr in pull_requests: |
|
759 | for pr in pull_requests: | |
760 | repo_id = pr.target_repo_id |
|
760 | repo_id = pr.target_repo_id | |
761 | comments_count = comments_model.get_all_comments( |
|
761 | comments_count = comments_model.get_all_comments( | |
762 | repo_id, pull_request=pr, include_drafts=False, count_only=True) |
|
762 | repo_id, pull_request=pr, include_drafts=False, count_only=True) | |
763 | owned = pr.user_id == self._rhodecode_user.user_id |
|
763 | owned = pr.user_id == self._rhodecode_user.user_id | |
764 |
|
764 | |||
765 | review_statuses = pr.reviewers_statuses(user=self._rhodecode_db_user) |
|
765 | review_statuses = pr.reviewers_statuses(user=self._rhodecode_db_user) | |
766 | my_review_status = ChangesetStatus.STATUS_NOT_REVIEWED |
|
766 | my_review_status = ChangesetStatus.STATUS_NOT_REVIEWED | |
767 | if review_statuses and review_statuses[4]: |
|
767 | if review_statuses and review_statuses[4]: | |
768 | _review_obj, _user, _reasons, _mandatory, statuses = review_statuses |
|
768 | _review_obj, _user, _reasons, _mandatory, statuses = review_statuses | |
769 | my_review_status = statuses[0][1].status |
|
769 | my_review_status = statuses[0][1].status | |
770 |
|
770 | |||
771 | data.append({ |
|
771 | data.append({ | |
772 | 'target_repo': _render('pullrequest_target_repo', |
|
772 | 'target_repo': _render('pullrequest_target_repo', | |
773 | pr.target_repo.repo_name), |
|
773 | pr.target_repo.repo_name), | |
774 | 'name': _render('pullrequest_name', |
|
774 | 'name': _render('pullrequest_name', | |
775 | pr.pull_request_id, pr.pull_request_state, |
|
775 | pr.pull_request_id, pr.pull_request_state, | |
776 | pr.work_in_progress, pr.target_repo.repo_name, |
|
776 | pr.work_in_progress, pr.target_repo.repo_name, | |
777 | short=True), |
|
777 | short=True), | |
778 | 'name_raw': pr.pull_request_id, |
|
778 | 'name_raw': pr.pull_request_id, | |
779 | 'status': _render('pullrequest_status', |
|
779 | 'status': _render('pullrequest_status', | |
780 | pr.calculated_review_status()), |
|
780 | pr.calculated_review_status()), | |
781 | 'my_status': _render('pullrequest_status', |
|
781 | 'my_status': _render('pullrequest_status', | |
782 | my_review_status), |
|
782 | my_review_status), | |
783 | 'title': _render('pullrequest_title', pr.title, pr.description), |
|
783 | 'title': _render('pullrequest_title', pr.title, pr.description), | |
784 | 'pr_flow': _render('pullrequest_commit_flow', pr), |
|
784 | 'pr_flow': _render('pullrequest_commit_flow', pr), | |
785 | 'description': h.escape(pr.description), |
|
785 | 'description': h.escape(pr.description), | |
786 | 'updated_on': _render('pullrequest_updated_on', |
|
786 | 'updated_on': _render('pullrequest_updated_on', | |
787 | h.datetime_to_time(pr.updated_on), |
|
787 | h.datetime_to_time(pr.updated_on), | |
788 | pr.versions_count), |
|
788 | pr.versions_count), | |
789 | 'updated_on_raw': h.datetime_to_time(pr.updated_on), |
|
789 | 'updated_on_raw': h.datetime_to_time(pr.updated_on), | |
790 | 'created_on': _render('pullrequest_updated_on', |
|
790 | 'created_on': _render('pullrequest_updated_on', | |
791 | h.datetime_to_time(pr.created_on)), |
|
791 | h.datetime_to_time(pr.created_on)), | |
792 | 'created_on_raw': h.datetime_to_time(pr.created_on), |
|
792 | 'created_on_raw': h.datetime_to_time(pr.created_on), | |
793 | 'state': pr.pull_request_state, |
|
793 | 'state': pr.pull_request_state, | |
794 | 'author': _render('pullrequest_author', |
|
794 | 'author': _render('pullrequest_author', | |
795 | pr.author.full_contact, ), |
|
795 | pr.author.full_contact, ), | |
796 | 'author_raw': pr.author.full_name, |
|
796 | 'author_raw': pr.author.full_name, | |
797 | 'comments': _render('pullrequest_comments', comments_count), |
|
797 | 'comments': _render('pullrequest_comments', comments_count), | |
798 | 'comments_raw': comments_count, |
|
798 | 'comments_raw': comments_count, | |
799 | 'closed': pr.is_closed(), |
|
799 | 'closed': pr.is_closed(), | |
800 | 'owned': owned |
|
800 | 'owned': owned | |
801 | }) |
|
801 | }) | |
802 |
|
802 | |||
803 | # json used to render the grid |
|
803 | # json used to render the grid | |
804 | data = ({ |
|
804 | data = ({ | |
805 | 'draw': draw, |
|
805 | 'draw': draw, | |
806 | 'data': data, |
|
806 | 'data': data, | |
807 | 'recordsTotal': pull_requests_total_count, |
|
807 | 'recordsTotal': pull_requests_total_count, | |
808 | 'recordsFiltered': pull_requests_total_count, |
|
808 | 'recordsFiltered': pull_requests_total_count, | |
809 | }) |
|
809 | }) | |
810 | return data |
|
810 | return data | |
811 |
|
811 | |||
812 | @LoginRequired() |
|
812 | @LoginRequired() | |
813 | @NotAnonymous() |
|
813 | @NotAnonymous() | |
814 | def my_account_pullrequests(self): |
|
814 | def my_account_pullrequests(self): | |
815 | c = self.load_default_context() |
|
815 | c = self.load_default_context() | |
816 | c.active = 'pullrequests' |
|
816 | c.active = 'pullrequests' | |
817 | req_get = self.request.GET |
|
817 | req_get = self.request.GET | |
818 |
|
818 | |||
819 | c.closed = str2bool(req_get.get('closed')) |
|
819 | c.closed = str2bool(req_get.get('closed')) | |
820 | c.awaiting_my_review = str2bool(req_get.get('awaiting_my_review')) |
|
820 | c.awaiting_my_review = str2bool(req_get.get('awaiting_my_review')) | |
821 |
|
821 | |||
822 | c.selected_filter = 'all' |
|
822 | c.selected_filter = 'all' | |
823 | if c.closed: |
|
823 | if c.closed: | |
824 | c.selected_filter = 'all_closed' |
|
824 | c.selected_filter = 'all_closed' | |
825 | if c.awaiting_my_review: |
|
825 | if c.awaiting_my_review: | |
826 | c.selected_filter = 'awaiting_my_review' |
|
826 | c.selected_filter = 'awaiting_my_review' | |
827 |
|
827 | |||
828 | return self._get_template_context(c) |
|
828 | return self._get_template_context(c) | |
829 |
|
829 | |||
830 | @LoginRequired() |
|
830 | @LoginRequired() | |
831 | @NotAnonymous() |
|
831 | @NotAnonymous() | |
832 | def my_account_pullrequests_data(self): |
|
832 | def my_account_pullrequests_data(self): | |
833 | self.load_default_context() |
|
833 | self.load_default_context() | |
834 | req_get = self.request.GET |
|
834 | req_get = self.request.GET | |
835 |
|
835 | |||
836 | awaiting_my_review = str2bool(req_get.get('awaiting_my_review')) |
|
836 | awaiting_my_review = str2bool(req_get.get('awaiting_my_review')) | |
837 | closed = str2bool(req_get.get('closed')) |
|
837 | closed = str2bool(req_get.get('closed')) | |
838 |
|
838 | |||
839 | statuses = [PullRequest.STATUS_NEW, PullRequest.STATUS_OPEN] |
|
839 | statuses = [PullRequest.STATUS_NEW, PullRequest.STATUS_OPEN] | |
840 | if closed: |
|
840 | if closed: | |
841 | statuses += [PullRequest.STATUS_CLOSED] |
|
841 | statuses += [PullRequest.STATUS_CLOSED] | |
842 |
|
842 | |||
843 | filter_type = \ |
|
843 | filter_type = \ | |
844 | 'awaiting_my_review' if awaiting_my_review \ |
|
844 | 'awaiting_my_review' if awaiting_my_review \ | |
845 | else None |
|
845 | else None | |
846 |
|
846 | |||
847 | data = self._get_pull_requests_list(statuses=statuses, filter_type=filter_type) |
|
847 | data = self._get_pull_requests_list(statuses=statuses, filter_type=filter_type) | |
848 | return data |
|
848 | return data | |
849 |
|
849 | |||
850 | @LoginRequired() |
|
850 | @LoginRequired() | |
851 | @NotAnonymous() |
|
851 | @NotAnonymous() | |
852 | def my_account_user_group_membership(self): |
|
852 | def my_account_user_group_membership(self): | |
853 | c = self.load_default_context() |
|
853 | c = self.load_default_context() | |
854 | c.active = 'user_group_membership' |
|
854 | c.active = 'user_group_membership' | |
855 | groups = [UserGroupModel.get_user_groups_as_dict(group.users_group) |
|
855 | groups = [UserGroupModel.get_user_groups_as_dict(group.users_group) | |
856 | for group in self._rhodecode_db_user.group_member] |
|
856 | for group in self._rhodecode_db_user.group_member] | |
857 | c.user_groups = ext_json.str_json(groups) |
|
857 | c.user_groups = ext_json.str_json(groups) | |
858 | return self._get_template_context(c) |
|
858 | return self._get_template_context(c) |
@@ -1,419 +1,419 b'' | |||||
1 |
|
1 | |||
2 | /****************************************************************************** |
|
2 | /****************************************************************************** | |
3 | * * |
|
3 | * * | |
4 | * DO NOT CHANGE THIS FILE MANUALLY * |
|
4 | * DO NOT CHANGE THIS FILE MANUALLY * | |
5 | * * |
|
5 | * * | |
6 | * * |
|
6 | * * | |
7 | * This file is automatically generated when the app starts up with * |
|
7 | * This file is automatically generated when the app starts up with * | |
8 | * generate_js_files = true * |
|
8 | * generate_js_files = true * | |
9 | * * |
|
9 | * * | |
10 | * To add a route here pass jsroute=True to the route definition in the app * |
|
10 | * To add a route here pass jsroute=True to the route definition in the app * | |
11 | * * |
|
11 | * * | |
12 | ******************************************************************************/ |
|
12 | ******************************************************************************/ | |
13 | function registerRCRoutes() { |
|
13 | function registerRCRoutes() { | |
14 | // routes registration |
|
14 | // routes registration | |
15 | pyroutes.register('admin_artifacts', '/_admin/artifacts', []); |
|
15 | pyroutes.register('admin_artifacts', '/_admin/artifacts', []); | |
16 | pyroutes.register('admin_artifacts_data', '/_admin/artifacts-data', []); |
|
16 | pyroutes.register('admin_artifacts_data', '/_admin/artifacts-data', []); | |
17 | pyroutes.register('admin_artifacts_delete', '/_admin/artifacts/%(uid)s/delete', ['uid']); |
|
17 | pyroutes.register('admin_artifacts_delete', '/_admin/artifacts/%(uid)s/delete', ['uid']); | |
18 | pyroutes.register('admin_artifacts_show_all', '/_admin/artifacts', []); |
|
18 | pyroutes.register('admin_artifacts_show_all', '/_admin/artifacts', []); | |
19 | pyroutes.register('admin_artifacts_show_info', '/_admin/artifacts/%(uid)s', ['uid']); |
|
19 | pyroutes.register('admin_artifacts_show_info', '/_admin/artifacts/%(uid)s', ['uid']); | |
20 | pyroutes.register('admin_artifacts_update', '/_admin/artifacts/%(uid)s/update', ['uid']); |
|
20 | pyroutes.register('admin_artifacts_update', '/_admin/artifacts/%(uid)s/update', ['uid']); | |
21 | pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']); |
|
21 | pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']); | |
22 | pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []); |
|
22 | pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []); | |
23 | pyroutes.register('admin_automation', '/_admin/automation', []); |
|
23 | pyroutes.register('admin_automation', '/_admin/automation', []); | |
24 | pyroutes.register('admin_automation_update', '/_admin/automation/%(entry_id)s/update', ['entry_id']); |
|
24 | pyroutes.register('admin_automation_update', '/_admin/automation/%(entry_id)s/update', ['entry_id']); | |
25 | pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []); |
|
25 | pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []); | |
26 | pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []); |
|
26 | pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []); | |
27 | pyroutes.register('admin_home', '/_admin', []); |
|
27 | pyroutes.register('admin_home', '/_admin', []); | |
28 | pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []); |
|
28 | pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []); | |
29 | pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []); |
|
29 | pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []); | |
30 | pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []); |
|
30 | pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []); | |
31 | pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []); |
|
31 | pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []); | |
32 | pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []); |
|
32 | pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []); | |
33 | pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []); |
|
33 | pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []); | |
34 | pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []); |
|
34 | pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []); | |
35 | pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []); |
|
35 | pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []); | |
36 | pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []); |
|
36 | pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []); | |
37 | pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []); |
|
37 | pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []); | |
38 | pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []); |
|
38 | pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []); | |
39 | pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []); |
|
39 | pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []); | |
40 | pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []); |
|
40 | pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []); | |
41 | pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []); |
|
41 | pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []); | |
42 | pyroutes.register('admin_scheduler', '/_admin/scheduler', []); |
|
42 | pyroutes.register('admin_scheduler', '/_admin/scheduler', []); | |
43 | pyroutes.register('admin_scheduler_show_tasks', '/_admin/scheduler/_tasks', []); |
|
43 | pyroutes.register('admin_scheduler_show_tasks', '/_admin/scheduler/_tasks', []); | |
44 | pyroutes.register('admin_settings', '/_admin/settings', []); |
|
44 | pyroutes.register('admin_settings', '/_admin/settings', []); | |
45 | pyroutes.register('admin_settings_email', '/_admin/settings/email', []); |
|
45 | pyroutes.register('admin_settings_email', '/_admin/settings/email', []); | |
46 | pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []); |
|
46 | pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []); | |
47 | pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []); |
|
47 | pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []); | |
48 | pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']); |
|
48 | pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']); | |
49 | pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions_delete_all', []); |
|
49 | pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions_delete_all', []); | |
50 | pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']); |
|
50 | pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']); | |
51 | pyroutes.register('admin_settings_global', '/_admin/settings/global', []); |
|
51 | pyroutes.register('admin_settings_global', '/_admin/settings/global', []); | |
52 | pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []); |
|
52 | pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []); | |
53 | pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []); |
|
53 | pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []); | |
54 | pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []); |
|
54 | pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []); | |
55 | pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []); |
|
55 | pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []); | |
56 | pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []); |
|
56 | pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []); | |
57 | pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []); |
|
57 | pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []); | |
58 | pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []); |
|
58 | pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []); | |
59 | pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []); |
|
59 | pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []); | |
60 | pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []); |
|
60 | pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []); | |
61 | pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []); |
|
61 | pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []); | |
62 | pyroutes.register('admin_settings_license', '/_admin/settings/license', []); |
|
62 | pyroutes.register('admin_settings_license', '/_admin/settings/license', []); | |
63 | pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []); |
|
63 | pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []); | |
64 | pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []); |
|
64 | pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []); | |
65 | pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []); |
|
65 | pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []); | |
66 | pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []); |
|
66 | pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []); | |
67 | pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []); |
|
67 | pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []); | |
68 | pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []); |
|
68 | pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []); | |
69 | pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []); |
|
69 | pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []); | |
70 | pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []); |
|
70 | pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []); | |
71 | pyroutes.register('admin_settings_scheduler_create', '/_admin/scheduler/create', []); |
|
71 | pyroutes.register('admin_settings_scheduler_create', '/_admin/scheduler/create', []); | |
72 | pyroutes.register('admin_settings_scheduler_delete', '/_admin/scheduler/%(schedule_id)s/delete', ['schedule_id']); |
|
72 | pyroutes.register('admin_settings_scheduler_delete', '/_admin/scheduler/%(schedule_id)s/delete', ['schedule_id']); | |
73 | pyroutes.register('admin_settings_scheduler_edit', '/_admin/scheduler/%(schedule_id)s', ['schedule_id']); |
|
73 | pyroutes.register('admin_settings_scheduler_edit', '/_admin/scheduler/%(schedule_id)s', ['schedule_id']); | |
74 | pyroutes.register('admin_settings_scheduler_execute', '/_admin/scheduler/%(schedule_id)s/execute', ['schedule_id']); |
|
74 | pyroutes.register('admin_settings_scheduler_execute', '/_admin/scheduler/%(schedule_id)s/execute', ['schedule_id']); | |
75 | pyroutes.register('admin_settings_scheduler_new', '/_admin/scheduler/new', []); |
|
75 | pyroutes.register('admin_settings_scheduler_new', '/_admin/scheduler/new', []); | |
76 | pyroutes.register('admin_settings_scheduler_update', '/_admin/scheduler/%(schedule_id)s/update', ['schedule_id']); |
|
76 | pyroutes.register('admin_settings_scheduler_update', '/_admin/scheduler/%(schedule_id)s/update', ['schedule_id']); | |
77 | pyroutes.register('admin_settings_search', '/_admin/settings/search', []); |
|
77 | pyroutes.register('admin_settings_search', '/_admin/settings/search', []); | |
78 | pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []); |
|
78 | pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []); | |
79 | pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []); |
|
79 | pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []); | |
80 | pyroutes.register('admin_settings_system', '/_admin/settings/system', []); |
|
80 | pyroutes.register('admin_settings_system', '/_admin/settings/system', []); | |
81 | pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []); |
|
81 | pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []); | |
82 | pyroutes.register('admin_settings_update', '/_admin/settings/update', []); |
|
82 | pyroutes.register('admin_settings_update', '/_admin/settings/update', []); | |
83 | pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []); |
|
83 | pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []); | |
84 | pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []); |
|
84 | pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []); | |
85 | pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []); |
|
85 | pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []); | |
86 | pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []); |
|
86 | pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []); | |
87 | pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []); |
|
87 | pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []); | |
88 | pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []); |
|
88 | pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []); | |
89 | pyroutes.register('apiv2', '/_admin/api', []); |
|
89 | pyroutes.register('apiv2', '/_admin/api', []); | |
90 | pyroutes.register('atom_feed_home', '/%(repo_name)s/feed-atom', ['repo_name']); |
|
90 | pyroutes.register('atom_feed_home', '/%(repo_name)s/feed-atom', ['repo_name']); | |
91 | pyroutes.register('atom_feed_home_old', '/%(repo_name)s/feed/atom', ['repo_name']); |
|
91 | pyroutes.register('atom_feed_home_old', '/%(repo_name)s/feed/atom', ['repo_name']); | |
92 | pyroutes.register('auth_home', '/_admin/auth*traverse', []); |
|
92 | pyroutes.register('auth_home', '/_admin/auth*traverse', []); | |
93 | pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']); |
|
93 | pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']); | |
94 | pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']); |
|
94 | pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']); | |
95 | pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []); |
|
95 | pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []); | |
96 | pyroutes.register('channelstream_proxy', '/_channelstream', []); |
|
96 | pyroutes.register('channelstream_proxy', '/_channelstream', []); | |
97 | pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []); |
|
97 | pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []); | |
98 | pyroutes.register('check_2fa', '/_admin/check_2fa', []); |
|
98 | pyroutes.register('check_2fa', '/_admin/check_2fa', []); | |
99 | pyroutes.register('commit_draft_comments_submit', '/%(repo_name)s/changeset/%(commit_id)s/draft_comments_submit', ['repo_name', 'commit_id']); |
|
99 | pyroutes.register('commit_draft_comments_submit', '/%(repo_name)s/changeset/%(commit_id)s/draft_comments_submit', ['repo_name', 'commit_id']); | |
100 | pyroutes.register('debug_style_email', '/_admin/debug_style/email/%(email_id)s', ['email_id']); |
|
100 | pyroutes.register('debug_style_email', '/_admin/debug_style/email/%(email_id)s', ['email_id']); | |
101 | pyroutes.register('debug_style_email_plain_rendered', '/_admin/debug_style/email-rendered/%(email_id)s', ['email_id']); |
|
101 | pyroutes.register('debug_style_email_plain_rendered', '/_admin/debug_style/email-rendered/%(email_id)s', ['email_id']); | |
102 | pyroutes.register('debug_style_home', '/_admin/debug_style', []); |
|
102 | pyroutes.register('debug_style_home', '/_admin/debug_style', []); | |
103 | pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']); |
|
103 | pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']); | |
104 | pyroutes.register('download_file', '/_file_store/download/%(fid)s', ['fid']); |
|
104 | pyroutes.register('download_file', '/_file_store/download/%(fid)s', ['fid']); | |
105 | pyroutes.register('download_file_by_token', '/_file_store/token-download/%(_auth_token)s/%(fid)s', ['_auth_token', 'fid']); |
|
105 | pyroutes.register('download_file_by_token', '/_file_store/token-download/%(_auth_token)s/%(fid)s', ['_auth_token', 'fid']); | |
106 | pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']); |
|
106 | pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']); | |
107 | pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']); |
|
107 | pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']); | |
108 | pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']); |
|
108 | pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']); | |
109 | pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']); |
|
109 | pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']); | |
110 | pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']); |
|
110 | pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']); | |
111 | pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']); |
|
111 | pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']); | |
112 | pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']); |
|
112 | pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']); | |
113 | pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']); |
|
113 | pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']); | |
114 | pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']); |
|
114 | pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']); | |
115 | pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']); |
|
115 | pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']); | |
116 | pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']); |
|
116 | pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']); | |
117 | pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']); |
|
117 | pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']); | |
118 | pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']); |
|
118 | pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']); | |
119 | pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']); |
|
119 | pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']); | |
120 | pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']); |
|
120 | pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']); | |
121 | pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']); |
|
121 | pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']); | |
122 | pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']); |
|
122 | pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']); | |
123 | pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']); |
|
123 | pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']); | |
124 | pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']); |
|
124 | pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']); | |
125 | pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']); |
|
125 | pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']); | |
126 | pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']); |
|
126 | pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']); | |
127 | pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']); |
|
127 | pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']); | |
128 | pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']); |
|
128 | pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']); | |
129 | pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']); |
|
129 | pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']); | |
130 | pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']); |
|
130 | pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']); | |
131 | pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']); |
|
131 | pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']); | |
132 | pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']); |
|
132 | pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']); | |
133 | pyroutes.register('edit_repo_perms_set_private', '/%(repo_name)s/settings/permissions/set_private', ['repo_name']); |
|
133 | pyroutes.register('edit_repo_perms_set_private', '/%(repo_name)s/settings/permissions/set_private', ['repo_name']); | |
134 | pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']); |
|
134 | pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']); | |
135 | pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']); |
|
135 | pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']); | |
136 | pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']); |
|
136 | pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']); | |
137 | pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']); |
|
137 | pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']); | |
138 | pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']); |
|
138 | pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']); | |
139 | pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']); |
|
139 | pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']); | |
140 | pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']); |
|
140 | pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']); | |
141 | pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']); |
|
141 | pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']); | |
142 | pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']); |
|
142 | pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']); | |
143 | pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']); |
|
143 | pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']); | |
144 | pyroutes.register('edit_user_audit_logs_download', '/_admin/users/%(user_id)s/edit/audit/download', ['user_id']); |
|
144 | pyroutes.register('edit_user_audit_logs_download', '/_admin/users/%(user_id)s/edit/audit/download', ['user_id']); | |
145 | pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']); |
|
145 | pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']); | |
146 | pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']); |
|
146 | pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']); | |
147 | pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']); |
|
147 | pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']); | |
148 | pyroutes.register('edit_user_auth_tokens_view', '/_admin/users/%(user_id)s/edit/auth_tokens/view', ['user_id']); |
|
148 | pyroutes.register('edit_user_auth_tokens_view', '/_admin/users/%(user_id)s/edit/auth_tokens/view', ['user_id']); | |
149 | pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']); |
|
149 | pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']); | |
150 | pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']); |
|
150 | pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']); | |
151 | pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']); |
|
151 | pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']); | |
152 | pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']); |
|
152 | pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']); | |
153 | pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']); |
|
153 | pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']); | |
154 | pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']); |
|
154 | pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']); | |
155 | pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']); |
|
155 | pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']); | |
156 | pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']); |
|
156 | pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']); | |
157 | pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']); |
|
157 | pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']); | |
158 | pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']); |
|
158 | pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']); | |
159 | pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']); |
|
159 | pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']); | |
160 | pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']); |
|
160 | pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']); | |
161 | pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']); |
|
161 | pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']); | |
162 | pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']); |
|
162 | pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']); | |
163 | pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']); |
|
163 | pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']); | |
164 | pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']); |
|
164 | pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']); | |
165 | pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']); |
|
165 | pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']); | |
166 | pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']); |
|
166 | pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']); | |
167 | pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']); |
|
167 | pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']); | |
168 | pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']); |
|
168 | pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']); | |
169 | pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']); |
|
169 | pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']); | |
170 | pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']); |
|
170 | pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']); | |
171 | pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']); |
|
171 | pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']); | |
172 | pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']); |
|
172 | pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']); | |
173 | pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']); |
|
173 | pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']); | |
174 | pyroutes.register('favicon', '/favicon.ico', []); |
|
174 | pyroutes.register('favicon', '/favicon.ico', []); | |
175 | pyroutes.register('file_preview', '/_file_preview', []); |
|
175 | pyroutes.register('file_preview', '/_file_preview', []); | |
176 | pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']); |
|
176 | pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']); | |
177 | pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']); |
|
177 | pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']); | |
178 | pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']); |
|
178 | pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']); | |
179 | pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']); |
|
179 | pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']); | |
180 | pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/rev/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']); |
|
180 | pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/rev/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']); | |
181 | pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/rev/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']); |
|
181 | pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/rev/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']); | |
182 | pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/rev/%(revision)s', ['gist_id', 'revision']); |
|
182 | pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/rev/%(revision)s', ['gist_id', 'revision']); | |
183 | pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']); |
|
183 | pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']); | |
184 | pyroutes.register('gists_create', '/_admin/gists/create', []); |
|
184 | pyroutes.register('gists_create', '/_admin/gists/create', []); | |
185 | pyroutes.register('gists_new', '/_admin/gists/new', []); |
|
185 | pyroutes.register('gists_new', '/_admin/gists/new', []); | |
186 | pyroutes.register('gists_show', '/_admin/gists', []); |
|
186 | pyroutes.register('gists_show', '/_admin/gists', []); | |
187 | pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']); |
|
187 | pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']); | |
188 | pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']); |
|
188 | pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']); | |
189 | pyroutes.register('global_integrations_home', '/_admin/integrations', []); |
|
189 | pyroutes.register('global_integrations_home', '/_admin/integrations', []); | |
190 | pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']); |
|
190 | pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']); | |
191 | pyroutes.register('global_integrations_new', '/_admin/integrations/new', []); |
|
191 | pyroutes.register('global_integrations_new', '/_admin/integrations/new', []); | |
192 | pyroutes.register('goto_switcher_data', '/_goto_data', []); |
|
192 | pyroutes.register('goto_switcher_data', '/_goto_data', []); | |
193 | pyroutes.register('home', '/', []); |
|
193 | pyroutes.register('home', '/', []); | |
194 | pyroutes.register('hovercard_pull_request', '/_hovercard/pull_request/%(pull_request_id)s', ['pull_request_id']); |
|
194 | pyroutes.register('hovercard_pull_request', '/_hovercard/pull_request/%(pull_request_id)s', ['pull_request_id']); | |
195 | pyroutes.register('hovercard_repo_commit', '/_hovercard/commit/%(repo_name)s/%(commit_id)s', ['repo_name', 'commit_id']); |
|
195 | pyroutes.register('hovercard_repo_commit', '/_hovercard/commit/%(repo_name)s/%(commit_id)s', ['repo_name', 'commit_id']); | |
196 | pyroutes.register('hovercard_user', '/_hovercard/user/%(user_id)s', ['user_id']); |
|
196 | pyroutes.register('hovercard_user', '/_hovercard/user/%(user_id)s', ['user_id']); | |
197 | pyroutes.register('hovercard_user_group', '/_hovercard/user_group/%(user_group_id)s', ['user_group_id']); |
|
197 | pyroutes.register('hovercard_user_group', '/_hovercard/user_group/%(user_group_id)s', ['user_group_id']); | |
198 | pyroutes.register('hovercard_username', '/_hovercard/username/%(username)s', ['username']); |
|
198 | pyroutes.register('hovercard_username', '/_hovercard/username/%(username)s', ['username']); | |
199 | pyroutes.register('journal', '/_admin/journal', []); |
|
199 | pyroutes.register('journal', '/_admin/journal', []); | |
200 | pyroutes.register('journal_atom', '/_admin/journal/atom', []); |
|
200 | pyroutes.register('journal_atom', '/_admin/journal/atom', []); | |
201 | pyroutes.register('journal_public', '/_admin/public_journal', []); |
|
201 | pyroutes.register('journal_public', '/_admin/public_journal', []); | |
202 | pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []); |
|
202 | pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []); | |
203 | pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []); |
|
203 | pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []); | |
204 | pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []); |
|
204 | pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []); | |
205 | pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []); |
|
205 | pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []); | |
206 | pyroutes.register('journal_rss', '/_admin/journal/rss', []); |
|
206 | pyroutes.register('journal_rss', '/_admin/journal/rss', []); | |
207 | pyroutes.register('login', '/_admin/login', []); |
|
207 | pyroutes.register('login', '/_admin/login', []); | |
208 | pyroutes.register('logout', '/_admin/logout', []); |
|
208 | pyroutes.register('logout', '/_admin/logout', []); | |
209 | pyroutes.register('main_page_repo_groups_data', '/_home_repo_groups', []); |
|
209 | pyroutes.register('main_page_repo_groups_data', '/_home_repo_groups', []); | |
210 | pyroutes.register('main_page_repos_data', '/_home_repos', []); |
|
210 | pyroutes.register('main_page_repos_data', '/_home_repos', []); | |
211 | pyroutes.register('markup_preview', '/_markup_preview', []); |
|
211 | pyroutes.register('markup_preview', '/_markup_preview', []); | |
212 | pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []); |
|
212 | pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []); | |
213 | pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []); |
|
213 | pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []); | |
214 | pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []); |
|
214 | pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []); | |
215 | pyroutes.register('my_account_auth_tokens_view', '/_admin/my_account/auth_tokens/view', []); |
|
215 | pyroutes.register('my_account_auth_tokens_view', '/_admin/my_account/auth_tokens/view', []); | |
216 | pyroutes.register('my_account_bookmarks', '/_admin/my_account/bookmarks', []); |
|
216 | pyroutes.register('my_account_bookmarks', '/_admin/my_account/bookmarks', []); | |
217 | pyroutes.register('my_account_bookmarks_update', '/_admin/my_account/bookmarks/update', []); |
|
217 | pyroutes.register('my_account_bookmarks_update', '/_admin/my_account/bookmarks/update', []); | |
|
218 | pyroutes.register('my_account_configure_2fa', '/_admin/my_account/configure_2fa', []); | |||
|
219 | pyroutes.register('my_account_configure_2fa_update', '/_admin/my_account/configure_2fa_update', []); | |||
218 | pyroutes.register('my_account_edit', '/_admin/my_account/edit', []); |
|
220 | pyroutes.register('my_account_edit', '/_admin/my_account/edit', []); | |
219 | pyroutes.register('my_account_emails', '/_admin/my_account/emails', []); |
|
221 | pyroutes.register('my_account_emails', '/_admin/my_account/emails', []); | |
220 | pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []); |
|
222 | pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []); | |
221 | pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []); |
|
223 | pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []); | |
222 | pyroutes.register('my_account_enable_2fa', '/_admin/my_account/enable_2fa', []); |
|
|||
223 | pyroutes.register('my_account_enable_2fa_save', '/_admin/my_account/enable_2fa_save', []); |
|
|||
224 | pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []); |
|
224 | pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []); | |
225 | pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []); |
|
225 | pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []); | |
226 | pyroutes.register('my_account_goto_bookmark', '/_admin/my_account/bookmark/%(bookmark_id)s', ['bookmark_id']); |
|
226 | pyroutes.register('my_account_goto_bookmark', '/_admin/my_account/bookmark/%(bookmark_id)s', ['bookmark_id']); | |
227 | pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []); |
|
227 | pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []); | |
228 | pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []); |
|
228 | pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []); | |
229 | pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []); |
|
229 | pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []); | |
230 | pyroutes.register('my_account_password', '/_admin/my_account/password', []); |
|
230 | pyroutes.register('my_account_password', '/_admin/my_account/password', []); | |
231 | pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []); |
|
231 | pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []); | |
232 | pyroutes.register('my_account_perms', '/_admin/my_account/perms', []); |
|
232 | pyroutes.register('my_account_perms', '/_admin/my_account/perms', []); | |
233 | pyroutes.register('my_account_profile', '/_admin/my_account/profile', []); |
|
233 | pyroutes.register('my_account_profile', '/_admin/my_account/profile', []); | |
234 | pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []); |
|
234 | pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []); | |
235 | pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []); |
|
235 | pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []); | |
236 | pyroutes.register('my_account_regenerate_2fa_recovery_codes', '/_admin/my_account/regenerate_recovery_codes', []); |
|
236 | pyroutes.register('my_account_regenerate_2fa_recovery_codes', '/_admin/my_account/regenerate_recovery_codes', []); | |
237 | pyroutes.register('my_account_repos', '/_admin/my_account/repos', []); |
|
237 | pyroutes.register('my_account_repos', '/_admin/my_account/repos', []); | |
238 | pyroutes.register('my_account_show_2fa_recovery_codes', '/_admin/my_account/recovery_codes', []); |
|
238 | pyroutes.register('my_account_show_2fa_recovery_codes', '/_admin/my_account/recovery_codes', []); | |
239 | pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []); |
|
239 | pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []); | |
240 | pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []); |
|
240 | pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []); | |
241 | pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []); |
|
241 | pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []); | |
242 | pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []); |
|
242 | pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []); | |
243 | pyroutes.register('my_account_update', '/_admin/my_account/update', []); |
|
243 | pyroutes.register('my_account_update', '/_admin/my_account/update', []); | |
244 | pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []); |
|
244 | pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []); | |
245 | pyroutes.register('my_account_watched', '/_admin/my_account/watched', []); |
|
245 | pyroutes.register('my_account_watched', '/_admin/my_account/watched', []); | |
246 | pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']); |
|
246 | pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']); | |
247 | pyroutes.register('notifications_mark_all_read', '/_admin/notifications_mark_all_read', []); |
|
247 | pyroutes.register('notifications_mark_all_read', '/_admin/notifications_mark_all_read', []); | |
248 | pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']); |
|
248 | pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']); | |
249 | pyroutes.register('notifications_show_all', '/_admin/notifications', []); |
|
249 | pyroutes.register('notifications_show_all', '/_admin/notifications', []); | |
250 | pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']); |
|
250 | pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']); | |
251 | pyroutes.register('ops_error_test', '/_admin/ops/error', []); |
|
251 | pyroutes.register('ops_error_test', '/_admin/ops/error', []); | |
252 | pyroutes.register('ops_healthcheck', '/_admin/ops/status', []); |
|
252 | pyroutes.register('ops_healthcheck', '/_admin/ops/status', []); | |
253 | pyroutes.register('ops_ping', '/_admin/ops/ping', []); |
|
253 | pyroutes.register('ops_ping', '/_admin/ops/ping', []); | |
254 | pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []); |
|
254 | pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []); | |
255 | pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']); |
|
255 | pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']); | |
256 | pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']); |
|
256 | pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']); | |
257 | pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']); |
|
257 | pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']); | |
258 | pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']); |
|
258 | pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']); | |
259 | pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']); |
|
259 | pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']); | |
260 | pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']); |
|
260 | pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']); | |
261 | pyroutes.register('pullrequest_comment_edit', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/edit', ['repo_name', 'pull_request_id', 'comment_id']); |
|
261 | pyroutes.register('pullrequest_comment_edit', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/edit', ['repo_name', 'pull_request_id', 'comment_id']); | |
262 | pyroutes.register('pullrequest_comments', '/%(repo_name)s/pull-request/%(pull_request_id)s/comments', ['repo_name', 'pull_request_id']); |
|
262 | pyroutes.register('pullrequest_comments', '/%(repo_name)s/pull-request/%(pull_request_id)s/comments', ['repo_name', 'pull_request_id']); | |
263 | pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']); |
|
263 | pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']); | |
264 | pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']); |
|
264 | pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']); | |
265 | pyroutes.register('pullrequest_draft_comments_submit', '/%(repo_name)s/pull-request/%(pull_request_id)s/draft_comments_submit', ['repo_name', 'pull_request_id']); |
|
265 | pyroutes.register('pullrequest_draft_comments_submit', '/%(repo_name)s/pull-request/%(pull_request_id)s/draft_comments_submit', ['repo_name', 'pull_request_id']); | |
266 | pyroutes.register('pullrequest_drafts', '/%(repo_name)s/pull-request/%(pull_request_id)s/drafts', ['repo_name', 'pull_request_id']); |
|
266 | pyroutes.register('pullrequest_drafts', '/%(repo_name)s/pull-request/%(pull_request_id)s/drafts', ['repo_name', 'pull_request_id']); | |
267 | pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']); |
|
267 | pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']); | |
268 | pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']); |
|
268 | pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']); | |
269 | pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']); |
|
269 | pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']); | |
270 | pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']); |
|
270 | pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']); | |
271 | pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']); |
|
271 | pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']); | |
272 | pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']); |
|
272 | pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']); | |
273 | pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']); |
|
273 | pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']); | |
274 | pyroutes.register('pullrequest_todos', '/%(repo_name)s/pull-request/%(pull_request_id)s/todos', ['repo_name', 'pull_request_id']); |
|
274 | pyroutes.register('pullrequest_todos', '/%(repo_name)s/pull-request/%(pull_request_id)s/todos', ['repo_name', 'pull_request_id']); | |
275 | pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']); |
|
275 | pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']); | |
276 | pyroutes.register('register', '/_admin/register', []); |
|
276 | pyroutes.register('register', '/_admin/register', []); | |
277 | pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']); |
|
277 | pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']); | |
278 | pyroutes.register('repo_artifacts_data', '/%(repo_name)s/artifacts_data', ['repo_name']); |
|
278 | pyroutes.register('repo_artifacts_data', '/%(repo_name)s/artifacts_data', ['repo_name']); | |
279 | pyroutes.register('repo_artifacts_delete', '/%(repo_name)s/artifacts/delete/%(uid)s', ['repo_name', 'uid']); |
|
279 | pyroutes.register('repo_artifacts_delete', '/%(repo_name)s/artifacts/delete/%(uid)s', ['repo_name', 'uid']); | |
280 | pyroutes.register('repo_artifacts_get', '/%(repo_name)s/artifacts/download/%(uid)s', ['repo_name', 'uid']); |
|
280 | pyroutes.register('repo_artifacts_get', '/%(repo_name)s/artifacts/download/%(uid)s', ['repo_name', 'uid']); | |
281 | pyroutes.register('repo_artifacts_info', '/%(repo_name)s/artifacts/info/%(uid)s', ['repo_name', 'uid']); |
|
281 | pyroutes.register('repo_artifacts_info', '/%(repo_name)s/artifacts/info/%(uid)s', ['repo_name', 'uid']); | |
282 | pyroutes.register('repo_artifacts_list', '/%(repo_name)s/artifacts', ['repo_name']); |
|
282 | pyroutes.register('repo_artifacts_list', '/%(repo_name)s/artifacts', ['repo_name']); | |
283 | pyroutes.register('repo_artifacts_new', '/%(repo_name)s/artifacts/new', ['repo_name']); |
|
283 | pyroutes.register('repo_artifacts_new', '/%(repo_name)s/artifacts/new', ['repo_name']); | |
284 | pyroutes.register('repo_artifacts_store', '/%(repo_name)s/artifacts/store', ['repo_name']); |
|
284 | pyroutes.register('repo_artifacts_store', '/%(repo_name)s/artifacts/store', ['repo_name']); | |
285 | pyroutes.register('repo_artifacts_stream_script', '/_file_store/stream-upload-script', []); |
|
285 | pyroutes.register('repo_artifacts_stream_script', '/_file_store/stream-upload-script', []); | |
286 | pyroutes.register('repo_artifacts_stream_store', '/_file_store/stream-upload', []); |
|
286 | pyroutes.register('repo_artifacts_stream_store', '/_file_store/stream-upload', []); | |
287 | pyroutes.register('repo_artifacts_update', '/%(repo_name)s/artifacts/update/%(uid)s', ['repo_name', 'uid']); |
|
287 | pyroutes.register('repo_artifacts_update', '/%(repo_name)s/artifacts/update/%(uid)s', ['repo_name', 'uid']); | |
288 | pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']); |
|
288 | pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']); | |
289 | pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']); |
|
289 | pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']); | |
290 | pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']); |
|
290 | pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']); | |
291 | pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
291 | pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
292 | pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']); |
|
292 | pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']); | |
293 | pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']); |
|
293 | pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']); | |
294 | pyroutes.register('repo_commit_comment_attachment_upload', '/%(repo_name)s/changeset/%(commit_id)s/comment/attachment_upload', ['repo_name', 'commit_id']); |
|
294 | pyroutes.register('repo_commit_comment_attachment_upload', '/%(repo_name)s/changeset/%(commit_id)s/comment/attachment_upload', ['repo_name', 'commit_id']); | |
295 | pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']); |
|
295 | pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']); | |
296 | pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']); |
|
296 | pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']); | |
297 | pyroutes.register('repo_commit_comment_edit', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/edit', ['repo_name', 'commit_id', 'comment_id']); |
|
297 | pyroutes.register('repo_commit_comment_edit', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/edit', ['repo_name', 'commit_id', 'comment_id']); | |
298 | pyroutes.register('repo_commit_comment_history_view', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/history_view/%(comment_history_id)s', ['repo_name', 'commit_id', 'comment_id', 'comment_history_id']); |
|
298 | pyroutes.register('repo_commit_comment_history_view', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/history_view/%(comment_history_id)s', ['repo_name', 'commit_id', 'comment_id', 'comment_history_id']); | |
299 | pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']); |
|
299 | pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']); | |
300 | pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']); |
|
300 | pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']); | |
301 | pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']); |
|
301 | pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']); | |
302 | pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']); |
|
302 | pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']); | |
303 | pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']); |
|
303 | pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']); | |
304 | pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']); |
|
304 | pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']); | |
305 | pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']); |
|
305 | pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']); | |
306 | pyroutes.register('repo_commits', '/%(repo_name)s/commits', ['repo_name']); |
|
306 | pyroutes.register('repo_commits', '/%(repo_name)s/commits', ['repo_name']); | |
307 | pyroutes.register('repo_commits_elements', '/%(repo_name)s/commits_elements', ['repo_name']); |
|
307 | pyroutes.register('repo_commits_elements', '/%(repo_name)s/commits_elements', ['repo_name']); | |
308 | pyroutes.register('repo_commits_elements_file', '/%(repo_name)s/commits_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
308 | pyroutes.register('repo_commits_elements_file', '/%(repo_name)s/commits_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
309 | pyroutes.register('repo_commits_file', '/%(repo_name)s/commits/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
309 | pyroutes.register('repo_commits_file', '/%(repo_name)s/commits/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
310 | pyroutes.register('repo_compare', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']); |
|
310 | pyroutes.register('repo_compare', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']); | |
311 | pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']); |
|
311 | pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']); | |
312 | pyroutes.register('repo_create', '/_admin/repos/create', []); |
|
312 | pyroutes.register('repo_create', '/_admin/repos/create', []); | |
313 | pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']); |
|
313 | pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']); | |
314 | pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']); |
|
314 | pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']); | |
315 | pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']); |
|
315 | pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']); | |
316 | pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
316 | pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
317 | pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
317 | pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
318 | pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
318 | pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
319 | pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
319 | pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
320 | pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
320 | pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
321 | pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
321 | pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
322 | pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
322 | pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
323 | pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
323 | pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
324 | pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']); |
|
324 | pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']); | |
325 | pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']); |
|
325 | pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']); | |
326 | pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
326 | pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
327 | pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
327 | pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
328 | pyroutes.register('repo_files_check_head', '/%(repo_name)s/check_head/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
328 | pyroutes.register('repo_files_check_head', '/%(repo_name)s/check_head/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
329 | pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
329 | pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
330 | pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
330 | pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
331 | pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']); |
|
331 | pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']); | |
332 | pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']); |
|
332 | pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']); | |
333 | pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
333 | pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
334 | pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
334 | pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
335 | pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
335 | pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
336 | pyroutes.register('repo_files_replace_binary', '/%(repo_name)s/replace_binary/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
336 | pyroutes.register('repo_files_replace_binary', '/%(repo_name)s/replace_binary/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
337 | pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
337 | pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
338 | pyroutes.register('repo_files_upload_file', '/%(repo_name)s/upload_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
338 | pyroutes.register('repo_files_upload_file', '/%(repo_name)s/upload_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
339 | pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']); |
|
339 | pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']); | |
340 | pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']); |
|
340 | pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']); | |
341 | pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']); |
|
341 | pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']); | |
342 | pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']); |
|
342 | pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']); | |
343 | pyroutes.register('repo_group_create', '/_admin/repo_group/create', []); |
|
343 | pyroutes.register('repo_group_create', '/_admin/repo_group/create', []); | |
344 | pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']); |
|
344 | pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']); | |
345 | pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']); |
|
345 | pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']); | |
346 | pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']); |
|
346 | pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']); | |
347 | pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']); |
|
347 | pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']); | |
348 | pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']); |
|
348 | pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']); | |
349 | pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']); |
|
349 | pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']); | |
350 | pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']); |
|
350 | pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']); | |
351 | pyroutes.register('repo_group_list_data', '/_repo_groups', []); |
|
351 | pyroutes.register('repo_group_list_data', '/_repo_groups', []); | |
352 | pyroutes.register('repo_group_new', '/_admin/repo_group/new', []); |
|
352 | pyroutes.register('repo_group_new', '/_admin/repo_group/new', []); | |
353 | pyroutes.register('repo_groups', '/_admin/repo_groups', []); |
|
353 | pyroutes.register('repo_groups', '/_admin/repo_groups', []); | |
354 | pyroutes.register('repo_groups_data', '/_admin/repo_groups_data', []); |
|
354 | pyroutes.register('repo_groups_data', '/_admin/repo_groups_data', []); | |
355 | pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']); |
|
355 | pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']); | |
356 | pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']); |
|
356 | pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']); | |
357 | pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']); |
|
357 | pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']); | |
358 | pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']); |
|
358 | pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']); | |
359 | pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']); |
|
359 | pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']); | |
360 | pyroutes.register('repo_list_data', '/_repos', []); |
|
360 | pyroutes.register('repo_list_data', '/_repos', []); | |
361 | pyroutes.register('repo_new', '/_admin/repos/new', []); |
|
361 | pyroutes.register('repo_new', '/_admin/repos/new', []); | |
362 | pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
362 | pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); | |
363 | pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']); |
|
363 | pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']); | |
364 | pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']); |
|
364 | pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']); | |
365 | pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']); |
|
365 | pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']); | |
366 | pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']); |
|
366 | pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']); | |
367 | pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']); |
|
367 | pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']); | |
368 | pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']); |
|
368 | pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']); | |
369 | pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']); |
|
369 | pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']); | |
370 | pyroutes.register('repo_settings_quick_actions', '/%(repo_name)s/settings/quick-action', ['repo_name']); |
|
370 | pyroutes.register('repo_settings_quick_actions', '/%(repo_name)s/settings/quick-action', ['repo_name']); | |
371 | pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']); |
|
371 | pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']); | |
372 | pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']); |
|
372 | pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']); | |
373 | pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']); |
|
373 | pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']); | |
374 | pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']); |
|
374 | pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']); | |
375 | pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']); |
|
375 | pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']); | |
376 | pyroutes.register('repos', '/_admin/repos', []); |
|
376 | pyroutes.register('repos', '/_admin/repos', []); | |
377 | pyroutes.register('repos_data', '/_admin/repos_data', []); |
|
377 | pyroutes.register('repos_data', '/_admin/repos_data', []); | |
378 | pyroutes.register('reset_password', '/_admin/password_reset', []); |
|
378 | pyroutes.register('reset_password', '/_admin/password_reset', []); | |
379 | pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []); |
|
379 | pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []); | |
380 | pyroutes.register('robots', '/robots.txt', []); |
|
380 | pyroutes.register('robots', '/robots.txt', []); | |
381 | pyroutes.register('rss_feed_home', '/%(repo_name)s/feed-rss', ['repo_name']); |
|
381 | pyroutes.register('rss_feed_home', '/%(repo_name)s/feed-rss', ['repo_name']); | |
382 | pyroutes.register('rss_feed_home_old', '/%(repo_name)s/feed/rss', ['repo_name']); |
|
382 | pyroutes.register('rss_feed_home_old', '/%(repo_name)s/feed/rss', ['repo_name']); | |
383 | pyroutes.register('search', '/_admin/search', []); |
|
383 | pyroutes.register('search', '/_admin/search', []); | |
384 | pyroutes.register('search_repo', '/%(repo_name)s/_search', ['repo_name']); |
|
384 | pyroutes.register('search_repo', '/%(repo_name)s/_search', ['repo_name']); | |
385 | pyroutes.register('search_repo_alt', '/%(repo_name)s/search', ['repo_name']); |
|
385 | pyroutes.register('search_repo_alt', '/%(repo_name)s/search', ['repo_name']); | |
386 | pyroutes.register('search_repo_group', '/%(repo_group_name)s/_search', ['repo_group_name']); |
|
386 | pyroutes.register('search_repo_group', '/%(repo_group_name)s/_search', ['repo_group_name']); | |
387 | pyroutes.register('setup_2fa', '/_admin/setup_2fa', []); |
|
387 | pyroutes.register('setup_2fa', '/_admin/setup_2fa', []); | |
388 | pyroutes.register('store_user_session_value', '/_store_session_attr', []); |
|
388 | pyroutes.register('store_user_session_value', '/_store_session_attr', []); | |
389 | pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']); |
|
389 | pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']); | |
390 | pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']); |
|
390 | pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']); | |
391 | pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']); |
|
391 | pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']); | |
392 | pyroutes.register('toggle_following', '/_admin/toggle_following', []); |
|
392 | pyroutes.register('toggle_following', '/_admin/toggle_following', []); | |
393 | pyroutes.register('upload_file', '/_file_store/upload', []); |
|
393 | pyroutes.register('upload_file', '/_file_store/upload', []); | |
394 | pyroutes.register('user_autocomplete_data', '/_users', []); |
|
394 | pyroutes.register('user_autocomplete_data', '/_users', []); | |
395 | pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']); |
|
395 | pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']); | |
396 | pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']); |
|
396 | pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']); | |
397 | pyroutes.register('user_disable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_disable', ['user_id']); |
|
397 | pyroutes.register('user_disable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_disable', ['user_id']); | |
398 | pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']); |
|
398 | pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']); | |
399 | pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']); |
|
399 | pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']); | |
400 | pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']); |
|
400 | pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']); | |
401 | pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']); |
|
401 | pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']); | |
402 | pyroutes.register('user_enable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_enable', ['user_id']); |
|
402 | pyroutes.register('user_enable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_enable', ['user_id']); | |
403 | pyroutes.register('user_group_autocomplete_data', '/_user_groups', []); |
|
403 | pyroutes.register('user_group_autocomplete_data', '/_user_groups', []); | |
404 | pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']); |
|
404 | pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']); | |
405 | pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']); |
|
405 | pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']); | |
406 | pyroutes.register('user_groups', '/_admin/user_groups', []); |
|
406 | pyroutes.register('user_groups', '/_admin/user_groups', []); | |
407 | pyroutes.register('user_groups_create', '/_admin/user_groups/create', []); |
|
407 | pyroutes.register('user_groups_create', '/_admin/user_groups/create', []); | |
408 | pyroutes.register('user_groups_data', '/_admin/user_groups_data', []); |
|
408 | pyroutes.register('user_groups_data', '/_admin/user_groups_data', []); | |
409 | pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']); |
|
409 | pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']); | |
410 | pyroutes.register('user_groups_new', '/_admin/user_groups/new', []); |
|
410 | pyroutes.register('user_groups_new', '/_admin/user_groups/new', []); | |
411 | pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']); |
|
411 | pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']); | |
412 | pyroutes.register('user_notice_dismiss', '/_admin/users/%(user_id)s/notice_dismiss', ['user_id']); |
|
412 | pyroutes.register('user_notice_dismiss', '/_admin/users/%(user_id)s/notice_dismiss', ['user_id']); | |
413 | pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']); |
|
413 | pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']); | |
414 | pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']); |
|
414 | pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']); | |
415 | pyroutes.register('users', '/_admin/users', []); |
|
415 | pyroutes.register('users', '/_admin/users', []); | |
416 | pyroutes.register('users_create', '/_admin/users/create', []); |
|
416 | pyroutes.register('users_create', '/_admin/users/create', []); | |
417 | pyroutes.register('users_data', '/_admin/users_data', []); |
|
417 | pyroutes.register('users_data', '/_admin/users_data', []); | |
418 | pyroutes.register('users_new', '/_admin/users/new', []); |
|
418 | pyroutes.register('users_new', '/_admin/users/new', []); | |
419 | } |
|
419 | } |
@@ -1,57 +1,57 b'' | |||||
1 | <%inherit file="/base/base.mako"/> |
|
1 | <%inherit file="/base/base.mako"/> | |
2 |
|
2 | |||
3 | <%def name="title()"> |
|
3 | <%def name="title()"> | |
4 | ${_('My account')} ${c.rhodecode_user.username} |
|
4 | ${_('My account')} ${c.rhodecode_user.username} | |
5 | %if c.rhodecode_name: |
|
5 | %if c.rhodecode_name: | |
6 | · ${h.branding(c.rhodecode_name)} |
|
6 | · ${h.branding(c.rhodecode_name)} | |
7 | %endif |
|
7 | %endif | |
8 | </%def> |
|
8 | </%def> | |
9 |
|
9 | |||
10 | <%def name="breadcrumbs_links()"> |
|
10 | <%def name="breadcrumbs_links()"> | |
11 | ${_('My Account')} |
|
11 | ${_('My Account')} | |
12 | </%def> |
|
12 | </%def> | |
13 |
|
13 | |||
14 | <%def name="menu_bar_nav()"> |
|
14 | <%def name="menu_bar_nav()"> | |
15 | ${self.menu_items(active='my_account')} |
|
15 | ${self.menu_items(active='my_account')} | |
16 | </%def> |
|
16 | </%def> | |
17 |
|
17 | |||
18 | <%def name="main()"> |
|
18 | <%def name="main()"> | |
19 | <div class="box"> |
|
19 | <div class="box"> | |
20 | <div class="title"> |
|
20 | <div class="title"> | |
21 | ${self.breadcrumbs()} |
|
21 | ${self.breadcrumbs()} | |
22 | </div> |
|
22 | </div> | |
23 |
|
23 | |||
24 | <div class="sidebar-col-wrapper scw-small"> |
|
24 | <div class="sidebar-col-wrapper scw-small"> | |
25 | ##main |
|
25 | ##main | |
26 | <div class="sidebar"> |
|
26 | <div class="sidebar"> | |
27 | <ul class="nav nav-pills nav-stacked"> |
|
27 | <ul class="nav nav-pills nav-stacked"> | |
28 | <li class="${h.is_active(['profile', 'profile_edit'], c.active)}"><a href="${h.route_path('my_account_profile')}">${_('Profile')}</a></li> |
|
28 | <li class="${h.is_active(['profile', 'profile_edit'], c.active)}"><a href="${h.route_path('my_account_profile')}">${_('Profile')}</a></li> | |
29 | <li class="${h.is_active('emails', c.active)}"><a href="${h.route_path('my_account_emails')}">${_('Emails')}</a></li> |
|
29 | <li class="${h.is_active('emails', c.active)}"><a href="${h.route_path('my_account_emails')}">${_('Emails')}</a></li> | |
30 | <li class="${h.is_active('password', c.active)}"><a href="${h.route_path('my_account_password')}">${_('Password')}</a></li> |
|
30 | <li class="${h.is_active('password', c.active)}"><a href="${h.route_path('my_account_password')}">${_('Password')}</a></li> | |
31 |
<li class="${h.is_active('2FA', c.active)}"><a href="${h.route_path('my_account_ |
|
31 | <li class="${h.is_active('2FA', c.active)}"><a href="${h.route_path('my_account_configure_2fa')}">${_('2FA')}</a></li> | |
32 | <li class="${h.is_active('bookmarks', c.active)}"><a href="${h.route_path('my_account_bookmarks')}">${_('Bookmarks')}</a></li> |
|
32 | <li class="${h.is_active('bookmarks', c.active)}"><a href="${h.route_path('my_account_bookmarks')}">${_('Bookmarks')}</a></li> | |
33 | <li class="${h.is_active('auth_tokens', c.active)}"><a href="${h.route_path('my_account_auth_tokens')}">${_('Auth Tokens')}</a></li> |
|
33 | <li class="${h.is_active('auth_tokens', c.active)}"><a href="${h.route_path('my_account_auth_tokens')}">${_('Auth Tokens')}</a></li> | |
34 | <li class="${h.is_active(['ssh_keys', 'ssh_keys_generate'], c.active)}"><a href="${h.route_path('my_account_ssh_keys')}">${_('SSH Keys')}</a></li> |
|
34 | <li class="${h.is_active(['ssh_keys', 'ssh_keys_generate'], c.active)}"><a href="${h.route_path('my_account_ssh_keys')}">${_('SSH Keys')}</a></li> | |
35 | <li class="${h.is_active('user_group_membership', c.active)}"><a href="${h.route_path('my_account_user_group_membership')}">${_('User Group Membership')}</a></li> |
|
35 | <li class="${h.is_active('user_group_membership', c.active)}"><a href="${h.route_path('my_account_user_group_membership')}">${_('User Group Membership')}</a></li> | |
36 |
|
36 | |||
37 | ## TODO: Find a better integration of oauth/saml views into navigation. |
|
37 | ## TODO: Find a better integration of oauth/saml views into navigation. | |
38 | <% my_account_external_url = h.route_path_or_none('my_account_external_identity') %> |
|
38 | <% my_account_external_url = h.route_path_or_none('my_account_external_identity') %> | |
39 | % if my_account_external_url: |
|
39 | % if my_account_external_url: | |
40 | <li class="${h.is_active('external_identity', c.active)}"><a href="${my_account_external_url}">${_('External Identities')}</a></li> |
|
40 | <li class="${h.is_active('external_identity', c.active)}"><a href="${my_account_external_url}">${_('External Identities')}</a></li> | |
41 | % endif |
|
41 | % endif | |
42 |
|
42 | |||
43 | <li class="${h.is_active('repos', c.active)}"><a href="${h.route_path('my_account_repos')}">${_('Owned Repositories')}</a></li> |
|
43 | <li class="${h.is_active('repos', c.active)}"><a href="${h.route_path('my_account_repos')}">${_('Owned Repositories')}</a></li> | |
44 | <li class="${h.is_active('watched', c.active)}"><a href="${h.route_path('my_account_watched')}">${_('Watched Repositories')}</a></li> |
|
44 | <li class="${h.is_active('watched', c.active)}"><a href="${h.route_path('my_account_watched')}">${_('Watched Repositories')}</a></li> | |
45 | <li class="${h.is_active('pullrequests', c.active)}"><a href="${h.route_path('my_account_pullrequests')}">${_('Pull Requests')}</a></li> |
|
45 | <li class="${h.is_active('pullrequests', c.active)}"><a href="${h.route_path('my_account_pullrequests')}">${_('Pull Requests')}</a></li> | |
46 | <li class="${h.is_active('perms', c.active)}"><a href="${h.route_path('my_account_perms')}">${_('Permissions')}</a></li> |
|
46 | <li class="${h.is_active('perms', c.active)}"><a href="${h.route_path('my_account_perms')}">${_('Permissions')}</a></li> | |
47 | <li class="${h.is_active('my_notifications', c.active)}"><a href="${h.route_path('my_account_notifications')}">${_('Live Notifications')}</a></li> |
|
47 | <li class="${h.is_active('my_notifications', c.active)}"><a href="${h.route_path('my_account_notifications')}">${_('Live Notifications')}</a></li> | |
48 | </ul> |
|
48 | </ul> | |
49 | </div> |
|
49 | </div> | |
50 |
|
50 | |||
51 | <div class="main-content-full-width"> |
|
51 | <div class="main-content-full-width"> | |
52 | <%include file="/admin/my_account/my_account_${c.active}.mako"/> |
|
52 | <%include file="/admin/my_account/my_account_${c.active}.mako"/> | |
53 | </div> |
|
53 | </div> | |
54 | </div> |
|
54 | </div> | |
55 | </div> |
|
55 | </div> | |
56 |
|
56 | |||
57 | </%def> |
|
57 | </%def> |
@@ -1,134 +1,134 b'' | |||||
1 | <%namespace name="base" file="/base/base.mako"/> |
|
1 | <%namespace name="base" file="/base/base.mako"/> | |
2 |
|
2 | |||
3 | <div class="panel panel-default"> |
|
3 | <div class="panel panel-default"> | |
4 | <div class="panel-heading"> |
|
4 | <div class="panel-heading"> | |
5 | <h3 class="panel-title">${_('Enable/Disable 2FA for your account')}</h3> |
|
5 | <h3 class="panel-title">${_('Enable/Disable 2FA for your account')}</h3> | |
6 | </div> |
|
6 | </div> | |
7 |
${h.secure_form(h.route_path('my_account_ |
|
7 | ${h.secure_form(h.route_path('my_account_configure_2fa_update'), request=request)} | |
8 | <div class="panel-body"> |
|
8 | <div class="panel-body"> | |
9 | <div class="form"> |
|
9 | <div class="form"> | |
10 | <div class="fields"> |
|
10 | <div class="fields"> | |
11 | <div class="field"> |
|
11 | <div class="field"> | |
12 | <div class="label"> |
|
12 | <div class="label"> | |
13 | <label>${_('2FA status')}:</label> |
|
13 | <label>${_('2FA status')}:</label> | |
14 | </div> |
|
14 | </div> | |
15 | <div class="checkboxes"> |
|
15 | <div class="checkboxes"> | |
16 | % if c.locked_2fa: |
|
16 | % if c.locked_2fa: | |
17 | <span class="help-block">${_('2FA settings cannot be changed here, because 2FA was forced enabled by RhodeCode Administrator.')}</span> |
|
17 | <span class="help-block">${_('2FA settings cannot be changed here, because 2FA was forced enabled by RhodeCode Administrator.')}</span> | |
18 |
|
18 | |||
19 | % else: |
|
19 | % else: | |
20 | <div class="form-check"> |
|
20 | <div class="form-check"> | |
21 | <input type="radio" id="2faEnabled" name="2fa_status" value="1" ${'checked=1' if c.state_of_2fa else ''}/> |
|
21 | <input type="radio" id="2faEnabled" name="2fa_status" value="1" ${'checked=1' if c.state_of_2fa else ''}/> | |
22 | <label for="2faEnabled">${_('Enable 2FA')}</label> |
|
22 | <label for="2faEnabled">${_('Enable 2FA')}</label> | |
23 |
|
23 | |||
24 | <input type="radio" id="2faDisabled" name="2fa_status" value="0" ${'checked=1' if not c.state_of_2fa else ''} /> |
|
24 | <input type="radio" id="2faDisabled" name="2fa_status" value="0" ${'checked=1' if not c.state_of_2fa else ''} /> | |
25 | <label for="2faDisabled">${_('Disable 2FA')}</label> |
|
25 | <label for="2faDisabled">${_('Disable 2FA')}</label> | |
26 | </div> |
|
26 | </div> | |
27 | % endif |
|
27 | % endif | |
28 |
|
28 | |||
29 | </div> |
|
29 | </div> | |
30 | </div> |
|
30 | </div> | |
31 | </div> |
|
31 | </div> | |
32 | <button id="saveBtn" class="btn btn-primary" ${'disabled' if c.locked_2fa else ''}>${_('Save')}</button> |
|
32 | <button id="saveBtn" class="btn btn-primary" ${'disabled' if c.locked_2fa else ''}>${_('Save')}</button> | |
33 | </div> |
|
33 | </div> | |
34 | </div> |
|
34 | </div> | |
35 | ${h.end_form()} |
|
35 | ${h.end_form()} | |
36 | </div> |
|
36 | </div> | |
37 |
|
37 | |||
38 | % if c.state_of_2fa: |
|
38 | % if c.state_of_2fa: | |
39 |
|
39 | |||
40 |
|
40 | |||
41 | % if not c.user_seen_2fa_recovery_codes: |
|
41 | % if not c.user_seen_2fa_recovery_codes: | |
42 |
|
42 | |||
43 | <div class="panel panel-warning"> |
|
43 | <div class="panel panel-warning"> | |
44 | <div class="panel-heading" id="advanced-archive"> |
|
44 | <div class="panel-heading" id="advanced-archive"> | |
45 | <h3 class="panel-title">${_('2FA Recovery codes')} <a class="permalink" href="#advanced-archive"> ΒΆ</a></h3> |
|
45 | <h3 class="panel-title">${_('2FA Recovery codes')} <a class="permalink" href="#advanced-archive"> ΒΆ</a></h3> | |
46 | </div> |
|
46 | </div> | |
47 | <div class="panel-body"> |
|
47 | <div class="panel-body"> | |
48 | <p> |
|
48 | <p> | |
49 | ${_('You have not seen your 2FA recovery codes yet.')} |
|
49 | ${_('You have not seen your 2FA recovery codes yet.')} | |
50 | ${_('Please save them in a safe place, or you will lose access to your account in case of lost access to authenticator app.')} |
|
50 | ${_('Please save them in a safe place, or you will lose access to your account in case of lost access to authenticator app.')} | |
51 | </p> |
|
51 | </p> | |
52 | <br/> |
|
52 | <br/> | |
53 |
<a href="${request.route_path('my_account_ |
|
53 | <a href="${request.route_path('my_account_configure_2fa', _query={'show-recovery-codes': 1})}" class="btn btn-primary">${_('Show recovery codes')}</a> | |
54 | </div> |
|
54 | </div> | |
55 | </div> |
|
55 | </div> | |
56 | % endif |
|
56 | % endif | |
57 |
|
57 | |||
58 |
|
58 | |||
59 | ${h.secure_form(h.route_path('my_account_regenerate_2fa_recovery_codes'), request=request)} |
|
59 | ${h.secure_form(h.route_path('my_account_regenerate_2fa_recovery_codes'), request=request)} | |
60 | <div class="panel panel-default"> |
|
60 | <div class="panel panel-default"> | |
61 | <div class="panel-heading"> |
|
61 | <div class="panel-heading"> | |
62 | <h3 class="panel-title">${_('Regenerate 2FA recovery codes for your account')}</h3> |
|
62 | <h3 class="panel-title">${_('Regenerate 2FA recovery codes for your account')}</h3> | |
63 | </div> |
|
63 | </div> | |
64 | <div class="panel-body"> |
|
64 | <div class="panel-body"> | |
65 | <form id="2faForm"> |
|
65 | <form id="2faForm"> | |
66 | <input type="text" name="totp" placeholder="${_('Verify the code from the app')}" pattern="\d{6}" style="width: 20%"> |
|
66 | <input type="text" name="totp" placeholder="${_('Verify the code from the app')}" pattern="\d{6}" style="width: 20%"> | |
67 | <button type="submit" class="btn btn-primary">${_('Verify and generate new codes')}</button> |
|
67 | <button type="submit" class="btn btn-primary">${_('Verify and generate new codes')}</button> | |
68 | </form> |
|
68 | </form> | |
69 | </div> |
|
69 | </div> | |
70 |
|
70 | |||
71 | </div> |
|
71 | </div> | |
72 | ${h.end_form()} |
|
72 | ${h.end_form()} | |
73 | % endif |
|
73 | % endif | |
74 |
|
74 | |||
75 |
|
75 | |||
76 | <script> |
|
76 | <script> | |
77 |
|
77 | |||
78 | function showRecoveryCodesPopup() { |
|
78 | function showRecoveryCodesPopup() { | |
79 |
|
79 | |||
80 | SwalNoAnimation.fire({ |
|
80 | SwalNoAnimation.fire({ | |
81 | title: _gettext('2FA recovery codes'), |
|
81 | title: _gettext('2FA recovery codes'), | |
82 | html: '<span>Should you ever lose your phone or access to your one time password secret, each of these recovery codes can be used one time each to regain access to your account. Please save them in a safe place, or you will lose access to your account.</span>', |
|
82 | html: '<span>Should you ever lose your phone or access to your one time password secret, each of these recovery codes can be used one time each to regain access to your account. Please save them in a safe place, or you will lose access to your account.</span>', | |
83 | showCancelButton: false, |
|
83 | showCancelButton: false, | |
84 | showConfirmButton: true, |
|
84 | showConfirmButton: true, | |
85 | showLoaderOnConfirm: true, |
|
85 | showLoaderOnConfirm: true, | |
86 | confirmButtonText: _gettext('Show now'), |
|
86 | confirmButtonText: _gettext('Show now'), | |
87 | allowOutsideClick: function () { |
|
87 | allowOutsideClick: function () { | |
88 | !Swal.isLoading() |
|
88 | !Swal.isLoading() | |
89 | }, |
|
89 | }, | |
90 |
|
90 | |||
91 | preConfirm: function () { |
|
91 | preConfirm: function () { | |
92 |
|
92 | |||
93 | var postData = { |
|
93 | var postData = { | |
94 | 'csrf_token': CSRF_TOKEN |
|
94 | 'csrf_token': CSRF_TOKEN | |
95 | }; |
|
95 | }; | |
96 | return new Promise(function (resolve, reject) { |
|
96 | return new Promise(function (resolve, reject) { | |
97 | $.ajax({ |
|
97 | $.ajax({ | |
98 | type: 'POST', |
|
98 | type: 'POST', | |
99 | data: postData, |
|
99 | data: postData, | |
100 | url: pyroutes.url('my_account_show_2fa_recovery_codes'), |
|
100 | url: pyroutes.url('my_account_show_2fa_recovery_codes'), | |
101 | headers: {'X-PARTIAL-XHR': true} |
|
101 | headers: {'X-PARTIAL-XHR': true} | |
102 | }) |
|
102 | }) | |
103 | .done(function (data) { |
|
103 | .done(function (data) { | |
104 | resolve(data); |
|
104 | resolve(data); | |
105 | }) |
|
105 | }) | |
106 | .fail(function (jqXHR, textStatus, errorThrown) { |
|
106 | .fail(function (jqXHR, textStatus, errorThrown) { | |
107 | var message = formatErrorMessage(jqXHR, textStatus, errorThrown); |
|
107 | var message = formatErrorMessage(jqXHR, textStatus, errorThrown); | |
108 | ajaxErrorSwal(message); |
|
108 | ajaxErrorSwal(message); | |
109 | }); |
|
109 | }); | |
110 | }) |
|
110 | }) | |
111 | } |
|
111 | } | |
112 |
|
112 | |||
113 | }) |
|
113 | }) | |
114 | .then(function (result) { |
|
114 | .then(function (result) { | |
115 | if (result.value) { |
|
115 | if (result.value) { | |
116 | let funcData = {'recoveryCodes': result.value.recovery_codes} |
|
116 | let funcData = {'recoveryCodes': result.value.recovery_codes} | |
117 | let recoveryCodesHtml = renderTemplate('recoveryCodes', funcData); |
|
117 | let recoveryCodesHtml = renderTemplate('recoveryCodes', funcData); | |
118 | SwalNoAnimation.fire({ |
|
118 | SwalNoAnimation.fire({ | |
119 | allowOutsideClick: false, |
|
119 | allowOutsideClick: false, | |
120 | confirmButtonText: _gettext('I Copied the codes'), |
|
120 | confirmButtonText: _gettext('I Copied the codes'), | |
121 | title: _gettext('2FA Recovery Codes'), |
|
121 | title: _gettext('2FA Recovery Codes'), | |
122 | html: recoveryCodesHtml |
|
122 | html: recoveryCodesHtml | |
123 | }).then(function (result) { |
|
123 | }).then(function (result) { | |
124 | if (result.isConfirmed) { |
|
124 | if (result.isConfirmed) { | |
125 | window.location.reload() |
|
125 | window.location.reload() | |
126 | } |
|
126 | } | |
127 | }) |
|
127 | }) | |
128 | } |
|
128 | } | |
129 | }) |
|
129 | }) | |
130 | } |
|
130 | } | |
131 | % if request.GET.get('show-recovery-codes') == '1' and not c.user_seen_2fa_recovery_codes: |
|
131 | % if request.GET.get('show-recovery-codes') == '1' and not c.user_seen_2fa_recovery_codes: | |
132 | showRecoveryCodesPopup(); |
|
132 | showRecoveryCodesPopup(); | |
133 | % endif |
|
133 | % endif | |
134 | </script> |
|
134 | </script> |
General Comments 0
You need to be logged in to leave comments.
Login now