"""The base Controller API
Provides the BaseController class for subclassing.
"""
import logging
import time
from pylons import config, tmpl_context as c, request, session, url
from pylons.controllers import WSGIController
from pylons.controllers.util import redirect
from pylons.templating import render_mako as render
from paste.deploy.converters import asbool
from rhodecode import __version__
from rhodecode.lib import str2bool
from rhodecode.lib.auth import AuthUser, get_container_username
from rhodecode.lib.utils import get_repo_slug
from rhodecode.model import meta
from rhodecode.model.scm import ScmModel
from rhodecode import BACKENDS
from rhodecode.model.db import Repository
log = logging.getLogger(__name__)
class BaseController(WSGIController):
def __before__(self):
c.rhodecode_version = __version__
c.rhodecode_name = config.get('rhodecode_title')
c.use_gravatar = str2bool(config.get('use_gravatar'))
c.ga_code = config.get('rhodecode_ga_code')
c.repo_name = get_repo_slug(request)
c.backends = BACKENDS.keys()
self.cut_off_limit = int(config.get('cut_off_limit'))
self.sa = meta.Session()
self.scm_model = ScmModel(self.sa)
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']
start = time.time()
try:
# make sure that we update permissions each time we call controller
api_key = request.GET.get('api_key')
user_id = getattr(session.get('rhodecode_user'), 'user_id', None)
if asbool(config.get('container_auth_enabled', False)):
username = get_container_username(environ)
else:
username = None
auth_user = AuthUser(user_id, api_key, username)
self.rhodecode_user = c.rhodecode_user = auth_user
if not self.rhodecode_user.is_authenticated and \
self.rhodecode_user.user_id is not None:
self.rhodecode_user.set_authenticated(
getattr(session.get('rhodecode_user'),
'is_authenticated', False))
session['rhodecode_user'] = self.rhodecode_user
session.save()
return WSGIController.__call__(self, environ, start_response)
finally:
log.debug('Request time: %.3fs' % (time.time()-start))
meta.Session.remove()
class BaseRepoController(BaseController):
Base class for controllers responsible for loading all needed data for
repository loaded items are
c.rhodecode_repo: instance of scm repository
c.rhodecode_db_repo: instance of db
c.repository_followers: number of followers
c.repository_forks: number of forks
super(BaseRepoController, self).__before__()
if c.repo_name:
c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name)
c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
if c.rhodecode_repo is None:
log.error('%s this repository is present in database but it '
'cannot be created as an scm instance', c.repo_name)
redirect(url('home'))
c.repository_followers = self.scm_model.get_followers(c.repo_name)
c.repository_forks = self.scm_model.get_forks(c.repo_name)
@@ -361,195 +361,194 @@ def action_parser(user_log, feed=False):
html_tmpl = ('<span> %s '
'<a class="show_more" id="_%s" href="#more">%s</a> '
'%s</span>')
if not feed:
cs_links.append(html_tmpl % (_('and'), uniq_id, _('%s more') \
% (len(revs) - revs_limit),
_('revisions')))
html_tmpl = '<span id="%s" style="display:none"> %s </span>'
html_tmpl = '<span id="%s"> %s </span>'
cs_links.append(html_tmpl % (uniq_id, ', '.join([link_to(rev,
url('changeset_home',
repo_name=repo_name, revision=rev),
title=message(rev), class_='tooltip')
for rev in revs[revs_limit:revs_top_limit]])))
if len(revs) > 1:
cs_links.append(compare_view)
return ''.join(cs_links)
def get_fork_name():
repo_name = action_params
return _('fork name ') + str(link_to(action_params, url('summary_home',
repo_name=repo_name,)))
action_map = {'user_deleted_repo':(_('[deleted] repository'), None),
'user_created_repo':(_('[created] repository'), None),
'user_forked_repo':(_('[forked] repository'), get_fork_name),
'user_updated_repo':(_('[updated] repository'), None),
'admin_deleted_repo':(_('[delete] repository'), None),
'admin_created_repo':(_('[created] repository'), None),
'admin_forked_repo':(_('[forked] repository'), None),
'admin_updated_repo':(_('[updated] repository'), None),
'push':(_('[pushed] into'), get_cs_links),
'push_local':(_('[committed via RhodeCode] into'), get_cs_links),
'push_remote':(_('[pulled from remote] into'), get_cs_links),
'pull':(_('[pulled] from'), None),
'started_following_repo':(_('[started following] repository'), None),
'stopped_following_repo':(_('[stopped following] repository'), None),
}
action_str = action_map.get(action, action)
if feed:
action = action_str[0].replace('[', '').replace(']', '')
action = action_str[0].replace('[', '<span class="journal_highlight">')\
.replace(']', '</span>')
action_params_func = lambda :""
if callable(action_str[1]):
action_params_func = action_str[1]
return [literal(action), action_params_func]
def action_parser_icon(user_log):
action = user_log.action
action_params = None
x = action.split(':')
if len(x) > 1:
action, action_params = x
tmpl = """<img src="%s%s" alt="%s"/>"""
map = {'user_deleted_repo':'database_delete.png',
'user_created_repo':'database_add.png',
'user_forked_repo':'arrow_divide.png',
'user_updated_repo':'database_edit.png',
'admin_deleted_repo':'database_delete.png',
'admin_created_repo':'database_add.png',
'admin_forked_repo':'arrow_divide.png',
'admin_updated_repo':'database_edit.png',
'push':'script_add.png',
'push_local':'script_edit.png',
'push_remote':'connect.png',
'pull':'down_16.png',
'started_following_repo':'heart_add.png',
'stopped_following_repo':'heart_delete.png',
return literal(tmpl % ((url('/images/icons/')),
map.get(action, action), action))
#==============================================================================
# PERMS
from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
HasRepoPermissionAny, HasRepoPermissionAll
# GRAVATAR URL
def gravatar_url(email_address, size=30):
if not str2bool(config['app_conf'].get('use_gravatar')) or \
not email_address or \
email_address == 'anonymous@rhodecode.org':
if (not str2bool(config['app_conf'].get('use_gravatar')) or
not email_address or email_address == 'anonymous@rhodecode.org'):
return url("/images/user%s.png" % size)
ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
default = 'identicon'
baseurl_nossl = "http://www.gravatar.com/avatar/"
baseurl_ssl = "https://secure.gravatar.com/avatar/"
baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
if isinstance(email_address, unicode):
#hashlib crashes on unicode items
email_address = safe_str(email_address)
# construct the url
gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
return gravatar_url
# REPO PAGER, PAGER FOR REPOSITORY
class RepoPage(Page):
def __init__(self, collection, page=1, items_per_page=20,
item_count=None, url=None, branch_name=None, **kwargs):
"""Create a "RepoPage" instance. special pager for paging
repository
self._url_generator = url
# Safe the kwargs class-wide so they can be used in the pager() method
self.kwargs = kwargs
# Save a reference to the collection
self.original_collection = collection
self.collection = collection
# The self.page is the number of the current page.
# The first page has the number 1!
self.page = int(page) # make it int() if we get it as a string
except (ValueError, TypeError):
self.page = 1
self.items_per_page = items_per_page
# Unless the user tells us how many items the collections has
# we calculate that ourselves.
if item_count is not None:
self.item_count = item_count
self.item_count = len(self.collection)
# Compute the number of the first and last available page
if self.item_count > 0:
self.first_page = 1
self.page_count = int(math.ceil(float(self.item_count) /
self.items_per_page))
self.last_page = self.first_page + self.page_count - 1
# Make sure that the requested page number is the range of valid pages
if self.page > self.last_page:
self.page = self.last_page
elif self.page < self.first_page:
self.page = self.first_page
# Note: the number of items on this page can be less than
# items_per_page if the last page is not full
self.first_item = max(0, (self.item_count) - (self.page *
items_per_page))
self.last_item = ((self.item_count - 1) - items_per_page *
(self.page - 1))
iterator = self.collection.get_changesets(start=self.first_item,
end=self.last_item,
reverse=True,
branch_name=branch_name)
self.items = list(iterator)
# Links to previous and next page
if self.page > self.first_page:
self.previous_page = self.page - 1
self.previous_page = None
if self.page < self.last_page:
self.next_page = self.page + 1
self.next_page = None
# No items available
self.first_page = None
self.page_count = 0
## -*- coding: utf-8 -*-
<%inherit file="/base/base.html"/>
<%def name="title()">
${_('Edit user')} ${c.user.username} - ${c.rhodecode_name}
</%def>
<%def name="breadcrumbs_links()">
${h.link_to(_('Admin'),h.url('admin_home'))}
»
${h.link_to(_('Users'),h.url('users'))}
${_('edit')} "${c.user.username}"
<%def name="page_nav()">
${self.menu('admin')}
<%def name="main()">
<div class="box box-left">
<!-- box / title -->
<div class="title">
${self.breadcrumbs()}
</div>
<!-- end box / title -->
${h.form(url('update_user', id=c.user.user_id),method='put')}
<div class="form">
<div class="field">
<div class="gravatar_box">
<div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div>
<p>
<strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong><br/>
${_('Using')} ${c.user.email}
</p>
%if c.use_gravatar:
<strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong>
<br/>${_('Using')} ${c.user.email}
%else:
<br/>${c.user.email}
%endif
<div class="label">
<label>${_('API key')}</label> ${c.user.api_key}
<div class="fields">
<label for="username">${_('Username')}:</label>
<div class="input">
${h.text('username',class_='medium')}
<label for="ldap_dn">${_('LDAP DN')}:</label>
${h.text('ldap_dn',class_='medium')}
<label for="new_password">${_('New password')}:</label>
${h.password('new_password',class_='medium',autocomplete="off")}
<label for="password_confirmation">${_('New password confirmation')}:</label>
${h.password('password_confirmation',class_="medium",autocomplete="off")}
<label for="name">${_('First Name')}:</label>
${h.text('name',class_='medium')}
<label for="lastname">${_('Last Name')}:</label>
${h.text('lastname',class_='medium')}
<label for="email">${_('Email')}:</label>
${h.text('email',class_='medium')}
<div class="label label-checkbox">
<label for="active">${_('Active')}:</label>
<div class="checkboxes">
${h.checkbox('active',value=True)}
<label for="admin">${_('Admin')}:</label>
${h.checkbox('admin',value=True)}
<div class="buttons">
${h.submit('save',_('Save'),class_="ui-button")}
${h.reset('reset',_('Reset'),class_="ui-button")}
${h.end_form()}
${_('My account')} ${c.rhodecode_user.username} - ${c.rhodecode_name}
${_('My Account')}
<div>
${h.form(url('admin_settings_my_account_update'),method='put')}
${h.text('username',class_="medium")}
${h.password('new_password',class_="medium",autocomplete="off")}
${h.text('name',class_="medium")}
${h.text('lastname',class_="medium")}
${h.text('email',class_="medium")}
<div class="box box-right">
<h5>${_('My repositories')}
<input class="top-right-rounded-corner top-left-rounded-corner bottom-left-rounded-corner bottom-right-rounded-corner" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/>
</h5>
%if h.HasPermissionAny('hg.admin','hg.create.repository')():
<ul class="links">
<li>
<span>${h.link_to(_('ADD REPOSITORY'),h.url('admin_settings_create_repository'))}</span>
</li>
</ul>
<div class="table">
<table>
<thead>
<tr>
<th class="left">${_('Name')}</th>
<th class="left">${_('revision')}</th>
<th colspan="2" class="left">${_('action')}</th>
</thead>
Status change: