diff --git a/rhodecode/apps/my_account/__init__.py b/rhodecode/apps/my_account/__init__.py
--- a/rhodecode/apps/my_account/__init__.py
+++ b/rhodecode/apps/my_account/__init__.py
@@ -46,6 +46,16 @@ def includeme(config):
name='my_account_auth_tokens_delete',
pattern=ADMIN_PREFIX + '/my_account/auth_tokens/delete')
+ config.add_route(
+ name='my_account_emails',
+ pattern=ADMIN_PREFIX + '/my_account/emails')
+ config.add_route(
+ name='my_account_emails_add',
+ pattern=ADMIN_PREFIX + '/my_account/emails/new')
+ config.add_route(
+ name='my_account_emails_delete',
+ pattern=ADMIN_PREFIX + '/my_account/emails/delete')
+
# channelstream test
config.add_route(
name='my_account_notifications_test_channelstream',
diff --git a/rhodecode/apps/my_account/tests/test_my_account_emails.py b/rhodecode/apps/my_account/tests/test_my_account_emails.py
new file mode 100644
--- /dev/null
+++ b/rhodecode/apps/my_account/tests/test_my_account_emails.py
@@ -0,0 +1,93 @@
+# -*- 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 .
+#
+# 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
+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_emails':
+ ADMIN_PREFIX + '/my_account/emails',
+ 'my_account_emails_add':
+ ADMIN_PREFIX + '/my_account/emails/new',
+ 'my_account_emails_delete':
+ ADMIN_PREFIX + '/my_account/emails/delete',
+ }[name].format(**kwargs)
+
+
+class TestMyAccountEmails(TestController):
+ def test_my_account_my_emails(self):
+ self.log_user()
+ response = self.app.get(route_path('my_account_emails'))
+ response.mustcontain('No additional emails specified')
+
+ def test_my_account_my_emails_add_existing_email(self):
+ self.log_user()
+ response = self.app.get(route_path('my_account_emails'))
+ response.mustcontain('No additional emails specified')
+ response = self.app.post(route_path('my_account_emails_add'),
+ {'new_email': TEST_USER_REGULAR_EMAIL,
+ 'csrf_token': self.csrf_token})
+ assert_session_flash(response, 'This e-mail address is already taken')
+
+ def test_my_account_my_emails_add_mising_email_in_form(self):
+ self.log_user()
+ response = self.app.get(route_path('my_account_emails'))
+ response.mustcontain('No additional emails specified')
+ response = self.app.post(route_path('my_account_emails_add'),
+ {'csrf_token': self.csrf_token})
+ assert_session_flash(response, 'Please enter an email address')
+
+ def test_my_account_my_emails_add_remove(self):
+ self.log_user()
+ response = self.app.get(route_path('my_account_emails'))
+ response.mustcontain('No additional emails specified')
+
+ response = self.app.post(route_path('my_account_emails_add'),
+ {'new_email': 'foo@barz.com',
+ 'csrf_token': self.csrf_token})
+
+ response = self.app.get(route_path('my_account_emails'))
+
+ email_id = UserEmailMap.query().filter(
+ UserEmailMap.user == User.get_by_username(
+ TEST_USER_ADMIN_LOGIN)).filter(
+ UserEmailMap.email == 'foo@barz.com').one().email_id
+
+ response.mustcontain('foo@barz.com')
+ response.mustcontain('' % email_id)
+
+ response = self.app.post(
+ route_path('my_account_emails_delete'), {
+ 'del_email_id': email_id,
+ 'csrf_token': self.csrf_token})
+ assert_session_flash(response, 'Email successfully deleted')
+ response = self.app.get(route_path('my_account_emails'))
+ response.mustcontain('No additional emails specified')
diff --git a/rhodecode/apps/my_account/views.py b/rhodecode/apps/my_account/views.py
--- a/rhodecode/apps/my_account/views.py
+++ b/rhodecode/apps/my_account/views.py
@@ -21,6 +21,7 @@
import logging
import datetime
+import formencode
from pyramid.httpexceptions import HTTPFound
from pyramid.view import view_config
@@ -32,6 +33,7 @@ from rhodecode.lib.channelstream import
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.meta import Session
from rhodecode.model.user import UserModel
from rhodecode.model.validation_schema.schemas import user_schema
@@ -161,7 +163,7 @@ class MyAccountView(BaseAppView):
@NotAnonymous()
@CSRFRequired()
@view_config(
- route_name='my_account_auth_tokens_add', request_method='POST')
+ route_name='my_account_auth_tokens_add', request_method='POST',)
def my_account_auth_tokens_add(self):
_ = self.request.translate
c = self.load_default_context()
@@ -198,6 +200,65 @@ class MyAccountView(BaseAppView):
@LoginRequired()
@NotAnonymous()
+ @view_config(
+ route_name='my_account_emails', request_method='GET',
+ renderer='rhodecode:templates/admin/my_account/my_account.mako')
+ def my_account_emails(self):
+ _ = self.request.translate
+
+ c = self.load_default_context()
+ c.active = 'emails'
+
+ c.user_email_map = UserEmailMap.query()\
+ .filter(UserEmailMap.user == c.user).all()
+ return self._get_template_context(c)
+
+ @LoginRequired()
+ @NotAnonymous()
+ @CSRFRequired()
+ @view_config(
+ route_name='my_account_emails_add', request_method='POST')
+ def my_account_emails_add(self):
+ _ = self.request.translate
+ c = self.load_default_context()
+
+ email = self.request.POST.get('new_email')
+
+ try:
+ UserModel().add_extra_email(c.user.user_id, email)
+ Session().commit()
+ h.flash(_("Added new email address `%s` for user account") % email,
+ category='success')
+ except formencode.Invalid as error:
+ msg = error.error_dict['email']
+ h.flash(msg, category='error')
+ except Exception:
+ log.exception("Exception in my_account_emails")
+ h.flash(_('An error occurred during email saving'),
+ category='error')
+ return HTTPFound(h.route_path('my_account_emails'))
+
+ @LoginRequired()
+ @NotAnonymous()
+ @CSRFRequired()
+ @view_config(
+ route_name='my_account_emails_delete', request_method='POST')
+ def my_account_emails_delete(self):
+ _ = self.request.translate
+ c = self.load_default_context()
+
+ del_email_id = self.request.POST.get('del_email_id')
+ if del_email_id:
+
+ UserModel().delete_extra_email(
+ c.user.user_id, del_email_id)
+ Session().commit()
+ h.flash(_("Email successfully deleted"),
+ category='success')
+ return HTTPFound(h.route_path('my_account_emails'))
+
+ @LoginRequired()
+ @NotAnonymous()
@CSRFRequired()
@view_config(
route_name='my_account_notifications_test_channelstream',
diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py
--- a/rhodecode/config/routing.py
+++ b/rhodecode/config/routing.py
@@ -497,13 +497,6 @@ def make_map(config):
m.connect('my_account_perms', '/my_account/perms',
action='my_account_perms', conditions={'method': ['GET']})
- m.connect('my_account_emails', '/my_account/emails',
- action='my_account_emails', conditions={'method': ['GET']})
- m.connect('my_account_emails', '/my_account/emails',
- action='my_account_emails_add', conditions={'method': ['POST']})
- m.connect('my_account_emails', '/my_account/emails',
- action='my_account_emails_delete', conditions={'method': ['DELETE']})
-
m.connect('my_account_notifications', '/my_account/notifications',
action='my_notifications',
conditions={'method': ['GET']})
diff --git a/rhodecode/controllers/admin/my_account.py b/rhodecode/controllers/admin/my_account.py
--- a/rhodecode/controllers/admin/my_account.py
+++ b/rhodecode/controllers/admin/my_account.py
@@ -200,42 +200,6 @@ class MyAccountController(BaseController
return render('admin/my_account/my_account.mako')
- def my_account_emails(self):
- c.active = 'emails'
- self.__load_data()
-
- c.user_email_map = UserEmailMap.query()\
- .filter(UserEmailMap.user == c.user).all()
- return render('admin/my_account/my_account.mako')
-
- @auth.CSRFRequired()
- def my_account_emails_add(self):
- email = request.POST.get('new_email')
-
- try:
- UserModel().add_extra_email(c.rhodecode_user.user_id, email)
- Session().commit()
- h.flash(_("Added new email address `%s` for user account") % email,
- category='success')
- except formencode.Invalid as error:
- msg = error.error_dict['email']
- h.flash(msg, category='error')
- except Exception:
- log.exception("Exception in my_account_emails")
- h.flash(_('An error occurred during email saving'),
- category='error')
- return redirect(url('my_account_emails'))
-
- @auth.CSRFRequired()
- def my_account_emails_delete(self):
- email_id = request.POST.get('del_email_id')
- user_model = UserModel()
- user_model.delete_extra_email(c.rhodecode_user.user_id, email_id)
- Session().commit()
- h.flash(_("Removed email address from user account"),
- category='success')
- return redirect(url('my_account_emails'))
-
def _extract_ordering(self, request):
column_index = safe_int(request.GET.get('order[0][column]'))
order_dir = request.GET.get('order[0][dir]', 'desc')
diff --git a/rhodecode/templates/admin/my_account/my_account.mako b/rhodecode/templates/admin/my_account/my_account.mako
--- a/rhodecode/templates/admin/my_account/my_account.mako
+++ b/rhodecode/templates/admin/my_account/my_account.mako
@@ -34,7 +34,7 @@
% if my_account_oauth_url:
${_('OAuth Identities')}
% endif
- ${_('Emails')}
+ ${_('Emails')}
${_('Repositories')}
${_('Watched')}
${_('Pull Requests')}
diff --git a/rhodecode/templates/admin/my_account/my_account_emails.mako b/rhodecode/templates/admin/my_account/my_account_emails.mako
--- a/rhodecode/templates/admin/my_account/my_account_emails.mako
+++ b/rhodecode/templates/admin/my_account/my_account_emails.mako
@@ -25,10 +25,10 @@
${em.email}
- ${h.secure_form(url('my_account_emails'),method='delete')}
+ ${h.secure_form(h.route_path('my_account_emails_delete'), method='POST')}
${h.hidden('del_email_id',em.email_id)}
- |