my-account: moved few my account views into pyramid.

This commit is contained in:
Marcin Kuzminski 2017-06-20 00:11:36 +02:00
parent e919908333
commit 214e9059ec
9 changed files with 197 additions and 104 deletions

View file

@ -56,6 +56,26 @@ def includeme(config):
name='my_account_emails_delete',
pattern=ADMIN_PREFIX + '/my_account/emails/delete')
config.add_route(
name='my_account_repos',
pattern=ADMIN_PREFIX + '/my_account/repos')
config.add_route(
name='my_account_watched',
pattern=ADMIN_PREFIX + '/my_account/watched')
config.add_route(
name='my_account_perms',
pattern=ADMIN_PREFIX + '/my_account/perms')
config.add_route(
name='my_account_notifications',
pattern=ADMIN_PREFIX + '/my_account/notifications')
config.add_route(
name='my_account_notifications_toggle_visibility',
pattern=ADMIN_PREFIX + '/my_account/toggle_visibility')
# channelstream test
config.add_route(
name='my_account_notifications_test_channelstream',

View file

@ -0,0 +1,76 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2010-2017 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import pytest
from rhodecode.apps._base import ADMIN_PREFIX
from rhodecode.model.db import User, UserEmailMap, Repository, UserFollowing
from rhodecode.tests import (
TestController, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_EMAIL,
assert_session_flash)
from rhodecode.tests.fixture import Fixture
fixture = Fixture()
def route_path(name, **kwargs):
return {
'my_account_repos':
ADMIN_PREFIX + '/my_account/repos',
'my_account_watched':
ADMIN_PREFIX + '/my_account/watched',
'my_account_perms':
ADMIN_PREFIX + '/my_account/perms',
'my_account_notifications':
ADMIN_PREFIX + '/my_account/notifications',
}[name].format(**kwargs)
class TestMyAccountSimpleViews(TestController):
def test_my_account_my_repos(self, autologin_user):
response = self.app.get(route_path('my_account_repos'))
repos = Repository.query().filter(
Repository.user == User.get_by_username(
TEST_USER_ADMIN_LOGIN)).all()
for repo in repos:
response.mustcontain('"name_raw": "%s"' % repo.repo_name)
def test_my_account_my_watched(self, autologin_user):
response = self.app.get(route_path('my_account_watched'))
repos = UserFollowing.query().filter(
UserFollowing.user == User.get_by_username(
TEST_USER_ADMIN_LOGIN)).all()
for repo in repos:
response.mustcontain(
'"name_raw": "%s"' % repo.follows_repository.repo_name)
def test_my_account_perms(self, autologin_user):
response = self.app.get(route_path('my_account_perms'))
assert_response = response.assert_response()
assert assert_response.get_elements('.perm_tag.none')
assert assert_response.get_elements('.perm_tag.read')
assert assert_response.get_elements('.perm_tag.write')
assert assert_response.get_elements('.perm_tag.admin')
def test_my_account_notifications(self, autologin_user):
response = self.app.get(route_path('my_account_notifications'))
response.mustcontain('Test flash message')

View file

@ -28,14 +28,18 @@ from pyramid.view import view_config
from rhodecode.apps._base import BaseAppView
from rhodecode import forms
from rhodecode.lib import helpers as h
from rhodecode.lib.ext_json import json
from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired
from rhodecode.lib.channelstream import channelstream_request, \
ChannelstreamException
from rhodecode.lib.utils2 import safe_int, md5
from rhodecode.model.auth_token import AuthTokenModel
from rhodecode.model.db import UserEmailMap
from rhodecode.model.db import (
Repository, PullRequest, UserEmailMap, User, UserFollowing, joinedload)
from rhodecode.model.meta import Session
from rhodecode.model.scm import RepoList
from rhodecode.model.user import UserModel
from rhodecode.model.repo import RepoModel
from rhodecode.model.validation_schema.schemas import user_schema
log = logging.getLogger(__name__)
@ -290,3 +294,85 @@ class MyAccountView(BaseAppView):
return {"response": 'ERROR: {}'.format(e.__class__.__name__)}
return {"response": 'Channelstream data sent. '
'You should see a new live message now.'}
def _load_my_repos_data(self, watched=False):
if watched:
admin = False
follows_repos = Session().query(UserFollowing)\
.filter(UserFollowing.user_id == self._rhodecode_user.user_id)\
.options(joinedload(UserFollowing.follows_repository))\
.all()
repo_list = [x.follows_repository for x in follows_repos]
else:
admin = True
repo_list = Repository.get_all_repos(
user_id=self._rhodecode_user.user_id)
repo_list = RepoList(repo_list, perm_set=[
'repository.read', 'repository.write', 'repository.admin'])
repos_data = RepoModel().get_repos_as_dict(
repo_list=repo_list, admin=admin)
# json used to render the grid
return json.dumps(repos_data)
@LoginRequired()
@NotAnonymous()
@view_config(
route_name='my_account_repos', request_method='GET',
renderer='rhodecode:templates/admin/my_account/my_account.mako')
def my_account_repos(self):
c = self.load_default_context()
c.active = 'repos'
# json used to render the grid
c.data = self._load_my_repos_data()
return self._get_template_context(c)
@LoginRequired()
@NotAnonymous()
@view_config(
route_name='my_account_watched', request_method='GET',
renderer='rhodecode:templates/admin/my_account/my_account.mako')
def my_account_watched(self):
c = self.load_default_context()
c.active = 'watched'
# json used to render the grid
c.data = self._load_my_repos_data(watched=True)
return self._get_template_context(c)
@LoginRequired()
@NotAnonymous()
@view_config(
route_name='my_account_perms', request_method='GET',
renderer='rhodecode:templates/admin/my_account/my_account.mako')
def my_account_perms(self):
c = self.load_default_context()
c.active = 'perms'
c.perm_user = c.auth_user
return self._get_template_context(c)
@LoginRequired()
@NotAnonymous()
@view_config(
route_name='my_account_notifications', request_method='GET',
renderer='rhodecode:templates/admin/my_account/my_account.mako')
def my_notifications(self):
c = self.load_default_context()
c.active = 'notifications'
return self._get_template_context(c)
@LoginRequired()
@NotAnonymous()
@CSRFRequired()
@view_config(
route_name='my_account_notifications_toggle_visibility',
request_method='POST', renderer='json_ext')
def my_notifications_toggle_visibility(self):
user = self._rhodecode_db_user
new_status = not user.user_data.get('notification_status', True)
user.update_userdata(notification_status=new_status)
Session().commit()
return user.user_data['notification_status']

View file

@ -485,26 +485,9 @@ def make_map(config):
m.connect('my_account_password', '/my_account/password',
action='my_account_password', conditions={'method': ['GET']})
m.connect('my_account_repos', '/my_account/repos',
action='my_account_repos', conditions={'method': ['GET']})
m.connect('my_account_watched', '/my_account/watched',
action='my_account_watched', conditions={'method': ['GET']})
m.connect('my_account_pullrequests', '/my_account/pull_requests',
action='my_account_pullrequests', conditions={'method': ['GET']})
m.connect('my_account_perms', '/my_account/perms',
action='my_account_perms', conditions={'method': ['GET']})
m.connect('my_account_notifications', '/my_account/notifications',
action='my_notifications',
conditions={'method': ['GET']})
m.connect('my_account_notifications_toggle_visibility',
'/my_account/toggle_visibility',
action='my_notifications_toggle_visibility',
conditions={'method': ['POST']})
# NOTIFICATION REST ROUTES
with rmap.submapper(path_prefix=ADMIN_PREFIX,
controller='admin/notifications') as m:

View file

@ -29,26 +29,22 @@ import formencode
from formencode import htmlfill
from pyramid.httpexceptions import HTTPFound
from pylons import request, tmpl_context as c, url
from pylons import request, tmpl_context as c
from pylons.controllers.util import redirect
from pylons.i18n.translation import _
from sqlalchemy.orm import joinedload
from rhodecode.lib import helpers as h
from rhodecode.lib import auth
from rhodecode.lib.auth import (
LoginRequired, NotAnonymous, AuthUser)
from rhodecode.lib.base import BaseController, render
from rhodecode.lib.utils import jsonify
from rhodecode.lib.utils2 import safe_int, str2bool
from rhodecode.lib.ext_json import json
from rhodecode.model.db import (
Repository, PullRequest, UserEmailMap, User, UserFollowing)
from rhodecode.model.forms import UserForm
from rhodecode.model.scm import RepoList
from rhodecode.model.user import UserModel
from rhodecode.model.repo import RepoModel
from rhodecode.model.meta import Session
from rhodecode.model.pull_request import PullRequestModel
from rhodecode.model.comment import CommentsModel
@ -78,26 +74,6 @@ class MyAccountController(BaseController):
c.auth_user = AuthUser(
user_id=c.rhodecode_user.user_id, ip_addr=self.ip_addr)
def _load_my_repos_data(self, watched=False):
if watched:
admin = False
follows_repos = Session().query(UserFollowing)\
.filter(UserFollowing.user_id == c.rhodecode_user.user_id)\
.options(joinedload(UserFollowing.follows_repository))\
.all()
repo_list = [x.follows_repository for x in follows_repos]
else:
admin = True
repo_list = Repository.get_all_repos(
user_id=c.rhodecode_user.user_id)
repo_list = RepoList(repo_list, perm_set=[
'repository.read', 'repository.write', 'repository.admin'])
repos_data = RepoModel().get_repos_as_dict(
repo_list=repo_list, admin=admin)
# json used to render the grid
return json.dumps(repos_data)
@auth.CSRFRequired()
def my_account_update(self):
"""
@ -177,29 +153,6 @@ class MyAccountController(BaseController):
force_defaults=False
)
def my_account_repos(self):
c.active = 'repos'
self.__load_data()
# json used to render the grid
c.data = self._load_my_repos_data()
return render('admin/my_account/my_account.mako')
def my_account_watched(self):
c.active = 'watched'
self.__load_data()
# json used to render the grid
c.data = self._load_my_repos_data(watched=True)
return render('admin/my_account/my_account.mako')
def my_account_perms(self):
c.active = 'perms'
self.__load_data()
c.perm_user = c.auth_user
return render('admin/my_account/my_account.mako')
def _extract_ordering(self, request):
column_index = safe_int(request.GET.get('order[0][column]'))
order_dir = request.GET.get('order[0][dir]', 'desc')
@ -280,15 +233,4 @@ class MyAccountController(BaseController):
else:
return json.dumps(data)
def my_notifications(self):
c.active = 'notifications'
return render('admin/my_account/my_account.mako')
@auth.CSRFRequired()
@jsonify
def my_notifications_toggle_visibility(self):
user = c.rhodecode_user.get_instance()
new_status = not user.user_data.get('notification_status', True)
user.update_userdata(notification_status=new_status)
Session().commit()
return user.user_data['notification_status']

View file

@ -134,6 +134,14 @@ function registerRCRoutes() {
pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
pyroutes.register('apiv2', '/_admin/api', []);
}

View file

@ -35,11 +35,11 @@
<li class="${'active' if c.active=='oauth' else ''}"><a href="${my_account_oauth_url}">${_('OAuth Identities')}</a></li>
% endif
<li class="${'active' if c.active=='emails' else ''}"><a href="${h.route_path('my_account_emails')}">${_('Emails')}</a></li>
<li class="${'active' if c.active=='repos' else ''}"><a href="${h.url('my_account_repos')}">${_('Repositories')}</a></li>
<li class="${'active' if c.active=='watched' else ''}"><a href="${h.url('my_account_watched')}">${_('Watched')}</a></li>
<li class="${'active' if c.active=='repos' else ''}"><a href="${h.route_path('my_account_repos')}">${_('Repositories')}</a></li>
<li class="${'active' if c.active=='watched' else ''}"><a href="${h.route_path('my_account_watched')}">${_('Watched')}</a></li>
<li class="${'active' if c.active=='pullrequests' else ''}"><a href="${h.url('my_account_pullrequests')}">${_('Pull Requests')}</a></li>
<li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('my_account_perms')}">${_('Permissions')}</a></li>
<li class="${'active' if c.active=='my_notifications' else ''}"><a href="${h.url('my_account_notifications')}">${_('Live Notifications')}</a></li>
<li class="${'active' if c.active=='perms' else ''}"><a href="${h.route_path('my_account_perms')}">${_('Permissions')}</a></li>
<li class="${'active' if c.active=='my_notifications' else ''}"><a href="${h.route_path('my_account_notifications')}">${_('Live Notifications')}</a></li>
</ul>
</div>

View file

@ -1,7 +1,7 @@
<template is="dom-bind" id="notificationsPage">
<iron-ajax id="toggleNotifications"
method="post"
url="${url('my_account_notifications_toggle_visibility')}"
url="${h.route_path('my_account_notifications_toggle_visibility')}"
content-type="application/json"
loading="{{changeNotificationsLoading}}"
on-response="handleNotifications"

View file

@ -57,26 +57,6 @@ class TestMyAccountController(TestController):
response.mustcontain('value="test_admin')
def test_my_account_my_repos(self):
self.log_user()
response = self.app.get(url('my_account_repos'))
repos = Repository.query().filter(
Repository.user == User.get_by_username(
TEST_USER_ADMIN_LOGIN)).all()
for repo in repos:
response.mustcontain('"name_raw": "%s"' % repo.repo_name)
def test_my_account_my_watched(self):
self.log_user()
response = self.app.get(url('my_account_watched'))
repos = UserFollowing.query().filter(
UserFollowing.user == User.get_by_username(
TEST_USER_ADMIN_LOGIN)).all()
for repo in repos:
response.mustcontain(
'"name_raw": "%s"' % repo.follows_repository.repo_name)
@pytest.mark.backends("git", "hg")
def test_my_account_my_pullrequests(self, pr_util):
self.log_user()
@ -89,8 +69,6 @@ class TestMyAccountController(TestController):
response.mustcontain('"name_raw": %s' % pr.pull_request_id)
response.mustcontain('TestMyAccountPR')
@pytest.mark.parametrize(
"name, attrs", [
('firstname', {'firstname': 'new_username'}),