Show More
@@ -0,0 +1,27 b'' | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | ||
|
3 | # Copyright (C) 2016-2018 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_group_profile', | |
|
25 | pattern='/_profile_user_group/{user_group_name}') | |
|
26 | # Scan module for configuration decorators. | |
|
27 | config.scan('.views', ignore='.tests') |
@@ -0,0 +1,19 b'' | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | ||
|
3 | # Copyright (C) 2016-2018 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/ |
@@ -0,0 +1,76 b'' | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | ||
|
3 | # Copyright (C) 2010-2018 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 | from rhodecode.model.user_group import UserGroupModel | |
|
21 | from rhodecode.tests import ( | |
|
22 | TestController, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |
|
23 | from rhodecode.tests.fixture import Fixture | |
|
24 | from rhodecode.tests.utils import AssertResponse | |
|
25 | ||
|
26 | fixture = Fixture() | |
|
27 | ||
|
28 | ||
|
29 | def route_path(name, **kwargs): | |
|
30 | return '/_profile_user_group/{user_group_name}'.format(**kwargs) | |
|
31 | ||
|
32 | ||
|
33 | class TestUsersController(TestController): | |
|
34 | ||
|
35 | def test_user_group_profile(self, user_util): | |
|
36 | self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |
|
37 | user, usergroup = user_util.create_user_with_group() | |
|
38 | ||
|
39 | response = self.app.get(route_path('profile_user_group', user_group_name=usergroup.users_group_name)) | |
|
40 | response.mustcontain(usergroup.users_group_name) | |
|
41 | response.mustcontain(user.username) | |
|
42 | ||
|
43 | def test_user_can_check_own_group(self, user_util): | |
|
44 | user = user_util.create_user( | |
|
45 | TEST_USER_REGULAR_LOGIN, password=TEST_USER_REGULAR_PASS, email='testme@rhodecode.org') | |
|
46 | self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |
|
47 | usergroup = user_util.create_user_group(owner=user) | |
|
48 | response = self.app.get(route_path('profile_user_group', user_group_name=usergroup.users_group_name)) | |
|
49 | response.mustcontain(usergroup.users_group_name) | |
|
50 | response.mustcontain(user.username) | |
|
51 | ||
|
52 | def test_user_can_not_check_other_group(self, user_util): | |
|
53 | self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |
|
54 | user_group = user_util.create_user_group() | |
|
55 | UserGroupModel().grant_user_permission(user_group, self._get_logged_user(), 'usergroup.none') | |
|
56 | response = self.app.get(route_path('profile_user_group', user_group_name=user_group.users_group_name), status=404) | |
|
57 | assert response.status_code == 404 | |
|
58 | ||
|
59 | def test_another_user_can_check_if_he_is_in_group(self, user_util): | |
|
60 | self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |
|
61 | user = user_util.create_user( | |
|
62 | 'test-my-user', password='qweqwe', email='testme@rhodecode.org') | |
|
63 | user_group = user_util.create_user_group() | |
|
64 | UserGroupModel().add_user_to_group(user_group, user) | |
|
65 | UserGroupModel().grant_user_permission(user_group, self._get_logged_user(), 'usergroup.read') | |
|
66 | response = self.app.get(route_path('profile_user_group', user_group_name=user_group.users_group_name)) | |
|
67 | response.mustcontain(user_group.users_group_name) | |
|
68 | response.mustcontain(user.username) | |
|
69 | ||
|
70 | def test_with_anonymous_user(self, user_util): | |
|
71 | user = user_util.create_user( | |
|
72 | 'test-my-user', password='qweqwe', email='testme@rhodecode.org') | |
|
73 | user_group = user_util.create_user_group() | |
|
74 | UserGroupModel().add_user_to_group(user_group, user) | |
|
75 | response = self.app.get(route_path('profile_user_group', user_group_name=user_group.users_group_name), status=302) | |
|
76 | assert response.status_code == 302 No newline at end of file |
@@ -0,0 +1,53 b'' | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | ||
|
3 | # Copyright (C) 2016-2018 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 HasUserGroupPermissionAnyDecorator, LoginRequired, NotAnonymous | |
|
28 | from rhodecode.model.db import UserGroup, User | |
|
29 | ||
|
30 | ||
|
31 | log = logging.getLogger(__name__) | |
|
32 | ||
|
33 | ||
|
34 | class UserGroupProfileView(BaseAppView): | |
|
35 | ||
|
36 | @LoginRequired() | |
|
37 | @NotAnonymous() | |
|
38 | @HasUserGroupPermissionAnyDecorator('usergroup.read', 'usergroup.write', 'usergroup.admin',) | |
|
39 | @view_config( | |
|
40 | route_name='user_group_profile', request_method='GET', | |
|
41 | renderer='rhodecode:templates/user_group/user_group.mako') | |
|
42 | def user_group_profile(self): | |
|
43 | c = self._get_local_tmpl_context() | |
|
44 | c.active = 'profile' | |
|
45 | self.db_user_group_name = self.request.matchdict.get('user_group_name') | |
|
46 | c.user_group = UserGroup().get_by_group_name(self.db_user_group_name) | |
|
47 | if not c.user_group: | |
|
48 | raise HTTPNotFound() | |
|
49 | group_members_obj = sorted((x.user for x in c.user_group.members), | |
|
50 | key=lambda u: u.username.lower()) | |
|
51 | c.group_members = group_members_obj | |
|
52 | c.anonymous = self._rhodecode_user.username == User.DEFAULT_USER | |
|
53 | return self._get_template_context(c) |
@@ -0,0 +1,70 b'' | |||
|
1 | <%namespace name="base" file="/base/base.mako"/> | |
|
2 | ||
|
3 | <div class="panel panel-default user-profile"> | |
|
4 | <div class="panel-heading"> | |
|
5 | <h3 class="panel-title">${_('User group profile')}</h3> | |
|
6 | %if h.HasPermissionAny('hg.admin')(): | |
|
7 | ${h.link_to(_('Edit'), h.route_path('edit_user_group', user_group_id=c.user_group.users_group_id), class_='panel-edit')} | |
|
8 | %endif | |
|
9 | </div> | |
|
10 | ||
|
11 | <div class="panel-body user-profile-content"> | |
|
12 | ||
|
13 | <div class="fieldset"> | |
|
14 | <div class="left-label"> | |
|
15 | ${_('Group Name')}: | |
|
16 | </div> | |
|
17 | <div class="right-content"> | |
|
18 | ${c.user_group.users_group_name} | |
|
19 | </div> | |
|
20 | </div> | |
|
21 | <div class="fieldset"> | |
|
22 | <div class="left-label"> | |
|
23 | ${_('Owner')}: | |
|
24 | </div> | |
|
25 | <div class="group_member"> | |
|
26 | ${base.gravatar(c.user_group.user.email, 16)} | |
|
27 | <span class="username user">${h.link_to_user(c.user_group.user)}</span> | |
|
28 | ||
|
29 | </div> | |
|
30 | </div> | |
|
31 | <div class="fieldset"> | |
|
32 | <div class="left-label"> | |
|
33 | ${_('Active')}: | |
|
34 | </div> | |
|
35 | <div class="right-content"> | |
|
36 | ${c.user_group.users_group_active} | |
|
37 | </div> | |
|
38 | </div> | |
|
39 | % if not c.anonymous: | |
|
40 | <div class="fieldset"> | |
|
41 | <div class="left-label"> | |
|
42 | ${_('Members')}: | |
|
43 | </div> | |
|
44 | <div class="right-content"> | |
|
45 | <table id="group_members_placeholder" class="rctable group_members"> | |
|
46 | <th>${_('Username')}</th> | |
|
47 | % if c.group_members: | |
|
48 | % for user in c.group_members: | |
|
49 | <tr> | |
|
50 | <td id="member_user_${user.user_id}" class="td-author"> | |
|
51 | <div class="group_member"> | |
|
52 | ${base.gravatar(user.email, 16)} | |
|
53 | <span class="username user">${h.link_to(h.person(user), h.route_path('user_edit',user_id=user.user_id))}</span> | |
|
54 | <input type="hidden" name="__start__" value="member:mapping"> | |
|
55 | <input type="hidden" name="member_user_id" value="${user.user_id}"> | |
|
56 | <input type="hidden" name="type" value="existing" id="member_${user.user_id}"> | |
|
57 | <input type="hidden" name="__end__" value="member:mapping"> | |
|
58 | </div> | |
|
59 | </td> | |
|
60 | </tr> | |
|
61 | % endfor | |
|
62 | % else: | |
|
63 | <tr><td colspan="2">${_('No members yet')}</td></tr> | |
|
64 | % endif | |
|
65 | </table> | |
|
66 | </div> | |
|
67 | </div> | |
|
68 | % endif | |
|
69 | </div> | |
|
70 | </div> No newline at end of file |
@@ -0,0 +1,46 b'' | |||
|
1 | <%inherit file="/base/base.mako"/> | |
|
2 | ||
|
3 | <%def name="title()"> | |
|
4 | ${_('User group')}: ${c.user_group.users_group_name} | |
|
5 | %if c.rhodecode_name: | |
|
6 | · ${h.branding(c.rhodecode_name)} | |
|
7 | %endif | |
|
8 | </%def> | |
|
9 | ||
|
10 | <%def name="breadcrumbs_links()"> | |
|
11 | ${_('User group')}: ${c.user_group.users_group_name} | |
|
12 | </%def> | |
|
13 | ||
|
14 | <%def name="menu_bar_nav()"> | |
|
15 | ${self.menu_items(active='my_account')} | |
|
16 | </%def> | |
|
17 | ||
|
18 | <%def name="main()"> | |
|
19 | <div class="box"> | |
|
20 | <div class="title"> | |
|
21 | ${self.breadcrumbs()} | |
|
22 | </div> | |
|
23 | ||
|
24 | <div class="sidebar-col-wrapper scw-small"> | |
|
25 | ##main | |
|
26 | <div class="sidebar"> | |
|
27 | <ul class="nav nav-pills nav-stacked"> | |
|
28 | <li class="${'active' if c.active=='profile' else ''}"> | |
|
29 | <a href="${h.route_path('user_group_profile', user_group_name=c.user_group.users_group_name)}">${_('User Group Profile')}</a></li> | |
|
30 | ## These placeholders are here only for styling purposes. For every new item added to the list, you should remove one placeholder | |
|
31 | <li class="placeholder"><a href="#" style="visibility: hidden;">placeholder</a></li> | |
|
32 | <li class="placeholder"><a href="#" style="visibility: hidden;">placeholder</a></li> | |
|
33 | <li class="placeholder"><a href="#" style="visibility: hidden;">placeholder</a></li> | |
|
34 | <li class="placeholder"><a href="#" style="visibility: hidden;">placeholder</a></li> | |
|
35 | <li class="placeholder"><a href="#" style="visibility: hidden;">placeholder</a></li> | |
|
36 | <li class="placeholder"><a href="#" style="visibility: hidden;">placeholder</a></li> | |
|
37 | </ul> | |
|
38 | </div> | |
|
39 | ||
|
40 | <div class="main-content-full-width"> | |
|
41 | <%include file="/user_group/${c.active}.mako"/> | |
|
42 | </div> | |
|
43 | </div> | |
|
44 | </div> | |
|
45 | ||
|
46 | </%def> |
@@ -226,6 +226,7 b' def includeme(config):' | |||
|
226 | 226 | config.include('rhodecode.apps.user_group') |
|
227 | 227 | config.include('rhodecode.apps.search') |
|
228 | 228 | config.include('rhodecode.apps.user_profile') |
|
229 | config.include('rhodecode.apps.user_group_profile') | |
|
229 | 230 | config.include('rhodecode.apps.my_account') |
|
230 | 231 | config.include('rhodecode.apps.svn_support') |
|
231 | 232 | config.include('rhodecode.apps.ssh_support') |
@@ -896,6 +896,13 b' def link_to_user(author, length=0, **kwa' | |||
|
896 | 896 | return escape(display_person) |
|
897 | 897 | |
|
898 | 898 | |
|
899 | def link_to_group(users_group_name, **kwargs): | |
|
900 | return link_to( | |
|
901 | escape(users_group_name), | |
|
902 | route_path('user_group_profile', user_group_name=users_group_name), | |
|
903 | **kwargs) | |
|
904 | ||
|
905 | ||
|
899 | 906 | def person(author, show_attr="username_and_name"): |
|
900 | 907 | user = discover_user(author) |
|
901 | 908 | if user: |
@@ -134,13 +134,17 b' def get_user_group_slug(request):' | |||
|
134 | 134 | elif getattr(request, 'matchdict', None): |
|
135 | 135 | # pyramid |
|
136 | 136 | _user_group = request.matchdict.get('user_group_id') |
|
137 | ||
|
137 | _user_group_name = request.matchdict.get('user_group_name') | |
|
138 | 138 | try: |
|
139 | if _user_group: | |
|
139 | 140 | _user_group = UserGroup.get(_user_group) |
|
141 | elif _user_group_name: | |
|
142 | _user_group = UserGroup.get_by_group_name(_user_group_name) | |
|
143 | ||
|
140 | 144 | if _user_group: |
|
141 | 145 | _user_group = _user_group.users_group_name |
|
142 | 146 | except Exception: |
|
143 | log.exception('Failed to get user group by id') | |
|
147 | log.exception('Failed to get user group by id and name') | |
|
144 | 148 | # catch all failures here |
|
145 | 149 | return None |
|
146 | 150 |
@@ -98,7 +98,7 b'' | |||
|
98 | 98 | ${_user_group.users_group_name} |
|
99 | 99 | </a> |
|
100 | 100 | %else: |
|
101 | ${_user_group.users_group_name} | |
|
101 | ${h.link_to_group(_user_group.users_group_name)} | |
|
102 | 102 | %endif |
|
103 | 103 | </td> |
|
104 | 104 | <td class="td-action"> |
General Comments 0
You need to be logged in to leave comments.
Login now