##// END OF EJS Templates
my-account: migrated left over controller functions into pyramid views....
dan -
r1892:89ddfad2 default
parent child Browse files
Show More
@@ -0,0 +1,205 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 # -*- coding: utf-8 -*-
21
22 # Copyright (C) 2016-2017 RhodeCode GmbH
23 #
24 # This program is free software: you can redistribute it and/or modify
25 # it under the terms of the GNU Affero General Public License, version 3
26 # (only), as published by the Free Software Foundation.
27 #
28 # This program is distributed in the hope that it will be useful,
29 # but WITHOUT ANY WARRANTY; without even the implied warranty of
30 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 # GNU General Public License for more details.
32 #
33 # You should have received a copy of the GNU Affero General Public License
34 # along with this program. If not, see <http://www.gnu.org/licenses/>.
35 #
36 # This program is dual-licensed. If you wish to learn more about the
37 # RhodeCode Enterprise Edition, including its added features, Support services,
38 # and proprietary license terms, please see https://rhodecode.com/licenses/
39
40 import pytest
41
42 from rhodecode.model.db import User
43 from rhodecode.tests import TestController, assert_session_flash
44 from rhodecode.lib import helpers as h
45
46
47 def route_path(name, params=None, **kwargs):
48 import urllib
49 from rhodecode.apps._base import ADMIN_PREFIX
50
51 base_url = {
52 'my_account_edit': ADMIN_PREFIX + '/my_account/edit',
53 'my_account_update': ADMIN_PREFIX + '/my_account/update',
54 'my_account_pullrequests': ADMIN_PREFIX + '/my_account/pull_requests',
55 'my_account_pullrequests_data': ADMIN_PREFIX + '/my_account/pull_requests/data',
56 }[name].format(**kwargs)
57
58 if params:
59 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
60 return base_url
61
62
63 class TestMyAccountEdit(TestController):
64
65 def test_my_account_edit(self):
66 self.log_user()
67 response = self.app.get(route_path('my_account_edit'))
68
69 response.mustcontain('value="test_admin')
70
71 @pytest.mark.backends("git", "hg")
72 def test_my_account_my_pullrequests(self, pr_util):
73 self.log_user()
74 response = self.app.get(route_path('my_account_pullrequests'))
75 response.mustcontain('There are currently no open pull '
76 'requests requiring your participation.')
77
78 @pytest.mark.backends("git", "hg")
79 def test_my_account_my_pullrequests_data(self, pr_util, xhr_header):
80 self.log_user()
81 response = self.app.get(route_path('my_account_pullrequests_data'),
82 extra_environ=xhr_header)
83 assert response.json == {
84 u'data': [], u'draw': None,
85 u'recordsFiltered': 0, u'recordsTotal': 0}
86
87 pr = pr_util.create_pull_request(title='TestMyAccountPR')
88 expected = {
89 'author_raw': 'RhodeCode Admin',
90 'name_raw': pr.pull_request_id
91 }
92 response = self.app.get(route_path('my_account_pullrequests_data'),
93 extra_environ=xhr_header)
94 assert response.json['recordsTotal'] == 1
95 assert response.json['data'][0]['author_raw'] == expected['author_raw']
96
97 assert response.json['data'][0]['author_raw'] == expected['author_raw']
98 assert response.json['data'][0]['name_raw'] == expected['name_raw']
99
100 @pytest.mark.parametrize(
101 "name, attrs", [
102 ('firstname', {'firstname': 'new_username'}),
103 ('lastname', {'lastname': 'new_username'}),
104 ('admin', {'admin': True}),
105 ('admin', {'admin': False}),
106 ('extern_type', {'extern_type': 'ldap'}),
107 ('extern_type', {'extern_type': None}),
108 # ('extern_name', {'extern_name': 'test'}),
109 # ('extern_name', {'extern_name': None}),
110 ('active', {'active': False}),
111 ('active', {'active': True}),
112 ('email', {'email': 'some@email.com'}),
113 ])
114 def test_my_account_update(self, name, attrs, user_util):
115 usr = user_util.create_user(password='qweqwe')
116 params = usr.get_api_data() # current user data
117 user_id = usr.user_id
118 self.log_user(
119 username=usr.username, password='qweqwe')
120
121 params.update({'password_confirmation': ''})
122 params.update({'new_password': ''})
123 params.update({'extern_type': 'rhodecode'})
124 params.update({'extern_name': 'rhodecode'})
125 params.update({'csrf_token': self.csrf_token})
126
127 params.update(attrs)
128 # my account page cannot set language param yet, only for admins
129 del params['language']
130 response = self.app.post(route_path('my_account_update'), params)
131
132 assert_session_flash(
133 response, 'Your account was updated successfully')
134
135 del params['csrf_token']
136
137 updated_user = User.get(user_id)
138 updated_params = updated_user.get_api_data()
139 updated_params.update({'password_confirmation': ''})
140 updated_params.update({'new_password': ''})
141
142 params['last_login'] = updated_params['last_login']
143 params['last_activity'] = updated_params['last_activity']
144 # my account page cannot set language param yet, only for admins
145 # but we get this info from API anyway
146 params['language'] = updated_params['language']
147
148 if name == 'email':
149 params['emails'] = [attrs['email']]
150 if name == 'extern_type':
151 # cannot update this via form, expected value is original one
152 params['extern_type'] = "rhodecode"
153 if name == 'extern_name':
154 # cannot update this via form, expected value is original one
155 params['extern_name'] = str(user_id)
156 if name == 'active':
157 # my account cannot deactivate account
158 params['active'] = True
159 if name == 'admin':
160 # my account cannot make you an admin !
161 params['admin'] = False
162
163 assert params == updated_params
164
165 def test_my_account_update_err_email_exists(self):
166 self.log_user()
167
168 new_email = 'test_regular@mail.com' # already existing email
169 params = {
170 'username': 'test_admin',
171 'new_password': 'test12',
172 'password_confirmation': 'test122',
173 'firstname': 'NewName',
174 'lastname': 'NewLastname',
175 'email': new_email,
176 'csrf_token': self.csrf_token,
177 }
178
179 response = self.app.post(route_path('my_account_update'),
180 params=params)
181
182 response.mustcontain('This e-mail address is already taken')
183
184 def test_my_account_update_bad_email_address(self):
185 self.log_user('test_regular2', 'test12')
186
187 new_email = 'newmail.pl'
188 params = {
189 'username': 'test_admin',
190 'new_password': 'test12',
191 'password_confirmation': 'test122',
192 'firstname': 'NewName',
193 'lastname': 'NewLastname',
194 'email': new_email,
195 'csrf_token': self.csrf_token,
196 }
197 response = self.app.post(route_path('my_account_update'),
198 params=params)
199
200 response.mustcontain('An email address must contain a single @')
201 from rhodecode.model import validators
202 msg = validators.ValidUsername(
203 edit=False, old_data={})._messages['username_exists']
204 msg = h.html_escape(msg % {'username': 'test_admin'})
205 response.mustcontain(u"%s" % msg)
@@ -1,134 +1,140 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21
22 22 import pytest
23 23
24 24 import rhodecode
25 25 from rhodecode.model.db import Repository
26 26 from rhodecode.model.meta import Session
27 27 from rhodecode.model.repo import RepoModel
28 28 from rhodecode.model.repo_group import RepoGroupModel
29 29 from rhodecode.model.settings import SettingsModel
30 30 from rhodecode.tests import TestController
31 31 from rhodecode.tests.fixture import Fixture
32 32 from rhodecode.lib import helpers as h
33 33
34 34 fixture = Fixture()
35 35
36 36
37 37 def route_path(name, **kwargs):
38 38 return {
39 39 'home': '/',
40 40 'repo_group_home': '/{repo_group_name}'
41 41 }[name].format(**kwargs)
42 42
43 43
44 44 class TestHomeController(TestController):
45 45
46 46 def test_index(self):
47 47 self.log_user()
48 48 response = self.app.get(route_path('home'))
49 49 # if global permission is set
50 50 response.mustcontain('Add Repository')
51 51
52 52 # search for objects inside the JavaScript JSON
53 53 for repo in Repository.getAll():
54 54 response.mustcontain('"name_raw": "%s"' % repo.repo_name)
55 55
56 56 def test_index_contains_statics_with_ver(self):
57 57 from pylons import tmpl_context as c
58 58
59 59 self.log_user()
60 60 response = self.app.get(route_path('home'))
61 61
62 62 rhodecode_version_hash = c.rhodecode_version_hash
63 63 response.mustcontain('style.css?ver={0}'.format(rhodecode_version_hash))
64 64 response.mustcontain('rhodecode-components.js?ver={0}'.format(rhodecode_version_hash))
65 65
66 66 def test_index_contains_backend_specific_details(self, backend):
67 67 self.log_user()
68 68 response = self.app.get(route_path('home'))
69 69 tip = backend.repo.get_commit().raw_id
70 70
71 71 # html in javascript variable:
72 72 response.mustcontain(r'<i class=\"icon-%s\"' % (backend.alias, ))
73 73 response.mustcontain(r'href=\"/%s\"' % (backend.repo_name, ))
74 74
75 75 response.mustcontain("""/%s/changeset/%s""" % (backend.repo_name, tip))
76 76 response.mustcontain("""Added a symlink""")
77 77
78 78 def test_index_with_anonymous_access_disabled(self):
79 79 with fixture.anon_access(False):
80 80 response = self.app.get(route_path('home'), status=302)
81 81 assert 'login' in response.location
82 82
83 83 def test_index_page_on_groups(self, autologin_user, repo_group):
84 84 response = self.app.get(route_path('repo_group_home', repo_group_name='gr1'))
85 85 response.mustcontain("gr1/repo_in_group")
86 86
87 87 def test_index_page_on_group_with_trailing_slash(
88 88 self, autologin_user, repo_group):
89 89 response = self.app.get(route_path('repo_group_home', repo_group_name='gr1') + '/')
90 90 response.mustcontain("gr1/repo_in_group")
91 91
92 92 @pytest.fixture(scope='class')
93 93 def repo_group(self, request):
94 94 gr = fixture.create_repo_group('gr1')
95 95 fixture.create_repo(name='gr1/repo_in_group', repo_group=gr)
96 96
97 97 @request.addfinalizer
98 98 def cleanup():
99 99 RepoModel().delete('gr1/repo_in_group')
100 100 RepoGroupModel().delete(repo_group='gr1', force_delete=True)
101 101 Session().commit()
102 102
103 103 def test_index_with_name_with_tags(self, user_util, autologin_user):
104 104 user = user_util.create_user()
105 105 username = user.username
106 106 user.name = '<img src="/image1" onload="alert(\'Hello, World!\');">'
107 107 user.lastname = '#"><img src=x onerror=prompt(document.cookie);>'
108 108
109 109 Session().add(user)
110 110 Session().commit()
111 111 user_util.create_repo(owner=username)
112 112
113 113 response = self.app.get(route_path('home'))
114 114 response.mustcontain(h.html_escape(user.first_name))
115 115 response.mustcontain(h.html_escape(user.last_name))
116 116
117 117 @pytest.mark.parametrize("name, state", [
118 118 ('Disabled', False),
119 119 ('Enabled', True),
120 120 ])
121 121 def test_index_show_version(self, autologin_user, name, state):
122 122 version_string = 'RhodeCode Enterprise %s' % rhodecode.__version__
123 123
124 124 sett = SettingsModel().create_or_update_setting(
125 125 'show_version', state, 'bool')
126 126 Session().add(sett)
127 127 Session().commit()
128 128 SettingsModel().invalidate_settings_cache()
129 129
130 130 response = self.app.get(route_path('home'))
131 131 if state is True:
132 132 response.mustcontain(version_string)
133 133 if state is False:
134 134 response.mustcontain(no=[version_string])
135
136 def test_logout_form_contains_csrf(self, autologin_user, csrf_token):
137 response = self.app.get(route_path('home'))
138 assert_response = response.assert_response()
139 element = assert_response.get_element('.logout #csrf_token')
140 assert element.value == csrf_token
@@ -1,85 +1,104 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21
22 22 from rhodecode.apps._base import ADMIN_PREFIX
23 23
24 24
25 25 def includeme(config):
26 26
27 27 config.add_route(
28 28 name='my_account_profile',
29 29 pattern=ADMIN_PREFIX + '/my_account/profile')
30 30
31 # my account edit details
32 config.add_route(
33 name='my_account_edit',
34 pattern=ADMIN_PREFIX + '/my_account/edit')
35 config.add_route(
36 name='my_account_update',
37 pattern=ADMIN_PREFIX + '/my_account/update')
38
39 # my account password
31 40 config.add_route(
32 41 name='my_account_password',
33 42 pattern=ADMIN_PREFIX + '/my_account/password')
34 43
35 44 config.add_route(
36 45 name='my_account_password_update',
37 46 pattern=ADMIN_PREFIX + '/my_account/password')
38 47
48 # my account tokens
39 49 config.add_route(
40 50 name='my_account_auth_tokens',
41 51 pattern=ADMIN_PREFIX + '/my_account/auth_tokens')
42 52 config.add_route(
43 53 name='my_account_auth_tokens_add',
44 54 pattern=ADMIN_PREFIX + '/my_account/auth_tokens/new')
45 55 config.add_route(
46 56 name='my_account_auth_tokens_delete',
47 57 pattern=ADMIN_PREFIX + '/my_account/auth_tokens/delete')
48 58
59 # my account emails
49 60 config.add_route(
50 61 name='my_account_emails',
51 62 pattern=ADMIN_PREFIX + '/my_account/emails')
52 63 config.add_route(
53 64 name='my_account_emails_add',
54 65 pattern=ADMIN_PREFIX + '/my_account/emails/new')
55 66 config.add_route(
56 67 name='my_account_emails_delete',
57 68 pattern=ADMIN_PREFIX + '/my_account/emails/delete')
58 69
59 70 config.add_route(
60 71 name='my_account_repos',
61 72 pattern=ADMIN_PREFIX + '/my_account/repos')
62 73
63 74 config.add_route(
64 75 name='my_account_watched',
65 76 pattern=ADMIN_PREFIX + '/my_account/watched')
66 77
67 78 config.add_route(
68 79 name='my_account_perms',
69 80 pattern=ADMIN_PREFIX + '/my_account/perms')
70 81
71 82 config.add_route(
72 83 name='my_account_notifications',
73 84 pattern=ADMIN_PREFIX + '/my_account/notifications')
74 85
75 86 config.add_route(
76 87 name='my_account_notifications_toggle_visibility',
77 88 pattern=ADMIN_PREFIX + '/my_account/toggle_visibility')
78 89
90 # my account pull requests
91 config.add_route(
92 name='my_account_pullrequests',
93 pattern=ADMIN_PREFIX + '/my_account/pull_requests')
94 config.add_route(
95 name='my_account_pullrequests_data',
96 pattern=ADMIN_PREFIX + '/my_account/pull_requests/data')
97
79 98 # channelstream test
80 99 config.add_route(
81 100 name='my_account_notifications_test_channelstream',
82 101 pattern=ADMIN_PREFIX + '/my_account/test_channelstream')
83 102
84 103 # Scan module for configuration decorators.
85 104 config.scan()
@@ -1,399 +1,584 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import logging
22 22 import datetime
23 23
24 24 import formencode
25 25 from pyramid.httpexceptions import HTTPFound
26 26 from pyramid.view import view_config
27 from pyramid.renderers import render
28 from pyramid.response import Response
27 29
28 from rhodecode.apps._base import BaseAppView
30 from rhodecode.apps._base import BaseAppView, DataGridAppView
29 31 from rhodecode import forms
30 32 from rhodecode.lib import helpers as h
31 33 from rhodecode.lib import audit_logger
32 34 from rhodecode.lib.ext_json import json
33 35 from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired
34 36 from rhodecode.lib.channelstream import channelstream_request, \
35 37 ChannelstreamException
36 from rhodecode.lib.utils2 import safe_int, md5
38 from rhodecode.lib.utils import PartialRenderer
39 from rhodecode.lib.utils2 import safe_int, md5, str2bool
37 40 from rhodecode.model.auth_token import AuthTokenModel
41 from rhodecode.model.comment import CommentsModel
38 42 from rhodecode.model.db import (
39 Repository, UserEmailMap, UserApiKeys, UserFollowing, joinedload)
43 Repository, UserEmailMap, UserApiKeys, UserFollowing, joinedload,
44 PullRequest)
45 from rhodecode.model.forms import UserForm
40 46 from rhodecode.model.meta import Session
47 from rhodecode.model.pull_request import PullRequestModel
41 48 from rhodecode.model.scm import RepoList
42 49 from rhodecode.model.user import UserModel
43 50 from rhodecode.model.repo import RepoModel
44 51 from rhodecode.model.validation_schema.schemas import user_schema
45 52
46 53 log = logging.getLogger(__name__)
47 54
48 55
49 class MyAccountView(BaseAppView):
56 class MyAccountView(BaseAppView, DataGridAppView):
50 57 ALLOW_SCOPED_TOKENS = False
51 58 """
52 59 This view has alternative version inside EE, if modified please take a look
53 60 in there as well.
54 61 """
55 62
56 63 def load_default_context(self):
57 64 c = self._get_local_tmpl_context()
58 65 c.user = c.auth_user.get_instance()
59 66 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
60 67 self._register_global_c(c)
61 68 return c
62 69
63 70 @LoginRequired()
64 71 @NotAnonymous()
65 72 @view_config(
66 73 route_name='my_account_profile', request_method='GET',
67 74 renderer='rhodecode:templates/admin/my_account/my_account.mako')
68 75 def my_account_profile(self):
69 76 c = self.load_default_context()
70 77 c.active = 'profile'
71 78 return self._get_template_context(c)
72 79
73 80 @LoginRequired()
74 81 @NotAnonymous()
75 82 @view_config(
76 83 route_name='my_account_password', request_method='GET',
77 84 renderer='rhodecode:templates/admin/my_account/my_account.mako')
78 85 def my_account_password(self):
79 86 c = self.load_default_context()
80 87 c.active = 'password'
81 88 c.extern_type = c.user.extern_type
82 89
83 90 schema = user_schema.ChangePasswordSchema().bind(
84 91 username=c.user.username)
85 92
86 93 form = forms.Form(
87 94 schema, buttons=(forms.buttons.save, forms.buttons.reset))
88 95
89 96 c.form = form
90 97 return self._get_template_context(c)
91 98
92 99 @LoginRequired()
93 100 @NotAnonymous()
94 101 @CSRFRequired()
95 102 @view_config(
96 103 route_name='my_account_password', request_method='POST',
97 104 renderer='rhodecode:templates/admin/my_account/my_account.mako')
98 105 def my_account_password_update(self):
99 106 _ = self.request.translate
100 107 c = self.load_default_context()
101 108 c.active = 'password'
102 109 c.extern_type = c.user.extern_type
103 110
104 111 schema = user_schema.ChangePasswordSchema().bind(
105 112 username=c.user.username)
106 113
107 114 form = forms.Form(
108 115 schema, buttons=(forms.buttons.save, forms.buttons.reset))
109 116
110 117 if c.extern_type != 'rhodecode':
111 118 raise HTTPFound(self.request.route_path('my_account_password'))
112 119
113 120 controls = self.request.POST.items()
114 121 try:
115 122 valid_data = form.validate(controls)
116 123 UserModel().update_user(c.user.user_id, **valid_data)
117 124 c.user.update_userdata(force_password_change=False)
118 125 Session().commit()
119 126 except forms.ValidationFailure as e:
120 127 c.form = e
121 128 return self._get_template_context(c)
122 129
123 130 except Exception:
124 131 log.exception("Exception updating password")
125 132 h.flash(_('Error occurred during update of user password'),
126 133 category='error')
127 134 else:
128 135 instance = c.auth_user.get_instance()
129 136 self.session.setdefault('rhodecode_user', {}).update(
130 137 {'password': md5(instance.password)})
131 138 self.session.save()
132 139 h.flash(_("Successfully updated password"), category='success')
133 140
134 141 raise HTTPFound(self.request.route_path('my_account_password'))
135 142
136 143 @LoginRequired()
137 144 @NotAnonymous()
138 145 @view_config(
139 146 route_name='my_account_auth_tokens', request_method='GET',
140 147 renderer='rhodecode:templates/admin/my_account/my_account.mako')
141 148 def my_account_auth_tokens(self):
142 149 _ = self.request.translate
143 150
144 151 c = self.load_default_context()
145 152 c.active = 'auth_tokens'
146 153
147 154 c.lifetime_values = [
148 155 (str(-1), _('forever')),
149 156 (str(5), _('5 minutes')),
150 157 (str(60), _('1 hour')),
151 158 (str(60 * 24), _('1 day')),
152 159 (str(60 * 24 * 30), _('1 month')),
153 160 ]
154 161 c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
155 162 c.role_values = [
156 163 (x, AuthTokenModel.cls._get_role_name(x))
157 164 for x in AuthTokenModel.cls.ROLES]
158 165 c.role_options = [(c.role_values, _("Role"))]
159 166 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
160 167 c.user.user_id, show_expired=True)
161 168 return self._get_template_context(c)
162 169
163 170 def maybe_attach_token_scope(self, token):
164 171 # implemented in EE edition
165 172 pass
166 173
167 174 @LoginRequired()
168 175 @NotAnonymous()
169 176 @CSRFRequired()
170 177 @view_config(
171 178 route_name='my_account_auth_tokens_add', request_method='POST',)
172 179 def my_account_auth_tokens_add(self):
173 180 _ = self.request.translate
174 181 c = self.load_default_context()
175 182
176 183 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
177 184 description = self.request.POST.get('description')
178 185 role = self.request.POST.get('role')
179 186
180 187 token = AuthTokenModel().create(
181 188 c.user.user_id, description, lifetime, role)
182 189 token_data = token.get_api_data()
183 190
184 191 self.maybe_attach_token_scope(token)
185 192 audit_logger.store_web(
186 193 'user.edit.token.add', action_data={
187 194 'data': {'token': token_data, 'user': 'self'}},
188 195 user=self._rhodecode_user, )
189 196 Session().commit()
190 197
191 198 h.flash(_("Auth token successfully created"), category='success')
192 199 return HTTPFound(h.route_path('my_account_auth_tokens'))
193 200
194 201 @LoginRequired()
195 202 @NotAnonymous()
196 203 @CSRFRequired()
197 204 @view_config(
198 205 route_name='my_account_auth_tokens_delete', request_method='POST')
199 206 def my_account_auth_tokens_delete(self):
200 207 _ = self.request.translate
201 208 c = self.load_default_context()
202 209
203 210 del_auth_token = self.request.POST.get('del_auth_token')
204 211
205 212 if del_auth_token:
206 213 token = UserApiKeys.get_or_404(del_auth_token, pyramid_exc=True)
207 214 token_data = token.get_api_data()
208 215
209 216 AuthTokenModel().delete(del_auth_token, c.user.user_id)
210 217 audit_logger.store_web(
211 218 'user.edit.token.delete', action_data={
212 219 'data': {'token': token_data, 'user': 'self'}},
213 220 user=self._rhodecode_user,)
214 221 Session().commit()
215 222 h.flash(_("Auth token successfully deleted"), category='success')
216 223
217 224 return HTTPFound(h.route_path('my_account_auth_tokens'))
218 225
219 226 @LoginRequired()
220 227 @NotAnonymous()
221 228 @view_config(
222 229 route_name='my_account_emails', request_method='GET',
223 230 renderer='rhodecode:templates/admin/my_account/my_account.mako')
224 231 def my_account_emails(self):
225 232 _ = self.request.translate
226 233
227 234 c = self.load_default_context()
228 235 c.active = 'emails'
229 236
230 237 c.user_email_map = UserEmailMap.query()\
231 238 .filter(UserEmailMap.user == c.user).all()
232 239 return self._get_template_context(c)
233 240
234 241 @LoginRequired()
235 242 @NotAnonymous()
236 243 @CSRFRequired()
237 244 @view_config(
238 245 route_name='my_account_emails_add', request_method='POST')
239 246 def my_account_emails_add(self):
240 247 _ = self.request.translate
241 248 c = self.load_default_context()
242 249
243 250 email = self.request.POST.get('new_email')
244 251
245 252 try:
246 253 UserModel().add_extra_email(c.user.user_id, email)
247 254 audit_logger.store_web(
248 255 'user.edit.email.add', action_data={
249 256 'data': {'email': email, 'user': 'self'}},
250 257 user=self._rhodecode_user,)
251 258
252 259 Session().commit()
253 260 h.flash(_("Added new email address `%s` for user account") % email,
254 261 category='success')
255 262 except formencode.Invalid as error:
256 263 h.flash(h.escape(error.error_dict['email']), category='error')
257 264 except Exception:
258 265 log.exception("Exception in my_account_emails")
259 266 h.flash(_('An error occurred during email saving'),
260 267 category='error')
261 268 return HTTPFound(h.route_path('my_account_emails'))
262 269
263 270 @LoginRequired()
264 271 @NotAnonymous()
265 272 @CSRFRequired()
266 273 @view_config(
267 274 route_name='my_account_emails_delete', request_method='POST')
268 275 def my_account_emails_delete(self):
269 276 _ = self.request.translate
270 277 c = self.load_default_context()
271 278
272 279 del_email_id = self.request.POST.get('del_email_id')
273 280 if del_email_id:
274 281 email = UserEmailMap.get_or_404(del_email_id, pyramid_exc=True).email
275 282 UserModel().delete_extra_email(c.user.user_id, del_email_id)
276 283 audit_logger.store_web(
277 284 'user.edit.email.delete', action_data={
278 285 'data': {'email': email, 'user': 'self'}},
279 286 user=self._rhodecode_user,)
280 287 Session().commit()
281 288 h.flash(_("Email successfully deleted"),
282 289 category='success')
283 290 return HTTPFound(h.route_path('my_account_emails'))
284 291
285 292 @LoginRequired()
286 293 @NotAnonymous()
287 294 @CSRFRequired()
288 295 @view_config(
289 296 route_name='my_account_notifications_test_channelstream',
290 297 request_method='POST', renderer='json_ext')
291 298 def my_account_notifications_test_channelstream(self):
292 299 message = 'Test message sent via Channelstream by user: {}, on {}'.format(
293 300 self._rhodecode_user.username, datetime.datetime.now())
294 301 payload = {
295 302 # 'channel': 'broadcast',
296 303 'type': 'message',
297 304 'timestamp': datetime.datetime.utcnow(),
298 305 'user': 'system',
299 306 'pm_users': [self._rhodecode_user.username],
300 307 'message': {
301 308 'message': message,
302 309 'level': 'info',
303 310 'topic': '/notifications'
304 311 }
305 312 }
306 313
307 314 registry = self.request.registry
308 315 rhodecode_plugins = getattr(registry, 'rhodecode_plugins', {})
309 316 channelstream_config = rhodecode_plugins.get('channelstream', {})
310 317
311 318 try:
312 319 channelstream_request(channelstream_config, [payload], '/message')
313 320 except ChannelstreamException as e:
314 321 log.exception('Failed to send channelstream data')
315 322 return {"response": 'ERROR: {}'.format(e.__class__.__name__)}
316 323 return {"response": 'Channelstream data sent. '
317 324 'You should see a new live message now.'}
318 325
319 326 def _load_my_repos_data(self, watched=False):
320 327 if watched:
321 328 admin = False
322 329 follows_repos = Session().query(UserFollowing)\
323 330 .filter(UserFollowing.user_id == self._rhodecode_user.user_id)\
324 331 .options(joinedload(UserFollowing.follows_repository))\
325 332 .all()
326 333 repo_list = [x.follows_repository for x in follows_repos]
327 334 else:
328 335 admin = True
329 336 repo_list = Repository.get_all_repos(
330 337 user_id=self._rhodecode_user.user_id)
331 338 repo_list = RepoList(repo_list, perm_set=[
332 339 'repository.read', 'repository.write', 'repository.admin'])
333 340
334 341 repos_data = RepoModel().get_repos_as_dict(
335 342 repo_list=repo_list, admin=admin)
336 343 # json used to render the grid
337 344 return json.dumps(repos_data)
338 345
339 346 @LoginRequired()
340 347 @NotAnonymous()
341 348 @view_config(
342 349 route_name='my_account_repos', request_method='GET',
343 350 renderer='rhodecode:templates/admin/my_account/my_account.mako')
344 351 def my_account_repos(self):
345 352 c = self.load_default_context()
346 353 c.active = 'repos'
347 354
348 355 # json used to render the grid
349 356 c.data = self._load_my_repos_data()
350 357 return self._get_template_context(c)
351 358
352 359 @LoginRequired()
353 360 @NotAnonymous()
354 361 @view_config(
355 362 route_name='my_account_watched', request_method='GET',
356 363 renderer='rhodecode:templates/admin/my_account/my_account.mako')
357 364 def my_account_watched(self):
358 365 c = self.load_default_context()
359 366 c.active = 'watched'
360 367
361 368 # json used to render the grid
362 369 c.data = self._load_my_repos_data(watched=True)
363 370 return self._get_template_context(c)
364 371
365 372 @LoginRequired()
366 373 @NotAnonymous()
367 374 @view_config(
368 375 route_name='my_account_perms', request_method='GET',
369 376 renderer='rhodecode:templates/admin/my_account/my_account.mako')
370 377 def my_account_perms(self):
371 378 c = self.load_default_context()
372 379 c.active = 'perms'
373 380
374 381 c.perm_user = c.auth_user
375 382 return self._get_template_context(c)
376 383
377 384 @LoginRequired()
378 385 @NotAnonymous()
379 386 @view_config(
380 387 route_name='my_account_notifications', request_method='GET',
381 388 renderer='rhodecode:templates/admin/my_account/my_account.mako')
382 389 def my_notifications(self):
383 390 c = self.load_default_context()
384 391 c.active = 'notifications'
385 392
386 393 return self._get_template_context(c)
387 394
388 395 @LoginRequired()
389 396 @NotAnonymous()
390 397 @CSRFRequired()
391 398 @view_config(
392 399 route_name='my_account_notifications_toggle_visibility',
393 400 request_method='POST', renderer='json_ext')
394 401 def my_notifications_toggle_visibility(self):
395 402 user = self._rhodecode_db_user
396 403 new_status = not user.user_data.get('notification_status', True)
397 404 user.update_userdata(notification_status=new_status)
398 405 Session().commit()
399 return user.user_data['notification_status'] No newline at end of file
406 return user.user_data['notification_status']
407
408 @LoginRequired()
409 @NotAnonymous()
410 @view_config(
411 route_name='my_account_edit',
412 request_method='GET',
413 renderer='rhodecode:templates/admin/my_account/my_account.mako')
414 def my_account_edit(self):
415 c = self.load_default_context()
416 c.active = 'profile_edit'
417
418 c.perm_user = c.auth_user
419 c.extern_type = c.user.extern_type
420 c.extern_name = c.user.extern_name
421
422 defaults = c.user.get_dict()
423
424 data = render('rhodecode:templates/admin/my_account/my_account.mako',
425 self._get_template_context(c), self.request)
426 html = formencode.htmlfill.render(
427 data,
428 defaults=defaults,
429 encoding="UTF-8",
430 force_defaults=False
431 )
432 return Response(html)
433
434 @LoginRequired()
435 @NotAnonymous()
436 @CSRFRequired()
437 @view_config(
438 route_name='my_account_update',
439 request_method='POST',
440 renderer='rhodecode:templates/admin/my_account/my_account.mako')
441 def my_account_update(self):
442 _ = self.request.translate
443 c = self.load_default_context()
444 c.active = 'profile_edit'
445
446 c.perm_user = c.auth_user
447 c.extern_type = c.user.extern_type
448 c.extern_name = c.user.extern_name
449
450 _form = UserForm(edit=True,
451 old_data={'user_id': self._rhodecode_user.user_id,
452 'email': self._rhodecode_user.email})()
453 form_result = {}
454 try:
455 post_data = dict(self.request.POST)
456 post_data['new_password'] = ''
457 post_data['password_confirmation'] = ''
458 form_result = _form.to_python(post_data)
459 # skip updating those attrs for my account
460 skip_attrs = ['admin', 'active', 'extern_type', 'extern_name',
461 'new_password', 'password_confirmation']
462 # TODO: plugin should define if username can be updated
463 if c.extern_type != "rhodecode":
464 # forbid updating username for external accounts
465 skip_attrs.append('username')
466
467 UserModel().update_user(
468 self._rhodecode_user.user_id, skip_attrs=skip_attrs,
469 **form_result)
470 h.flash(_('Your account was updated successfully'),
471 category='success')
472 Session().commit()
473
474 except formencode.Invalid as errors:
475 data = render(
476 'rhodecode:templates/admin/my_account/my_account.mako',
477 self._get_template_context(c), self.request)
478
479 html = formencode.htmlfill.render(
480 data,
481 defaults=errors.value,
482 errors=errors.error_dict or {},
483 prefix_error=False,
484 encoding="UTF-8",
485 force_defaults=False)
486 return Response(html)
487
488 except Exception:
489 log.exception("Exception updating user")
490 h.flash(_('Error occurred during update of user %s')
491 % form_result.get('username'), category='error')
492 raise HTTPFound(h.route_path('my_account_profile'))
493
494 raise HTTPFound(h.route_path('my_account_profile'))
495
496 def _get_pull_requests_list(self, statuses):
497 draw, start, limit = self._extract_chunk(self.request)
498 search_q, order_by, order_dir = self._extract_ordering(self.request)
499 _render = PartialRenderer('data_table/_dt_elements.mako')
500
501 pull_requests = PullRequestModel().get_im_participating_in(
502 user_id=self._rhodecode_user.user_id,
503 statuses=statuses,
504 offset=start, length=limit, order_by=order_by,
505 order_dir=order_dir)
506
507 pull_requests_total_count = PullRequestModel().count_im_participating_in(
508 user_id=self._rhodecode_user.user_id, statuses=statuses)
509
510 data = []
511 comments_model = CommentsModel()
512 for pr in pull_requests:
513 repo_id = pr.target_repo_id
514 comments = comments_model.get_all_comments(
515 repo_id, pull_request=pr)
516 owned = pr.user_id == self._rhodecode_user.user_id
517
518 data.append({
519 'target_repo': _render('pullrequest_target_repo',
520 pr.target_repo.repo_name),
521 'name': _render('pullrequest_name',
522 pr.pull_request_id, pr.target_repo.repo_name,
523 short=True),
524 'name_raw': pr.pull_request_id,
525 'status': _render('pullrequest_status',
526 pr.calculated_review_status()),
527 'title': _render(
528 'pullrequest_title', pr.title, pr.description),
529 'description': h.escape(pr.description),
530 'updated_on': _render('pullrequest_updated_on',
531 h.datetime_to_time(pr.updated_on)),
532 'updated_on_raw': h.datetime_to_time(pr.updated_on),
533 'created_on': _render('pullrequest_updated_on',
534 h.datetime_to_time(pr.created_on)),
535 'created_on_raw': h.datetime_to_time(pr.created_on),
536 'author': _render('pullrequest_author',
537 pr.author.full_contact, ),
538 'author_raw': pr.author.full_name,
539 'comments': _render('pullrequest_comments', len(comments)),
540 'comments_raw': len(comments),
541 'closed': pr.is_closed(),
542 'owned': owned
543 })
544
545 # json used to render the grid
546 data = ({
547 'draw': draw,
548 'data': data,
549 'recordsTotal': pull_requests_total_count,
550 'recordsFiltered': pull_requests_total_count,
551 })
552 return data
553
554 @LoginRequired()
555 @NotAnonymous()
556 @view_config(
557 route_name='my_account_pullrequests',
558 request_method='GET',
559 renderer='rhodecode:templates/admin/my_account/my_account.mako')
560 def my_account_pullrequests(self):
561 c = self.load_default_context()
562 c.active = 'pullrequests'
563 req_get = self.request.GET
564
565 c.closed = str2bool(req_get.get('pr_show_closed'))
566
567 return self._get_template_context(c)
568
569 @LoginRequired()
570 @NotAnonymous()
571 @view_config(
572 route_name='my_account_pullrequests_data',
573 request_method='GET', renderer='json_ext')
574 def my_account_pullrequests_data(self):
575 req_get = self.request.GET
576 closed = str2bool(req_get.get('closed'))
577
578 statuses = [PullRequest.STATUS_NEW, PullRequest.STATUS_OPEN]
579 if closed:
580 statuses += [PullRequest.STATUS_CLOSED]
581
582 data = self._get_pull_requests_list(statuses=statuses)
583 return data
584
@@ -1,912 +1,904 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 Routes configuration
23 23
24 24 The more specific and detailed routes should be defined first so they
25 25 may take precedent over the more generic routes. For more information
26 26 refer to the routes manual at http://routes.groovie.org/docs/
27 27
28 28 IMPORTANT: if you change any routing here, make sure to take a look at lib/base.py
29 29 and _route_name variable which uses some of stored naming here to do redirects.
30 30 """
31 31 import os
32 32 import re
33 33 from routes import Mapper
34 34
35 35 # prefix for non repository related links needs to be prefixed with `/`
36 36 ADMIN_PREFIX = '/_admin'
37 37 STATIC_FILE_PREFIX = '/_static'
38 38
39 39 # Default requirements for URL parts
40 40 URL_NAME_REQUIREMENTS = {
41 41 # group name can have a slash in them, but they must not end with a slash
42 42 'group_name': r'.*?[^/]',
43 43 'repo_group_name': r'.*?[^/]',
44 44 # repo names can have a slash in them, but they must not end with a slash
45 45 'repo_name': r'.*?[^/]',
46 46 # file path eats up everything at the end
47 47 'f_path': r'.*',
48 48 # reference types
49 49 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
50 50 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
51 51 }
52 52
53 53
54 54 def add_route_requirements(route_path, requirements):
55 55 """
56 56 Adds regex requirements to pyramid routes using a mapping dict
57 57
58 58 >>> add_route_requirements('/{action}/{id}', {'id': r'\d+'})
59 59 '/{action}/{id:\d+}'
60 60
61 61 """
62 62 for key, regex in requirements.items():
63 63 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
64 64 return route_path
65 65
66 66
67 67 class JSRoutesMapper(Mapper):
68 68 """
69 69 Wrapper for routes.Mapper to make pyroutes compatible url definitions
70 70 """
71 71 _named_route_regex = re.compile(r'^[a-z-_0-9A-Z]+$')
72 72 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
73 73 def __init__(self, *args, **kw):
74 74 super(JSRoutesMapper, self).__init__(*args, **kw)
75 75 self._jsroutes = []
76 76
77 77 def connect(self, *args, **kw):
78 78 """
79 79 Wrapper for connect to take an extra argument jsroute=True
80 80
81 81 :param jsroute: boolean, if True will add the route to the pyroutes list
82 82 """
83 83 if kw.pop('jsroute', False):
84 84 if not self._named_route_regex.match(args[0]):
85 85 raise Exception('only named routes can be added to pyroutes')
86 86 self._jsroutes.append(args[0])
87 87
88 88 super(JSRoutesMapper, self).connect(*args, **kw)
89 89
90 90 def _extract_route_information(self, route):
91 91 """
92 92 Convert a route into tuple(name, path, args), eg:
93 93 ('show_user', '/profile/%(username)s', ['username'])
94 94 """
95 95 routepath = route.routepath
96 96 def replace(matchobj):
97 97 if matchobj.group(1):
98 98 return "%%(%s)s" % matchobj.group(1).split(':')[0]
99 99 else:
100 100 return "%%(%s)s" % matchobj.group(2)
101 101
102 102 routepath = self._argument_prog.sub(replace, routepath)
103 103 return (
104 104 route.name,
105 105 routepath,
106 106 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
107 107 for arg in self._argument_prog.findall(route.routepath)]
108 108 )
109 109
110 110 def jsroutes(self):
111 111 """
112 112 Return a list of pyroutes.js compatible routes
113 113 """
114 114 for route_name in self._jsroutes:
115 115 yield self._extract_route_information(self._routenames[route_name])
116 116
117 117
118 118 def make_map(config):
119 119 """Create, configure and return the routes Mapper"""
120 120 rmap = JSRoutesMapper(
121 121 directory=config['pylons.paths']['controllers'],
122 122 always_scan=config['debug'])
123 123 rmap.minimization = False
124 124 rmap.explicit = False
125 125
126 126 from rhodecode.lib.utils2 import str2bool
127 127 from rhodecode.model import repo, repo_group
128 128
129 129 def check_repo(environ, match_dict):
130 130 """
131 131 check for valid repository for proper 404 handling
132 132
133 133 :param environ:
134 134 :param match_dict:
135 135 """
136 136 repo_name = match_dict.get('repo_name')
137 137
138 138 if match_dict.get('f_path'):
139 139 # fix for multiple initial slashes that causes errors
140 140 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
141 141 repo_model = repo.RepoModel()
142 142 by_name_match = repo_model.get_by_repo_name(repo_name)
143 143 # if we match quickly from database, short circuit the operation,
144 144 # and validate repo based on the type.
145 145 if by_name_match:
146 146 return True
147 147
148 148 by_id_match = repo_model.get_repo_by_id(repo_name)
149 149 if by_id_match:
150 150 repo_name = by_id_match.repo_name
151 151 match_dict['repo_name'] = repo_name
152 152 return True
153 153
154 154 return False
155 155
156 156 def check_group(environ, match_dict):
157 157 """
158 158 check for valid repository group path for proper 404 handling
159 159
160 160 :param environ:
161 161 :param match_dict:
162 162 """
163 163 repo_group_name = match_dict.get('group_name')
164 164 repo_group_model = repo_group.RepoGroupModel()
165 165 by_name_match = repo_group_model.get_by_group_name(repo_group_name)
166 166 if by_name_match:
167 167 return True
168 168
169 169 return False
170 170
171 171 def check_user_group(environ, match_dict):
172 172 """
173 173 check for valid user group for proper 404 handling
174 174
175 175 :param environ:
176 176 :param match_dict:
177 177 """
178 178 return True
179 179
180 180 def check_int(environ, match_dict):
181 181 return match_dict.get('id').isdigit()
182 182
183 183
184 184 #==========================================================================
185 185 # CUSTOM ROUTES HERE
186 186 #==========================================================================
187 187
188 188 # ping and pylons error test
189 189 rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
190 190 rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test')
191 191
192 192 # ADMIN REPOSITORY ROUTES
193 193 with rmap.submapper(path_prefix=ADMIN_PREFIX,
194 194 controller='admin/repos') as m:
195 195 m.connect('repos', '/repos',
196 196 action='create', conditions={'method': ['POST']})
197 197 m.connect('repos', '/repos',
198 198 action='index', conditions={'method': ['GET']})
199 199 m.connect('new_repo', '/create_repository', jsroute=True,
200 200 action='create_repository', conditions={'method': ['GET']})
201 201 m.connect('delete_repo', '/repos/{repo_name}',
202 202 action='delete', conditions={'method': ['DELETE']},
203 203 requirements=URL_NAME_REQUIREMENTS)
204 204 m.connect('repo', '/repos/{repo_name}',
205 205 action='show', conditions={'method': ['GET'],
206 206 'function': check_repo},
207 207 requirements=URL_NAME_REQUIREMENTS)
208 208
209 209 # ADMIN REPOSITORY GROUPS ROUTES
210 210 with rmap.submapper(path_prefix=ADMIN_PREFIX,
211 211 controller='admin/repo_groups') as m:
212 212 m.connect('repo_groups', '/repo_groups',
213 213 action='create', conditions={'method': ['POST']})
214 214 m.connect('repo_groups', '/repo_groups',
215 215 action='index', conditions={'method': ['GET']})
216 216 m.connect('new_repo_group', '/repo_groups/new',
217 217 action='new', conditions={'method': ['GET']})
218 218 m.connect('update_repo_group', '/repo_groups/{group_name}',
219 219 action='update', conditions={'method': ['PUT'],
220 220 'function': check_group},
221 221 requirements=URL_NAME_REQUIREMENTS)
222 222
223 223 # EXTRAS REPO GROUP ROUTES
224 224 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
225 225 action='edit',
226 226 conditions={'method': ['GET'], 'function': check_group},
227 227 requirements=URL_NAME_REQUIREMENTS)
228 228 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
229 229 action='edit',
230 230 conditions={'method': ['PUT'], 'function': check_group},
231 231 requirements=URL_NAME_REQUIREMENTS)
232 232
233 233 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
234 234 action='edit_repo_group_advanced',
235 235 conditions={'method': ['GET'], 'function': check_group},
236 236 requirements=URL_NAME_REQUIREMENTS)
237 237 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
238 238 action='edit_repo_group_advanced',
239 239 conditions={'method': ['PUT'], 'function': check_group},
240 240 requirements=URL_NAME_REQUIREMENTS)
241 241
242 242 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
243 243 action='edit_repo_group_perms',
244 244 conditions={'method': ['GET'], 'function': check_group},
245 245 requirements=URL_NAME_REQUIREMENTS)
246 246 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
247 247 action='update_perms',
248 248 conditions={'method': ['PUT'], 'function': check_group},
249 249 requirements=URL_NAME_REQUIREMENTS)
250 250
251 251 m.connect('delete_repo_group', '/repo_groups/{group_name}',
252 252 action='delete', conditions={'method': ['DELETE'],
253 253 'function': check_group},
254 254 requirements=URL_NAME_REQUIREMENTS)
255 255
256 256 # ADMIN USER ROUTES
257 257 with rmap.submapper(path_prefix=ADMIN_PREFIX,
258 258 controller='admin/users') as m:
259 259 m.connect('users', '/users',
260 260 action='create', conditions={'method': ['POST']})
261 261 m.connect('new_user', '/users/new',
262 262 action='new', conditions={'method': ['GET']})
263 263 m.connect('update_user', '/users/{user_id}',
264 264 action='update', conditions={'method': ['PUT']})
265 265 m.connect('delete_user', '/users/{user_id}',
266 266 action='delete', conditions={'method': ['DELETE']})
267 267 m.connect('edit_user', '/users/{user_id}/edit',
268 268 action='edit', conditions={'method': ['GET']}, jsroute=True)
269 269 m.connect('user', '/users/{user_id}',
270 270 action='show', conditions={'method': ['GET']})
271 271 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
272 272 action='reset_password', conditions={'method': ['POST']})
273 273 m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group',
274 274 action='create_personal_repo_group', conditions={'method': ['POST']})
275 275
276 276 # EXTRAS USER ROUTES
277 277 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
278 278 action='edit_advanced', conditions={'method': ['GET']})
279 279 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
280 280 action='update_advanced', conditions={'method': ['PUT']})
281 281
282 282 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
283 283 action='edit_global_perms', conditions={'method': ['GET']})
284 284 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
285 285 action='update_global_perms', conditions={'method': ['PUT']})
286 286
287 287 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
288 288 action='edit_perms_summary', conditions={'method': ['GET']})
289 289
290 290
291 291 # ADMIN USER GROUPS REST ROUTES
292 292 with rmap.submapper(path_prefix=ADMIN_PREFIX,
293 293 controller='admin/user_groups') as m:
294 294 m.connect('users_groups', '/user_groups',
295 295 action='create', conditions={'method': ['POST']})
296 296 m.connect('users_groups', '/user_groups',
297 297 action='index', conditions={'method': ['GET']})
298 298 m.connect('new_users_group', '/user_groups/new',
299 299 action='new', conditions={'method': ['GET']})
300 300 m.connect('update_users_group', '/user_groups/{user_group_id}',
301 301 action='update', conditions={'method': ['PUT']})
302 302 m.connect('delete_users_group', '/user_groups/{user_group_id}',
303 303 action='delete', conditions={'method': ['DELETE']})
304 304 m.connect('edit_users_group', '/user_groups/{user_group_id}/edit',
305 305 action='edit', conditions={'method': ['GET']},
306 306 function=check_user_group)
307 307
308 308 # EXTRAS USER GROUP ROUTES
309 309 m.connect('edit_user_group_global_perms',
310 310 '/user_groups/{user_group_id}/edit/global_permissions',
311 311 action='edit_global_perms', conditions={'method': ['GET']})
312 312 m.connect('edit_user_group_global_perms',
313 313 '/user_groups/{user_group_id}/edit/global_permissions',
314 314 action='update_global_perms', conditions={'method': ['PUT']})
315 315 m.connect('edit_user_group_perms_summary',
316 316 '/user_groups/{user_group_id}/edit/permissions_summary',
317 317 action='edit_perms_summary', conditions={'method': ['GET']})
318 318
319 319 m.connect('edit_user_group_perms',
320 320 '/user_groups/{user_group_id}/edit/permissions',
321 321 action='edit_perms', conditions={'method': ['GET']})
322 322 m.connect('edit_user_group_perms',
323 323 '/user_groups/{user_group_id}/edit/permissions',
324 324 action='update_perms', conditions={'method': ['PUT']})
325 325
326 326 m.connect('edit_user_group_advanced',
327 327 '/user_groups/{user_group_id}/edit/advanced',
328 328 action='edit_advanced', conditions={'method': ['GET']})
329 329
330 330 m.connect('edit_user_group_advanced_sync',
331 331 '/user_groups/{user_group_id}/edit/advanced/sync',
332 332 action='edit_advanced_set_synchronization', conditions={'method': ['POST']})
333 333
334 334 m.connect('edit_user_group_members',
335 335 '/user_groups/{user_group_id}/edit/members', jsroute=True,
336 336 action='user_group_members', conditions={'method': ['GET']})
337 337
338 338 # ADMIN PERMISSIONS ROUTES
339 339 with rmap.submapper(path_prefix=ADMIN_PREFIX,
340 340 controller='admin/permissions') as m:
341 341 m.connect('admin_permissions_application', '/permissions/application',
342 342 action='permission_application_update', conditions={'method': ['POST']})
343 343 m.connect('admin_permissions_application', '/permissions/application',
344 344 action='permission_application', conditions={'method': ['GET']})
345 345
346 346 m.connect('admin_permissions_global', '/permissions/global',
347 347 action='permission_global_update', conditions={'method': ['POST']})
348 348 m.connect('admin_permissions_global', '/permissions/global',
349 349 action='permission_global', conditions={'method': ['GET']})
350 350
351 351 m.connect('admin_permissions_object', '/permissions/object',
352 352 action='permission_objects_update', conditions={'method': ['POST']})
353 353 m.connect('admin_permissions_object', '/permissions/object',
354 354 action='permission_objects', conditions={'method': ['GET']})
355 355
356 356 m.connect('admin_permissions_ips', '/permissions/ips',
357 357 action='permission_ips', conditions={'method': ['POST']})
358 358 m.connect('admin_permissions_ips', '/permissions/ips',
359 359 action='permission_ips', conditions={'method': ['GET']})
360 360
361 361 m.connect('admin_permissions_overview', '/permissions/overview',
362 362 action='permission_perms', conditions={'method': ['GET']})
363 363
364 364 # ADMIN DEFAULTS REST ROUTES
365 365 with rmap.submapper(path_prefix=ADMIN_PREFIX,
366 366 controller='admin/defaults') as m:
367 367 m.connect('admin_defaults_repositories', '/defaults/repositories',
368 368 action='update_repository_defaults', conditions={'method': ['POST']})
369 369 m.connect('admin_defaults_repositories', '/defaults/repositories',
370 370 action='index', conditions={'method': ['GET']})
371 371
372 372 # ADMIN DEBUG STYLE ROUTES
373 373 if str2bool(config.get('debug_style')):
374 374 with rmap.submapper(path_prefix=ADMIN_PREFIX + '/debug_style',
375 375 controller='debug_style') as m:
376 376 m.connect('debug_style_home', '',
377 377 action='index', conditions={'method': ['GET']})
378 378 m.connect('debug_style_template', '/t/{t_path}',
379 379 action='template', conditions={'method': ['GET']})
380 380
381 381 # ADMIN SETTINGS ROUTES
382 382 with rmap.submapper(path_prefix=ADMIN_PREFIX,
383 383 controller='admin/settings') as m:
384 384
385 385 # default
386 386 m.connect('admin_settings', '/settings',
387 387 action='settings_global_update',
388 388 conditions={'method': ['POST']})
389 389 m.connect('admin_settings', '/settings',
390 390 action='settings_global', conditions={'method': ['GET']})
391 391
392 392 m.connect('admin_settings_vcs', '/settings/vcs',
393 393 action='settings_vcs_update',
394 394 conditions={'method': ['POST']})
395 395 m.connect('admin_settings_vcs', '/settings/vcs',
396 396 action='settings_vcs',
397 397 conditions={'method': ['GET']})
398 398 m.connect('admin_settings_vcs', '/settings/vcs',
399 399 action='delete_svn_pattern',
400 400 conditions={'method': ['DELETE']})
401 401
402 402 m.connect('admin_settings_mapping', '/settings/mapping',
403 403 action='settings_mapping_update',
404 404 conditions={'method': ['POST']})
405 405 m.connect('admin_settings_mapping', '/settings/mapping',
406 406 action='settings_mapping', conditions={'method': ['GET']})
407 407
408 408 m.connect('admin_settings_global', '/settings/global',
409 409 action='settings_global_update',
410 410 conditions={'method': ['POST']})
411 411 m.connect('admin_settings_global', '/settings/global',
412 412 action='settings_global', conditions={'method': ['GET']})
413 413
414 414 m.connect('admin_settings_visual', '/settings/visual',
415 415 action='settings_visual_update',
416 416 conditions={'method': ['POST']})
417 417 m.connect('admin_settings_visual', '/settings/visual',
418 418 action='settings_visual', conditions={'method': ['GET']})
419 419
420 420 m.connect('admin_settings_issuetracker',
421 421 '/settings/issue-tracker', action='settings_issuetracker',
422 422 conditions={'method': ['GET']})
423 423 m.connect('admin_settings_issuetracker_save',
424 424 '/settings/issue-tracker/save',
425 425 action='settings_issuetracker_save',
426 426 conditions={'method': ['POST']})
427 427 m.connect('admin_issuetracker_test', '/settings/issue-tracker/test',
428 428 action='settings_issuetracker_test',
429 429 conditions={'method': ['POST']})
430 430 m.connect('admin_issuetracker_delete',
431 431 '/settings/issue-tracker/delete',
432 432 action='settings_issuetracker_delete',
433 433 conditions={'method': ['DELETE']})
434 434
435 435 m.connect('admin_settings_email', '/settings/email',
436 436 action='settings_email_update',
437 437 conditions={'method': ['POST']})
438 438 m.connect('admin_settings_email', '/settings/email',
439 439 action='settings_email', conditions={'method': ['GET']})
440 440
441 441 m.connect('admin_settings_hooks', '/settings/hooks',
442 442 action='settings_hooks_update',
443 443 conditions={'method': ['POST', 'DELETE']})
444 444 m.connect('admin_settings_hooks', '/settings/hooks',
445 445 action='settings_hooks', conditions={'method': ['GET']})
446 446
447 447 m.connect('admin_settings_search', '/settings/search',
448 448 action='settings_search', conditions={'method': ['GET']})
449 449
450 450 m.connect('admin_settings_supervisor', '/settings/supervisor',
451 451 action='settings_supervisor', conditions={'method': ['GET']})
452 452 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
453 453 action='settings_supervisor_log', conditions={'method': ['GET']})
454 454
455 455 m.connect('admin_settings_labs', '/settings/labs',
456 456 action='settings_labs_update',
457 457 conditions={'method': ['POST']})
458 458 m.connect('admin_settings_labs', '/settings/labs',
459 459 action='settings_labs', conditions={'method': ['GET']})
460 460
461 461 # ADMIN MY ACCOUNT
462 462 with rmap.submapper(path_prefix=ADMIN_PREFIX,
463 463 controller='admin/my_account') as m:
464 464
465 m.connect('my_account_edit', '/my_account/edit',
466 action='my_account_edit', conditions={'method': ['GET']})
467 m.connect('my_account', '/my_account/update',
468 action='my_account_update', conditions={'method': ['POST']})
469
470 465 # NOTE(marcink): this needs to be kept for password force flag to be
471 # handler, remove after migration to pyramid
466 # handled in pylons controllers, remove after full migration to pyramid
472 467 m.connect('my_account_password', '/my_account/password',
473 468 action='my_account_password', conditions={'method': ['GET']})
474 469
475 m.connect('my_account_pullrequests', '/my_account/pull_requests',
476 action='my_account_pullrequests', conditions={'method': ['GET']})
477
478 470 # NOTIFICATION REST ROUTES
479 471 with rmap.submapper(path_prefix=ADMIN_PREFIX,
480 472 controller='admin/notifications') as m:
481 473 m.connect('notifications', '/notifications',
482 474 action='index', conditions={'method': ['GET']})
483 475 m.connect('notifications_mark_all_read', '/notifications/mark_all_read',
484 476 action='mark_all_read', conditions={'method': ['POST']})
485 477 m.connect('/notifications/{notification_id}',
486 478 action='update', conditions={'method': ['PUT']})
487 479 m.connect('/notifications/{notification_id}',
488 480 action='delete', conditions={'method': ['DELETE']})
489 481 m.connect('notification', '/notifications/{notification_id}',
490 482 action='show', conditions={'method': ['GET']})
491 483
492 484 # USER JOURNAL
493 485 rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,),
494 486 controller='journal', action='index')
495 487 rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,),
496 488 controller='journal', action='journal_rss')
497 489 rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,),
498 490 controller='journal', action='journal_atom')
499 491
500 492 rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,),
501 493 controller='journal', action='public_journal')
502 494
503 495 rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,),
504 496 controller='journal', action='public_journal_rss')
505 497
506 498 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,),
507 499 controller='journal', action='public_journal_rss')
508 500
509 501 rmap.connect('public_journal_atom',
510 502 '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal',
511 503 action='public_journal_atom')
512 504
513 505 rmap.connect('public_journal_atom_old',
514 506 '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal',
515 507 action='public_journal_atom')
516 508
517 509 rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,),
518 510 controller='journal', action='toggle_following', jsroute=True,
519 511 conditions={'method': ['POST']})
520 512
521 513 # FEEDS
522 514 rmap.connect('rss_feed_home', '/{repo_name}/feed/rss',
523 515 controller='feed', action='rss',
524 516 conditions={'function': check_repo},
525 517 requirements=URL_NAME_REQUIREMENTS)
526 518
527 519 rmap.connect('atom_feed_home', '/{repo_name}/feed/atom',
528 520 controller='feed', action='atom',
529 521 conditions={'function': check_repo},
530 522 requirements=URL_NAME_REQUIREMENTS)
531 523
532 524 #==========================================================================
533 525 # REPOSITORY ROUTES
534 526 #==========================================================================
535 527
536 528 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
537 529 controller='admin/repos', action='repo_creating',
538 530 requirements=URL_NAME_REQUIREMENTS)
539 531 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
540 532 controller='admin/repos', action='repo_check',
541 533 requirements=URL_NAME_REQUIREMENTS)
542 534
543 535 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
544 536 controller='changeset', revision='tip',
545 537 conditions={'function': check_repo},
546 538 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
547 539 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
548 540 controller='changeset', revision='tip', action='changeset_children',
549 541 conditions={'function': check_repo},
550 542 requirements=URL_NAME_REQUIREMENTS)
551 543 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
552 544 controller='changeset', revision='tip', action='changeset_parents',
553 545 conditions={'function': check_repo},
554 546 requirements=URL_NAME_REQUIREMENTS)
555 547
556 548 # repo edit options
557 549 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
558 550 controller='admin/repos', action='edit_fields',
559 551 conditions={'method': ['GET'], 'function': check_repo},
560 552 requirements=URL_NAME_REQUIREMENTS)
561 553 rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new',
562 554 controller='admin/repos', action='create_repo_field',
563 555 conditions={'method': ['PUT'], 'function': check_repo},
564 556 requirements=URL_NAME_REQUIREMENTS)
565 557 rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}',
566 558 controller='admin/repos', action='delete_repo_field',
567 559 conditions={'method': ['DELETE'], 'function': check_repo},
568 560 requirements=URL_NAME_REQUIREMENTS)
569 561
570 562 rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle',
571 563 controller='admin/repos', action='toggle_locking',
572 564 conditions={'method': ['GET'], 'function': check_repo},
573 565 requirements=URL_NAME_REQUIREMENTS)
574 566
575 567 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
576 568 controller='admin/repos', action='edit_remote_form',
577 569 conditions={'method': ['GET'], 'function': check_repo},
578 570 requirements=URL_NAME_REQUIREMENTS)
579 571 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
580 572 controller='admin/repos', action='edit_remote',
581 573 conditions={'method': ['PUT'], 'function': check_repo},
582 574 requirements=URL_NAME_REQUIREMENTS)
583 575
584 576 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
585 577 controller='admin/repos', action='edit_statistics_form',
586 578 conditions={'method': ['GET'], 'function': check_repo},
587 579 requirements=URL_NAME_REQUIREMENTS)
588 580 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
589 581 controller='admin/repos', action='edit_statistics',
590 582 conditions={'method': ['PUT'], 'function': check_repo},
591 583 requirements=URL_NAME_REQUIREMENTS)
592 584 rmap.connect('repo_settings_issuetracker',
593 585 '/{repo_name}/settings/issue-tracker',
594 586 controller='admin/repos', action='repo_issuetracker',
595 587 conditions={'method': ['GET'], 'function': check_repo},
596 588 requirements=URL_NAME_REQUIREMENTS)
597 589 rmap.connect('repo_issuetracker_test',
598 590 '/{repo_name}/settings/issue-tracker/test',
599 591 controller='admin/repos', action='repo_issuetracker_test',
600 592 conditions={'method': ['POST'], 'function': check_repo},
601 593 requirements=URL_NAME_REQUIREMENTS)
602 594 rmap.connect('repo_issuetracker_delete',
603 595 '/{repo_name}/settings/issue-tracker/delete',
604 596 controller='admin/repos', action='repo_issuetracker_delete',
605 597 conditions={'method': ['DELETE'], 'function': check_repo},
606 598 requirements=URL_NAME_REQUIREMENTS)
607 599 rmap.connect('repo_issuetracker_save',
608 600 '/{repo_name}/settings/issue-tracker/save',
609 601 controller='admin/repos', action='repo_issuetracker_save',
610 602 conditions={'method': ['POST'], 'function': check_repo},
611 603 requirements=URL_NAME_REQUIREMENTS)
612 604 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
613 605 controller='admin/repos', action='repo_settings_vcs_update',
614 606 conditions={'method': ['POST'], 'function': check_repo},
615 607 requirements=URL_NAME_REQUIREMENTS)
616 608 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
617 609 controller='admin/repos', action='repo_settings_vcs',
618 610 conditions={'method': ['GET'], 'function': check_repo},
619 611 requirements=URL_NAME_REQUIREMENTS)
620 612 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
621 613 controller='admin/repos', action='repo_delete_svn_pattern',
622 614 conditions={'method': ['DELETE'], 'function': check_repo},
623 615 requirements=URL_NAME_REQUIREMENTS)
624 616 rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest',
625 617 controller='admin/repos', action='repo_settings_pullrequest',
626 618 conditions={'method': ['GET', 'POST'], 'function': check_repo},
627 619 requirements=URL_NAME_REQUIREMENTS)
628 620
629 621 # still working url for backward compat.
630 622 rmap.connect('raw_changeset_home_depraced',
631 623 '/{repo_name}/raw-changeset/{revision}',
632 624 controller='changeset', action='changeset_raw',
633 625 revision='tip', conditions={'function': check_repo},
634 626 requirements=URL_NAME_REQUIREMENTS)
635 627
636 628 # new URLs
637 629 rmap.connect('changeset_raw_home',
638 630 '/{repo_name}/changeset-diff/{revision}',
639 631 controller='changeset', action='changeset_raw',
640 632 revision='tip', conditions={'function': check_repo},
641 633 requirements=URL_NAME_REQUIREMENTS)
642 634
643 635 rmap.connect('changeset_patch_home',
644 636 '/{repo_name}/changeset-patch/{revision}',
645 637 controller='changeset', action='changeset_patch',
646 638 revision='tip', conditions={'function': check_repo},
647 639 requirements=URL_NAME_REQUIREMENTS)
648 640
649 641 rmap.connect('changeset_download_home',
650 642 '/{repo_name}/changeset-download/{revision}',
651 643 controller='changeset', action='changeset_download',
652 644 revision='tip', conditions={'function': check_repo},
653 645 requirements=URL_NAME_REQUIREMENTS)
654 646
655 647 rmap.connect('changeset_comment',
656 648 '/{repo_name}/changeset/{revision}/comment', jsroute=True,
657 649 controller='changeset', revision='tip', action='comment',
658 650 conditions={'function': check_repo},
659 651 requirements=URL_NAME_REQUIREMENTS)
660 652
661 653 rmap.connect('changeset_comment_preview',
662 654 '/{repo_name}/changeset/comment/preview', jsroute=True,
663 655 controller='changeset', action='preview_comment',
664 656 conditions={'function': check_repo, 'method': ['POST']},
665 657 requirements=URL_NAME_REQUIREMENTS)
666 658
667 659 rmap.connect('changeset_comment_delete',
668 660 '/{repo_name}/changeset/comment/{comment_id}/delete',
669 661 controller='changeset', action='delete_comment',
670 662 conditions={'function': check_repo, 'method': ['DELETE']},
671 663 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
672 664
673 665 rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}',
674 666 controller='changeset', action='changeset_info',
675 667 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
676 668
677 669 rmap.connect('compare_home',
678 670 '/{repo_name}/compare',
679 671 controller='compare', action='index',
680 672 conditions={'function': check_repo},
681 673 requirements=URL_NAME_REQUIREMENTS)
682 674
683 675 rmap.connect('compare_url',
684 676 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
685 677 controller='compare', action='compare',
686 678 conditions={'function': check_repo},
687 679 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
688 680
689 681 rmap.connect('pullrequest_home',
690 682 '/{repo_name}/pull-request/new', controller='pullrequests',
691 683 action='index', conditions={'function': check_repo,
692 684 'method': ['GET']},
693 685 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
694 686
695 687 rmap.connect('pullrequest',
696 688 '/{repo_name}/pull-request/new', controller='pullrequests',
697 689 action='create', conditions={'function': check_repo,
698 690 'method': ['POST']},
699 691 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
700 692
701 693 rmap.connect('pullrequest_repo_refs',
702 694 '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
703 695 controller='pullrequests',
704 696 action='get_repo_refs',
705 697 conditions={'function': check_repo, 'method': ['GET']},
706 698 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
707 699
708 700 rmap.connect('pullrequest_repo_destinations',
709 701 '/{repo_name}/pull-request/repo-destinations',
710 702 controller='pullrequests',
711 703 action='get_repo_destinations',
712 704 conditions={'function': check_repo, 'method': ['GET']},
713 705 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
714 706
715 707 rmap.connect('pullrequest_show',
716 708 '/{repo_name}/pull-request/{pull_request_id}',
717 709 controller='pullrequests',
718 710 action='show', conditions={'function': check_repo,
719 711 'method': ['GET']},
720 712 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
721 713
722 714 rmap.connect('pullrequest_update',
723 715 '/{repo_name}/pull-request/{pull_request_id}',
724 716 controller='pullrequests',
725 717 action='update', conditions={'function': check_repo,
726 718 'method': ['PUT']},
727 719 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
728 720
729 721 rmap.connect('pullrequest_merge',
730 722 '/{repo_name}/pull-request/{pull_request_id}',
731 723 controller='pullrequests',
732 724 action='merge', conditions={'function': check_repo,
733 725 'method': ['POST']},
734 726 requirements=URL_NAME_REQUIREMENTS)
735 727
736 728 rmap.connect('pullrequest_delete',
737 729 '/{repo_name}/pull-request/{pull_request_id}',
738 730 controller='pullrequests',
739 731 action='delete', conditions={'function': check_repo,
740 732 'method': ['DELETE']},
741 733 requirements=URL_NAME_REQUIREMENTS)
742 734
743 735 rmap.connect('pullrequest_comment',
744 736 '/{repo_name}/pull-request-comment/{pull_request_id}',
745 737 controller='pullrequests',
746 738 action='comment', conditions={'function': check_repo,
747 739 'method': ['POST']},
748 740 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
749 741
750 742 rmap.connect('pullrequest_comment_delete',
751 743 '/{repo_name}/pull-request-comment/{comment_id}/delete',
752 744 controller='pullrequests', action='delete_comment',
753 745 conditions={'function': check_repo, 'method': ['DELETE']},
754 746 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
755 747
756 748 rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True,
757 749 controller='changelog', conditions={'function': check_repo},
758 750 requirements=URL_NAME_REQUIREMENTS)
759 751
760 752 rmap.connect('changelog_file_home',
761 753 '/{repo_name}/changelog/{revision}/{f_path}',
762 754 controller='changelog', f_path=None,
763 755 conditions={'function': check_repo},
764 756 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
765 757
766 758 rmap.connect('changelog_elements', '/{repo_name}/changelog_details',
767 759 controller='changelog', action='changelog_elements',
768 760 conditions={'function': check_repo},
769 761 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
770 762
771 763 rmap.connect('files_home', '/{repo_name}/files/{revision}/{f_path}',
772 764 controller='files', revision='tip', f_path='',
773 765 conditions={'function': check_repo},
774 766 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
775 767
776 768 rmap.connect('files_home_simple_catchrev',
777 769 '/{repo_name}/files/{revision}',
778 770 controller='files', revision='tip', f_path='',
779 771 conditions={'function': check_repo},
780 772 requirements=URL_NAME_REQUIREMENTS)
781 773
782 774 rmap.connect('files_home_simple_catchall',
783 775 '/{repo_name}/files',
784 776 controller='files', revision='tip', f_path='',
785 777 conditions={'function': check_repo},
786 778 requirements=URL_NAME_REQUIREMENTS)
787 779
788 780 rmap.connect('files_history_home',
789 781 '/{repo_name}/history/{revision}/{f_path}',
790 782 controller='files', action='history', revision='tip', f_path='',
791 783 conditions={'function': check_repo},
792 784 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
793 785
794 786 rmap.connect('files_authors_home',
795 787 '/{repo_name}/authors/{revision}/{f_path}',
796 788 controller='files', action='authors', revision='tip', f_path='',
797 789 conditions={'function': check_repo},
798 790 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
799 791
800 792 rmap.connect('files_diff_home', '/{repo_name}/diff/{f_path}',
801 793 controller='files', action='diff', f_path='',
802 794 conditions={'function': check_repo},
803 795 requirements=URL_NAME_REQUIREMENTS)
804 796
805 797 rmap.connect('files_diff_2way_home',
806 798 '/{repo_name}/diff-2way/{f_path}',
807 799 controller='files', action='diff_2way', f_path='',
808 800 conditions={'function': check_repo},
809 801 requirements=URL_NAME_REQUIREMENTS)
810 802
811 803 rmap.connect('files_rawfile_home',
812 804 '/{repo_name}/rawfile/{revision}/{f_path}',
813 805 controller='files', action='rawfile', revision='tip',
814 806 f_path='', conditions={'function': check_repo},
815 807 requirements=URL_NAME_REQUIREMENTS)
816 808
817 809 rmap.connect('files_raw_home',
818 810 '/{repo_name}/raw/{revision}/{f_path}',
819 811 controller='files', action='raw', revision='tip', f_path='',
820 812 conditions={'function': check_repo},
821 813 requirements=URL_NAME_REQUIREMENTS)
822 814
823 815 rmap.connect('files_render_home',
824 816 '/{repo_name}/render/{revision}/{f_path}',
825 817 controller='files', action='index', revision='tip', f_path='',
826 818 rendered=True, conditions={'function': check_repo},
827 819 requirements=URL_NAME_REQUIREMENTS)
828 820
829 821 rmap.connect('files_annotate_home',
830 822 '/{repo_name}/annotate/{revision}/{f_path}',
831 823 controller='files', action='index', revision='tip',
832 824 f_path='', annotate=True, conditions={'function': check_repo},
833 825 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
834 826
835 827 rmap.connect('files_annotate_previous',
836 828 '/{repo_name}/annotate-previous/{revision}/{f_path}',
837 829 controller='files', action='annotate_previous', revision='tip',
838 830 f_path='', annotate=True, conditions={'function': check_repo},
839 831 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
840 832
841 833 rmap.connect('files_edit',
842 834 '/{repo_name}/edit/{revision}/{f_path}',
843 835 controller='files', action='edit', revision='tip',
844 836 f_path='',
845 837 conditions={'function': check_repo, 'method': ['POST']},
846 838 requirements=URL_NAME_REQUIREMENTS)
847 839
848 840 rmap.connect('files_edit_home',
849 841 '/{repo_name}/edit/{revision}/{f_path}',
850 842 controller='files', action='edit_home', revision='tip',
851 843 f_path='', conditions={'function': check_repo},
852 844 requirements=URL_NAME_REQUIREMENTS)
853 845
854 846 rmap.connect('files_add',
855 847 '/{repo_name}/add/{revision}/{f_path}',
856 848 controller='files', action='add', revision='tip',
857 849 f_path='',
858 850 conditions={'function': check_repo, 'method': ['POST']},
859 851 requirements=URL_NAME_REQUIREMENTS)
860 852
861 853 rmap.connect('files_add_home',
862 854 '/{repo_name}/add/{revision}/{f_path}',
863 855 controller='files', action='add_home', revision='tip',
864 856 f_path='', conditions={'function': check_repo},
865 857 requirements=URL_NAME_REQUIREMENTS)
866 858
867 859 rmap.connect('files_delete',
868 860 '/{repo_name}/delete/{revision}/{f_path}',
869 861 controller='files', action='delete', revision='tip',
870 862 f_path='',
871 863 conditions={'function': check_repo, 'method': ['POST']},
872 864 requirements=URL_NAME_REQUIREMENTS)
873 865
874 866 rmap.connect('files_delete_home',
875 867 '/{repo_name}/delete/{revision}/{f_path}',
876 868 controller='files', action='delete_home', revision='tip',
877 869 f_path='', conditions={'function': check_repo},
878 870 requirements=URL_NAME_REQUIREMENTS)
879 871
880 872 rmap.connect('files_archive_home', '/{repo_name}/archive/{fname}',
881 873 controller='files', action='archivefile',
882 874 conditions={'function': check_repo},
883 875 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
884 876
885 877 rmap.connect('files_nodelist_home',
886 878 '/{repo_name}/nodelist/{revision}/{f_path}',
887 879 controller='files', action='nodelist',
888 880 conditions={'function': check_repo},
889 881 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
890 882
891 883 rmap.connect('files_nodetree_full',
892 884 '/{repo_name}/nodetree_full/{commit_id}/{f_path}',
893 885 controller='files', action='nodetree_full',
894 886 conditions={'function': check_repo},
895 887 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
896 888
897 889 rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
898 890 controller='forks', action='fork_create',
899 891 conditions={'function': check_repo, 'method': ['POST']},
900 892 requirements=URL_NAME_REQUIREMENTS)
901 893
902 894 rmap.connect('repo_fork_home', '/{repo_name}/fork',
903 895 controller='forks', action='fork',
904 896 conditions={'function': check_repo},
905 897 requirements=URL_NAME_REQUIREMENTS)
906 898
907 899 rmap.connect('repo_forks_home', '/{repo_name}/forks',
908 900 controller='forks', action='forks',
909 901 conditions={'function': check_repo},
910 902 requirements=URL_NAME_REQUIREMENTS)
911 903
912 904 return rmap
@@ -1,165 +1,169 b''
1 1
2 2 /******************************************************************************
3 3 * *
4 4 * DO NOT CHANGE THIS FILE MANUALLY *
5 5 * *
6 6 * *
7 7 * This file is automatically generated when the app starts up with *
8 8 * generate_js_files = true *
9 9 * *
10 10 * To add a route here pass jsroute=True to the route definition in the app *
11 11 * *
12 12 ******************************************************************************/
13 13 function registerRCRoutes() {
14 14 // routes registration
15 15 pyroutes.register('new_repo', '/_admin/create_repository', []);
16 16 pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']);
17 17 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
18 18 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
19 19 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
20 20 pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
21 21 pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
22 22 pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
23 23 pyroutes.register('changeset_info', '/%(repo_name)s/changeset_info/%(revision)s', ['repo_name', 'revision']);
24 24 pyroutes.register('compare_url', '/%(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']);
25 25 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
26 26 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
27 27 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
28 28 pyroutes.register('pullrequest_repo_destinations', '/%(repo_name)s/pull-request/repo-destinations', ['repo_name']);
29 29 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
30 30 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
31 31 pyroutes.register('pullrequest_comment', '/%(repo_name)s/pull-request-comment/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
32 32 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request-comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
33 33 pyroutes.register('changelog_home', '/%(repo_name)s/changelog', ['repo_name']);
34 34 pyroutes.register('changelog_file_home', '/%(repo_name)s/changelog/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
35 35 pyroutes.register('changelog_elements', '/%(repo_name)s/changelog_details', ['repo_name']);
36 36 pyroutes.register('files_home', '/%(repo_name)s/files/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
37 37 pyroutes.register('files_history_home', '/%(repo_name)s/history/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
38 38 pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
39 39 pyroutes.register('files_annotate_home', '/%(repo_name)s/annotate/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
40 40 pyroutes.register('files_annotate_previous', '/%(repo_name)s/annotate-previous/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
41 41 pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
42 42 pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
43 43 pyroutes.register('files_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
44 44 pyroutes.register('favicon', '/favicon.ico', []);
45 45 pyroutes.register('robots', '/robots.txt', []);
46 46 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
47 47 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
48 48 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
49 49 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
50 50 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
51 51 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
52 52 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/settings/integrations', ['repo_group_name']);
53 53 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
54 54 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/settings/integrations/new', ['repo_group_name']);
55 55 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
56 56 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
57 57 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
58 58 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
59 59 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
60 60 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
61 61 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
62 62 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
63 63 pyroutes.register('admin_home', '/_admin', []);
64 64 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
65 65 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
66 66 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
67 67 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
68 68 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
69 69 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
70 70 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
71 71 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
72 72 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
73 73 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
74 74 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
75 75 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
76 76 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
77 77 pyroutes.register('users', '/_admin/users', []);
78 78 pyroutes.register('users_data', '/_admin/users_data', []);
79 79 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
80 80 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
81 81 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
82 82 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
83 83 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
84 84 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
85 85 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
86 86 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
87 87 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
88 88 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
89 89 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
90 90 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
91 91 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
92 92 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
93 93 pyroutes.register('channelstream_proxy', '/_channelstream', []);
94 94 pyroutes.register('login', '/_admin/login', []);
95 95 pyroutes.register('logout', '/_admin/logout', []);
96 96 pyroutes.register('register', '/_admin/register', []);
97 97 pyroutes.register('reset_password', '/_admin/password_reset', []);
98 98 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
99 99 pyroutes.register('home', '/', []);
100 100 pyroutes.register('user_autocomplete_data', '/_users', []);
101 101 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
102 102 pyroutes.register('repo_list_data', '/_repos', []);
103 103 pyroutes.register('goto_switcher_data', '/_goto_data', []);
104 104 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
105 105 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
106 106 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
107 107 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
108 108 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
109 109 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
110 110 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
111 111 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
112 112 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
113 113 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
114 114 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
115 115 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
116 116 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
117 117 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
118 118 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
119 119 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
120 120 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
121 121 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
122 122 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
123 123 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
124 124 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
125 125 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
126 126 pyroutes.register('repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
127 127 pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
128 128 pyroutes.register('strip', '/%(repo_name)s/settings/strip', ['repo_name']);
129 129 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
130 130 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
131 131 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
132 132 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
133 133 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
134 134 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
135 135 pyroutes.register('search', '/_admin/search', []);
136 136 pyroutes.register('search_repo', '/%(repo_name)s/search', ['repo_name']);
137 137 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
138 138 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
139 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
140 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
139 141 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
140 142 pyroutes.register('my_account_password_update', '/_admin/my_account/password', []);
141 143 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
142 144 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
143 145 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
144 146 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
145 147 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
146 148 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
147 149 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
148 150 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
149 151 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
150 152 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
151 153 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
154 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
155 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
152 156 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
153 157 pyroutes.register('gists_show', '/_admin/gists', []);
154 158 pyroutes.register('gists_new', '/_admin/gists/new', []);
155 159 pyroutes.register('gists_create', '/_admin/gists/create', []);
156 160 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
157 161 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
158 162 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
159 163 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
160 164 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
161 165 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/%(revision)s', ['gist_id', 'revision']);
162 166 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
163 167 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
164 168 pyroutes.register('apiv2', '/_admin/api', []);
165 169 }
@@ -1,52 +1,52 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.mako"/>
3 3
4 4 <%def name="title()">
5 5 ${_('My account')} ${c.rhodecode_user.username}
6 6 %if c.rhodecode_name:
7 7 &middot; ${h.branding(c.rhodecode_name)}
8 8 %endif
9 9 </%def>
10 10
11 11 <%def name="breadcrumbs_links()">
12 12 ${_('My Account')}
13 13 </%def>
14 14
15 15 <%def name="menu_bar_nav()">
16 16 ${self.menu_items(active='my_account')}
17 17 </%def>
18 18
19 19 <%def name="main()">
20 20 <div class="box">
21 21 <div class="title">
22 22 ${self.breadcrumbs()}
23 23 </div>
24 24
25 25 <div class="sidebar-col-wrapper scw-small">
26 26 ##main
27 27 <div class="sidebar">
28 28 <ul class="nav nav-pills nav-stacked">
29 29 <li class="${'active' if c.active=='profile' or c.active=='profile_edit' else ''}"><a href="${h.route_path('my_account_profile')}">${_('Profile')}</a></li>
30 30 <li class="${'active' if c.active=='password' else ''}"><a href="${h.route_path('my_account_password')}">${_('Password')}</a></li>
31 31 <li class="${'active' if c.active=='auth_tokens' else ''}"><a href="${h.route_path('my_account_auth_tokens')}">${_('Auth Tokens')}</a></li>
32 32 ## TODO: Find a better integration of oauth views into navigation.
33 33 <% my_account_oauth_url = h.route_path_or_none('my_account_oauth') %>
34 34 % if my_account_oauth_url:
35 35 <li class="${'active' if c.active=='oauth' else ''}"><a href="${my_account_oauth_url}">${_('OAuth Identities')}</a></li>
36 36 % endif
37 37 <li class="${'active' if c.active=='emails' else ''}"><a href="${h.route_path('my_account_emails')}">${_('Emails')}</a></li>
38 38 <li class="${'active' if c.active=='repos' else ''}"><a href="${h.route_path('my_account_repos')}">${_('Repositories')}</a></li>
39 39 <li class="${'active' if c.active=='watched' else ''}"><a href="${h.route_path('my_account_watched')}">${_('Watched')}</a></li>
40 <li class="${'active' if c.active=='pullrequests' else ''}"><a href="${h.url('my_account_pullrequests')}">${_('Pull Requests')}</a></li>
40 <li class="${'active' if c.active=='pullrequests' else ''}"><a href="${h.route_path('my_account_pullrequests')}">${_('Pull Requests')}</a></li>
41 41 <li class="${'active' if c.active=='perms' else ''}"><a href="${h.route_path('my_account_perms')}">${_('Permissions')}</a></li>
42 42 <li class="${'active' if c.active=='my_notifications' else ''}"><a href="${h.route_path('my_account_notifications')}">${_('Live Notifications')}</a></li>
43 43 </ul>
44 44 </div>
45 45
46 46 <div class="main-content-full-width">
47 47 <%include file="/admin/my_account/my_account_${c.active}.mako"/>
48 48 </div>
49 49 </div>
50 50 </div>
51 51
52 52 </%def>
@@ -1,55 +1,55 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2 <div class="panel panel-default user-profile">
3 3 <div class="panel-heading">
4 4 <h3 class="panel-title">${_('My Profile')}</h3>
5 <a href="${url('my_account_edit')}" class="panel-edit">${_('Edit')}</a>
5 <a href="${h.route_path('my_account_edit')}" class="panel-edit">${_('Edit')}</a>
6 6 </div>
7 7
8 8 <div class="panel-body">
9 9 <div class="fieldset">
10 10 <div class="left-label">
11 11 ${_('Photo')}:
12 12 </div>
13 13 <div class="right-content">
14 14 %if c.visual.use_gravatar:
15 15 ${base.gravatar(c.user.email, 100)}
16 16 %else:
17 17 ${base.gravatar(c.user.email, 20)}
18 18 ${_('Avatars are disabled')}
19 19 %endif
20 20 </div>
21 21 </div>
22 22 <div class="fieldset">
23 23 <div class="left-label">
24 24 ${_('Username')}:
25 25 </div>
26 26 <div class="right-content">
27 27 ${c.user.username}
28 28 </div>
29 29 </div>
30 30 <div class="fieldset">
31 31 <div class="left-label">
32 32 ${_('First Name')}:
33 33 </div>
34 34 <div class="right-content">
35 35 ${c.user.first_name}
36 36 </div>
37 37 </div>
38 38 <div class="fieldset">
39 39 <div class="left-label">
40 40 ${_('Last Name')}:
41 41 </div>
42 42 <div class="right-content">
43 43 ${c.user.last_name}
44 44 </div>
45 45 </div>
46 46 <div class="fieldset">
47 47 <div class="left-label">
48 48 ${_('Email')}:
49 49 </div>
50 50 <div class="right-content">
51 51 ${c.user.email or _('Missing email, please update your user email address.')}
52 52 </div>
53 53 </div>
54 54 </div>
55 55 </div> No newline at end of file
@@ -1,113 +1,113 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2 <div class="panel panel-default user-profile">
3 3 <div class="panel-heading">
4 4 <h3 class="panel-title">${_('My Profile')}</h3>
5 5 <a href="${h.route_path('my_account_profile')}" class="panel-edit">Close</a>
6 6 </div>
7 7
8 8 <div class="panel-body">
9 ${h.secure_form(url('my_account'), method='post', class_='form')}
9 ${h.secure_form(h.route_path('my_account_update'), class_='form', method='POST')}
10 10 <% readonly = None %>
11 11 <% disabled = "" %>
12 12
13 13 % if c.extern_type != 'rhodecode':
14 14 <% readonly = "readonly" %>
15 15 <% disabled = "disabled" %>
16 16 <div class="infoform">
17 17 <div class="fields">
18 18 <p>${_('Your user account details are managed by an external source. Details cannot be managed here.')}
19 19 <br/>${_('Source type')}: <strong>${c.extern_type}</strong>
20 20 </p>
21 21
22 22 <div class="field">
23 23 <div class="label">
24 24 <label for="username">${_('Username')}:</label>
25 25 </div>
26 26 <div class="input">
27 27 ${h.text('username', class_='input-valuedisplay', readonly=readonly)}
28 28 </div>
29 29 </div>
30 30
31 31 <div class="field">
32 32 <div class="label">
33 33 <label for="name">${_('First Name')}:</label>
34 34 </div>
35 35 <div class="input">
36 36 ${h.text('firstname', class_='input-valuedisplay', readonly=readonly)}
37 37 </div>
38 38 </div>
39 39
40 40 <div class="field">
41 41 <div class="label">
42 42 <label for="lastname">${_('Last Name')}:</label>
43 43 </div>
44 44 <div class="input-valuedisplay">
45 45 ${h.text('lastname', class_='input-valuedisplay', readonly=readonly)}
46 46 </div>
47 47 </div>
48 48 </div>
49 49 </div>
50 50 % else:
51 51 <div class="form">
52 52 <div class="fields">
53 53 <div class="field">
54 54 <div class="label photo">
55 55 ${_('Photo')}:
56 56 </div>
57 57 <div class="input profile">
58 58 %if c.visual.use_gravatar:
59 59 ${base.gravatar(c.user.email, 100)}
60 60 <p class="help-block">${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a>.</p>
61 61 %else:
62 62 ${base.gravatar(c.user.email, 20)}
63 63 ${_('Avatars are disabled')}
64 64 %endif
65 65 </div>
66 66 </div>
67 67 <div class="field">
68 68 <div class="label">
69 69 <label for="username">${_('Username')}:</label>
70 70 </div>
71 71 <div class="input">
72 72 ${h.text('username', class_='medium%s' % disabled, readonly=readonly)}
73 73 ${h.hidden('extern_name', c.extern_name)}
74 74 ${h.hidden('extern_type', c.extern_type)}
75 75 </div>
76 76 </div>
77 77 <div class="field">
78 78 <div class="label">
79 79 <label for="name">${_('First Name')}:</label>
80 80 </div>
81 81 <div class="input">
82 82 ${h.text('firstname', class_="medium")}
83 83 </div>
84 84 </div>
85 85
86 86 <div class="field">
87 87 <div class="label">
88 88 <label for="lastname">${_('Last Name')}:</label>
89 89 </div>
90 90 <div class="input">
91 91 ${h.text('lastname', class_="medium")}
92 92 </div>
93 93 </div>
94 94
95 95 <div class="field">
96 96 <div class="label">
97 97 <label for="email">${_('Email')}:</label>
98 98 </div>
99 99 <div class="input">
100 100 ## we should be able to edit email !
101 101 ${h.text('email', class_="medium")}
102 102 </div>
103 103 </div>
104 104
105 105 <div class="buttons">
106 106 ${h.submit('save', _('Save'), class_="btn")}
107 107 ${h.reset('reset', _('Reset'), class_="btn")}
108 108 </div>
109 109 </div>
110 110 </div>
111 111 % endif
112 112 </div>
113 113 </div> No newline at end of file
@@ -1,78 +1,90 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2
3 3 <div class="panel panel-default">
4 4 <div class="panel-body">
5 %if c.show_closed:
5 %if c.closed:
6 6 ${h.checkbox('show_closed',checked="checked", label=_('Show Closed Pull Requests'))}
7 7 %else:
8 8 ${h.checkbox('show_closed',label=_('Show Closed Pull Requests'))}
9 9 %endif
10 10 </div>
11 11 </div>
12 12
13 13 <div class="panel panel-default">
14 14 <div class="panel-heading">
15 <h3 class="panel-title">${_('Pull Requests You Participate In')}: ${c.records_total_participate}</h3>
15 <h3 class="panel-title">${_('Pull Requests You Participate In')}</h3>
16 16 </div>
17 <div class="panel-body">
18 <table id="pull_request_list_table_participate" class="display"></table>
17 <div class="panel-body panel-body-min-height">
18 <table id="pull_request_list_table" class="display"></table>
19 19 </div>
20 20 </div>
21 21
22 <script>
22 <script type="text/javascript">
23 $(document).ready(function() {
24
23 25 $('#show_closed').on('click', function(e){
24 26 if($(this).is(":checked")){
25 window.location = "${h.url('my_account_pullrequests', pr_show_closed=1)}";
27 window.location = "${h.route_path('my_account_pullrequests', _query={'pr_show_closed':1})}";
26 28 }
27 29 else{
28 window.location = "${h.url('my_account_pullrequests')}";
30 window.location = "${h.route_path('my_account_pullrequests')}";
29 31 }
30 32 });
31 $(document).ready(function() {
33
34 var $pullRequestListTable = $('#pull_request_list_table');
32 35
33 var columnsDefs = [
36 // participating object list
37 $pullRequestListTable.DataTable({
38 processing: true,
39 serverSide: true,
40 ajax: {
41 "url": "${h.route_path('my_account_pullrequests_data')}",
42 "data": function (d) {
43 d.closed = "${c.closed}";
44 }
45 },
46 dom: 'rtp',
47 pageLength: ${c.visual.dashboard_items},
48 order: [[ 2, "desc" ]],
49 columns: [
34 50 { data: {"_": "status",
35 51 "sort": "status"}, title: "", className: "td-status", orderable: false},
36 52 { data: {"_": "target_repo",
37 53 "sort": "target_repo"}, title: "${_('Target Repo')}", className: "td-targetrepo", orderable: false},
38 54 { data: {"_": "name",
39 55 "sort": "name_raw"}, title: "${_('Name')}", className: "td-componentname", "type": "num" },
40 56 { data: {"_": "author",
41 57 "sort": "author_raw"}, title: "${_('Author')}", className: "td-user", orderable: false },
42 58 { data: {"_": "title",
43 59 "sort": "title"}, title: "${_('Title')}", className: "td-description" },
44 60 { data: {"_": "comments",
45 61 "sort": "comments_raw"}, title: "", className: "td-comments", orderable: false},
46 62 { data: {"_": "updated_on",
47 63 "sort": "updated_on_raw"}, title: "${_('Last Update')}", className: "td-time" }
48 ];
49
50 // participating object list
51 $('#pull_request_list_table_participate').DataTable({
52 data: ${c.data_participate|n},
53 processing: true,
54 serverSide: true,
55 deferLoading: ${c.records_total_participate},
56 ajax: "",
57 dom: 'tp',
58 pageLength: ${c.visual.dashboard_items},
59 order: [[ 2, "desc" ]],
60 columns: columnsDefs,
64 ],
61 65 language: {
62 66 paginate: DEFAULT_GRID_PAGINATION,
67 sProcessing: _gettext('loading...'),
63 68 emptyTable: _gettext("There are currently no open pull requests requiring your participation.")
64 69 },
65 70 "drawCallback": function( settings, json ) {
66 71 timeagoActivate();
67 72 },
68 73 "createdRow": function ( row, data, index ) {
69 74 if (data['closed']) {
70 75 $(row).addClass('closed');
71 76 }
72 77 if (data['owned']) {
73 78 $(row).addClass('owned');
74 79 }
75 80 }
76 81 });
82 $pullRequestListTable.on('xhr.dt', function(e, settings, json, xhr){
83 $pullRequestListTable.css('opacity', 1);
84 });
85
86 $pullRequestListTable.on('preXhr.dt', function(e, settings, data){
87 $pullRequestListTable.css('opacity', 0.3);
88 });
77 89 });
78 90 </script>
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now