Show More
@@ -0,0 +1,53 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 | ||
|
21 | import logging | |
|
22 | from pylons import tmpl_context as c | |
|
23 | ||
|
24 | from rhodecode.lib.utils2 import StrictAttributeDict | |
|
25 | ||
|
26 | log = logging.getLogger(__name__) | |
|
27 | ||
|
28 | ||
|
29 | class TemplateArgs(StrictAttributeDict): | |
|
30 | pass | |
|
31 | ||
|
32 | ||
|
33 | class BaseAppView(object): | |
|
34 | ||
|
35 | def __init__(self, context, request): | |
|
36 | self.request = request | |
|
37 | self.context = context | |
|
38 | self.session = request.session | |
|
39 | self._rhodecode_user = request.user | |
|
40 | ||
|
41 | def _get_local_tmpl_context(self): | |
|
42 | return TemplateArgs() | |
|
43 | ||
|
44 | def _get_template_context(self, tmpl_args): | |
|
45 | ||
|
46 | for k, v in tmpl_args.items(): | |
|
47 | setattr(c, k, v) | |
|
48 | ||
|
49 | return { | |
|
50 | 'defaults': {}, | |
|
51 | 'errors': {}, | |
|
52 | } | |
|
53 |
@@ -0,0 +1,28 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 | ||
|
21 | ||
|
22 | def includeme(config): | |
|
23 | config.add_route( | |
|
24 | name='user_profile', | |
|
25 | pattern='/_profiles/{username}') | |
|
26 | ||
|
27 | # Scan module for configuration decorators. | |
|
28 | config.scan() |
|
1 | NO CONTENT: new file 100644 |
@@ -0,0 +1,75 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.model.db import User | |
|
24 | from rhodecode.tests import ( | |
|
25 | TestController, TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS, | |
|
26 | TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |
|
27 | from rhodecode.tests.fixture import Fixture | |
|
28 | from rhodecode.tests.utils import AssertResponse | |
|
29 | ||
|
30 | fixture = Fixture() | |
|
31 | ||
|
32 | ||
|
33 | def route_path(name, **kwargs): | |
|
34 | return '/_profiles/{username}'.format(**kwargs) | |
|
35 | ||
|
36 | ||
|
37 | class TestUsersController(TestController): | |
|
38 | ||
|
39 | def test_user_profile(self, user_util): | |
|
40 | edit_link_css = '.user-profile .panel-edit' | |
|
41 | self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |
|
42 | user = user_util.create_user( | |
|
43 | 'test-my-user', password='qweqwe', email='testme@rhodecode.org') | |
|
44 | username = user.username | |
|
45 | ||
|
46 | response = self.app.get(route_path('user_profile', username=username)) | |
|
47 | response.mustcontain('testme') | |
|
48 | response.mustcontain('testme@rhodecode.org') | |
|
49 | assert_response = AssertResponse(response) | |
|
50 | assert_response.no_element_exists(edit_link_css) | |
|
51 | ||
|
52 | # edit should be available to superadmin users | |
|
53 | self.logout_user() | |
|
54 | self.log_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS) | |
|
55 | response = self.app.get(route_path('user_profile', username=username)) | |
|
56 | assert_response = AssertResponse(response) | |
|
57 | assert_response.element_contains(edit_link_css, 'Edit') | |
|
58 | ||
|
59 | def test_user_profile_not_available(self, user_util): | |
|
60 | user = user_util.create_user() | |
|
61 | username = user.username | |
|
62 | ||
|
63 | # not logged in, redirect | |
|
64 | self.app.get(route_path('user_profile', username=username), status=302) | |
|
65 | ||
|
66 | self.log_user() | |
|
67 | # after log-in show | |
|
68 | self.app.get(route_path('user_profile', username=username), status=200) | |
|
69 | ||
|
70 | # default user, not allowed to show it | |
|
71 | self.app.get( | |
|
72 | route_path('user_profile', username=User.DEFAULT_USER), status=404) | |
|
73 | ||
|
74 | # actual 404 | |
|
75 | self.app.get(route_path('user_profile', username='unknown'), status=404) |
@@ -0,0 +1,53 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 | ||
|
21 | import logging | |
|
22 | ||
|
23 | from pyramid.httpexceptions import HTTPNotFound | |
|
24 | from pyramid.view import view_config | |
|
25 | ||
|
26 | from rhodecode.apps._base import BaseAppView | |
|
27 | from rhodecode.lib.auth import LoginRequired, NotAnonymous | |
|
28 | ||
|
29 | from rhodecode.model.db import User | |
|
30 | from rhodecode.model.user import UserModel | |
|
31 | ||
|
32 | log = logging.getLogger(__name__) | |
|
33 | ||
|
34 | ||
|
35 | class UserProfileView(BaseAppView): | |
|
36 | ||
|
37 | @LoginRequired() | |
|
38 | @NotAnonymous() | |
|
39 | @view_config( | |
|
40 | route_name='user_profile', request_method='GET', | |
|
41 | renderer='rhodecode:templates/users/user.mako') | |
|
42 | def login(self): | |
|
43 | # register local template context | |
|
44 | c = self._get_local_tmpl_context() | |
|
45 | c.active = 'user_profile' | |
|
46 | ||
|
47 | username = self.request.matchdict.get('username') | |
|
48 | ||
|
49 | c.user = UserModel().get_by_username(username) | |
|
50 | if not c.user or c.user.username == User.DEFAULT_USER: | |
|
51 | raise HTTPNotFound() | |
|
52 | ||
|
53 | return self._get_template_context(c) |
@@ -281,7 +281,11 b' def includeme(config):' | |||
|
281 | 281 | config.include('rhodecode.admin') |
|
282 | 282 | config.include('rhodecode.authentication') |
|
283 | 283 | config.include('rhodecode.integrations') |
|
284 | ||
|
285 | # apps | |
|
284 | 286 | config.include('rhodecode.apps.login') |
|
287 | config.include('rhodecode.apps.user_profile') | |
|
288 | ||
|
285 | 289 | config.include('rhodecode.tweens') |
|
286 | 290 | config.include('rhodecode.api') |
|
287 | 291 | config.include('rhodecode.svn_support') |
@@ -92,7 +92,7 b' class JSRoutesMapper(Mapper):' | |||
|
92 | 92 | def _extract_route_information(self, route): |
|
93 | 93 | """ |
|
94 | 94 | Convert a route into tuple(name, path, args), eg: |
|
95 |
('user |
|
|
95 | ('show_user', '/profile/%(username)s', ['username']) | |
|
96 | 96 | """ |
|
97 | 97 | routepath = route.routepath |
|
98 | 98 | def replace(matchobj): |
@@ -198,10 +198,6 b' def make_map(config):' | |||
|
198 | 198 | rmap.connect('user_group_autocomplete_data', '/_user_groups', controller='home', |
|
199 | 199 | action='user_group_autocomplete_data', jsroute=True) |
|
200 | 200 | |
|
201 | rmap.connect( | |
|
202 | 'user_profile', '/_profiles/{username}', controller='users', | |
|
203 | action='user_profile') | |
|
204 | ||
|
205 | 201 | # TODO: johbo: Static links, to be replaced by our redirection mechanism |
|
206 | 202 | rmap.connect('rst_help', |
|
207 | 203 | 'http://docutils.sourceforge.net/docs/user/rst/quickref.html', |
@@ -871,7 +871,7 b' def link_to_user(author, length=0, **kwa' | |||
|
871 | 871 | if user: |
|
872 | 872 | return link_to( |
|
873 | 873 | escape(display_person), |
|
874 |
|
|
|
874 | route_path('user_profile', username=user.username), | |
|
875 | 875 | **kwargs) |
|
876 | 876 | else: |
|
877 | 877 | return escape(display_person) |
@@ -12,16 +12,16 b' A new user `${user.username}` has regist' | |||
|
12 | 12 | - Username: ${user.username} |
|
13 | 13 | - Full Name: ${user.firstname} ${user.lastname} |
|
14 | 14 | - Email: ${user.email} |
|
15 |
- Profile link: ${h. |
|
|
15 | - Profile link: ${h.route_path('user_profile', username=user.username, qualified=True)} | |
|
16 | 16 | |
|
17 | 17 | ${self.plaintext_footer()} |
|
18 | 18 | </%def> |
|
19 | 19 | |
|
20 | 20 | ## BODY GOES BELOW |
|
21 | 21 | <table style="text-align:left;vertical-align:middle;"> |
|
22 |
<tr><td colspan="2" style="width:100%;padding-bottom:15px;border-bottom:1px solid #dbd9da;"><h4><a href="${h. |
|
|
22 | <tr><td colspan="2" style="width:100%;padding-bottom:15px;border-bottom:1px solid #dbd9da;"><h4><a href="${h.route_path('user_profile', username=user.username, qualified=True)}" style="color:#427cc9;text-decoration:none;cursor:pointer">${_('New user %(user)s has registered on %(date)s') % {'user': user.username, 'date': h.format_date(date)}}</a></h4></td></tr> | |
|
23 | 23 | <tr><td style="padding-right:20px;padding-top:20px;">${_('Username')}</td><td style="line-height:1;padding-top:20px;"><img style="margin-bottom:-5px;text-align:left;border:1px solid #dbd9da" src="${h.gravatar_url(user.email, 16)}" height="16" width="16"> ${user.username}</td></tr> |
|
24 | 24 | <tr><td style="padding-right:20px;">${_('Full Name')}</td><td>${user.firstname} ${user.lastname}</td></tr> |
|
25 | 25 | <tr><td style="padding-right:20px;">${_('Email')}</td><td>${user.email}</td></tr> |
|
26 |
<tr><td style="padding-right:20px;">${_('Profile')}</td><td><a href="${h. |
|
|
26 | <tr><td style="padding-right:20px;">${_('Profile')}</td><td><a href="${h.route_path('user_profile', username=user.username, qualified=True)}">${h.route_path('user_profile', username=user.username, qualified=True)}</a></td></tr> | |
|
27 | 27 | </table> No newline at end of file |
@@ -12,7 +12,7 b'' | |||
|
12 | 12 | </%def> |
|
13 | 13 | |
|
14 | 14 | <%def name="menu_bar_nav()"> |
|
15 |
${self.menu_items(active=' |
|
|
15 | ${self.menu_items(active='my_account')} | |
|
16 | 16 | </%def> |
|
17 | 17 | |
|
18 | 18 | <%def name="main()"> |
@@ -26,7 +26,7 b'' | |||
|
26 | 26 | <div class="sidebar"> |
|
27 | 27 | <ul class="nav nav-pills nav-stacked"> |
|
28 | 28 | <li class="${'active' if c.active=='user_profile' else ''}"> |
|
29 |
<a href="${h. |
|
|
29 | <a href="${h.route_path('user_profile', username=c.user.username)}">${_('Profile')}</a></li> | |
|
30 | 30 | ## These placeholders are here only for styling purposes. For every new item added to the list, you should remove one placeholder |
|
31 | 31 | <li class="placeholder"><a href="#" style="visibility: hidden;">placeholder</a></li> |
|
32 | 32 | <li class="placeholder"><a href="#" style="visibility: hidden;">placeholder</a></li> |
@@ -276,7 +276,7 b' class TestGistsController(TestController' | |||
|
276 | 276 | assert_response = AssertResponse(response) |
|
277 | 277 | assert_response.element_equals_to( |
|
278 | 278 | 'div.rc-user span.user', |
|
279 | '<span class="user"> %s</span>' % h.link_to_user('test_admin')) | |
|
279 | '<a href="/_profiles/test_admin">test_admin</a></span>') | |
|
280 | 280 | |
|
281 | 281 | response.mustcontain('gist-desc') |
|
282 | 282 | |
@@ -299,7 +299,7 b' class TestGistsController(TestController' | |||
|
299 | 299 | assert_response = AssertResponse(response) |
|
300 | 300 | assert_response.element_equals_to( |
|
301 | 301 | 'div.rc-user span.user', |
|
302 | '<span class="user"> %s</span>' % h.link_to_user('test_admin')) | |
|
302 | '<a href="/_profiles/test_admin">test_admin</a></span>') | |
|
303 | 303 | response.mustcontain('gist-desc') |
|
304 | 304 | |
|
305 | 305 | def test_show_as_raw(self, create_gist): |
|
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