##// END OF EJS Templates
fix to strict permission check on notification messages
marcink -
r3428:edb9a42d beta
parent child Browse files
Show More
@@ -1,172 +1,173 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.notifications
3 rhodecode.controllers.admin.notifications
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 notifications controller for RhodeCode
6 notifications controller for RhodeCode
7
7
8 :created_on: Nov 23, 2010
8 :created_on: Nov 23, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28
28
29 from pylons import request
29 from pylons import request
30 from pylons import tmpl_context as c, url
30 from pylons import tmpl_context as c, url
31 from pylons.controllers.util import redirect
31 from pylons.controllers.util import redirect, abort
32
32
33 from webhelpers.paginate import Page
33 from webhelpers.paginate import Page
34
34
35 from rhodecode.lib.base import BaseController, render
35 from rhodecode.lib.base import BaseController, render
36 from rhodecode.model.db import Notification
36 from rhodecode.model.db import Notification
37
37
38 from rhodecode.model.notification import NotificationModel
38 from rhodecode.model.notification import NotificationModel
39 from rhodecode.lib.auth import LoginRequired, NotAnonymous
39 from rhodecode.lib.auth import LoginRequired, NotAnonymous
40 from rhodecode.lib import helpers as h
40 from rhodecode.lib import helpers as h
41 from rhodecode.model.meta import Session
41 from rhodecode.model.meta import Session
42 from rhodecode.lib.utils2 import safe_int
42 from rhodecode.lib.utils2 import safe_int
43
43
44
44
45 log = logging.getLogger(__name__)
45 log = logging.getLogger(__name__)
46
46
47
47
48 class NotificationsController(BaseController):
48 class NotificationsController(BaseController):
49 """REST Controller styled on the Atom Publishing Protocol"""
49 """REST Controller styled on the Atom Publishing Protocol"""
50 # To properly map this controller, ensure your config/routing.py
50 # To properly map this controller, ensure your config/routing.py
51 # file has a resource setup:
51 # file has a resource setup:
52 # map.resource('notification', 'notifications', controller='_admin/notifications',
52 # map.resource('notification', 'notifications', controller='_admin/notifications',
53 # path_prefix='/_admin', name_prefix='_admin_')
53 # path_prefix='/_admin', name_prefix='_admin_')
54
54
55 @LoginRequired()
55 @LoginRequired()
56 @NotAnonymous()
56 @NotAnonymous()
57 def __before__(self):
57 def __before__(self):
58 super(NotificationsController, self).__before__()
58 super(NotificationsController, self).__before__()
59
59
60 def index(self, format='html'):
60 def index(self, format='html'):
61 """GET /_admin/notifications: All items in the collection"""
61 """GET /_admin/notifications: All items in the collection"""
62 # url('notifications')
62 # url('notifications')
63 c.user = self.rhodecode_user
63 c.user = self.rhodecode_user
64 notif = NotificationModel().get_for_user(self.rhodecode_user.user_id,
64 notif = NotificationModel().get_for_user(self.rhodecode_user.user_id,
65 filter_=request.GET.getall('type'))
65 filter_=request.GET.getall('type'))
66
66
67 p = safe_int(request.params.get('page', 1), 1)
67 p = safe_int(request.params.get('page', 1), 1)
68 c.notifications = Page(notif, page=p, items_per_page=10)
68 c.notifications = Page(notif, page=p, items_per_page=10)
69 c.pull_request_type = Notification.TYPE_PULL_REQUEST
69 c.pull_request_type = Notification.TYPE_PULL_REQUEST
70 c.comment_type = [Notification.TYPE_CHANGESET_COMMENT,
70 c.comment_type = [Notification.TYPE_CHANGESET_COMMENT,
71 Notification.TYPE_PULL_REQUEST_COMMENT]
71 Notification.TYPE_PULL_REQUEST_COMMENT]
72
72
73 _current_filter = request.GET.getall('type')
73 _current_filter = request.GET.getall('type')
74 c.current_filter = 'all'
74 c.current_filter = 'all'
75 if _current_filter == [c.pull_request_type]:
75 if _current_filter == [c.pull_request_type]:
76 c.current_filter = 'pull_request'
76 c.current_filter = 'pull_request'
77 elif _current_filter == c.comment_type:
77 elif _current_filter == c.comment_type:
78 c.current_filter = 'comment'
78 c.current_filter = 'comment'
79
79
80 return render('admin/notifications/notifications.html')
80 return render('admin/notifications/notifications.html')
81
81
82 def mark_all_read(self):
82 def mark_all_read(self):
83 if request.environ.get('HTTP_X_PARTIAL_XHR'):
83 if request.environ.get('HTTP_X_PARTIAL_XHR'):
84 nm = NotificationModel()
84 nm = NotificationModel()
85 # mark all read
85 # mark all read
86 nm.mark_all_read_for_user(self.rhodecode_user.user_id,
86 nm.mark_all_read_for_user(self.rhodecode_user.user_id,
87 filter_=request.GET.getall('type'))
87 filter_=request.GET.getall('type'))
88 Session().commit()
88 Session().commit()
89 c.user = self.rhodecode_user
89 c.user = self.rhodecode_user
90 notif = nm.get_for_user(self.rhodecode_user.user_id,
90 notif = nm.get_for_user(self.rhodecode_user.user_id,
91 filter_=request.GET.getall('type'))
91 filter_=request.GET.getall('type'))
92 c.notifications = Page(notif, page=1, items_per_page=10)
92 c.notifications = Page(notif, page=1, items_per_page=10)
93 return render('admin/notifications/notifications_data.html')
93 return render('admin/notifications/notifications_data.html')
94
94
95 def create(self):
95 def create(self):
96 """POST /_admin/notifications: Create a new item"""
96 """POST /_admin/notifications: Create a new item"""
97 # url('notifications')
97 # url('notifications')
98
98
99 def new(self, format='html'):
99 def new(self, format='html'):
100 """GET /_admin/notifications/new: Form to create a new item"""
100 """GET /_admin/notifications/new: Form to create a new item"""
101 # url('new_notification')
101 # url('new_notification')
102
102
103 def update(self, notification_id):
103 def update(self, notification_id):
104 """PUT /_admin/notifications/id: Update an existing item"""
104 """PUT /_admin/notifications/id: Update an existing item"""
105 # Forms posted to this method should contain a hidden field:
105 # Forms posted to this method should contain a hidden field:
106 # <input type="hidden" name="_method" value="PUT" />
106 # <input type="hidden" name="_method" value="PUT" />
107 # Or using helpers:
107 # Or using helpers:
108 # h.form(url('notification', notification_id=ID),
108 # h.form(url('notification', notification_id=ID),
109 # method='put')
109 # method='put')
110 # url('notification', notification_id=ID)
110 # url('notification', notification_id=ID)
111 try:
111 try:
112 no = Notification.get(notification_id)
112 no = Notification.get(notification_id)
113 owner = all(un.user.user_id == c.rhodecode_user.user_id
113 owner = all(un.user.user_id == c.rhodecode_user.user_id
114 for un in no.notifications_to_users)
114 for un in no.notifications_to_users)
115 if h.HasPermissionAny('hg.admin')() or owner:
115 if h.HasPermissionAny('hg.admin')() or owner:
116 NotificationModel().mark_read(c.rhodecode_user.user_id, no)
116 NotificationModel().mark_read(c.rhodecode_user.user_id, no)
117 Session().commit()
117 Session().commit()
118 return 'ok'
118 return 'ok'
119 except Exception:
119 except Exception:
120 Session.rollback()
120 Session().rollback()
121 log.error(traceback.format_exc())
121 log.error(traceback.format_exc())
122 return 'fail'
122 return 'fail'
123
123
124 def delete(self, notification_id):
124 def delete(self, notification_id):
125 """DELETE /_admin/notifications/id: Delete an existing item"""
125 """DELETE /_admin/notifications/id: Delete an existing item"""
126 # Forms posted to this method should contain a hidden field:
126 # Forms posted to this method should contain a hidden field:
127 # <input type="hidden" name="_method" value="DELETE" />
127 # <input type="hidden" name="_method" value="DELETE" />
128 # Or using helpers:
128 # Or using helpers:
129 # h.form(url('notification', notification_id=ID),
129 # h.form(url('notification', notification_id=ID),
130 # method='delete')
130 # method='delete')
131 # url('notification', notification_id=ID)
131 # url('notification', notification_id=ID)
132
132
133 try:
133 try:
134 no = Notification.get(notification_id)
134 no = Notification.get(notification_id)
135 owner = all(un.user.user_id == c.rhodecode_user.user_id
135 owner = all(un.user.user_id == c.rhodecode_user.user_id
136 for un in no.notifications_to_users)
136 for un in no.notifications_to_users)
137 if h.HasPermissionAny('hg.admin')() or owner:
137 if h.HasPermissionAny('hg.admin')() or owner:
138 NotificationModel().delete(c.rhodecode_user.user_id, no)
138 NotificationModel().delete(c.rhodecode_user.user_id, no)
139 Session().commit()
139 Session().commit()
140 return 'ok'
140 return 'ok'
141 except Exception:
141 except Exception:
142 Session.rollback()
142 Session().rollback()
143 log.error(traceback.format_exc())
143 log.error(traceback.format_exc())
144 return 'fail'
144 return 'fail'
145
145
146 def show(self, notification_id, format='html'):
146 def show(self, notification_id, format='html'):
147 """GET /_admin/notifications/id: Show a specific item"""
147 """GET /_admin/notifications/id: Show a specific item"""
148 # url('notification', notification_id=ID)
148 # url('notification', notification_id=ID)
149 c.user = self.rhodecode_user
149 c.user = self.rhodecode_user
150 no = Notification.get(notification_id)
150 no = Notification.get(notification_id)
151
151
152 owner = all(un.user.user_id == c.rhodecode_user.user_id
152 owner = any(un.user.user_id == c.rhodecode_user.user_id
153 for un in no.notifications_to_users)
153 for un in no.notifications_to_users)
154
154 if no and (h.HasPermissionAny('hg.admin', 'repository.admin')() or owner):
155 if no and (h.HasPermissionAny('hg.admin', 'repository.admin')() or owner):
155 unotification = NotificationModel()\
156 unotification = NotificationModel()\
156 .get_user_notification(c.user.user_id, no)
157 .get_user_notification(c.user.user_id, no)
157
158
158 # if this association to user is not valid, we don't want to show
159 # if this association to user is not valid, we don't want to show
159 # this message
160 # this message
160 if unotification:
161 if unotification:
161 if unotification.read is False:
162 if unotification.read is False:
162 unotification.mark_as_read()
163 unotification.mark_as_read()
163 Session().commit()
164 Session().commit()
164 c.notification = no
165 c.notification = no
165
166
166 return render('admin/notifications/show_notification.html')
167 return render('admin/notifications/show_notification.html')
167
168
168 return redirect(url('notifications'))
169 return abort(403)
169
170
170 def edit(self, notification_id, format='html'):
171 def edit(self, notification_id, format='html'):
171 """GET /_admin/notifications/id/edit: Form to edit an existing item"""
172 """GET /_admin/notifications/id/edit: Form to edit an existing item"""
172 # url('edit_notification', notification_id=ID)
173 # url('edit_notification', notification_id=ID)
General Comments 0
You need to be logged in to leave comments. Login now