##// END OF EJS Templates
implemented public journal for anonymous users, admin can control which repositories...
marcink -
r1085:3fe32858 beta
parent child Browse files
Show More
@@ -0,0 +1,31 b''
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
3 <%def name="title()">
4 ${_('Journal')} - ${c.rhodecode_name}
5 </%def>
6 <%def name="breadcrumbs()">
7 ${c.rhodecode_name}
8 </%def>
9 <%def name="page_nav()">
10 ${self.menu('home')}
11 </%def>
12 <%def name="main()">
13
14 <div class="box">
15 <!-- box / title -->
16 <div class="title">
17 <h5>${_('Public Journal')}</h5>
18 </div>
19 <script type="text/javascript">
20 function show_more_event(){
21 YUE.on(YUD.getElementsByClassName('show_more'),'click',function(e){
22 var el = e.target;
23 YUD.setStyle(YUD.get(el.id.substring(1)),'display','');
24 YUD.setStyle(el.parentNode,'display','none');
25 });
26 }
27 </script>
28 <div id="journal">${c.journal_data}</div>
29 </div>
30
31 </%def>
@@ -86,6 +86,9 b' def make_map(config):'
86 m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
86 m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
87 action="repo_cache", conditions=dict(method=["DELETE"],
87 action="repo_cache", conditions=dict(method=["DELETE"],
88 function=check_repo))
88 function=check_repo))
89 m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*}",
90 action="repo_public_journal", conditions=dict(method=["PUT"],
91 function=check_repo))
89
92
90 #ADMIN USER REST ROUTES
93 #ADMIN USER REST ROUTES
91 routes_map.resource('user', 'users', controller='admin/users', path_prefix='/_admin')
94 routes_map.resource('user', 'users', controller='admin/users', path_prefix='/_admin')
@@ -145,6 +148,8 b' def make_map(config):'
145
148
146 #USER JOURNAL
149 #USER JOURNAL
147 routes_map.connect('journal', '/_admin/journal', controller='journal',)
150 routes_map.connect('journal', '/_admin/journal', controller='journal',)
151 routes_map.connect('public_journal', '/_admin/public_journal', controller='journal',
152 action="public_journal")
148 routes_map.connect('toggle_following', '/_admin/toggle_following', controller='journal',
153 routes_map.connect('toggle_following', '/_admin/toggle_following', controller='journal',
149 action='toggle_following', conditions=dict(method=["POST"]))
154 action='toggle_following', conditions=dict(method=["POST"]))
150
155
@@ -41,7 +41,8 b' from rhodecode.lib.auth import LoginRequ'
41 HasPermissionAnyDecorator
41 HasPermissionAnyDecorator
42 from rhodecode.lib.base import BaseController, render
42 from rhodecode.lib.base import BaseController, render
43 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
43 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
44 from rhodecode.model.db import User
44 from rhodecode.lib.helpers import get_token
45 from rhodecode.model.db import User, Repository, UserFollowing
45 from rhodecode.model.forms import RepoForm
46 from rhodecode.model.forms import RepoForm
46 from rhodecode.model.scm import ScmModel
47 from rhodecode.model.scm import ScmModel
47 from rhodecode.model.repo import RepoModel
48 from rhodecode.model.repo import RepoModel
@@ -50,7 +51,8 b' from rhodecode.model.repo import RepoMod'
50 log = logging.getLogger(__name__)
51 log = logging.getLogger(__name__)
51
52
52 class ReposController(BaseController):
53 class ReposController(BaseController):
53 """REST Controller styled on the Atom Publishing Protocol"""
54 """
55 REST Controller styled on the Atom Publishing Protocol"""
54 # To properly map this controller, ensure your config/routing.py
56 # To properly map this controller, ensure your config/routing.py
55 # file has a resource setup:
57 # file has a resource setup:
56 # map.resource('repo', 'repos')
58 # map.resource('repo', 'repos')
@@ -72,7 +74,8 b' class ReposController(BaseController):'
72
74
73 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
75 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
74 def create(self):
76 def create(self):
75 """POST /repos: Create a new item"""
77 """
78 POST /repos: Create a new item"""
76 # url('repos')
79 # url('repos')
77 repo_model = RepoModel()
80 repo_model = RepoModel()
78 _form = RepoForm()()
81 _form = RepoForm()()
@@ -124,7 +127,8 b' class ReposController(BaseController):'
124
127
125 @HasPermissionAllDecorator('hg.admin')
128 @HasPermissionAllDecorator('hg.admin')
126 def update(self, repo_name):
129 def update(self, repo_name):
127 """PUT /repos/repo_name: Update an existing item"""
130 """
131 PUT /repos/repo_name: Update an existing item"""
128 # Forms posted to this method should contain a hidden field:
132 # Forms posted to this method should contain a hidden field:
129 # <input type="hidden" name="_method" value="PUT" />
133 # <input type="hidden" name="_method" value="PUT" />
130 # Or using helpers:
134 # Or using helpers:
@@ -156,6 +160,11 b' class ReposController(BaseController):'
156 repo, dbrepo = ScmModel().get(repo_name, retval='repo')
160 repo, dbrepo = ScmModel().get(repo_name, retval='repo')
157 c.repo_last_rev = repo.count() if repo.revisions else 0
161 c.repo_last_rev = repo.count() if repo.revisions else 0
158
162
163 c.default_user_id = User.by_username('default').user_id
164 c.in_public_journal = self.sa.query(UserFollowing)\
165 .filter(UserFollowing.user_id == c.default_user_id)\
166 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
167
159 if last_rev == 0:
168 if last_rev == 0:
160 c.stats_percentage = 0
169 c.stats_percentage = 0
161 else:
170 else:
@@ -182,7 +191,8 b' class ReposController(BaseController):'
182
191
183 @HasPermissionAllDecorator('hg.admin')
192 @HasPermissionAllDecorator('hg.admin')
184 def delete(self, repo_name):
193 def delete(self, repo_name):
185 """DELETE /repos/repo_name: Delete an existing item"""
194 """
195 DELETE /repos/repo_name: Delete an existing item"""
186 # Forms posted to this method should contain a hidden field:
196 # Forms posted to this method should contain a hidden field:
187 # <input type="hidden" name="_method" value="DELETE" />
197 # <input type="hidden" name="_method" value="DELETE" />
188 # Or using helpers:
198 # Or using helpers:
@@ -216,7 +226,8 b' class ReposController(BaseController):'
216
226
217 @HasPermissionAllDecorator('hg.admin')
227 @HasPermissionAllDecorator('hg.admin')
218 def delete_perm_user(self, repo_name):
228 def delete_perm_user(self, repo_name):
219 """DELETE an existing repository permission user
229 """
230 DELETE an existing repository permission user
220
231
221 :param repo_name:
232 :param repo_name:
222 """
233 """
@@ -231,7 +242,8 b' class ReposController(BaseController):'
231
242
232 @HasPermissionAllDecorator('hg.admin')
243 @HasPermissionAllDecorator('hg.admin')
233 def delete_perm_users_group(self, repo_name):
244 def delete_perm_users_group(self, repo_name):
234 """DELETE an existing repository permission users group
245 """
246 DELETE an existing repository permission users group
235
247
236 :param repo_name:
248 :param repo_name:
237 """
249 """
@@ -246,7 +258,8 b' class ReposController(BaseController):'
246
258
247 @HasPermissionAllDecorator('hg.admin')
259 @HasPermissionAllDecorator('hg.admin')
248 def repo_stats(self, repo_name):
260 def repo_stats(self, repo_name):
249 """DELETE an existing repository statistics
261 """
262 DELETE an existing repository statistics
250
263
251 :param repo_name:
264 :param repo_name:
252 """
265 """
@@ -261,7 +274,8 b' class ReposController(BaseController):'
261
274
262 @HasPermissionAllDecorator('hg.admin')
275 @HasPermissionAllDecorator('hg.admin')
263 def repo_cache(self, repo_name):
276 def repo_cache(self, repo_name):
264 """INVALIDATE existing repository cache
277 """
278 INVALIDATE existing repository cache
265
279
266 :param repo_name:
280 :param repo_name:
267 """
281 """
@@ -274,6 +288,35 b' class ReposController(BaseController):'
274 return redirect(url('edit_repo', repo_name=repo_name))
288 return redirect(url('edit_repo', repo_name=repo_name))
275
289
276 @HasPermissionAllDecorator('hg.admin')
290 @HasPermissionAllDecorator('hg.admin')
291 def repo_public_journal(self, repo_name):
292 """
293 Set's this repository to be visible in public journal,
294 in other words assing default user to follow this repo
295
296 :param repo_name:
297 """
298
299 cur_token = request.POST.get('auth_token')
300 token = get_token()
301 if cur_token == token:
302 try:
303 repo_id = Repository.by_repo_name(repo_name).repo_id
304 user_id = User.by_username('default').user_id
305 self.scm_model.toggle_following_repo(repo_id, user_id)
306 h.flash(_('Updated repository visibility in public journal'),
307 category='success')
308 except:
309 h.flash(_('An error occurred during setting this'
310 ' repository in public journal'),
311 category='error')
312
313 else:
314 h.flash(_('Token mismatch'), category='error')
315 return redirect(url('edit_repo', repo_name=repo_name))
316
317
318
319 @HasPermissionAllDecorator('hg.admin')
277 def show(self, repo_name, format='html'):
320 def show(self, repo_name, format='html'):
278 """GET /repos/repo_name: Show a specific item"""
321 """GET /repos/repo_name: Show a specific item"""
279 # url('repo', repo_name=ID)
322 # url('repo', repo_name=ID)
@@ -296,6 +339,11 b' class ReposController(BaseController):'
296
339
297 return redirect(url('repos'))
340 return redirect(url('repos'))
298
341
342 c.default_user_id = User.by_username('default').user_id
343 c.in_public_journal = self.sa.query(UserFollowing)\
344 .filter(UserFollowing.user_id == c.default_user_id)\
345 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
346
299 if c.repo_info.stats:
347 if c.repo_info.stats:
300 last_rev = c.repo_info.stats.stat_on_revision
348 last_rev = c.repo_info.stats.stat_on_revision
301 else:
349 else:
@@ -45,42 +45,20 b' class JournalController(BaseController):'
45
45
46
46
47 @LoginRequired()
47 @LoginRequired()
48 @NotAnonymous()
49 def __before__(self):
48 def __before__(self):
50 super(JournalController, self).__before__()
49 super(JournalController, self).__before__()
51
50
51 @NotAnonymous()
52 def index(self):
52 def index(self):
53 # Return a rendered template
53 # Return a rendered template
54 p = int(request.params.get('page', 1))
54
55
55 c.following = self.sa.query(UserFollowing)\
56 c.following = self.sa.query(UserFollowing)\
56 .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\
57 .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\
57 .options(joinedload(UserFollowing.follows_repository))\
58 .options(joinedload(UserFollowing.follows_repository))\
58 .all()
59 .all()
59
60
60
61 journal = self._get_journal_data(c.following)
61 repo_ids = [x.follows_repository.repo_id for x in c.following
62 if x.follows_repository is not None]
63 user_ids = [x.follows_user.user_id for x in c.following
64 if x.follows_user is not None]
65
66 filtering_criterion = None
67
68 if repo_ids and user_ids:
69 filtering_criterion = or_(UserLog.repository_id.in_(repo_ids),
70 UserLog.user_id.in_(user_ids))
71 if repo_ids and not user_ids:
72 filtering_criterion = UserLog.repository_id.in_(repo_ids)
73 if not repo_ids and user_ids:
74 filtering_criterion = UserLog.user_id.in_(user_ids)
75 if filtering_criterion is not None:
76 journal = self.sa.query(UserLog)\
77 .options(joinedload(UserLog.user))\
78 .options(joinedload(UserLog.repository))\
79 .filter(filtering_criterion)\
80 .order_by(UserLog.action_date.desc())
81 else:
82 journal = []
83 p = int(request.params.get('page', 1))
84
62
85 c.journal_pager = Page(journal, page=p, items_per_page=20)
63 c.journal_pager = Page(journal, page=p, items_per_page=20)
86
64
@@ -105,6 +83,34 b' class JournalController(BaseController):'
105 return groups
83 return groups
106
84
107
85
86 def _get_journal_data(self, following_repos):
87 repo_ids = [x.follows_repository.repo_id for x in following_repos
88 if x.follows_repository is not None]
89 user_ids = [x.follows_user.user_id for x in following_repos
90 if x.follows_user is not None]
91
92 filtering_criterion = None
93
94 if repo_ids and user_ids:
95 filtering_criterion = or_(UserLog.repository_id.in_(repo_ids),
96 UserLog.user_id.in_(user_ids))
97 if repo_ids and not user_ids:
98 filtering_criterion = UserLog.repository_id.in_(repo_ids)
99 if not repo_ids and user_ids:
100 filtering_criterion = UserLog.user_id.in_(user_ids)
101 if filtering_criterion is not None:
102 journal = self.sa.query(UserLog)\
103 .options(joinedload(UserLog.user))\
104 .options(joinedload(UserLog.repository))\
105 .filter(filtering_criterion)\
106 .order_by(UserLog.action_date.desc())
107 else:
108 journal = []
109
110
111 return journal
112
113 @NotAnonymous()
108 def toggle_following(self):
114 def toggle_following(self):
109 cur_token = request.POST.get('auth_token')
115 cur_token = request.POST.get('auth_token')
110 token = get_token()
116 token = get_token()
@@ -131,3 +137,26 b' class JournalController(BaseController):'
131
137
132 log.debug('token mismatch %s vs %s', cur_token, token)
138 log.debug('token mismatch %s vs %s', cur_token, token)
133 raise HTTPInternalServerError()
139 raise HTTPInternalServerError()
140
141
142
143
144 def public_journal(self):
145 # Return a rendered template
146 p = int(request.params.get('page', 1))
147
148 c.following = self.sa.query(UserFollowing)\
149 .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\
150 .options(joinedload(UserFollowing.follows_repository))\
151 .all()
152
153 journal = self._get_journal_data(c.following)
154
155 c.journal_pager = Page(journal, page=p, items_per_page=20)
156
157 c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
158
159 c.journal_data = render('journal/journal_data.html')
160 if request.params.get('partial'):
161 return c.journal_data
162 return render('journal/public_journal.html')
@@ -1987,6 +1987,20 b' padding-left:20px;'
1987 text-align:left;
1987 text-align:left;
1988 padding-top:1px;
1988 padding-top:1px;
1989 }
1989 }
1990 .start_following_icon {
1991 background:url("../images/icons/heart_add.png") no-repeat scroll 3px;
1992 height:16px;
1993 padding-left:20px;
1994 text-align:left;
1995 padding-top:1px;
1996 }
1997 .stop_following_icon {
1998 background:url("../images/icons/heart_delete.png") no-repeat scroll 3px;
1999 height:16px;
2000 padding-left:20px;
2001 text-align:left;
2002 padding-top:1px;
2003 }
1990
2004
1991 .action_button {
2005 .action_button {
1992 border:0;
2006 border:0;
@@ -302,7 +302,6 b''
302 <div class="form">
302 <div class="form">
303 <div class="fields">
303 <div class="fields">
304 ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="refresh_icon action_button",onclick="return confirm('Confirm to remove current statistics');")}
304 ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="refresh_icon action_button",onclick="return confirm('Confirm to remove current statistics');")}
305
306 <div class="field">
305 <div class="field">
307 <ul>
306 <ul>
308 <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
307 <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
@@ -323,6 +322,19 b''
323 </div>
322 </div>
324 ${h.end_form()}
323 ${h.end_form()}
325
324
325 <h3>${_('Public journal')}</h3>
326 ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')}
327 <div class="form">
328 <div class="fields">
329 ${h.hidden('auth_token',str(h.get_token()))}
330 %if c.in_public_journal:
331 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="stop_following_icon action_button")}
332 %else:
333 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="start_following_icon action_button")}
334 %endif
335 </div>
336 </div>
337 ${h.end_form()}
326
338
327 <h3>${_('Delete')}</h3>
339 <h3>${_('Delete')}</h3>
328 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
340 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
@@ -38,12 +38,7 b''
38 </div>
38 </div>
39 <div class="account">
39 <div class="account">
40 %if c.rhodecode_user.username == 'default':
40 %if c.rhodecode_user.username == 'default':
41 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
41 <a href="${h.url('public_journal')}">${_('Public journal')}</a>
42 ${h.link_to('anonymous',h.url('register'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
43 %else:
44 ${h.link_to('anonymous',h.url('#'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
45 %endif
46
47 %else:
42 %else:
48 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
43 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
49 %endif
44 %endif
@@ -373,20 +368,26 b' function onSuccess(target){'
373 }
368 }
374 }
369 }
375
370
376 function toggleFollowingUser(fallows_user_id,token){
371 function toggleFollowingUser(target,fallows_user_id,token,user_id){
377 args = 'follows_user_id='+fallows_user_id;
372 args = 'follows_user_id='+fallows_user_id;
378 args+= '&amp;auth_token='+token;
373 args+= '&amp;auth_token='+token;
374 if(user_id != undefined){
375 args+="&amp;user_id="+user_id;
376 }
379 YUC.asyncRequest('POST',base_url,{
377 YUC.asyncRequest('POST',base_url,{
380 success:function(o){
378 success:function(o){
381 onSuccess();
379 onSuccess(target);
382 }
380 }
383 },args); return false;
381 },args); return false;
384 }
382 }
385
383
386 function toggleFollowingRepo(target,fallows_repo_id,token){
384 function toggleFollowingRepo(target,fallows_repo_id,token,user_id){
387
385
388 args = 'follows_repo_id='+fallows_repo_id;
386 args = 'follows_repo_id='+fallows_repo_id;
389 args+= '&amp;auth_token='+token;
387 args+= '&amp;auth_token='+token;
388 if(user_id != undefined){
389 args+="&amp;user_id="+user_id;
390 }
390 YUC.asyncRequest('POST',base_url,{
391 YUC.asyncRequest('POST',base_url,{
391 success:function(o){
392 success:function(o){
392 onSuccess(target);
393 onSuccess(target);
General Comments 0
You need to be logged in to leave comments. Login now