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
@@ -95,6 +95,28 @@ def includeme(config):
name='my_account_pullrequests_data',
pattern=ADMIN_PREFIX + '/my_account/pull_requests/data')
+ # notifications
+ config.add_route(
+ name='notifications_show_all',
+ pattern=ADMIN_PREFIX + '/notifications')
+
+ # notifications
+ config.add_route(
+ name='notifications_mark_all_read',
+ pattern=ADMIN_PREFIX + '/notifications/mark_all_read')
+
+ config.add_route(
+ name='notifications_show',
+ pattern=ADMIN_PREFIX + '/notifications/{notification_id}')
+
+ config.add_route(
+ name='notifications_update',
+ pattern=ADMIN_PREFIX + '/notifications/{notification_id}/update')
+
+ config.add_route(
+ name='notifications_delete',
+ pattern=ADMIN_PREFIX + '/notifications/{notification_id}/delete')
+
# channelstream test
config.add_route(
name='my_account_notifications_test_channelstream',
diff --git a/rhodecode/tests/functional/test_admin_notifications.py b/rhodecode/apps/my_account/tests/test_my_account_notifications.py
rename from rhodecode/tests/functional/test_admin_notifications.py
rename to rhodecode/apps/my_account/tests/test_my_account_notifications.py
--- a/rhodecode/tests/functional/test_admin_notifications.py
+++ b/rhodecode/apps/my_account/tests/test_my_account_notifications.py
@@ -20,7 +20,10 @@
import pytest
-from rhodecode.tests import *
+from rhodecode.apps._base import ADMIN_PREFIX
+from rhodecode.tests import (
+ TestController, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,
+ TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS)
from rhodecode.tests.fixture import Fixture
from rhodecode.model.db import Notification, User
@@ -31,12 +34,25 @@ from rhodecode.model.meta import Session
fixture = Fixture()
-class TestNotificationsController(TestController):
- destroy_users = set()
+def route_path(name, params=None, **kwargs):
+ import urllib
+ from rhodecode.apps._base import ADMIN_PREFIX
- @classmethod
- def teardown_class(cls):
- fixture.destroy_users(cls.destroy_users)
+ base_url = {
+ 'notifications_show_all': ADMIN_PREFIX + '/notifications',
+ 'notifications_mark_all_read': ADMIN_PREFIX + '/notifications/mark_all_read',
+ 'notifications_show': ADMIN_PREFIX + '/notifications/{notification_id}',
+ 'notifications_update': ADMIN_PREFIX + '/notifications/{notification_id}/update',
+ 'notifications_delete': ADMIN_PREFIX + '/notifications/{notification_id}/delete',
+
+ }[name].format(**kwargs)
+
+ if params:
+ base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
+ return base_url
+
+
+class TestNotificationsController(TestController):
def teardown_method(self, method):
for n in Notification.query().all():
@@ -44,43 +60,61 @@ class TestNotificationsController(TestCo
Session().delete(inst)
Session().commit()
- def test_index(self):
- u1 = UserModel().create_or_update(
- username='u1', password='qweqwe', email='u1@rhodecode.org',
- firstname='u1', lastname='u1')
- u1 = u1.user_id
- self.destroy_users.add('u1')
+ def test_show_all(self, user_util):
+ user = user_util.create_user(password='qweqwe')
+ user_id = user.user_id
+ self.log_user(user.username, 'qweqwe')
- self.log_user('u1', 'qweqwe')
-
- response = self.app.get(url('notifications'))
+ response = self.app.get(
+ route_path('notifications_show_all', params={'type': 'all'}))
response.mustcontain(
'
No notifications here yet
')
- cur_user = self._get_logged_user()
- notif = NotificationModel().create(
- created_by=u1, notification_subject=u'test_notification_1',
- notification_body=u'notification_1', recipients=[cur_user])
+ notification = NotificationModel().create(
+ created_by=user_id, notification_subject=u'test_notification_1',
+ notification_body=u'notification_1', recipients=[user_id])
Session().commit()
- response = self.app.get(url('notifications'))
- response.mustcontain('id="notification_%s"' % notif.notification_id)
+ notification_id = notification.notification_id
+
+ response = self.app.get(route_path('notifications_show_all',
+ params={'type': 'all'}))
+ response.mustcontain('id="notification_%s"' % notification_id)
+
+ def test_show_unread(self, user_util):
+ user = user_util.create_user(password='qweqwe')
+ user_id = user.user_id
+ self.log_user(user.username, 'qweqwe')
+
+ response = self.app.get(route_path('notifications_show_all'))
+ response.mustcontain(
+ 'No notifications here yet
')
+
+ notification = NotificationModel().create(
+ created_by=user_id, notification_subject=u'test_notification_1',
+ notification_body=u'notification_1', recipients=[user_id])
+
+ # mark the USER notification as unread
+ user_notification = NotificationModel().get_user_notification(
+ user_id, notification)
+ user_notification.read = False
+
+ Session().commit()
+ notification_id = notification.notification_id
+
+ response = self.app.get(route_path('notifications_show_all'))
+ response.mustcontain('id="notification_%s"' % notification_id)
+ response.mustcontain('.
-#
-# 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/
-
-
-"""
-notifications controller for RhodeCode
-"""
-
-import logging
-import traceback
-
-from pylons import request
-from pylons import tmpl_context as c, url
-from pylons.controllers.util import redirect, abort
-import webhelpers.paginate
-from webob.exc import HTTPBadRequest
-
-from rhodecode.lib import auth
-from rhodecode.lib.auth import LoginRequired, NotAnonymous
-from rhodecode.lib.base import BaseController, render
-from rhodecode.lib import helpers as h
-from rhodecode.lib.helpers import Page
-from rhodecode.lib.utils2 import safe_int
-from rhodecode.model.db import Notification
-from rhodecode.model.notification import NotificationModel
-from rhodecode.model.meta import Session
-
-
-log = logging.getLogger(__name__)
-
-
-class NotificationsController(BaseController):
- """REST Controller styled on the Atom Publishing Protocol"""
-
- @LoginRequired()
- @NotAnonymous()
- def __before__(self):
- super(NotificationsController, self).__before__()
-
- def index(self):
- """GET /_admin/notifications: All items in the collection"""
- # url('notifications')
- c.user = c.rhodecode_user
- notif = NotificationModel().get_for_user(
- c.rhodecode_user.user_id, filter_=request.GET.getall('type'))
-
- p = safe_int(request.GET.get('page', 1), 1)
- notifications_url = webhelpers.paginate.PageURL(
- url('notifications'), request.GET)
- c.notifications = Page(notif, page=p, items_per_page=10,
- url=notifications_url)
- c.pull_request_type = Notification.TYPE_PULL_REQUEST
- c.comment_type = [Notification.TYPE_CHANGESET_COMMENT,
- Notification.TYPE_PULL_REQUEST_COMMENT]
-
- _current_filter = request.GET.getall('type')
- c.current_filter = 'all'
- if _current_filter == [c.pull_request_type]:
- c.current_filter = 'pull_request'
- elif _current_filter == c.comment_type:
- c.current_filter = 'comment'
-
- if request.is_xhr:
- return render('admin/notifications/notifications_data.mako')
-
- return render('admin/notifications/notifications.mako')
-
- @auth.CSRFRequired()
- def mark_all_read(self):
- if request.is_xhr:
- nm = NotificationModel()
- # mark all read
- nm.mark_all_read_for_user(c.rhodecode_user.user_id,
- filter_=request.GET.getall('type'))
- Session().commit()
- c.user = c.rhodecode_user
- notif = nm.get_for_user(c.rhodecode_user.user_id,
- filter_=request.GET.getall('type'))
- notifications_url = webhelpers.paginate.PageURL(
- url('notifications'), request.GET)
- c.notifications = Page(notif, page=1, items_per_page=10,
- url=notifications_url)
- return render('admin/notifications/notifications_data.mako')
-
- def _has_permissions(self, notification):
- def is_owner():
- user_id = c.rhodecode_user.user_id
- for user_notification in notification.notifications_to_users:
- if user_notification.user.user_id == user_id:
- return True
- return False
- return h.HasPermissionAny('hg.admin')() or is_owner()
-
- @auth.CSRFRequired()
- def update(self, notification_id):
- no = Notification.get_or_404(notification_id)
- try:
- if self._has_permissions(no):
- # deletes only notification2user
- NotificationModel().mark_read(c.rhodecode_user.user_id, no)
- Session().commit()
- return 'ok'
- except Exception:
- Session().rollback()
- log.exception("Exception updating a notification item")
- raise HTTPBadRequest()
-
- @auth.CSRFRequired()
- def delete(self, notification_id):
- no = Notification.get_or_404(notification_id)
- try:
- if self._has_permissions(no):
- # deletes only notification2user
- NotificationModel().delete(c.rhodecode_user.user_id, no)
- Session().commit()
- return 'ok'
- except Exception:
- Session().rollback()
- log.exception("Exception deleting a notification item")
- raise HTTPBadRequest()
-
- def show(self, notification_id):
- c.user = c.rhodecode_user
- no = Notification.get_or_404(notification_id)
-
- if no and self._has_permissions(no):
- unotification = NotificationModel()\
- .get_user_notification(c.user.user_id, no)
-
- # if this association to user is not valid, we don't want to show
- # this message
- if unotification:
- if not unotification.read:
- unotification.mark_as_read()
- Session().commit()
- c.notification = no
-
- return render('admin/notifications/show_notification.mako')
-
- return abort(403)
diff --git a/rhodecode/model/notification.py b/rhodecode/model/notification.py
--- a/rhodecode/model/notification.py
+++ b/rhodecode/model/notification.py
@@ -166,9 +166,6 @@ class NotificationModel(BaseModel):
def get_for_user(self, user, filter_=None):
"""
Get mentions for given user, filter them if filter dict is given
-
- :param user:
- :param filter:
"""
user = self._get_user(user)
@@ -177,11 +174,14 @@ class NotificationModel(BaseModel):
.join((
Notification, UserNotification.notification_id ==
Notification.notification_id))
-
- if filter_:
+ if filter_ == ['all']:
+ q = q # no filter
+ elif filter_ == ['unread']:
+ q = q.filter(UserNotification.read == false())
+ elif filter_:
q = q.filter(Notification.type_.in_(filter_))
- return q.all()
+ return q
def mark_read(self, user, notification):
try:
@@ -207,7 +207,9 @@ class NotificationModel(BaseModel):
.join((
Notification, UserNotification.notification_id ==
Notification.notification_id))
- if filter_:
+ if filter_ == ['unread']:
+ q = q.filter(UserNotification.read == false())
+ elif filter_:
q = q.filter(Notification.type_.in_(filter_))
# this is a little inefficient but sqlalchemy doesn't support
diff --git a/rhodecode/public/js/rhodecode/routes.js b/rhodecode/public/js/rhodecode/routes.js
--- a/rhodecode/public/js/rhodecode/routes.js
+++ b/rhodecode/public/js/rhodecode/routes.js
@@ -160,6 +160,11 @@ function registerRCRoutes() {
pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
+ pyroutes.register('notifications_show_all', '/_admin/notifications', []);
+ pyroutes.register('notifications_mark_all_read', '/_admin/notifications/mark_all_read', []);
+ pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
+ pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
+ pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
pyroutes.register('gists_show', '/_admin/gists', []);
pyroutes.register('gists_new', '/_admin/gists/new', []);
diff --git a/rhodecode/public/js/src/rhodecode/notifications.js b/rhodecode/public/js/src/rhodecode/notifications.js
--- a/rhodecode/public/js/src/rhodecode/notifications.js
+++ b/rhodecode/public/js/src/rhodecode/notifications.js
@@ -30,35 +30,37 @@ var _run_callbacks = function(callbacks)
}
};
-var deleteNotification = function(url, notification_id,callbacks){
+var deleteNotification = function(notification_id, callbacks){
var callback = function(o){
var obj = $("#notification_"+notification_id);
obj.remove();
_run_callbacks(callbacks);
};
- var postData = {'_method': 'delete', 'csrf_token': CSRF_TOKEN};
- var sUrl = url.replace('__NOTIFICATION_ID__',notification_id);
- var request = $.post(sUrl, postData)
- .done(callback)
- .fail(function(data, textStatus, errorThrown){
- alert("Error while deleting notification.\nError code {0} ({1}). URL: {2}".format(data.status,data.statusText,$(this)[0].url));
- });
+ var postData = {'csrf_token': CSRF_TOKEN};
+ var sUrl = pyroutes.url('notifications_delete', {'notification_id': notification_id});
+ var request =
+ $.post(sUrl, postData)
+ .done(callback)
+ .fail(function(data, textStatus, errorThrown){
+ alert("Error while deleting notification.\nError code {0} ({1}). URL: {2}".format(data.status,data.statusText,$(this)[0].url));
+ });
};
-var readNotification = function(url, notification_id,callbacks){
+var readNotification = function(notification_id, callbacks){
var callback = function(o){
var obj = $("#notification_"+notification_id);
obj.removeClass('unread');
- var r_button = $('.read-notification',obj)[0];
+ var r_button = $('.read-notification', obj)[0];
r_button.remove();
_run_callbacks(callbacks);
};
- var postData = {'_method': 'put', 'csrf_token': CSRF_TOKEN};
- var sUrl = url.replace('__NOTIFICATION_ID__',notification_id);
- var request = $.post(sUrl, postData)
- .done(callback)
- .fail(function(data, textStatus, errorThrown){
- alert("Error while saving notification.\nError code {0} ({1}). URL: {2}".format(data.status,data.statusText,$(this)[0].url));
- });
+ var postData = {'csrf_token': CSRF_TOKEN};
+ var sUrl = pyroutes.url('notifications_update', {'notification_id': notification_id});
+ var request =
+ $.post(sUrl, postData)
+ .done(callback)
+ .fail(function(data, textStatus, errorThrown){
+ alert("Error while saving notification.\nError code {0} ({1}). URL: {2}".format(data.status,data.statusText,$(this)[0].url));
+ });
};
diff --git a/rhodecode/templates/admin/notifications/notifications_data.mako b/rhodecode/templates/admin/notifications/notifications_data.mako
--- a/rhodecode/templates/admin/notifications/notifications_data.mako
+++ b/rhodecode/templates/admin/notifications/notifications_data.mako
@@ -1,40 +1,46 @@
<%namespace name="base" file="/base/base.mako"/>
-%if c.notifications:
-<%
-unread = lambda n:{False:'unread'}.get(n)
-%>
+
+
+
${_('My notifications')}
+
+
+
+ %if c.notifications:
-
-%for notification in c.notifications:
-
-%endfor
-
+
+ %for notification in c.notifications:
+
+ %endfor
+
-
-
-
-%else:
-
${_('No notifications here yet')}
-%endif
diff --git a/rhodecode/templates/admin/notifications/show_notification.mako b/rhodecode/templates/admin/notifications/notifications_show.mako
rename from rhodecode/templates/admin/notifications/show_notification.mako
rename to rhodecode/templates/admin/notifications/notifications_show.mako
--- a/rhodecode/templates/admin/notifications/show_notification.mako
+++ b/rhodecode/templates/admin/notifications/notifications_show.mako
@@ -9,7 +9,7 @@
%def>
<%def name="breadcrumbs_links()">
- ${h.link_to(_('Notifications'), h.url('notifications'))}
+ ${h.link_to(_('My Notifications'), h.route_path('notifications_show_all'))}
»
${_('Show notification')}
%def>
@@ -32,7 +32,7 @@
${c.notification.description}
-
+
@@ -46,12 +46,5 @@
-
+
%def>
diff --git a/rhodecode/templates/admin/notifications/notifications.mako b/rhodecode/templates/admin/notifications/notifications_show_all.mako
rename from rhodecode/templates/admin/notifications/notifications.mako
rename to rhodecode/templates/admin/notifications/notifications_show_all.mako
--- a/rhodecode/templates/admin/notifications/notifications.mako
+++ b/rhodecode/templates/admin/notifications/notifications_show_all.mako
@@ -13,66 +13,56 @@
%def>
<%def name="menu_bar_nav()">
- ${self.menu_items(active='admin')}
+ ${self.menu_items(active='my_account')}
%def>
<%def name="main()">
-
-
- ${self.breadcrumbs()}
- ##
-
+
+ ${self.breadcrumbs()}
+
+
+
+
%def>
diff --git a/rhodecode/templates/base/base.mako b/rhodecode/templates/base/base.mako
--- a/rhodecode/templates/base/base.mako
+++ b/rhodecode/templates/base/base.mako
@@ -359,11 +359,7 @@
%if c.rhodecode_user.username != h.DEFAULT_USER:
- % if c.unread_notifications == 0:
-
- % else:
-
- % endif
+
% endif