##// END OF EJS Templates
my-account: moved few my account views into pyramid.
marcink -
r1819:956c5cda default
parent child Browse files
Show More
@@ -0,0 +1,76 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2010-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
21 import pytest
22
23 from rhodecode.apps._base import ADMIN_PREFIX
24 from rhodecode.model.db import User, UserEmailMap, Repository, UserFollowing
25 from rhodecode.tests import (
26 TestController, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_EMAIL,
27 assert_session_flash)
28 from rhodecode.tests.fixture import Fixture
29
30 fixture = Fixture()
31
32
33 def route_path(name, **kwargs):
34 return {
35 'my_account_repos':
36 ADMIN_PREFIX + '/my_account/repos',
37 'my_account_watched':
38 ADMIN_PREFIX + '/my_account/watched',
39 'my_account_perms':
40 ADMIN_PREFIX + '/my_account/perms',
41 'my_account_notifications':
42 ADMIN_PREFIX + '/my_account/notifications',
43 }[name].format(**kwargs)
44
45
46 class TestMyAccountSimpleViews(TestController):
47
48 def test_my_account_my_repos(self, autologin_user):
49 response = self.app.get(route_path('my_account_repos'))
50 repos = Repository.query().filter(
51 Repository.user == User.get_by_username(
52 TEST_USER_ADMIN_LOGIN)).all()
53 for repo in repos:
54 response.mustcontain('"name_raw": "%s"' % repo.repo_name)
55
56 def test_my_account_my_watched(self, autologin_user):
57 response = self.app.get(route_path('my_account_watched'))
58
59 repos = UserFollowing.query().filter(
60 UserFollowing.user == User.get_by_username(
61 TEST_USER_ADMIN_LOGIN)).all()
62 for repo in repos:
63 response.mustcontain(
64 '"name_raw": "%s"' % repo.follows_repository.repo_name)
65
66 def test_my_account_perms(self, autologin_user):
67 response = self.app.get(route_path('my_account_perms'))
68 assert_response = response.assert_response()
69 assert assert_response.get_elements('.perm_tag.none')
70 assert assert_response.get_elements('.perm_tag.read')
71 assert assert_response.get_elements('.perm_tag.write')
72 assert assert_response.get_elements('.perm_tag.admin')
73
74 def test_my_account_notifications(self, autologin_user):
75 response = self.app.get(route_path('my_account_notifications'))
76 response.mustcontain('Test flash message')
@@ -56,6 +56,26 b' def includeme(config):'
56 name='my_account_emails_delete',
56 name='my_account_emails_delete',
57 pattern=ADMIN_PREFIX + '/my_account/emails/delete')
57 pattern=ADMIN_PREFIX + '/my_account/emails/delete')
58
58
59 config.add_route(
60 name='my_account_repos',
61 pattern=ADMIN_PREFIX + '/my_account/repos')
62
63 config.add_route(
64 name='my_account_watched',
65 pattern=ADMIN_PREFIX + '/my_account/watched')
66
67 config.add_route(
68 name='my_account_perms',
69 pattern=ADMIN_PREFIX + '/my_account/perms')
70
71 config.add_route(
72 name='my_account_notifications',
73 pattern=ADMIN_PREFIX + '/my_account/notifications')
74
75 config.add_route(
76 name='my_account_notifications_toggle_visibility',
77 pattern=ADMIN_PREFIX + '/my_account/toggle_visibility')
78
59 # channelstream test
79 # channelstream test
60 config.add_route(
80 config.add_route(
61 name='my_account_notifications_test_channelstream',
81 name='my_account_notifications_test_channelstream',
@@ -28,14 +28,18 b' from pyramid.view import view_config'
28 from rhodecode.apps._base import BaseAppView
28 from rhodecode.apps._base import BaseAppView
29 from rhodecode import forms
29 from rhodecode import forms
30 from rhodecode.lib import helpers as h
30 from rhodecode.lib import helpers as h
31 from rhodecode.lib.ext_json import json
31 from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired
32 from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired
32 from rhodecode.lib.channelstream import channelstream_request, \
33 from rhodecode.lib.channelstream import channelstream_request, \
33 ChannelstreamException
34 ChannelstreamException
34 from rhodecode.lib.utils2 import safe_int, md5
35 from rhodecode.lib.utils2 import safe_int, md5
35 from rhodecode.model.auth_token import AuthTokenModel
36 from rhodecode.model.auth_token import AuthTokenModel
36 from rhodecode.model.db import UserEmailMap
37 from rhodecode.model.db import (
38 Repository, PullRequest, UserEmailMap, User, UserFollowing, joinedload)
37 from rhodecode.model.meta import Session
39 from rhodecode.model.meta import Session
40 from rhodecode.model.scm import RepoList
38 from rhodecode.model.user import UserModel
41 from rhodecode.model.user import UserModel
42 from rhodecode.model.repo import RepoModel
39 from rhodecode.model.validation_schema.schemas import user_schema
43 from rhodecode.model.validation_schema.schemas import user_schema
40
44
41 log = logging.getLogger(__name__)
45 log = logging.getLogger(__name__)
@@ -290,3 +294,85 b' class MyAccountView(BaseAppView):'
290 return {"response": 'ERROR: {}'.format(e.__class__.__name__)}
294 return {"response": 'ERROR: {}'.format(e.__class__.__name__)}
291 return {"response": 'Channelstream data sent. '
295 return {"response": 'Channelstream data sent. '
292 'You should see a new live message now.'}
296 'You should see a new live message now.'}
297
298 def _load_my_repos_data(self, watched=False):
299 if watched:
300 admin = False
301 follows_repos = Session().query(UserFollowing)\
302 .filter(UserFollowing.user_id == self._rhodecode_user.user_id)\
303 .options(joinedload(UserFollowing.follows_repository))\
304 .all()
305 repo_list = [x.follows_repository for x in follows_repos]
306 else:
307 admin = True
308 repo_list = Repository.get_all_repos(
309 user_id=self._rhodecode_user.user_id)
310 repo_list = RepoList(repo_list, perm_set=[
311 'repository.read', 'repository.write', 'repository.admin'])
312
313 repos_data = RepoModel().get_repos_as_dict(
314 repo_list=repo_list, admin=admin)
315 # json used to render the grid
316 return json.dumps(repos_data)
317
318 @LoginRequired()
319 @NotAnonymous()
320 @view_config(
321 route_name='my_account_repos', request_method='GET',
322 renderer='rhodecode:templates/admin/my_account/my_account.mako')
323 def my_account_repos(self):
324 c = self.load_default_context()
325 c.active = 'repos'
326
327 # json used to render the grid
328 c.data = self._load_my_repos_data()
329 return self._get_template_context(c)
330
331 @LoginRequired()
332 @NotAnonymous()
333 @view_config(
334 route_name='my_account_watched', request_method='GET',
335 renderer='rhodecode:templates/admin/my_account/my_account.mako')
336 def my_account_watched(self):
337 c = self.load_default_context()
338 c.active = 'watched'
339
340 # json used to render the grid
341 c.data = self._load_my_repos_data(watched=True)
342 return self._get_template_context(c)
343
344 @LoginRequired()
345 @NotAnonymous()
346 @view_config(
347 route_name='my_account_perms', request_method='GET',
348 renderer='rhodecode:templates/admin/my_account/my_account.mako')
349 def my_account_perms(self):
350 c = self.load_default_context()
351 c.active = 'perms'
352
353 c.perm_user = c.auth_user
354 return self._get_template_context(c)
355
356 @LoginRequired()
357 @NotAnonymous()
358 @view_config(
359 route_name='my_account_notifications', request_method='GET',
360 renderer='rhodecode:templates/admin/my_account/my_account.mako')
361 def my_notifications(self):
362 c = self.load_default_context()
363 c.active = 'notifications'
364
365 return self._get_template_context(c)
366
367 @LoginRequired()
368 @NotAnonymous()
369 @CSRFRequired()
370 @view_config(
371 route_name='my_account_notifications_toggle_visibility',
372 request_method='POST', renderer='json_ext')
373 def my_notifications_toggle_visibility(self):
374 user = self._rhodecode_db_user
375 new_status = not user.user_data.get('notification_status', True)
376 user.update_userdata(notification_status=new_status)
377 Session().commit()
378 return user.user_data['notification_status'] No newline at end of file
@@ -485,26 +485,9 b' def make_map(config):'
485 m.connect('my_account_password', '/my_account/password',
485 m.connect('my_account_password', '/my_account/password',
486 action='my_account_password', conditions={'method': ['GET']})
486 action='my_account_password', conditions={'method': ['GET']})
487
487
488 m.connect('my_account_repos', '/my_account/repos',
489 action='my_account_repos', conditions={'method': ['GET']})
490
491 m.connect('my_account_watched', '/my_account/watched',
492 action='my_account_watched', conditions={'method': ['GET']})
493
494 m.connect('my_account_pullrequests', '/my_account/pull_requests',
488 m.connect('my_account_pullrequests', '/my_account/pull_requests',
495 action='my_account_pullrequests', conditions={'method': ['GET']})
489 action='my_account_pullrequests', conditions={'method': ['GET']})
496
490
497 m.connect('my_account_perms', '/my_account/perms',
498 action='my_account_perms', conditions={'method': ['GET']})
499
500 m.connect('my_account_notifications', '/my_account/notifications',
501 action='my_notifications',
502 conditions={'method': ['GET']})
503 m.connect('my_account_notifications_toggle_visibility',
504 '/my_account/toggle_visibility',
505 action='my_notifications_toggle_visibility',
506 conditions={'method': ['POST']})
507
508 # NOTIFICATION REST ROUTES
491 # NOTIFICATION REST ROUTES
509 with rmap.submapper(path_prefix=ADMIN_PREFIX,
492 with rmap.submapper(path_prefix=ADMIN_PREFIX,
510 controller='admin/notifications') as m:
493 controller='admin/notifications') as m:
@@ -29,26 +29,22 b' import formencode'
29 from formencode import htmlfill
29 from formencode import htmlfill
30 from pyramid.httpexceptions import HTTPFound
30 from pyramid.httpexceptions import HTTPFound
31
31
32 from pylons import request, tmpl_context as c, url
32 from pylons import request, tmpl_context as c
33 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
34 from pylons.i18n.translation import _
34 from pylons.i18n.translation import _
35 from sqlalchemy.orm import joinedload
36
35
37 from rhodecode.lib import helpers as h
36 from rhodecode.lib import helpers as h
38 from rhodecode.lib import auth
37 from rhodecode.lib import auth
39 from rhodecode.lib.auth import (
38 from rhodecode.lib.auth import (
40 LoginRequired, NotAnonymous, AuthUser)
39 LoginRequired, NotAnonymous, AuthUser)
41 from rhodecode.lib.base import BaseController, render
40 from rhodecode.lib.base import BaseController, render
42 from rhodecode.lib.utils import jsonify
43 from rhodecode.lib.utils2 import safe_int, str2bool
41 from rhodecode.lib.utils2 import safe_int, str2bool
44 from rhodecode.lib.ext_json import json
42 from rhodecode.lib.ext_json import json
45
43
46 from rhodecode.model.db import (
44 from rhodecode.model.db import (
47 Repository, PullRequest, UserEmailMap, User, UserFollowing)
45 Repository, PullRequest, UserEmailMap, User, UserFollowing)
48 from rhodecode.model.forms import UserForm
46 from rhodecode.model.forms import UserForm
49 from rhodecode.model.scm import RepoList
50 from rhodecode.model.user import UserModel
47 from rhodecode.model.user import UserModel
51 from rhodecode.model.repo import RepoModel
52 from rhodecode.model.meta import Session
48 from rhodecode.model.meta import Session
53 from rhodecode.model.pull_request import PullRequestModel
49 from rhodecode.model.pull_request import PullRequestModel
54 from rhodecode.model.comment import CommentsModel
50 from rhodecode.model.comment import CommentsModel
@@ -78,26 +74,6 b' class MyAccountController(BaseController'
78 c.auth_user = AuthUser(
74 c.auth_user = AuthUser(
79 user_id=c.rhodecode_user.user_id, ip_addr=self.ip_addr)
75 user_id=c.rhodecode_user.user_id, ip_addr=self.ip_addr)
80
76
81 def _load_my_repos_data(self, watched=False):
82 if watched:
83 admin = False
84 follows_repos = Session().query(UserFollowing)\
85 .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\
86 .options(joinedload(UserFollowing.follows_repository))\
87 .all()
88 repo_list = [x.follows_repository for x in follows_repos]
89 else:
90 admin = True
91 repo_list = Repository.get_all_repos(
92 user_id=c.rhodecode_user.user_id)
93 repo_list = RepoList(repo_list, perm_set=[
94 'repository.read', 'repository.write', 'repository.admin'])
95
96 repos_data = RepoModel().get_repos_as_dict(
97 repo_list=repo_list, admin=admin)
98 # json used to render the grid
99 return json.dumps(repos_data)
100
101 @auth.CSRFRequired()
77 @auth.CSRFRequired()
102 def my_account_update(self):
78 def my_account_update(self):
103 """
79 """
@@ -177,29 +153,6 b' class MyAccountController(BaseController'
177 force_defaults=False
153 force_defaults=False
178 )
154 )
179
155
180 def my_account_repos(self):
181 c.active = 'repos'
182 self.__load_data()
183
184 # json used to render the grid
185 c.data = self._load_my_repos_data()
186 return render('admin/my_account/my_account.mako')
187
188 def my_account_watched(self):
189 c.active = 'watched'
190 self.__load_data()
191
192 # json used to render the grid
193 c.data = self._load_my_repos_data(watched=True)
194 return render('admin/my_account/my_account.mako')
195
196 def my_account_perms(self):
197 c.active = 'perms'
198 self.__load_data()
199 c.perm_user = c.auth_user
200
201 return render('admin/my_account/my_account.mako')
202
203 def _extract_ordering(self, request):
156 def _extract_ordering(self, request):
204 column_index = safe_int(request.GET.get('order[0][column]'))
157 column_index = safe_int(request.GET.get('order[0][column]'))
205 order_dir = request.GET.get('order[0][dir]', 'desc')
158 order_dir = request.GET.get('order[0][dir]', 'desc')
@@ -280,15 +233,4 b' class MyAccountController(BaseController'
280 else:
233 else:
281 return json.dumps(data)
234 return json.dumps(data)
282
235
283 def my_notifications(self):
284 c.active = 'notifications'
285 return render('admin/my_account/my_account.mako')
286
236
287 @auth.CSRFRequired()
288 @jsonify
289 def my_notifications_toggle_visibility(self):
290 user = c.rhodecode_user.get_instance()
291 new_status = not user.user_data.get('notification_status', True)
292 user.update_userdata(notification_status=new_status)
293 Session().commit()
294 return user.user_data['notification_status']
@@ -134,6 +134,14 b' function registerRCRoutes() {'
134 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
134 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
135 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
135 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
136 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
136 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
137 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
138 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
139 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
140 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
141 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
142 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
143 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
144 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
137 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
145 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
138 pyroutes.register('apiv2', '/_admin/api', []);
146 pyroutes.register('apiv2', '/_admin/api', []);
139 }
147 }
@@ -35,11 +35,11 b''
35 <li class="${'active' if c.active=='oauth' else ''}"><a href="${my_account_oauth_url}">${_('OAuth Identities')}</a></li>
35 <li class="${'active' if c.active=='oauth' else ''}"><a href="${my_account_oauth_url}">${_('OAuth Identities')}</a></li>
36 % endif
36 % endif
37 <li class="${'active' if c.active=='emails' else ''}"><a href="${h.route_path('my_account_emails')}">${_('Emails')}</a></li>
37 <li class="${'active' if c.active=='emails' else ''}"><a href="${h.route_path('my_account_emails')}">${_('Emails')}</a></li>
38 <li class="${'active' if c.active=='repos' else ''}"><a href="${h.url('my_account_repos')}">${_('Repositories')}</a></li>
38 <li class="${'active' if c.active=='repos' else ''}"><a href="${h.route_path('my_account_repos')}">${_('Repositories')}</a></li>
39 <li class="${'active' if c.active=='watched' else ''}"><a href="${h.url('my_account_watched')}">${_('Watched')}</a></li>
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.url('my_account_pullrequests')}">${_('Pull Requests')}</a></li>
41 <li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('my_account_perms')}">${_('Permissions')}</a></li>
41 <li class="${'active' if c.active=='perms' else ''}"><a href="${h.route_path('my_account_perms')}">${_('Permissions')}</a></li>
42 <li class="${'active' if c.active=='my_notifications' else ''}"><a href="${h.url('my_account_notifications')}">${_('Live Notifications')}</a></li>
42 <li class="${'active' if c.active=='my_notifications' else ''}"><a href="${h.route_path('my_account_notifications')}">${_('Live Notifications')}</a></li>
43 </ul>
43 </ul>
44 </div>
44 </div>
45
45
@@ -1,7 +1,7 b''
1 <template is="dom-bind" id="notificationsPage">
1 <template is="dom-bind" id="notificationsPage">
2 <iron-ajax id="toggleNotifications"
2 <iron-ajax id="toggleNotifications"
3 method="post"
3 method="post"
4 url="${url('my_account_notifications_toggle_visibility')}"
4 url="${h.route_path('my_account_notifications_toggle_visibility')}"
5 content-type="application/json"
5 content-type="application/json"
6 loading="{{changeNotificationsLoading}}"
6 loading="{{changeNotificationsLoading}}"
7 on-response="handleNotifications"
7 on-response="handleNotifications"
@@ -57,26 +57,6 b' class TestMyAccountController(TestContro'
57
57
58 response.mustcontain('value="test_admin')
58 response.mustcontain('value="test_admin')
59
59
60 def test_my_account_my_repos(self):
61 self.log_user()
62 response = self.app.get(url('my_account_repos'))
63 repos = Repository.query().filter(
64 Repository.user == User.get_by_username(
65 TEST_USER_ADMIN_LOGIN)).all()
66 for repo in repos:
67 response.mustcontain('"name_raw": "%s"' % repo.repo_name)
68
69 def test_my_account_my_watched(self):
70 self.log_user()
71 response = self.app.get(url('my_account_watched'))
72
73 repos = UserFollowing.query().filter(
74 UserFollowing.user == User.get_by_username(
75 TEST_USER_ADMIN_LOGIN)).all()
76 for repo in repos:
77 response.mustcontain(
78 '"name_raw": "%s"' % repo.follows_repository.repo_name)
79
80 @pytest.mark.backends("git", "hg")
60 @pytest.mark.backends("git", "hg")
81 def test_my_account_my_pullrequests(self, pr_util):
61 def test_my_account_my_pullrequests(self, pr_util):
82 self.log_user()
62 self.log_user()
@@ -89,8 +69,6 b' class TestMyAccountController(TestContro'
89 response.mustcontain('"name_raw": %s' % pr.pull_request_id)
69 response.mustcontain('"name_raw": %s' % pr.pull_request_id)
90 response.mustcontain('TestMyAccountPR')
70 response.mustcontain('TestMyAccountPR')
91
71
92
93
94 @pytest.mark.parametrize(
72 @pytest.mark.parametrize(
95 "name, attrs", [
73 "name, attrs", [
96 ('firstname', {'firstname': 'new_username'}),
74 ('firstname', {'firstname': 'new_username'}),
General Comments 0
You need to be logged in to leave comments. Login now