Commits

Marcin Kuzminski committed 3fe3285

implemented public journal for anonymous users, admin can control which repositories
are visible in such journal in admin panel

  • Participants
  • Parent commits 17721a2
  • Branches beta

Comments (0)

Files changed (7)

File rhodecode/config/routing.py

         m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
              action="repo_cache", conditions=dict(method=["DELETE"],
                                                         function=check_repo))
+        m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*}",
+             action="repo_public_journal", conditions=dict(method=["PUT"],
+                                                        function=check_repo))
 
     #ADMIN USER REST ROUTES
     routes_map.resource('user', 'users', controller='admin/users', path_prefix='/_admin')
 
     #USER JOURNAL
     routes_map.connect('journal', '/_admin/journal', controller='journal',)
+    routes_map.connect('public_journal', '/_admin/public_journal', controller='journal',
+                       action="public_journal")
     routes_map.connect('toggle_following', '/_admin/toggle_following', controller='journal',
                 action='toggle_following', conditions=dict(method=["POST"]))
 

File rhodecode/controllers/admin/repos.py

     HasPermissionAnyDecorator
 from rhodecode.lib.base import BaseController, render
 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
-from rhodecode.model.db import User
+from rhodecode.lib.helpers import get_token
+from rhodecode.model.db import User, Repository, UserFollowing
 from rhodecode.model.forms import RepoForm
 from rhodecode.model.scm import ScmModel
 from rhodecode.model.repo import RepoModel
 log = logging.getLogger(__name__)
 
 class ReposController(BaseController):
-    """REST Controller styled on the Atom Publishing Protocol"""
+    """
+    REST Controller styled on the Atom Publishing Protocol"""
     # To properly map this controller, ensure your config/routing.py
     # file has a resource setup:
     #     map.resource('repo', 'repos')
 
     @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
     def create(self):
-        """POST /repos: Create a new item"""
+        """
+        POST /repos: Create a new item"""
         # url('repos')
         repo_model = RepoModel()
         _form = RepoForm()()
 
     @HasPermissionAllDecorator('hg.admin')
     def update(self, repo_name):
-        """PUT /repos/repo_name: Update an existing item"""
+        """
+        PUT /repos/repo_name: Update an existing item"""
         # Forms posted to this method should contain a hidden field:
         #    <input type="hidden" name="_method" value="PUT" />
         # Or using helpers:
             repo, dbrepo = ScmModel().get(repo_name, retval='repo')
             c.repo_last_rev = repo.count() if repo.revisions else 0
 
+            c.default_user_id = User.by_username('default').user_id
+            c.in_public_journal = self.sa.query(UserFollowing)\
+                .filter(UserFollowing.user_id == c.default_user_id)\
+                .filter(UserFollowing.follows_repository == c.repo_info).scalar()
+
             if last_rev == 0:
                 c.stats_percentage = 0
             else:
 
     @HasPermissionAllDecorator('hg.admin')
     def delete(self, repo_name):
-        """DELETE /repos/repo_name: Delete an existing item"""
+        """
+        DELETE /repos/repo_name: Delete an existing item"""
         # Forms posted to this method should contain a hidden field:
         #    <input type="hidden" name="_method" value="DELETE" />
         # Or using helpers:
 
     @HasPermissionAllDecorator('hg.admin')
     def delete_perm_user(self, repo_name):
-        """DELETE an existing repository permission user
+        """
+        DELETE an existing repository permission user
         
         :param repo_name:
         """
 
     @HasPermissionAllDecorator('hg.admin')
     def delete_perm_users_group(self, repo_name):
-        """DELETE an existing repository permission users group
+        """
+        DELETE an existing repository permission users group
         
         :param repo_name:
         """
 
     @HasPermissionAllDecorator('hg.admin')
     def repo_stats(self, repo_name):
-        """DELETE an existing repository statistics
+        """
+        DELETE an existing repository statistics
         
         :param repo_name:
         """
 
     @HasPermissionAllDecorator('hg.admin')
     def repo_cache(self, repo_name):
-        """INVALIDATE existing repository cache
+        """
+        INVALIDATE existing repository cache
         
         :param repo_name:
         """
         return redirect(url('edit_repo', repo_name=repo_name))
 
     @HasPermissionAllDecorator('hg.admin')
+    def repo_public_journal(self, repo_name):
+        """
+        Set's this repository to be visible in public journal,
+        in other words assing default user to follow this repo
+        
+        :param repo_name:
+        """
+
+        cur_token = request.POST.get('auth_token')
+        token = get_token()
+        if cur_token == token:
+            try:
+                repo_id = Repository.by_repo_name(repo_name).repo_id
+                user_id = User.by_username('default').user_id
+                self.scm_model.toggle_following_repo(repo_id, user_id)
+                h.flash(_('Updated repository visibility in public journal'),
+                        category='success')
+            except:
+                h.flash(_('An error occurred during setting this'
+                          ' repository in public journal'),
+                        category='error')
+
+        else:
+            h.flash(_('Token mismatch'), category='error')
+        return redirect(url('edit_repo', repo_name=repo_name))
+
+
+
+    @HasPermissionAllDecorator('hg.admin')
     def show(self, repo_name, format='html'):
         """GET /repos/repo_name: Show a specific item"""
         # url('repo', repo_name=ID)
 
             return redirect(url('repos'))
 
+        c.default_user_id = User.by_username('default').user_id
+        c.in_public_journal = self.sa.query(UserFollowing)\
+            .filter(UserFollowing.user_id == c.default_user_id)\
+            .filter(UserFollowing.follows_repository == c.repo_info).scalar()
+
         if c.repo_info.stats:
             last_rev = c.repo_info.stats.stat_on_revision
         else:

File rhodecode/controllers/journal.py

 
 
     @LoginRequired()
-    @NotAnonymous()
     def __before__(self):
         super(JournalController, self).__before__()
 
+    @NotAnonymous()
     def index(self):
         # Return a rendered template
+        p = int(request.params.get('page', 1))
 
         c.following = self.sa.query(UserFollowing)\
             .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\
             .options(joinedload(UserFollowing.follows_repository))\
             .all()
 
+        journal = self._get_journal_data(c.following)
 
-        repo_ids = [x.follows_repository.repo_id for x in c.following
+        c.journal_pager = Page(journal, page=p, items_per_page=20)
+
+        c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
+
+        c.journal_data = render('journal/journal_data.html')
+        if request.params.get('partial'):
+            return c.journal_data
+        return render('journal/journal.html')
+
+
+    def _get_daily_aggregate(self, journal):
+        groups = []
+        for k, g in groupby(journal, lambda x:x.action_as_day):
+            user_group = []
+            for k2, g2 in groupby(list(g), lambda x:x.user.email):
+                l = list(g2)
+                user_group.append((l[0].user, l))
+
+            groups.append((k, user_group,))
+
+        return groups
+
+
+    def _get_journal_data(self, following_repos):
+        repo_ids = [x.follows_repository.repo_id for x in following_repos
                     if x.follows_repository is not None]
-        user_ids = [x.follows_user.user_id for x in c.following
+        user_ids = [x.follows_user.user_id for x in following_repos
                     if x.follows_user is not None]
 
         filtering_criterion = None
                 .order_by(UserLog.action_date.desc())
         else:
             journal = []
-        p = int(request.params.get('page', 1))
 
-        c.journal_pager = Page(journal, page=p, items_per_page=20)
 
-        c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
+        return journal
 
-        c.journal_data = render('journal/journal_data.html')
-        if request.params.get('partial'):
-            return c.journal_data
-        return render('journal/journal.html')
-
-
-    def _get_daily_aggregate(self, journal):
-        groups = []
-        for k, g in groupby(journal, lambda x:x.action_as_day):
-            user_group = []
-            for k2, g2 in groupby(list(g), lambda x:x.user.email):
-                l = list(g2)
-                user_group.append((l[0].user, l))
-
-            groups.append((k, user_group,))
-
-        return groups
-
-
+    @NotAnonymous()
     def toggle_following(self):
         cur_token = request.POST.get('auth_token')
         token = get_token()
 
         log.debug('token mismatch %s vs %s', cur_token, token)
         raise HTTPInternalServerError()
+
+
+
+
+    def public_journal(self):
+        # Return a rendered template
+        p = int(request.params.get('page', 1))
+
+        c.following = self.sa.query(UserFollowing)\
+            .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\
+            .options(joinedload(UserFollowing.follows_repository))\
+            .all()
+
+        journal = self._get_journal_data(c.following)
+
+        c.journal_pager = Page(journal, page=p, items_per_page=20)
+
+        c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
+
+        c.journal_data = render('journal/journal_data.html')
+        if request.params.get('partial'):
+            return c.journal_data
+        return render('journal/public_journal.html')

File rhodecode/public/css/style.css

 text-align:left;
 padding-top:1px;
 }
+.start_following_icon {
+background:url("../images/icons/heart_add.png") no-repeat scroll 3px;
+height:16px;
+padding-left:20px;
+text-align:left;
+padding-top:1px;
+}
+.stop_following_icon {
+background:url("../images/icons/heart_delete.png") no-repeat scroll 3px;
+height:16px;
+padding-left:20px;
+text-align:left;
+padding-top:1px;
+}
 
 .action_button {
 border:0;

File rhodecode/templates/admin/repos/repo_edit.html

         <div class="form">
            <div class="fields">
                ${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');")}
-               
                <div class="field">
                <ul>
                     <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
         </div>                    
         ${h.end_form()}
         
+        <h3>${_('Public journal')}</h3>
+        ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')}
+        <div class="form">
+            <div class="fields">
+                ${h.hidden('auth_token',str(h.get_token()))}
+                %if c.in_public_journal:
+                    ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="stop_following_icon action_button")}
+                %else:
+		            ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="start_following_icon action_button")}
+		        %endif
+	         </div>        
+        </div>
+        ${h.end_form()}
         
         <h3>${_('Delete')}</h3>
         ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}

File rhodecode/templates/base/base.html

 	                </div>
 		            <div class="account">
 		            %if c.rhodecode_user.username == 'default':
-                        %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')(): 
-                            ${h.link_to('anonymous',h.url('register'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
-                        %else:
-                            ${h.link_to('anonymous',h.url('#'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
-                        %endif		            
-                        
+		                <a href="${h.url('public_journal')}">${_('Public journal')}</a>   
                     %else:                        		            
 		            	${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
 		            %endif
     }
 }
 
-function toggleFollowingUser(fallows_user_id,token){
+function toggleFollowingUser(target,fallows_user_id,token,user_id){
     args = 'follows_user_id='+fallows_user_id;
     args+= '&amp;auth_token='+token;
+    if(user_id != undefined){
+    	args+="&amp;user_id="+user_id;
+    }
     YUC.asyncRequest('POST',base_url,{
         success:function(o){
-        	onSuccess();
+        	onSuccess(target);
         }
     },args); return false;
 }
 
-function toggleFollowingRepo(target,fallows_repo_id,token){
+function toggleFollowingRepo(target,fallows_repo_id,token,user_id){
 
     args = 'follows_repo_id='+fallows_repo_id;
     args+= '&amp;auth_token='+token;
+    if(user_id != undefined){
+        args+="&amp;user_id="+user_id;
+    }    
     YUC.asyncRequest('POST',base_url,{
         success:function(o){
         	onSuccess(target);

File rhodecode/templates/journal/public_journal.html

+## -*- coding: utf-8 -*-
+<%inherit file="/base/base.html"/>
+<%def name="title()">
+    ${_('Journal')} - ${c.rhodecode_name}
+</%def>
+<%def name="breadcrumbs()">
+	${c.rhodecode_name}
+</%def>
+<%def name="page_nav()">
+	${self.menu('home')}
+</%def>
+<%def name="main()">
+	
+    <div class="box">
+	    <!-- box / title -->
+	    <div class="title">
+	        <h5>${_('Public Journal')}</h5>
+	    </div>
+		<script type="text/javascript">
+		function show_more_event(){
+		YUE.on(YUD.getElementsByClassName('show_more'),'click',function(e){
+		    var el = e.target;
+		    YUD.setStyle(YUD.get(el.id.substring(1)),'display','');
+		    YUD.setStyle(el.parentNode,'display','none');
+		});
+		}
+		</script> 	    
+	    <div id="journal">${c.journal_data}</div>
+    </div>
+     
+</%def>