Changeset - 30d3161c6683
[Not reviewed]
beta
0 5 0
Marcin Kuzminski - 15 years ago 2010-11-28 05:26:26
marcin@python-works.com
Implemented fancier top menu for logged and anonymous users
little error fix for cached query
5 files changed with 65 insertions and 38 deletions:
0 comments (0 inline, 0 general)
rhodecode/lib/base.py
Show inline comments
 
@@ -12,40 +12,41 @@ from rhodecode.model import meta
 
from rhodecode.model.scm import ScmModel
 
from rhodecode import BACKENDS
 

	
 
class BaseController(WSGIController):
 

	
 
    def __before__(self):
 
        c.rhodecode_version = __version__
 
        c.rhodecode_name = config['rhodecode_title']
 
        c.repo_name = get_repo_slug(request)
 
        c.cached_repo_list = ScmModel().get_repos()
 
        c.backends = BACKENDS.keys()
 

	
 
        self.sa = meta.Session()
 
        scm_model = ScmModel(self.sa)
 
        #c.unread_journal = scm_model.get_unread_journal()
 

	
 
        if c.repo_name:
 
            scm_model = ScmModel()
 
            cached_repo = scm_model.get(c.repo_name)
 

	
 
            if cached_repo:
 
                c.repository_tags = cached_repo.tags
 
                c.repository_branches = cached_repo.branches
 
                c.repository_followers = scm_model.get_followers(cached_repo.dbrepo.repo_id)
 
                c.repository_forks = scm_model.get_forks(cached_repo.dbrepo.repo_id)
 
            else:
 
                c.repository_tags = {}
 
                c.repository_branches = {}
 
                c.repository_followers = 0
 
                c.repository_forks = 0
 

	
 
        self.sa = meta.Session()
 

	
 
    def __call__(self, environ, start_response):
 
        """Invoke the Controller"""
 
        # WSGIController.__call__ dispatches to the Controller method
 
        # the request is routed to. This routing information is
 
        # available in environ['pylons.routes_dict']
 
        try:
 
            #putting this here makes sure that we update permissions every time
 
            self.rhodecode_user = c.rhodecode_user = auth.get_user(session)
 
            return WSGIController.__call__(self, environ, start_response)
 
        finally:
 
            meta.Session.remove()
rhodecode/model/caching_query.py
Show inline comments
 
@@ -46,29 +46,29 @@ class CachingQuery(Query):
 
    requests, i.e. such as ``Query(User.id, User.name)``.
 
    
 
    The Beaker cache is then loaded from the cache manager based
 
    on the region and composed namespace.  The key within the cache
 
    itself is then constructed against the bind parameters specified
 
    by this query, which are usually literals defined in the 
 
    WHERE clause.
 

	
 
    The FromCache and RelationshipCache mapper options below represent
 
    the "public" method of configuring this state upon the CachingQuery.
 
    
 
    """
 
    
 

	
 
    def __init__(self, manager, *args, **kw):
 
        self.cache_manager = manager
 
        Query.__init__(self, *args, **kw)
 
        
 

	
 
    def __iter__(self):
 
        """override __iter__ to pull results from Beaker
 
           if particular attributes have been configured.
 
           
 
           Note that this approach does *not* detach the loaded objects from
 
           the current session. If the cache backend is an in-process cache
 
           (like "memory") and lives beyond the scope of the current session's
 
           transaction, those objects may be expired. The method here can be
 
           modified to first expunge() each loaded item from the current
 
           session before returning the list of items, so that the items
 
           in the cache are not the same ones in the current Session.
 
           
 
@@ -92,49 +92,49 @@ class CachingQuery(Query):
 

	
 
        """
 
        cache, cache_key = _get_cache_parameters(self)
 
        ret = cache.get_value(cache_key, createfunc=createfunc)
 
        if merge:
 
            ret = self.merge_result(ret, load=False)
 
        return ret
 

	
 
    def set_value(self, value):
 
        """Set the value in the cache for this query."""
 

	
 
        cache, cache_key = _get_cache_parameters(self)
 
        cache.put(cache_key, value)        
 
        cache.put(cache_key, value)
 

	
 
def query_callable(manager):
 
    def query(*arg, **kw):
 
        return CachingQuery(manager, *arg, **kw)
 
    return query
 

	
 
def get_cache_region(name, region):
 
    if region not in beaker.cache.cache_regions:
 
        raise BeakerException('Cache region not configured: %s'
 
        raise BeakerException('Cache region `%s` not configured '
 
            'Check if proper cache settings are in the .ini files' % region)
 
    kw = beaker.cache.cache_regions[region]
 
    return beaker.cache.Cache._get_cache(name, kw)
 
    
 

	
 
def _get_cache_parameters(query):
 
    """For a query with cache_region and cache_namespace configured,
 
    return the correspoinding Cache instance and cache key, based
 
    on this query's current criterion and parameter values.
 

	
 
    """
 
    if not hasattr(query, '_cache_parameters'):
 
        raise ValueError("This Query does not have caching parameters configured.")
 

	
 
    region, namespace, cache_key = query._cache_parameters
 
    
 

	
 
    namespace = _namespace_from_query(namespace, query)
 

	
 
    if cache_key is None:
 
        # cache key - the value arguments from this query's parameters.
 
        args = _params_from_query(query)
 
        cache_key = " ".join([str(x) for x in args])
 

	
 
    # get cache
 
    #cache = query.cache_manager.get_cache_region(namespace, region)
 
    cache = get_cache_region(namespace, region)
 
    # optional - hash the cache_key too for consistent length
 
    # import uuid
 
@@ -144,33 +144,33 @@ def _get_cache_parameters(query):
 

	
 
def _namespace_from_query(namespace, query):
 
    # cache namespace - the token handed in by the 
 
    # option + class we're querying against
 
    namespace = " ".join([namespace] + [str(x) for x in query._entities])
 

	
 
    # memcached wants this
 
    namespace = namespace.replace(' ', '_')
 

	
 
    return namespace
 

	
 
def _set_cache_parameters(query, region, namespace, cache_key):
 
    
 

	
 
    if hasattr(query, '_cache_parameters'):
 
        region, namespace, cache_key = query._cache_parameters
 
        raise ValueError("This query is already configured "
 
                        "for region %r namespace %r" % 
 
                        "for region %r namespace %r" %
 
                        (region, namespace)
 
                    )
 
    query._cache_parameters = region, namespace, cache_key
 
    
 

	
 
class FromCache(MapperOption):
 
    """Specifies that a Query should load results from a cache."""
 

	
 
    propagate_to_loaders = False
 

	
 
    def __init__(self, region, namespace, cache_key=None):
 
        """Construct a new FromCache.
 
        
 
        :param region: the cache region.  Should be a
 
        region configured in the Beaker CacheManager.
 
        
 
        :param namespace: the cache namespace.  Should
 
@@ -178,28 +178,28 @@ class FromCache(MapperOption):
 
        lexical structure.
 
        
 
        :param cache_key: optional.  A string cache key 
 
        that will serve as the key to the query.   Use this
 
        if your query has a huge amount of parameters (such
 
        as when using in_()) which correspond more simply to 
 
        some other identifier.
 

	
 
        """
 
        self.region = region
 
        self.namespace = namespace
 
        self.cache_key = cache_key
 
    
 

	
 
    def process_query(self, query):
 
        """Process a Query during normal loading operation."""
 
        
 

	
 
        _set_cache_parameters(query, self.region, self.namespace, self.cache_key)
 

	
 
class RelationshipCache(MapperOption):
 
    """Specifies that a Query as called within a "lazy load" 
 
       should load results from a cache."""
 

	
 
    propagate_to_loaders = True
 

	
 
    def __init__(self, region, namespace, attribute):
 
        """Construct a new RelationshipCache.
 
        
 
        :param region: the cache region.  Should be a
 
@@ -254,23 +254,23 @@ class RelationshipCache(MapperOption):
 
def _params_from_query(query):
 
    """Pull the bind parameter values from a query.
 
    
 
    This takes into account any scalar attribute bindparam set up.
 
    
 
    E.g. params_from_query(query.filter(Cls.foo==5).filter(Cls.bar==7)))
 
    would return [5, 7].
 
    
 
    """
 
    v = []
 
    def visit_bindparam(bind):
 
        value = query._params.get(bind.key, bind.value)
 
        
 

	
 
        # lazyloader may dig a callable in here, intended
 
        # to late-evaluate params after autoflush is called.
 
        # convert to a scalar value.
 
        if callable(value):
 
            value = value()
 
            
 

	
 
        v.append(value)
 
    if query._criterion is not None:
 
        visitors.traverse(query._criterion, {}, {'bindparam':visit_bindparam})
 
    return v
rhodecode/model/scm.py
Show inline comments
 
@@ -37,25 +37,25 @@ from vcs.utils.lazy import LazyProperty
 
from mercurial import ui
 

	
 
from beaker.cache import cache_region, region_invalidate
 

	
 
from rhodecode import BACKENDS
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.auth import HasRepoPermissionAny
 
from rhodecode.lib.utils import get_repos, make_ui, action_logger
 
from rhodecode.model import BaseModel
 
from rhodecode.model.user import UserModel
 

	
 
from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
 
    UserFollowing
 
    UserFollowing, UserLog
 
from rhodecode.model.caching_query import FromCache
 

	
 
from sqlalchemy.orm import joinedload
 
from sqlalchemy.orm.session import make_transient
 
from sqlalchemy.exc import DatabaseError
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class UserTemp(object):
 
    def __init__(self, user_id):
 
        self.user_id = user_id
 
@@ -324,24 +324,29 @@ class ScmModel(BaseModel):
 
            .filter(UserFollowing.user_id == user_id).scalar()
 

	
 
        return f is not None
 

	
 
    def get_followers(self, repo_id):
 
        return self.sa.query(UserFollowing)\
 
                .filter(UserFollowing.follows_repo_id == repo_id).count()
 

	
 
    def get_forks(self, repo_id):
 
        return self.sa.query(Repository)\
 
                .filter(Repository.fork_id == repo_id).count()
 

	
 

	
 
    def get_unread_journal(self):
 
        return self.sa.query(UserLog).count()
 

	
 

	
 
    def _should_invalidate(self, repo_name):
 
        """
 
        Looks up database for invalidation signals for this repo_name
 
        :param repo_name:
 
        """
 

	
 
        ret = self.sa.query(CacheInvalidation)\
 
            .options(FromCache('sql_cache_short',
 
                           'get_invalidation_%s' % repo_name))\
 
            .filter(CacheInvalidation.cache_key == repo_name)\
 
            .filter(CacheInvalidation.cache_active == False)\
 
            .scalar()
rhodecode/public/css/style.css
Show inline comments
 
@@ -181,64 +181,77 @@ border-bottom-left-radius: 8px;
 
-webkit-border-bottom-right-radius: 8px;
 
-khtml-border-radius-bottomright: 8px; 
 
-moz-border-radius-bottomright: 8px;
 
border-bottom-right-radius: 8px;
 
}
 
 
 
#header {
 
margin:0;
 
padding:0 30px;
 
}
 
 
 
#header ul#logged-user{
 
margin-bottom:5px !important;
 
-webkit-border-radius: 0px 0px 8px 8px;
 
-khtml-border-radius: 0px 0px 8px 8px; 
 
-moz-border-radius: 0px 0px 8px 8px;
 
border-radius: 0px 0px 8px 8px;
 
height:37px;
 
background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367
 
}
 
 
#header ul#logged-user li {
 
list-style:none;
 
float:left;
 
border-left:1px solid #bbb;
 
border-right:1px solid #a5a5a5;
 
margin:-2px 0 0;
 
padding:10px 12px;
 
margin:8px 0 0;
 
padding:4px 12px;
 
border-left: 1px solid #316293;
 
}
 
 
#header ul#logged-user li.first {
 
border-left:none;
 
margin:-6px;
 
margin:4px;
 
}
 
 
#header ul#logged-user li.first div.gravatar {
 
margin-top:-2px;
 
}
 
 
#header ul#logged-user li.first div.account {
 
padding-top:4px;
 
float:left;
 
}
 
 
#header ul#logged-user li.last {
 
border-right:none;
 
}
 
 
#header ul#logged-user li a {
 
color:#4e4e4e;
 
color:#fff;
 
font-weight:700;
 
text-decoration:none;
 
}
 
 
#header ul#logged-user li a:hover {
 
color:#376ea6;
 
text-decoration:underline;
 
}
 
 
#header ul#logged-user li.highlight a {
 
color:#fff;
 
}
 
 
#header ul#logged-user li.highlight a:hover {
 
color:#376ea6;
 
color:#FFF;
 
}
 
 
#header #header-inner {
 
height:40px;
 
clear:both;
 
position:relative;
 
background:#003367 url("../images/header_inner.png") repeat-x;
 
border-bottom:2px solid #fff;
 
margin:0;
 
padding:0;
 
}
 
rhodecode/templates/base/base.html
Show inline comments
 
@@ -7,44 +7,52 @@
 
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
 
    <meta name="robots" content="index, nofollow"/>
 
    <!-- stylesheets -->
 
    ${self.css()}
 
    <!-- scripts -->
 
    ${self.js()}
 
</head>
 
<body>
 
    <!-- header -->
 
    <div id="header">
 
        <!-- user -->
 
        <ul id="logged-user">
 
            %if c.rhodecode_user.username == 'default':
 
	            <li class="first">
 
	                <div class="account">
 
	                  ##  ${h.link_to('%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname),h.url('#'))}<br/>
 
	                  ##  ${h.link_to(c.rhodecode_user.username,h.url('#'))}
 
	                </div>  
 
	            </li>
 
            <li class="last highlight">${h.link_to(u'Login',h.url('login_home'))}</li>
 
	        %else:
 
	            <li class="first">
 
	                <div class="gravatar">
 
	                    <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,24)}" />
 
	                    <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,20)}" />
 
	                </div>
 
		            <div class="account">
 
		            	${h.link_to('%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname),h.url('admin_settings_my_account'))}<br/>
 
		            %if c.rhodecode_user.username == 'default':
 
                        ##${h.link_to('%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname),h.url('register'))}<br/>
 
                        ${h.link_to('anonymous',h.url('register'))}
 
                    %else:                        		            
 
		            	##${h.link_to('%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname),h.url('admin_settings_my_account'))}<br/>
 
		            	${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'))}
 
		            %endif
 
		            </div>	
 
	            </li>
 
	            <li class="last highlight">${h.link_to(u'Logout',h.url('logout_home'))}</li>
 
            %endif
 
	            <li>
 
	               <a href="${h.url('home')}">${_('Home')}</a>
 
	            </li>
 
                <li>
 
                   <a href="${h.url('journal')}">${_('Journal')}</a> 
 
                   ##(${c.unread_journal})</a>
 
                </li>	         
 
                %if c.rhodecode_user.username == 'default':
 
                    <li class="last highlight">${h.link_to(u'Login',h.url('login_home'))}</li>
 
                %else:                                          
 
                    <li class="last highlight">${h.link_to(u'Log Out',h.url('logout_home'))}</li>
 
                %endif                   
 
	            
 
	            
 
        </ul>
 
        <!-- end user -->
 
        <div id="header-inner" class="title top-left-rounded-corner top-right-rounded-corner">
 
            <!-- logo -->
 
            <div id="logo">
 
                <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
 
            </div>
 
            <!-- end logo -->
 
            <!-- menu -->
 
            ${self.page_nav()}
 
            <!-- quick -->
 
        </div>
0 comments (0 inline, 0 general)