Show More
@@ -0,0 +1,39 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 | from rhodecode.apps._base import ADMIN_PREFIX | |
|
23 | ||
|
24 | ||
|
25 | def includeme(config): | |
|
26 | config.add_route( | |
|
27 | name='my_account_auth_tokens', | |
|
28 | pattern=ADMIN_PREFIX + '/my_account/auth_tokens') | |
|
29 | config.add_route( | |
|
30 | name='my_account_auth_tokens_add', | |
|
31 | pattern=ADMIN_PREFIX + '/my_account/auth_tokens/new', | |
|
32 | ) | |
|
33 | config.add_route( | |
|
34 | name='my_account_auth_tokens_delete', | |
|
35 | pattern=ADMIN_PREFIX + '/my_account/auth_tokens/delete', | |
|
36 | ) | |
|
37 | ||
|
38 | # Scan module for configuration decorators. | |
|
39 | config.scan() |
@@ -0,0 +1,19 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/ |
@@ -0,0 +1,111 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 | |
|
25 | from rhodecode.tests import ( | |
|
26 | TestController, TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS, | |
|
27 | TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, assert_session_flash) | |
|
28 | from rhodecode.tests.fixture import Fixture | |
|
29 | from rhodecode.tests.utils import AssertResponse | |
|
30 | ||
|
31 | fixture = Fixture() | |
|
32 | ||
|
33 | ||
|
34 | def route_path(name, **kwargs): | |
|
35 | return { | |
|
36 | 'my_account_auth_tokens': | |
|
37 | ADMIN_PREFIX + '/my_account/auth_tokens', | |
|
38 | 'my_account_auth_tokens_add': | |
|
39 | ADMIN_PREFIX + '/my_account/auth_tokens/new', | |
|
40 | 'my_account_auth_tokens_delete': | |
|
41 | ADMIN_PREFIX + '/my_account/auth_tokens/delete', | |
|
42 | }[name].format(**kwargs) | |
|
43 | ||
|
44 | ||
|
45 | class TestMyAccountAuthTokens(TestController): | |
|
46 | ||
|
47 | def test_my_account_auth_tokens(self): | |
|
48 | usr = self.log_user('test_regular2', 'test12') | |
|
49 | user = User.get(usr['user_id']) | |
|
50 | response = self.app.get(route_path('my_account_auth_tokens')) | |
|
51 | for token in user.auth_tokens: | |
|
52 | response.mustcontain(token) | |
|
53 | response.mustcontain('never') | |
|
54 | ||
|
55 | def test_my_account_add_auth_tokens_wrong_csrf(self, user_util): | |
|
56 | user = user_util.create_user(password='qweqwe') | |
|
57 | self.log_user(user.username, 'qweqwe') | |
|
58 | ||
|
59 | self.app.post( | |
|
60 | route_path('my_account_auth_tokens_add'), | |
|
61 | {'description': 'desc', 'lifetime': -1}, status=403) | |
|
62 | ||
|
63 | @pytest.mark.parametrize("desc, lifetime", [ | |
|
64 | ('forever', -1), | |
|
65 | ('5mins', 60*5), | |
|
66 | ('30days', 60*60*24*30), | |
|
67 | ]) | |
|
68 | def test_my_account_add_auth_tokens(self, desc, lifetime, user_util): | |
|
69 | user = user_util.create_user(password='qweqwe') | |
|
70 | user_id = user.user_id | |
|
71 | self.log_user(user.username, 'qweqwe') | |
|
72 | ||
|
73 | response = self.app.post( | |
|
74 | route_path('my_account_auth_tokens_add'), | |
|
75 | {'description': desc, 'lifetime': lifetime, | |
|
76 | 'csrf_token': self.csrf_token}) | |
|
77 | assert_session_flash(response, 'Auth token successfully created') | |
|
78 | ||
|
79 | response = response.follow() | |
|
80 | user = User.get(user_id) | |
|
81 | for auth_token in user.auth_tokens: | |
|
82 | response.mustcontain(auth_token) | |
|
83 | ||
|
84 | def test_my_account_delete_auth_token(self, user_util): | |
|
85 | user = user_util.create_user(password='qweqwe') | |
|
86 | user_id = user.user_id | |
|
87 | self.log_user(user.username, 'qweqwe') | |
|
88 | ||
|
89 | user = User.get(user_id) | |
|
90 | keys = user.extra_auth_tokens | |
|
91 | assert 2 == len(keys) | |
|
92 | ||
|
93 | response = self.app.post( | |
|
94 | route_path('my_account_auth_tokens_add'), | |
|
95 | {'description': 'desc', 'lifetime': -1, | |
|
96 | 'csrf_token': self.csrf_token}) | |
|
97 | assert_session_flash(response, 'Auth token successfully created') | |
|
98 | response.follow() | |
|
99 | ||
|
100 | user = User.get(user_id) | |
|
101 | keys = user.extra_auth_tokens | |
|
102 | assert 3 == len(keys) | |
|
103 | ||
|
104 | response = self.app.post( | |
|
105 | route_path('my_account_auth_tokens_delete'), | |
|
106 | {'del_auth_token': keys[0].api_key, 'csrf_token': self.csrf_token}) | |
|
107 | assert_session_flash(response, 'Auth token successfully deleted') | |
|
108 | ||
|
109 | user = User.get(user_id) | |
|
110 | keys = user.extra_auth_tokens | |
|
111 | assert 2 == len(keys) |
@@ -0,0 +1,111 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 HTTPFound | |
|
24 | from pyramid.view import view_config | |
|
25 | ||
|
26 | from rhodecode.apps._base import BaseAppView | |
|
27 | from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired | |
|
28 | from rhodecode.lib.utils2 import safe_int | |
|
29 | from rhodecode.lib import helpers as h | |
|
30 | from rhodecode.model.auth_token import AuthTokenModel | |
|
31 | from rhodecode.model.meta import Session | |
|
32 | ||
|
33 | log = logging.getLogger(__name__) | |
|
34 | ||
|
35 | ||
|
36 | class MyAccountView(BaseAppView): | |
|
37 | ||
|
38 | def load_default_context(self): | |
|
39 | c = self._get_local_tmpl_context() | |
|
40 | ||
|
41 | c.auth_user = self.request.user | |
|
42 | c.user = c.auth_user.get_instance() | |
|
43 | ||
|
44 | self._register_global_c(c) | |
|
45 | return c | |
|
46 | ||
|
47 | @LoginRequired() | |
|
48 | @NotAnonymous() | |
|
49 | @view_config( | |
|
50 | route_name='my_account_auth_tokens', request_method='GET', | |
|
51 | renderer='rhodecode:templates/admin/my_account/my_account.mako') | |
|
52 | def my_account_auth_tokens(self): | |
|
53 | _ = self.request.translate | |
|
54 | ||
|
55 | c = self.load_default_context() | |
|
56 | c.active = 'auth_tokens' | |
|
57 | ||
|
58 | show_expired = True | |
|
59 | ||
|
60 | c.lifetime_values = [ | |
|
61 | (str(-1), _('forever')), | |
|
62 | (str(5), _('5 minutes')), | |
|
63 | (str(60), _('1 hour')), | |
|
64 | (str(60 * 24), _('1 day')), | |
|
65 | (str(60 * 24 * 30), _('1 month')), | |
|
66 | ] | |
|
67 | c.lifetime_options = [(c.lifetime_values, _("Lifetime"))] | |
|
68 | c.role_values = [ | |
|
69 | (x, AuthTokenModel.cls._get_role_name(x)) | |
|
70 | for x in AuthTokenModel.cls.ROLES] | |
|
71 | c.role_options = [(c.role_values, _("Role"))] | |
|
72 | c.user_auth_tokens = AuthTokenModel().get_auth_tokens( | |
|
73 | c.user.user_id, show_expired=show_expired) | |
|
74 | return self._get_template_context(c) | |
|
75 | ||
|
76 | @LoginRequired() | |
|
77 | @NotAnonymous() | |
|
78 | @CSRFRequired() | |
|
79 | @view_config( | |
|
80 | route_name='my_account_auth_tokens_add', request_method='POST') | |
|
81 | def my_account_auth_tokens_add(self): | |
|
82 | _ = self.request.translate | |
|
83 | c = self.load_default_context() | |
|
84 | ||
|
85 | lifetime = safe_int(self.request.POST.get('lifetime'), -1) | |
|
86 | description = self.request.POST.get('description') | |
|
87 | role = self.request.POST.get('role') | |
|
88 | ||
|
89 | AuthTokenModel().create(c.user.user_id, description, lifetime, role) | |
|
90 | Session().commit() | |
|
91 | h.flash(_("Auth token successfully created"), category='success') | |
|
92 | ||
|
93 | return HTTPFound(h.route_path('my_account_auth_tokens')) | |
|
94 | ||
|
95 | @LoginRequired() | |
|
96 | @NotAnonymous() | |
|
97 | @CSRFRequired() | |
|
98 | @view_config( | |
|
99 | route_name='my_account_auth_tokens_delete', request_method='POST') | |
|
100 | def my_account_auth_tokens_delete(self): | |
|
101 | _ = self.request.translate | |
|
102 | c = self.load_default_context() | |
|
103 | ||
|
104 | del_auth_token = self.request.POST.get('del_auth_token') | |
|
105 | ||
|
106 | if del_auth_token: | |
|
107 | AuthTokenModel().delete(del_auth_token, c.user.user_id) | |
|
108 | Session().commit() | |
|
109 | h.flash(_("Auth token successfully deleted"), category='success') | |
|
110 | ||
|
111 | return HTTPFound(h.route_path('my_account_auth_tokens')) |
@@ -26,6 +26,10 b' from rhodecode.lib.utils2 import StrictA' | |||
|
26 | 26 | log = logging.getLogger(__name__) |
|
27 | 27 | |
|
28 | 28 | |
|
29 | ADMIN_PREFIX = '/_admin' | |
|
30 | STATIC_FILE_PREFIX = '/_static' | |
|
31 | ||
|
32 | ||
|
29 | 33 | class TemplateArgs(StrictAttributeDict): |
|
30 | 34 | pass |
|
31 | 35 | |
@@ -41,10 +45,17 b' class BaseAppView(object):' | |||
|
41 | 45 | def _get_local_tmpl_context(self): |
|
42 | 46 | return TemplateArgs() |
|
43 | 47 | |
|
48 | def _register_global_c(self, tmpl_args): | |
|
49 | """ | |
|
50 | Registers attributes to pylons global `c` | |
|
51 | """ | |
|
52 | # TODO(marcink): remove once pyramid migration is finished | |
|
53 | for k, v in tmpl_args.items(): | |
|
54 | setattr(c, k, v) | |
|
55 | ||
|
44 | 56 | def _get_template_context(self, tmpl_args): |
|
45 | 57 | |
|
46 | for k, v in tmpl_args.items(): | |
|
47 | setattr(c, k, v) | |
|
58 | self._register_global_c(tmpl_args) | |
|
48 | 59 | |
|
49 | 60 | return { |
|
50 | 61 | 'defaults': {}, |
@@ -0,0 +1,19 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/ |
@@ -286,6 +286,7 b' def includeme(config):' | |||
|
286 | 286 | config.include('rhodecode.apps.channelstream') |
|
287 | 287 | config.include('rhodecode.apps.login') |
|
288 | 288 | config.include('rhodecode.apps.user_profile') |
|
289 | config.include('rhodecode.apps.my_account') | |
|
289 | 290 | |
|
290 | 291 | config.include('rhodecode.tweens') |
|
291 | 292 | config.include('rhodecode.api') |
@@ -543,12 +543,6 b' def make_map(config):' | |||
|
543 | 543 | m.connect('my_account_emails', '/my_account/emails', |
|
544 | 544 | action='my_account_emails_delete', conditions={'method': ['DELETE']}) |
|
545 | 545 | |
|
546 | m.connect('my_account_auth_tokens', '/my_account/auth_tokens', | |
|
547 | action='my_account_auth_tokens', conditions={'method': ['GET']}) | |
|
548 | m.connect('my_account_auth_tokens', '/my_account/auth_tokens', | |
|
549 | action='my_account_auth_tokens_add', conditions={'method': ['POST']}) | |
|
550 | m.connect('my_account_auth_tokens', '/my_account/auth_tokens', | |
|
551 | action='my_account_auth_tokens_delete', conditions={'method': ['DELETE']}) | |
|
552 | 546 | m.connect('my_account_notifications', '/my_account/notifications', |
|
553 | 547 | action='my_notifications', |
|
554 | 548 | conditions={'method': ['GET']}) |
@@ -33,13 +33,12 b' from pylons import request, tmpl_context' | |||
|
33 | 33 | from pylons.controllers.util import redirect |
|
34 | 34 | from pylons.i18n.translation import _ |
|
35 | 35 | from sqlalchemy.orm import joinedload |
|
36 | from webob.exc import HTTPBadGateway | |
|
37 | 36 | |
|
38 | 37 | from rhodecode import forms |
|
39 | 38 | from rhodecode.lib import helpers as h |
|
40 | 39 | from rhodecode.lib import auth |
|
41 | 40 | from rhodecode.lib.auth import ( |
|
42 |
LoginRequired, NotAnonymous, AuthUser |
|
|
41 | LoginRequired, NotAnonymous, AuthUser) | |
|
43 | 42 | from rhodecode.lib.base import BaseController, render |
|
44 | 43 | from rhodecode.lib.utils import jsonify |
|
45 | 44 | from rhodecode.lib.utils2 import safe_int, md5, str2bool |
@@ -54,7 +53,6 b' from rhodecode.model.forms import UserFo' | |||
|
54 | 53 | from rhodecode.model.scm import RepoList |
|
55 | 54 | from rhodecode.model.user import UserModel |
|
56 | 55 | from rhodecode.model.repo import RepoModel |
|
57 | from rhodecode.model.auth_token import AuthTokenModel | |
|
58 | 56 | from rhodecode.model.meta import Session |
|
59 | 57 | from rhodecode.model.pull_request import PullRequestModel |
|
60 | 58 | from rhodecode.model.comment import CommentsModel |
@@ -376,47 +374,6 b' class MyAccountController(BaseController' | |||
|
376 | 374 | else: |
|
377 | 375 | return json.dumps(data) |
|
378 | 376 | |
|
379 | def my_account_auth_tokens(self): | |
|
380 | c.active = 'auth_tokens' | |
|
381 | self.__load_data() | |
|
382 | show_expired = True | |
|
383 | c.lifetime_values = [ | |
|
384 | (str(-1), _('forever')), | |
|
385 | (str(5), _('5 minutes')), | |
|
386 | (str(60), _('1 hour')), | |
|
387 | (str(60 * 24), _('1 day')), | |
|
388 | (str(60 * 24 * 30), _('1 month')), | |
|
389 | ] | |
|
390 | c.lifetime_options = [(c.lifetime_values, _("Lifetime"))] | |
|
391 | c.role_values = [(x, AuthTokenModel.cls._get_role_name(x)) | |
|
392 | for x in AuthTokenModel.cls.ROLES] | |
|
393 | c.role_options = [(c.role_values, _("Role"))] | |
|
394 | c.user_auth_tokens = AuthTokenModel().get_auth_tokens( | |
|
395 | c.rhodecode_user.user_id, show_expired=show_expired) | |
|
396 | return render('admin/my_account/my_account.mako') | |
|
397 | ||
|
398 | @auth.CSRFRequired() | |
|
399 | def my_account_auth_tokens_add(self): | |
|
400 | lifetime = safe_int(request.POST.get('lifetime'), -1) | |
|
401 | description = request.POST.get('description') | |
|
402 | role = request.POST.get('role') | |
|
403 | AuthTokenModel().create(c.rhodecode_user.user_id, description, lifetime, | |
|
404 | role) | |
|
405 | Session().commit() | |
|
406 | h.flash(_("Auth token successfully created"), category='success') | |
|
407 | return redirect(url('my_account_auth_tokens')) | |
|
408 | ||
|
409 | @auth.CSRFRequired() | |
|
410 | def my_account_auth_tokens_delete(self): | |
|
411 | del_auth_token = request.POST.get('del_auth_token') | |
|
412 | ||
|
413 | if del_auth_token: | |
|
414 | AuthTokenModel().delete(del_auth_token, c.rhodecode_user.user_id) | |
|
415 | Session().commit() | |
|
416 | h.flash(_("Auth token successfully deleted"), category='success') | |
|
417 | ||
|
418 | return redirect(url('my_account_auth_tokens')) | |
|
419 | ||
|
420 | 377 | def my_notifications(self): |
|
421 | 378 | c.active = 'notifications' |
|
422 | 379 | return render('admin/my_account/my_account.mako') |
@@ -28,7 +28,7 b'' | |||
|
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.url('my_account')}">${_('Profile')}</a></li> |
|
30 | 30 | <li class="${'active' if c.active=='password' else ''}"><a href="${h.url('my_account_password')}">${_('Password')}</a></li> |
|
31 |
<li class="${'active' if c.active=='auth_tokens' else ''}"><a href="${h. |
|
|
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: |
@@ -42,7 +42,7 b'' | |||
|
42 | 42 | %endif |
|
43 | 43 | </td> |
|
44 | 44 | <td class="td-action"> |
|
45 |
${h.secure_form( |
|
|
45 | ${h.secure_form(h.route_path('my_account_auth_tokens_delete'), method='post')} | |
|
46 | 46 | ${h.hidden('del_auth_token',auth_token.api_key)} |
|
47 | 47 | <button class="btn btn-link btn-danger" type="submit" |
|
48 | 48 | onclick="return confirm('${_('Confirm to remove this auth token: %s') % auth_token.api_key}');"> |
@@ -58,7 +58,7 b'' | |||
|
58 | 58 | </table> |
|
59 | 59 | |
|
60 | 60 | <div class="user_auth_tokens"> |
|
61 |
${h.secure_form( |
|
|
61 | ${h.secure_form(h.route_path('my_account_auth_tokens_add'), method='post')} | |
|
62 | 62 | <div class="form form-vertical"> |
|
63 | 63 | <!-- fields --> |
|
64 | 64 | <div class="fields"> |
@@ -254,63 +254,6 b' class TestMyAccountController(TestContro' | |||
|
254 | 254 | msg = h.html_escape(msg % {'username': 'test_admin'}) |
|
255 | 255 | response.mustcontain(u"%s" % msg) |
|
256 | 256 | |
|
257 | def test_my_account_auth_tokens(self): | |
|
258 | usr = self.log_user('test_regular2', 'test12') | |
|
259 | user = User.get(usr['user_id']) | |
|
260 | response = self.app.get(url('my_account_auth_tokens')) | |
|
261 | for token in user.auth_tokens: | |
|
262 | response.mustcontain(token) | |
|
263 | response.mustcontain('never') | |
|
264 | ||
|
265 | @pytest.mark.parametrize("desc, lifetime", [ | |
|
266 | ('forever', -1), | |
|
267 | ('5mins', 60*5), | |
|
268 | ('30days', 60*60*24*30), | |
|
269 | ]) | |
|
270 | def test_my_account_add_auth_tokens(self, desc, lifetime, user_util): | |
|
271 | user = user_util.create_user(password='qweqwe') | |
|
272 | user_id = user.user_id | |
|
273 | self.log_user(user.username, 'qweqwe') | |
|
274 | ||
|
275 | response = self.app.post(url('my_account_auth_tokens'), | |
|
276 | {'description': desc, 'lifetime': lifetime, | |
|
277 | 'csrf_token': self.csrf_token}) | |
|
278 | assert_session_flash(response, 'Auth token successfully created') | |
|
279 | ||
|
280 | response = response.follow() | |
|
281 | user = User.get(user_id) | |
|
282 | for auth_token in user.auth_tokens: | |
|
283 | response.mustcontain(auth_token) | |
|
284 | ||
|
285 | def test_my_account_remove_auth_token(self, user_util): | |
|
286 | user = user_util.create_user(password='qweqwe') | |
|
287 | user_id = user.user_id | |
|
288 | self.log_user(user.username, 'qweqwe') | |
|
289 | ||
|
290 | user = User.get(user_id) | |
|
291 | keys = user.extra_auth_tokens | |
|
292 | assert 2 == len(keys) | |
|
293 | ||
|
294 | response = self.app.post(url('my_account_auth_tokens'), | |
|
295 | {'description': 'desc', 'lifetime': -1, | |
|
296 | 'csrf_token': self.csrf_token}) | |
|
297 | assert_session_flash(response, 'Auth token successfully created') | |
|
298 | response.follow() | |
|
299 | ||
|
300 | user = User.get(user_id) | |
|
301 | keys = user.extra_auth_tokens | |
|
302 | assert 3 == len(keys) | |
|
303 | ||
|
304 | response = self.app.post( | |
|
305 | url('my_account_auth_tokens'), | |
|
306 | {'_method': 'delete', 'del_auth_token': keys[0].api_key, | |
|
307 | 'csrf_token': self.csrf_token}) | |
|
308 | assert_session_flash(response, 'Auth token successfully deleted') | |
|
309 | ||
|
310 | user = User.get(user_id) | |
|
311 | keys = user.extra_auth_tokens | |
|
312 | assert 2 == len(keys) | |
|
313 | ||
|
314 | 257 | def test_valid_change_password(self, user_util): |
|
315 | 258 | new_password = 'my_new_valid_password' |
|
316 | 259 | user = user_util.create_user(password=self.test_user_1_password) |
General Comments 0
You need to be logged in to leave comments.
Login now