Changeset - 229437211bef
[Not reviewed]
beta
0 3 0
Marcin Kuzminski - 15 years ago 2011-02-06 00:27:45
marcin@python-works.com
Optimized queries on journal, and added quick stop following action button in journal
3 files changed with 10 insertions and 2 deletions:
0 comments (0 inline, 0 general)
rhodecode/controllers/journal.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.journal
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Journal controller for pylons
 
    
 
    :created_on: Nov 21, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>    
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software; you can redistribute it and/or
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
# 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 General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 
from sqlalchemy import or_
 

	
 
from pylons import request, response, session, tmpl_context as c, url
 

	
 
from webhelpers.paginate import Page
 

	
 
from rhodecode.lib.auth import LoginRequired, NotAnonymous
 
from rhodecode.lib.base import BaseController, render
 
from rhodecode.lib.helpers import get_token
 
from rhodecode.model.db import UserLog, UserFollowing
 
from rhodecode.model.scm import ScmModel
 

	
 
from paste.httpexceptions import HTTPInternalServerError
 
from sqlalchemy.orm import joinedload
 

	
 
log = logging.getLogger(__name__)
 

	
 
class JournalController(BaseController):
 

	
 

	
 
    @LoginRequired()
 
    @NotAnonymous()
 
    def __before__(self):
 
        super(JournalController, self).__before__()
 

	
 
    def index(self):
 
        # Return a rendered template
 

	
 
        c.following = self.sa.query(UserFollowing)\
 
            .filter(UserFollowing.user_id == c.rhodecode_user.user_id).all()
 
            .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\
 
            .options(joinedload(UserFollowing.follows_repository))\
 
            .all()
 

	
 
        repo_ids = [x.follows_repository.repo_id for x in c.following
 
                    if x.follows_repository is not None]
 
        user_ids = [x.follows_user.user_id for x in c.following
 
                    if x.follows_user is not None]
 

	
 
        journal = self.sa.query(UserLog)\
 
            .filter(or_(
 
                        UserLog.repository_id.in_(repo_ids),
 
                        UserLog.user_id.in_(user_ids),
 
                        ))\
 
            .order_by(UserLog.action_date.desc())
 

	
 

	
 
        p = int(request.params.get('page', 1))
 
        c.journal_pager = Page(journal, page=p, items_per_page=10)
 
        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):
 
        from itertools import groupby
 
        groups = []
 
        for k, g in groupby(journal, lambda x:x.action_as_day):
 
            groups.append((k, list(g),))      # Store group iterator as a list
 

	
 
        return groups
 

	
 

	
 
    def toggle_following(self):
 
        cur_token = request.POST.get('auth_token')
 
        token = get_token()
 
        if cur_token == token:
 
            scm_model = ScmModel()
 

	
 
            user_id = request.POST.get('follows_user_id')
 
            if user_id:
 
                try:
 
                    scm_model.toggle_following_user(user_id,
 
                                                    c.rhodecode_user.user_id)
 
                    return 'ok'
 
                except:
 
                    raise HTTPInternalServerError()
 

	
rhodecode/model/db.py
Show inline comments
 
@@ -268,75 +268,75 @@ class UsersGroupToPerm(Base, BaseModel):
 
    __tablename__ = 'users_group_to_perm'
 
    __table_args__ = (UniqueConstraint('users_group_id', 'permission_id'), {'useexisting':True})
 
    users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
 
    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 

	
 
    users_group = relationship('UsersGroup')
 
    permission = relationship('Permission')
 

	
 
class GroupToPerm(Base, BaseModel):
 
    __tablename__ = 'group_to_perm'
 
    __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'useexisting':True})
 

	
 
    group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 
    group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
 

	
 
    user = relationship('User')
 
    permission = relationship('Permission')
 
    group = relationship('Group')
 

	
 
class Statistics(Base, BaseModel):
 
    __tablename__ = 'statistics'
 
    __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
 
    stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
 
    stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
 
    commit_activity = Column("commit_activity", LargeBinary(), nullable=False)#JSON data
 
    commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
 
    languages = Column("languages", LargeBinary(), nullable=False)#JSON data
 

	
 
    repository = relationship('Repository', single_parent=True)
 

	
 
class UserFollowing(Base, BaseModel):
 
    __tablename__ = 'user_followings'
 
    __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
 
                      UniqueConstraint('user_id', 'follows_user_id')
 
                      , {'useexisting':True})
 

	
 
    user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
    follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
 
    follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
 

	
 
    user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
 

	
 
    follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
 
    follows_repository = relationship('Repository')
 
    follows_repository = relationship('Repository', order_by='Repository.repo_name')
 

	
 
class CacheInvalidation(Base, BaseModel):
 
    __tablename__ = 'cache_invalidation'
 
    __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
 
    cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    cache_key = Column("cache_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    cache_args = Column("cache_args", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
 

	
 

	
 
    def __init__(self, cache_key, cache_args=''):
 
        self.cache_key = cache_key
 
        self.cache_args = cache_args
 
        self.cache_active = False
 

	
 
    def __repr__(self):
 
        return "<%s('%s:%s')>" % (self.__class__.__name__,
 
                                  self.cache_id, self.cache_key)
 

	
 
class DbMigrateVersion(Base, BaseModel):
 
    __tablename__ = 'db_migrate_version'
 
    __table_args__ = {'useexisting':True}
 
    repository_id = Column('repository_id', String(250), primary_key=True)
 
    repository_path = Column('repository_path', Text)
 
    version = Column('version', Integer)
 

	
rhodecode/templates/journal/journal.html
Show inline comments
 
## -*- 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-left">
 
	    <!-- box / title -->
 
	    <div class="title">
 
	        <h5>${_('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>
 
    
 
    <div class="box box-right">
 
        <!-- box / title -->
 
        <div class="title">
 
            <h5>${_('Following')}</h5>
 
        </div>
 
        <div>
 
		%if c.following:
 
		    %for entry in c.following:
 
		        <div class="currently_following">
 
		            %if entry.follows_user_id:
 
		              <img title="${_('following user')}" alt="${_('user')}" src="/images/icons/user.png"/>
 
		              ${entry.follows_user.full_contact}
 
		            %endif
 
		            
 
		            %if entry.follows_repo_id:
 
		            
 
		              <div style="float:left;padding-right:5px">
 
                      <span id="follow_toggle_${entry.follows_repository.repo_id}" class="following" title="${_('Stop following this repository')}"
 
                            onclick="javascript:toggleFollowingRepo(this,${entry.follows_repository.repo_id},'${str(h.get_token())}')">
 
                      </span>		            
 
		              </div>
 
		              %if entry.follows_repository.private:
 
		                <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="/images/icons/lock.png"/>
 
		              %else:
 
		                <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="/images/icons/lock_open.png"/>
 
		              %endif
 
		              
 
		              ${h.link_to(entry.follows_repository.repo_name,h.url('summary_home',
 
		                repo_name=entry.follows_repository.repo_name))}
 
		              
 
		            %endif
 
		        </div>
 
		    %endfor
 
		%else:
 
		    ${_('You are not following any users or repositories')}
 
		%endif
 
        </div>
 
    </div>    
 
</%def>    
0 comments (0 inline, 0 general)