Changeset - a36a8804e7be
[Not reviewed]
default
0 12 0
Mads Kiilerich (mads) - 5 years ago 2020-12-18 22:24:48
mads@kiilerich.com
Grafted from: f7c6ee9b26f5
lib: use webutils for special mako templates - helpers is only for controller web templates
12 files changed with 48 insertions and 49 deletions:
0 comments (0 inline, 0 general)
kallithea/controllers/admin/repo_groups.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
# 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, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# 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, see <http://www.gnu.org/licenses/>.
 
"""
 
kallithea.controllers.admin.repo_groups
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
Repository groups controller for Kallithea
 

	
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Mar 23, 2010
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import logging
 
import traceback
 

	
 
import formencode
 
from formencode import htmlfill
 
from tg import app_globals, request
 
from tg import tmpl_context as c
 
from tg.i18n import ugettext as _
 
from tg.i18n import ungettext
 
from webob.exc import HTTPForbidden, HTTPFound, HTTPInternalServerError, HTTPNotFound
 

	
 
import kallithea.lib.helpers as h
 
from kallithea.controllers import base
 
from kallithea.lib import webutils
 
from kallithea.lib.auth import HasPermissionAny, HasRepoGroupPermissionLevel, HasRepoGroupPermissionLevelDecorator, LoginRequired
 
from kallithea.lib.utils2 import safe_int
 
from kallithea.lib.webutils import url
 
from kallithea.model import db, meta
 
from kallithea.model.forms import RepoGroupForm, RepoGroupPermsForm
 
from kallithea.model.repo import RepoModel
 
from kallithea.model.repo_group import RepoGroupModel
 
from kallithea.model.scm import AvailableRepoGroupChoices, RepoGroupList
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class RepoGroupsController(base.BaseController):
 

	
 
    @LoginRequired(allow_default_user=True)
 
    def _before(self, *args, **kwargs):
 
        super(RepoGroupsController, self)._before(*args, **kwargs)
 

	
 
    def __load_defaults(self, extras=(), exclude=()):
 
        """extras is used for keeping current parent ignoring permissions
 
        exclude is used for not moving group to itself TODO: also exclude descendants
 
        Note: only admin can create top level groups
 
        """
 
        repo_groups = AvailableRepoGroupChoices('admin', extras)
 
        exclude_group_ids = set(rg.group_id for rg in exclude)
 
        c.repo_groups = [rg for rg in repo_groups
 
                         if rg[0] not in exclude_group_ids]
 

	
 
    def __load_data(self, group_id):
 
        """
 
        Load defaults settings for edit, and update
 

	
 
        :param group_id:
 
        """
 
        repo_group = db.RepoGroup.get_or_404(group_id)
 
        data = repo_group.get_dict()
 
        data['group_name'] = repo_group.name
 

	
 
        # fill repository group users
 
        for p in repo_group.repo_group_to_perm:
 
            data.update({'u_perm_%s' % p.user.username:
 
                             p.permission.permission_name})
 

	
 
        # fill repository group groups
 
        for p in repo_group.users_group_to_perm:
 
            data.update({'g_perm_%s' % p.users_group.users_group_name:
 
                             p.permission.permission_name})
 

	
 
        return data
 

	
 
    def _revoke_perms_on_yourself(self, form_result):
 
        _up = [u for u in form_result['perms_updates'] if request.authuser.username == u[0]]
 
        _new = [u for u in form_result['perms_new'] if request.authuser.username == u[0]]
 
        if _new and _new[0][1] != 'group.admin' or _up and _up[0][1] != 'group.admin':
 
            return True
 
        return False
 

	
 
    def index(self, format='html'):
 
        _list = db.RepoGroup.query(sorted=True).all()
 
        group_iter = RepoGroupList(_list, perm_level='admin')
 
        repo_groups_data = []
 
        _tmpl_lookup = app_globals.mako_lookup
 
        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
 

	
 
        def repo_group_name(repo_group_name, children_groups):
 
            return template.get_def("repo_group_name") \
 
                .render_unicode(repo_group_name, children_groups, _=_, h=h, c=c)
 
                .render_unicode(repo_group_name, children_groups, _=_, webutils=webutils, c=c)
 

	
 
        def repo_group_actions(repo_group_id, repo_group_name, gr_count):
 
            return template.get_def("repo_group_actions") \
 
                .render_unicode(repo_group_id, repo_group_name, gr_count, _=_, h=h, c=c,
 
                .render_unicode(repo_group_id, repo_group_name, gr_count, _=_, webutils=webutils, c=c,
 
                        ungettext=ungettext)
 

	
 
        for repo_gr in group_iter:
 
            children_groups = [g.name for g in repo_gr.parents] + [repo_gr.name]
 
            repo_count = repo_gr.repositories.count()
 
            repo_groups_data.append({
 
                "raw_name": webutils.escape(repo_gr.group_name),
 
                "group_name": repo_group_name(repo_gr.group_name, children_groups),
 
                "desc": webutils.escape(repo_gr.group_description),
 
                "repos": repo_count,
 
                "owner": repo_gr.owner.username,
 
                "action": repo_group_actions(repo_gr.group_id, repo_gr.group_name,
 
                                             repo_count)
 
            })
 

	
 
        c.data = {
 
            "sort": None,
 
            "dir": "asc",
 
            "records": repo_groups_data
 
        }
 

	
 
        return base.render('admin/repo_groups/repo_groups.html')
 

	
 
    def create(self):
 
        self.__load_defaults()
 

	
 
        # permissions for can create group based on parent_id are checked
 
        # here in the Form
 
        repo_group_form = RepoGroupForm(repo_groups=c.repo_groups)
 
        form_result = None
 
        try:
 
            form_result = repo_group_form.to_python(dict(request.POST))
 
            gr = RepoGroupModel().create(
 
                group_name=form_result['group_name'],
 
                group_description=form_result['group_description'],
 
                parent=form_result['parent_group_id'],
 
                owner=request.authuser.user_id, # TODO: make editable
 
                copy_permissions=form_result['group_copy_permissions']
 
            )
 
            meta.Session().commit()
 
            # TODO: in future action_logger(, '', '', '')
 
        except formencode.Invalid as errors:
 
            return htmlfill.render(
 
                base.render('admin/repo_groups/repo_group_add.html'),
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8",
kallithea/controllers/admin/user_groups.py
Show inline comments
 
@@ -44,101 +44,101 @@ from kallithea.lib.auth import HasPermis
 
from kallithea.lib.exceptions import RepoGroupAssignmentError, UserGroupsAssignedException
 
from kallithea.lib.utils2 import safe_int, safe_str
 
from kallithea.lib.webutils import url
 
from kallithea.model import db, meta, userlog
 
from kallithea.model.forms import CustomDefaultPermissionsForm, UserGroupForm, UserGroupPermsForm
 
from kallithea.model.scm import UserGroupList
 
from kallithea.model.user_group import UserGroupModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class UserGroupsController(base.BaseController):
 

	
 
    @LoginRequired(allow_default_user=True)
 
    def _before(self, *args, **kwargs):
 
        super(UserGroupsController, self)._before(*args, **kwargs)
 

	
 
    def __load_data(self, user_group_id):
 
        c.group_members_obj = sorted((x.user for x in c.user_group.members),
 
                                     key=lambda u: u.username.lower())
 

	
 
        c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
 
        c.available_members = sorted(((x.user_id, x.username) for x in
 
                                      db.User.query().all()),
 
                                     key=lambda u: u[1].lower())
 

	
 
    def __load_defaults(self, user_group_id):
 
        """
 
        Load defaults settings for edit, and update
 

	
 
        :param user_group_id:
 
        """
 
        user_group = db.UserGroup.get_or_404(user_group_id)
 
        data = user_group.get_dict()
 
        return data
 

	
 
    def index(self, format='html'):
 
        _list = db.UserGroup.query() \
 
                        .order_by(func.lower(db.UserGroup.users_group_name)) \
 
                        .all()
 
        group_iter = UserGroupList(_list, perm_level='admin')
 
        user_groups_data = []
 
        _tmpl_lookup = app_globals.mako_lookup
 
        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
 

	
 
        def user_group_name(user_group_id, user_group_name):
 
            return template.get_def("user_group_name") \
 
                .render_unicode(user_group_id, user_group_name, _=_, h=h, c=c)
 
                .render_unicode(user_group_id, user_group_name, _=_, webutils=webutils, c=c)
 

	
 
        def user_group_actions(user_group_id, user_group_name):
 
            return template.get_def("user_group_actions") \
 
                .render_unicode(user_group_id, user_group_name, _=_, h=h, c=c)
 
                .render_unicode(user_group_id, user_group_name, _=_, webutils=webutils, c=c)
 

	
 
        for user_gr in group_iter:
 
            user_groups_data.append({
 
                "raw_name": user_gr.users_group_name,
 
                "group_name": user_group_name(user_gr.users_group_id,
 
                                              user_gr.users_group_name),
 
                "desc": webutils.escape(user_gr.user_group_description),
 
                "members": len(user_gr.members),
 
                "active": h.boolicon(user_gr.users_group_active),
 
                "owner": user_gr.owner.username,
 
                "action": user_group_actions(user_gr.users_group_id, user_gr.users_group_name)
 
            })
 

	
 
        c.data = {
 
            "sort": None,
 
            "dir": "asc",
 
            "records": user_groups_data
 
        }
 

	
 
        return base.render('admin/user_groups/user_groups.html')
 

	
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
 
    def create(self):
 
        users_group_form = UserGroupForm()()
 
        try:
 
            form_result = users_group_form.to_python(dict(request.POST))
 
            ug = UserGroupModel().create(name=form_result['users_group_name'],
 
                                         description=form_result['user_group_description'],
 
                                         owner=request.authuser.user_id,
 
                                         active=form_result['users_group_active'])
 

	
 
            gr = form_result['users_group_name']
 
            userlog.action_logger(request.authuser,
 
                          'admin_created_users_group:%s' % gr,
 
                          None, request.ip_addr)
 
            webutils.flash(webutils.HTML(_('Created user group %s')) % webutils.link_to(gr, url('edit_users_group', id=ug.users_group_id)),
 
                category='success')
 
            meta.Session().commit()
 
        except formencode.Invalid as errors:
 
            return htmlfill.render(
 
                base.render('admin/user_groups/user_group_add.html'),
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8",
 
                force_defaults=False)
 
        except Exception:
 
            log.error(traceback.format_exc())
kallithea/controllers/admin/users.py
Show inline comments
 
@@ -30,101 +30,101 @@ import traceback
 

	
 
import formencode
 
from formencode import htmlfill
 
from sqlalchemy.sql.expression import func
 
from tg import app_globals, request
 
from tg import tmpl_context as c
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPFound, HTTPNotFound
 

	
 
import kallithea
 
import kallithea.lib.helpers as h
 
from kallithea.controllers import base
 
from kallithea.lib import auth_modules, webutils
 
from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator, LoginRequired
 
from kallithea.lib.exceptions import DefaultUserException, UserCreationError, UserOwnsReposException
 
from kallithea.lib.utils2 import datetime_to_time, generate_api_key, safe_int
 
from kallithea.lib.webutils import fmt_date, url
 
from kallithea.model import db, meta, userlog
 
from kallithea.model.api_key import ApiKeyModel
 
from kallithea.model.forms import CustomDefaultPermissionsForm, UserForm
 
from kallithea.model.ssh_key import SshKeyModel, SshKeyModelException
 
from kallithea.model.user import UserModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class UsersController(base.BaseController):
 

	
 
    @LoginRequired()
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def _before(self, *args, **kwargs):
 
        super(UsersController, self)._before(*args, **kwargs)
 

	
 
    def index(self, format='html'):
 
        c.users_list = db.User.query().order_by(db.User.username) \
 
                        .filter_by(is_default_user=False) \
 
                        .order_by(func.lower(db.User.username)) \
 
                        .all()
 

	
 
        users_data = []
 
        _tmpl_lookup = app_globals.mako_lookup
 
        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
 

	
 
        grav_tmpl = '<div class="gravatar">%s</div>'
 

	
 
        def username(user_id, username):
 
            return template.get_def("user_name") \
 
                .render_unicode(user_id, username, _=_, h=h, c=c)
 
                .render_unicode(user_id, username, _=_, webutils=webutils, c=c)
 

	
 
        def user_actions(user_id, username):
 
            return template.get_def("user_actions") \
 
                .render_unicode(user_id, username, _=_, h=h, c=c)
 
                .render_unicode(user_id, username, _=_, webutils=webutils, c=c)
 

	
 
        for user in c.users_list:
 
            users_data.append({
 
                "gravatar": grav_tmpl % h.gravatar(user.email, size=20),
 
                "raw_name": user.username,
 
                "username": username(user.user_id, user.username),
 
                "firstname": webutils.escape(user.name),
 
                "lastname": webutils.escape(user.lastname),
 
                "last_login": fmt_date(user.last_login),
 
                "last_login_raw": datetime_to_time(user.last_login),
 
                "active": h.boolicon(user.active),
 
                "admin": h.boolicon(user.admin),
 
                "extern_type": user.extern_type,
 
                "extern_name": user.extern_name,
 
                "action": user_actions(user.user_id, user.username),
 
            })
 

	
 
        c.data = {
 
            "sort": None,
 
            "dir": "asc",
 
            "records": users_data
 
        }
 

	
 
        return base.render('admin/users/users.html')
 

	
 
    def create(self):
 
        c.default_extern_type = db.User.DEFAULT_AUTH_TYPE
 
        c.default_extern_name = ''
 
        user_model = UserModel()
 
        user_form = UserForm()()
 
        try:
 
            form_result = user_form.to_python(dict(request.POST))
 
            user = user_model.create(form_result)
 
            userlog.action_logger(request.authuser, 'admin_created_user:%s' % user.username,
 
                          None, request.ip_addr)
 
            webutils.flash(_('Created user %s') % user.username,
 
                    category='success')
 
            meta.Session().commit()
 
        except formencode.Invalid as errors:
 
            return htmlfill.render(
 
                base.render('admin/users/user_add.html'),
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8",
 
                force_defaults=False)
 
        except UserCreationError as e:
 
            webutils.flash(e, 'error')
kallithea/model/notification.py
Show inline comments
 
@@ -154,79 +154,77 @@ class EmailNotificationModel(object):
 
        self._tmpl_lookup = app_globals.mako_lookup
 
        self.email_types = {
 
            self.TYPE_CHANGESET_COMMENT: 'changeset_comment',
 
            self.TYPE_PASSWORD_RESET: 'password_reset',
 
            self.TYPE_REGISTRATION: 'registration',
 
            self.TYPE_DEFAULT: 'default',
 
            self.TYPE_PULL_REQUEST: 'pull_request',
 
            self.TYPE_PULL_REQUEST_COMMENT: 'pull_request_comment',
 
        }
 
        self._subj_map = {
 
            self.TYPE_CHANGESET_COMMENT: _('[Comment] %(repo_name)s changeset %(short_id)s "%(message_short)s" on %(branch)s by %(cs_author_username)s'),
 
            self.TYPE_MESSAGE: 'Test Message',
 
            # self.TYPE_PASSWORD_RESET
 
            self.TYPE_REGISTRATION: _('New user %(new_username)s registered'),
 
            # self.TYPE_DEFAULT
 
            self.TYPE_PULL_REQUEST: _('[Review] %(repo_name)s PR %(pr_nice_id)s "%(pr_title_short)s" from %(pr_source_branch)s by %(pr_owner_username)s'),
 
            self.TYPE_PULL_REQUEST_COMMENT: _('[Comment] %(repo_name)s PR %(pr_nice_id)s "%(pr_title_short)s" from %(pr_source_branch)s by %(pr_owner_username)s'),
 
        }
 

	
 
    def get_email_description(self, type_, **kwargs):
 
        """
 
        return subject for email based on given type
 
        """
 
        tmpl = self._subj_map[type_]
 
        try:
 
            subj = tmpl % kwargs
 
        except KeyError as e:
 
            log.error('error generating email subject for %r from %s: %s', type_, ', '.join(self._subj_map), e)
 
            raise
 
        # gmail doesn't do proper threading but will ignore leading square
 
        # bracket content ... so that is where we put status info
 
        bracket_tags = []
 
        status_change = kwargs.get('status_change')
 
        if status_change:
 
            bracket_tags.append(str(status_change))  # apply str to evaluate LazyString before .join
 
        if kwargs.get('closing_pr'):
 
            bracket_tags.append(_('Closing'))
 
        if bracket_tags:
 
            if subj.startswith('['):
 
                subj = '[' + ', '.join(bracket_tags) + ': ' + subj[1:]
 
            else:
 
                subj = '[' + ', '.join(bracket_tags) + '] ' + subj
 
        return subj
 

	
 
    def get_email_tmpl(self, type_, content_type, **kwargs):
 
        """
 
        return generated template for email based on given type
 
        """
 
        import kallithea.lib.helpers as h
 

	
 
        base = 'email/' + self.email_types.get(type_, self.email_types[self.TYPE_DEFAULT]) + '.' + content_type
 
        email_template = self._tmpl_lookup.get_template(base)
 
        # translator and helpers inject
 
        _kwargs = {'_': _,
 
                   'h': h,
 
                   'webutils': webutils,
 
                   'c': c}
 
        _kwargs.update(kwargs)
 
        if content_type == 'html':
 
            _kwargs.update({
 
                "color_text": "#202020",
 
                "color_emph": "#395fa0",
 
                "color_link": "#395fa0",
 
                "color_border": "#ddd",
 
                "color_background_grey": "#f9f9f9",
 
                "color_button": "#395fa0",
 
                "monospace_style": "font-family:Lucida Console,Consolas,Monaco,Inconsolata,Liberation Mono,monospace",
 
                "sans_style": "font-family:Helvetica,Arial,sans-serif",
 
                })
 
            _kwargs.update({
 
                "default_style": "%(sans_style)s;font-weight:200;font-size:14px;line-height:17px;color:%(color_text)s" % _kwargs,
 
                "comment_style": "%(monospace_style)s;white-space:pre-wrap" % _kwargs,
 
                "data_style": "border:%(color_border)s 1px solid;background:%(color_background_grey)s" % _kwargs,
 
                "emph_style": "font-weight:600;color:%(color_emph)s" % _kwargs,
 
                "link_style": "color:%(color_link)s;text-decoration:none" % _kwargs,
 
                "link_text_style": "color:%(color_text)s;text-decoration:none;border:%(color_border)s 1px solid;background:%(color_background_grey)s" % _kwargs,
 
                })
 

	
 
        log.debug('rendering tmpl %s with kwargs %s', base, _kwargs)
 
        return email_template.render_unicode(**_kwargs)
kallithea/model/repo.py
Show inline comments
 
@@ -50,104 +50,107 @@ class RepoModel(object):
 
    def _create_default_perms(self, repository, private):
 
        # create default permission
 
        default = 'repository.read'
 
        def_user = db.User.get_default_user()
 
        for p in def_user.user_perms:
 
            if p.permission.permission_name.startswith('repository.'):
 
                default = p.permission.permission_name
 
                break
 

	
 
        default_perm = 'repository.none' if private else default
 

	
 
        repo_to_perm = db.UserRepoToPerm()
 
        repo_to_perm.permission = db.Permission.get_by_key(default_perm)
 

	
 
        repo_to_perm.repository = repository
 
        repo_to_perm.user_id = def_user.user_id
 
        meta.Session().add(repo_to_perm)
 

	
 
        return repo_to_perm
 

	
 
    @LazyProperty
 
    def repos_path(self):
 
        """
 
        Gets the repositories root path from database
 
        """
 

	
 
        q = db.Ui.query().filter(db.Ui.ui_key == '/').one()
 
        return q.ui_value
 

	
 
    def get(self, repo_id):
 
        repo = db.Repository.query() \
 
            .filter(db.Repository.repo_id == repo_id)
 
        return repo.scalar()
 

	
 
    def get_repo(self, repository):
 
        return db.Repository.guess_instance(repository)
 

	
 
    def get_by_repo_name(self, repo_name):
 
        repo = db.Repository.query() \
 
            .filter(db.Repository.repo_name == repo_name)
 
        return repo.scalar()
 

	
 
    @classmethod
 
    def _render_datatable(cls, tmpl, *args, **kwargs):
 
        from tg import app_globals, request
 
        from tg import tmpl_context as c
 
        from tg.i18n import ugettext as _
 

	
 
        import kallithea.lib.helpers as h
 

	
 
        _tmpl_lookup = app_globals.mako_lookup
 
        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
 

	
 
        tmpl = template.get_def(tmpl)
 
        kwargs.update(dict(_=_, h=h, c=c, request=request))
 
        return tmpl.render_unicode(*args, **kwargs)
 
        return tmpl.render_unicode(
 
            *args,
 
            _=_,
 
            webutils=webutils,
 
            c=c,
 
            request=request,
 
            **kwargs)
 

	
 
    def get_repos_as_dict(self, repos_list, repo_groups_list=None,
 
                          admin=False,
 
                          short_name=False):
 
        """Return repository list for use by DataTable.
 
        repos_list: list of repositories - but will be filtered for read permission.
 
        repo_groups_list: added at top of list without permission check.
 
        admin: return data for action column.
 
        """
 
        _render = self._render_datatable
 
        from tg import request
 
        from tg import tmpl_context as c
 

	
 
        def repo_lnk(name, rtype, rstate, private, fork_of):
 
            return _render('repo_name', name, rtype, rstate, private, fork_of,
 
                           short_name=short_name)
 

	
 
        def following(repo_id, is_following):
 
            return _render('following', repo_id, is_following)
 

	
 
        def last_change(last_change):
 
            return _render("last_change", last_change)
 

	
 
        def rss_lnk(repo_name):
 
            return _render("rss", repo_name)
 

	
 
        def atom_lnk(repo_name):
 
            return _render("atom", repo_name)
 

	
 
        def last_rev(repo_name, cs_cache):
 
            return _render('revision', repo_name, cs_cache.get('revision'),
 
                           cs_cache.get('raw_id'), cs_cache.get('author'),
 
                           cs_cache.get('message'))
 

	
 
        def desc(desc):
 
            return webutils.urlify_text(desc, truncate=80, stylize=c.visual.stylify_metalabels)
 

	
 
        def state(repo_state):
 
            return _render("repo_state", repo_state)
 

	
 
        def repo_actions(repo_name):
 
            return _render('repo_actions', repo_name)
 

	
 
        def owner_actions(owner_id, username):
 
            return _render('user_name', owner_id, username)
 

	
 
        repos_data = []
 

	
kallithea/templates/data_table/_dt_elements.html
Show inline comments
 
## DATA TABLE RE USABLE ELEMENTS
 
## usage:
 
## <%namespace name="dt" file="/data_table/_dt_elements.html"/>
 

	
 
<%namespace name="base" file="/base/base.html"/>
 

	
 
<%def name="repo_name(name,rtype,rstate,private,fork_of,short_name=False)">
 
    <%
 
    def get_name(name,short_name=short_name):
 
      if short_name:
 
        return name.split('/')[-1]
 
      else:
 
        return name
 
    %>
 
  <div class="dt_repo ${'dt_repo_pending' if rstate == 'repo_state_pending' else ''}">
 
    ${base.repolabel(rtype)}
 
    <a href="${h.url('summary_home', repo_name=name)}">
 
    <a href="${webutils.url('summary_home', repo_name=name)}">
 
        ${get_name(name)}
 
    </a>
 
    %if private and c.visual.show_private_icon:
 
      <i class="icon-lock" title="${_('Private repository')}"></i>
 
    %elif not private and c.visual.show_public_icon:
 
      <i class="icon-globe" title="${_('Public repository')}"></i>
 
    %endif
 
    %if fork_of:
 
      <a href="${h.url('summary_home',repo_name=fork_of.repo_name)}"><i class="icon-fork"></i></a>
 
      <a href="${webutils.url('summary_home',repo_name=fork_of.repo_name)}"><i class="icon-fork"></i></a>
 
    %endif
 
    %if rstate == 'repo_state_pending':
 
      <i class="icon-wrench" title="${_('Repository creation in progress...')}"></i>
 
    %endif
 
  </div>
 
</%def>
 

	
 
<%def name="following(repo_id, repo_following)">
 
  %if request.authuser.username != 'default':
 
    <a href="#" class="${'following' if repo_following else 'follow'}" onclick="return toggleFollowingRepo(this, ${repo_id});"><i class="list-extra icon-heart-empty show-follow" title="${_('Follow')}"></i><i class="list-extra icon-heart show-following" title="${_('Unfollow')}"></i></a>
 
  %endif
 
</%def>
 

	
 
<%def name="last_change(last_change)">
 
  <span data-toggle="tooltip" title="${h.fmt_date(last_change)}" date="${last_change}">${h.age(last_change)}</span>
 
  <span data-toggle="tooltip" title="${webutils.fmt_date(last_change)}" date="${last_change}">${webutils.age(last_change)}</span>
 
</%def>
 

	
 
<%def name="revision(name,rev,tip,author,last_msg)">
 
  %if rev >= 0:
 
      <a data-toggle="popover" title="${author | entity}" data-content="${last_msg | entity}" class="changeset_hash" href="${h.url('changeset_home',repo_name=name,revision=tip)}">${'r%s:%s' % (rev,h.short_id(tip))}</a>
 
      <a data-toggle="popover" title="${author | entity}" data-content="${last_msg | entity}" class="changeset_hash" href="${webutils.url('changeset_home',repo_name=name,revision=tip)}">${'r%s:%s' % (rev,webutils.short_id(tip))}</a>
 
  %else:
 
      ${_('No changesets yet')}
 
  %endif
 
</%def>
 

	
 
<%def name="rss(name)">
 
  %if request.authuser.username != 'default':
 
    <a title="${_('Subscribe to %s rss feed')% name}" href="${h.url('rss_feed_home',repo_name=name,api_key=request.authuser.api_key)}"><i class="icon-rss-squared"></i></a>
 
    <a title="${_('Subscribe to %s rss feed')% name}" href="${webutils.url('rss_feed_home',repo_name=name,api_key=request.authuser.api_key)}"><i class="icon-rss-squared"></i></a>
 
  %else:
 
    <a title="${_('Subscribe to %s rss feed')% name}" href="${h.url('rss_feed_home',repo_name=name)}"><i class="icon-rss-squared"></i></a>
 
    <a title="${_('Subscribe to %s rss feed')% name}" href="${webutils.url('rss_feed_home',repo_name=name)}"><i class="icon-rss-squared"></i></a>
 
  %endif
 
</%def>
 

	
 
<%def name="atom(name)">
 
  %if request.authuser.username != 'default':
 
    <a title="${_('Subscribe to %s atom feed')% name}" href="${h.url('atom_feed_home',repo_name=name,api_key=request.authuser.api_key)}"><i class="icon-rss-squared"></i></a>
 
    <a title="${_('Subscribe to %s atom feed')% name}" href="${webutils.url('atom_feed_home',repo_name=name,api_key=request.authuser.api_key)}"><i class="icon-rss-squared"></i></a>
 
  %else:
 
    <a title="${_('Subscribe to %s atom feed')% name}" href="${h.url('atom_feed_home',repo_name=name)}"><i class="icon-rss-squared"></i></a>
 
    <a title="${_('Subscribe to %s atom feed')% name}" href="${webutils.url('atom_feed_home',repo_name=name)}"><i class="icon-rss-squared"></i></a>
 
  %endif
 
</%def>
 

	
 
<%def name="repo_actions(repo_name)">
 
      <a href="${h.url('edit_repo',repo_name=repo_name)}" title="${_('Edit')}" class="btn btn-default btn-xs">
 
      <a href="${webutils.url('edit_repo',repo_name=repo_name)}" title="${_('Edit')}" class="btn btn-default btn-xs">
 
        <i class="icon-pencil"></i>${_('Edit')}
 
      </a>
 
      ${h.form(h.url('delete_repo', repo_name=repo_name))}
 
      ${webutils.form(webutils.url('delete_repo', repo_name=repo_name))}
 
        <button name="${'remove_%s' % repo_name}" class="btn btn-default btn-xs"
 
            onclick="return confirm('${_('Confirm to delete this repository: %s') % repo_name}');">
 
          <i class="icon-trashcan"></i>${_('Delete')}
 
        </button>
 
      ${h.end_form()}
 
      ${webutils.end_form()}
 
</%def>
 

	
 
<%def name="repo_state(repo_state)">
 
    %if repo_state == u'repo_state_pending':
 
        <div class="label label-info">${_('Creating')}</div>
 
    %elif repo_state == u'repo_state_created':
 
        <div class="label label-success">${_('Created')}</div>
 
    %else:
 
        <div class="label label-danger" title="${repo_state}">invalid</div>
 
    %endif
 
</%def>
 

	
 
<%def name="user_actions(user_id, username)">
 
   <a href="${h.url('edit_user',id=user_id)}" title="${_('Edit')}" class="btn btn-default btn-xs">
 
   <a href="${webutils.url('edit_user',id=user_id)}" title="${_('Edit')}" class="btn btn-default btn-xs">
 
     <i class="icon-pencil"></i>${_('Edit')}
 
   </a>
 
  ${h.form(h.url('delete_user', id=user_id))}
 
  ${webutils.form(webutils.url('delete_user', id=user_id))}
 
    <button id="${'remove_user_%s' % user_id}" name="${'remove_user_%s' % repo_name}" class="btn btn-default btn-xs" title="${_('Delete')}"
 
        onclick="return confirm('${_('Confirm to delete this user: %s') % username}');">
 
      <i class="icon-trashcan"></i>${_('Delete')}
 
    </button>
 
  ${h.end_form()}
 
  ${webutils.end_form()}
 
</%def>
 

	
 
<%def name="user_group_actions(user_group_id, user_group_name)">
 
    <a href="${h.url('edit_users_group', id=user_group_id)}" title="${_('Edit')}" class="btn btn-default btn-xs">
 
    <a href="${webutils.url('edit_users_group', id=user_group_id)}" title="${_('Edit')}" class="btn btn-default btn-xs">
 
      <i class="icon-pencil"></i>${_('Edit')}
 
    </a>
 
    ${h.form(h.url('delete_users_group', id=user_group_id))}
 
    ${webutils.form(webutils.url('delete_users_group', id=user_group_id))}
 
      <button id="${'remove_group_%s' % user_group_id}" name="${'remove_user_%s' % repo_name}" class="btn btn-default btn-xs" title="${_('Delete')}"
 
          onclick="return confirm('${_('Confirm to delete this user group: %s') % user_group_name}');">
 
        <i class="icon-trashcan"></i>${_('Delete')}
 
      </button>
 
    ${h.end_form()}
 
    ${webutils.end_form()}
 
</%def>
 

	
 
<%def name="group_name_html(group_name,name)">
 
  <div class="dt_repo">
 
    <i class="icon-folder"></i>
 
    <a href="${h.url('repos_group_home',group_name=group_name)}">${name}</a>
 
    <a href="${webutils.url('repos_group_home',group_name=group_name)}">${name}</a>
 
  </div>
 
</%def>
 

	
 
<%def name="repo_group_actions(repo_group_id, repo_group_name, gr_count)">
 
    <a href="${h.url('edit_repo_group',group_name=repo_group_name)}" title="${_('Edit')}" class="btn btn-default btn-xs">
 
    <a href="${webutils.url('edit_repo_group',group_name=repo_group_name)}" title="${_('Edit')}" class="btn btn-default btn-xs">
 
      <i class="icon-pencil"></i>${_('Edit')}
 
    </a>
 
    ${h.form(h.url('delete_repo_group', group_name=repo_group_name))}
 
    ${webutils.form(webutils.url('delete_repo_group', group_name=repo_group_name))}
 
      <button id="${'remove_%s' % repo_group_name}" name="${'remove_%s' % repo_group_name}" class="btn btn-default btn-xs" title="${_('Delete')}"
 
          onclick="return confirm('${ungettext('Confirm to delete this group: %s with %s repository','Confirm to delete this group: %s with %s repositories',gr_count) % (repo_group_name, gr_count)}')">
 
        <i class="icon-trashcan"></i>${_('Delete')}
 
      </button>
 
    ${h.end_form()}
 
    ${webutils.end_form()}
 
</%def>
 

	
 
<%def name="user_name(user_id, username)">
 
    ${h.link_to(username,h.url('edit_user', id=user_id))}
 
    ${webutils.link_to(username,webutils.url('edit_user', id=user_id))}
 
</%def>
 

	
 
<%def name="repo_group_name(repo_group_name, children_groups)">
 
  <div class="text-nowrap">
 
  <a href="${h.url('repos_group_home',group_name=repo_group_name)}">
 
    <i class="icon-folder" title="${_('Repository group')}"></i>${h.literal(' &raquo; ').join(children_groups)}</a>
 
  <a href="${webutils.url('repos_group_home',group_name=repo_group_name)}">
 
    <i class="icon-folder" title="${_('Repository group')}"></i>${webutils.literal(' &raquo; ').join(children_groups)}</a>
 
  </div>
 
</%def>
 

	
 
<%def name="user_group_name(user_group_id, user_group_name)">
 
  <div class="text-nowrap">
 
  <a href="${h.url('edit_users_group', id=user_group_id)}">
 
  <a href="${webutils.url('edit_users_group', id=user_group_id)}">
 
    <i class="icon-users" title="${_('User group')}"></i>${user_group_name}</a>
 
  </div>
 
</%def>
kallithea/templates/email/changeset_comment.html
Show inline comments
 
<%inherit file="main.html"/>\
 
\
 
<%block name="header">\
 
<% title = _('Mention in Comment on Changeset "%s"') % h.shorter(message, 200, firstline=True) if is_mention else _('Comment on Changeset "%s"') % h.shorter(message, 200, firstline=True) %>\
 
<% title = _('Mention in Comment on Changeset "%s"') % webutils.shorter(message, 200, firstline=True) if is_mention else _('Comment on Changeset "%s"') % webutils.shorter(message, 200, firstline=True) %>\
 
<%include file="header.html" args="title=title,link=cs_comment_url"/>\
 
</%block>\
 
\
 
<table cellpadding="0" cellspacing="0" border="0" width="100%">
 
    <tr>
 
        <td>
 
<%include file="comment.html" args="text=body,author=cs_comment_user,status=status_change"/>\
 
        </td>
 
    </tr>
 
    <tr>
 
        <td height="30px" style="height:30px"></td>
 
    </tr>
 
    <tr>
 
        <td>
 
            <div>
 
                ${_('Changeset on')}
 
                <a style="${link_text_style}"
 
                   href="${cs_target_repo}">${cs_target_repo}</a>
 
                ${_('branch')}
 
                <span style="${data_style}">${branch}</span>:
 
            </div>
 
            <div>
 
                "<a style="${link_style}"
 
                   href="${cs_url}">${h.shorter(message, 60, firstline=True)}</a>"
 
                   href="${cs_url}">${webutils.shorter(message, 60, firstline=True)}</a>"
 
                ${_('by')}
 
                <span style="${data_style}">${cs_author.full_name_and_username}</span>.
 
            </div>
 
        </td>
 
    </tr>
 
    <tr>
 
        <td>
 
<% title = _('View Comment') %>\
 
<%include file="button.html" args="url=cs_comment_url,title=title,padding_bottom=False"/>\
 
        </td>
 
    </tr>
 
</table>
kallithea/templates/email/changeset_comment.txt
Show inline comments
 
<%block name="header">\
 
<% title = _('Mention in Comment on Changeset "%s"') % h.shorter(message, 200, firstline=True) if is_mention else _('Comment on Changeset "%s"') % h.shorter(message, 200, firstline=True) %>\
 
<% title = _('Mention in Comment on Changeset "%s"') % webutils.shorter(message, 200, firstline=True) if is_mention else _('Comment on Changeset "%s"') % webutils.shorter(message, 200, firstline=True) %>\
 
<%include file="header.txt" args="title=title,link=cs_comment_url"/>\
 
</%block>\
 

	
 
<%include file="comment.txt" args="text=body,author=cs_comment_user,status=status_change"/>\
 

	
 
${_('Changeset on')|n,unicode} \
 
${cs_target_repo|n,unicode} \
 
${_('branch')|n,unicode} \
 
${branch|n,unicode}:
 
"${h.shorter(message, 60, firstline=True)|n,unicode}" \
 
"${webutils.shorter(message, 60, firstline=True)|n,unicode}" \
 
${_('by')|n,unicode} \
 
${cs_author.full_name_and_username|n,unicode}.
 

	
 
<% title = _('View Comment') %>\
 
<%include file="button.txt" args="url=cs_comment_url,title=title"/>\
kallithea/templates/email/pull_request.html
Show inline comments
 
@@ -27,63 +27,63 @@
 
                   href="${pr_target_repo}">${pr_target_repo}</a>
 
                ${_('branch')}
 
                <span style="${data_style}">${pr_target_branch}</span>
 
            </div>
 
        </td>
 
    </tr>
 
    <tr><td height="10px" style="height:10px"></td></tr>
 
    <tr>
 
        <td>
 
            <div>
 
                ${_('Description')}:
 
            </div>
 
        </td>
 
    </tr>
 
    <tr><td height="10px" style="height:10px"></td></tr>
 
    <tr>
 
        <td>
 
            <table cellpadding="0" cellspacing="0" width="100%" border="0" bgcolor="${color_background_grey}" style="border:1px solid ${color_border};border-radius:4px">
 
                <tr>
 
                    <td height="10px" style="height:10px" colspan="3"></td>
 
                </tr>
 
                <tr>
 
                    <td width="20px" style="width:20px"></td>
 
                    <td>
 
                        <div style="${comment_style}">${body}</div>
 
                    </td>
 
                    <td width="20px" style="width:20px"></td>
 
                </tr>
 
                <tr>
 
                    <td height="10px" style="height:10px" colspan="3"></td>
 
                </tr>
 
            </table>
 
        </td>
 
    </tr>
 
    <tr><td height="15px" style="height:15px"></td></tr>
 
    <tr>
 
        <td>
 
            <div>${_('Changesets')}:</div>
 
        </td>
 
    </tr>
 
    <tr><td height="10px" style="height:10px"></td></tr>
 

	
 
    <tr>
 
        <td style="${sans_style}">
 
            <ul style="color:${color_link};padding-left:15px;margin:0">
 
                %for revision, desc in pr_revisions:
 
                    <li style="mso-special-format:bullet">
 
                        <a style="${link_style}"
 
                           href="${h.canonical_url('changeset_home', repo_name=org_repo_name, revision=revision)}">
 
                            ${h.shorter(desc, 80, firstline=True)}
 
                           href="${webutils.canonical_url('changeset_home', repo_name=org_repo_name, revision=revision)}">
 
                            ${webutils.shorter(desc, 80, firstline=True)}
 
                        </a>
 
                    </li>
 
                %endfor
 
            </ul>
 
        </td>
 
    </tr>
 
    <tr>
 
        <td>
 
<% title = _('View Pull Request') %>\
 
<%include file="button.html" args="url=pr_url,title=title,padding_bottom=False"/>\
 
        </td>
 
    </tr>
 
</table>
kallithea/templates/email/pull_request.txt
Show inline comments
 
<%block name="header">\
 
<% title = _('Mention on Pull Request %s "%s" by %s') % (pr_nice_id, pr_title, pr_user_created) if is_mention else _('Added as Reviewer of Pull Request %s "%s" by %s') % (pr_nice_id, pr_title, pr_user_created) %>\
 
<%include file="header.txt" args="title=title,link=pr_url"/>\
 
</%block>\
 

	
 
${_('Pull request')|n,unicode} \
 
${pr_nice_id|n,unicode} \
 
"${pr_title|n,unicode}" \
 
${_('by')|n,unicode} \
 
${pr_owner.full_name_and_username|n,unicode}
 
${_('from')} \
 
${pr_source_repo|n,unicode} \
 
${_('branch')|n,unicode} \
 
${pr_source_branch|n,unicode}
 
${_('to')|n,unicode} \
 
${pr_target_repo|n,unicode} \
 
${_('branch')|n,unicode} \
 
${pr_target_branch|n,unicode}
 

	
 

	
 
${_('Description')|n,unicode}:
 

	
 
${body|n,unicode}
 

	
 

	
 
${_('Changesets')|n,unicode}:
 

	
 
%for revision, desc in pr_revisions:
 
${h.shorter(desc, 80, firstline=True)|n,unicode}
 
${webutils.shorter(desc, 80, firstline=True)|n,unicode}
 
%endfor
 

	
 
<% title = _('View Pull Request') %>\
 
<%include file="button.txt" args="url=pr_url,title=title"/>\
kallithea/tests/models/test_notifications.py
Show inline comments
 
import os
 
import re
 

	
 
import mock
 
from tg.util.webtest import test_context
 

	
 
import kallithea.lib.celerylib
 
import kallithea.lib.helpers as h
 
import kallithea.model.async_tasks
 
from kallithea.lib import webutils
 
from kallithea.model import db, meta
 
from kallithea.model.notification import EmailNotificationModel, NotificationModel
 
from kallithea.model.user import UserModel
 
from kallithea.tests import base
 

	
 

	
 
class TestNotifications(base.TestController):
 

	
 
    def setup_method(self, method):
 
        meta.Session.remove()
 
        u1 = UserModel().create_or_update(username='u1',
 
                                        password='qweqwe',
 
                                        email='u1@example.com',
 
                                        firstname='u1', lastname='u1')
 
        meta.Session().commit()
 
        self.u1 = u1.user_id
 

	
 
        u2 = UserModel().create_or_update(username='u2',
 
                                        password='qweqwe',
 
                                        email='u2@example.com',
 
                                        firstname='u2', lastname='u3')
 
        meta.Session().commit()
 
        self.u2 = u2.user_id
 

	
 
        u3 = UserModel().create_or_update(username='u3',
 
                                        password='qweqwe',
 
                                        email='u3@example.com',
 
                                        firstname='u3', lastname='u3')
 
        meta.Session().commit()
 
        self.u3 = u3.user_id
 

	
 
    def test_create_notification(self):
 
        with test_context(self.app):
 
            usrs = [self.u1, self.u2]
 

	
 
            def send_email(recipients, subject, body='', html_body='', headers=None, from_name=None):
 
                assert recipients == ['u2@example.com']
 
                assert subject == 'Test Message'
 
                assert body == "hi there"
 
                assert '>hi there<' in html_body
 
                assert from_name == 'u1 u1'
 
            with mock.patch.object(kallithea.model.async_tasks, 'send_email', send_email):
 
                NotificationModel().create(created_by=self.u1,
 
                                                   body='hi there',
 
                                                   recipients=usrs)
 

	
 
    @mock.patch.object(h, 'canonical_url', (lambda arg, **kwargs: 'http://%s/?%s' % (arg, '&'.join('%s=%s' % (k, v) for (k, v) in sorted(kwargs.items())))))
 
    @mock.patch.object(webutils, 'canonical_url', (lambda arg, **kwargs: 'http://%s/?%s' % (arg, '&'.join('%s=%s' % (k, v) for (k, v) in sorted(kwargs.items())))))
 
    def test_dump_html_mails(self):
 
        # Exercise all notification types and dump them to one big html file
 
        l = []
 

	
 
        def send_email(recipients, subject, body='', html_body='', headers=None, from_name=None):
 
            l.append('<hr/>\n')
 
            l.append('<h1>%s</h1>\n' % desc) # desc is from outer scope
 
            l.append('<pre>\n')
 
            l.append('From: %s <name@example.com>\n' % from_name)
 
            l.append('To: %s\n' % ' '.join(recipients))
 
            l.append('Subject: %s\n' % subject)
 
            l.append('</pre>\n')
 
            l.append('<hr/>\n')
 
            l.append('<pre>%s</pre>\n' % body)
 
            l.append('<hr/>\n')
 
            l.append(html_body)
 
            l.append('<hr/>\n')
 

	
 
        with test_context(self.app):
 
            with mock.patch.object(kallithea.model.async_tasks, 'send_email', send_email):
 
                pr_kwargs = dict(
 
                    pr_nice_id='#7',
 
                    pr_title='The Title',
 
                    pr_title_short='The Title',
 
                    pr_url='http://pr.org/7',
 
                    pr_target_repo='http://mainline.com/repo',
 
                    pr_target_branch='trunk',
 
                    pr_source_repo='https://dev.org/repo',
 
                    pr_source_branch='devbranch',
 
                    pr_owner=db.User.get(self.u2),
 
                    pr_owner_username='u2'
 
                    )
 

	
 
                for type_, body, kwargs in [
 
                        (NotificationModel.TYPE_CHANGESET_COMMENT,
 
                         'This is the new \'comment\'.\n\n - and here it ends indented.',
 
                         dict(
 
                            short_id='cafe1234',
 
                            raw_id='cafe1234c0ffeecafe',
 
                            branch='brunch',
 
                            cs_comment_user='Opinionated User (jsmith)',
 
                            cs_comment_url='http://comment.org',
 
                            is_mention=[False, True],
 
                            message='This changeset did something clever which is hard to explain',
 
                            message_short='This changeset did something cl...',
 
                            status_change=[None, 'Approved'],
 
                            cs_target_repo='http://example.com/repo_target',
 
                            cs_url='http://changeset.com',
scripts/deps.py
Show inline comments
 
@@ -119,97 +119,96 @@ tg
 
mercurial
 
sqlalchemy
 
alembic
 
formencode
 
pygments
 
dulwich
 
beaker
 
psycopg2
 
docs
 
setup
 
conftest
 
'''.split())
 

	
 
normal_modules = set('''
 
kallithea
 
kallithea.controllers.base
 
kallithea.lib
 
kallithea.lib.auth
 
kallithea.lib.auth_modules
 
kallithea.lib.celerylib
 
kallithea.lib.db_manage
 
kallithea.lib.helpers
 
kallithea.lib.hooks
 
kallithea.lib.indexers
 
kallithea.lib.utils
 
kallithea.lib.utils2
 
kallithea.lib.vcs
 
kallithea.lib.webutils
 
kallithea.model
 
kallithea.model.async_tasks
 
kallithea.model.scm
 
kallithea.templates.py
 
'''.split())
 

	
 
shown_modules = normal_modules | top_modules
 

	
 
# break the chains somehow - this is a cleanup TODO list
 
known_violations = [
 
('kallithea.lib.auth_modules', 'kallithea.lib.auth'),  # needs base&facade
 
('kallithea.lib.utils', 'kallithea.model'),  # clean up utils
 
('kallithea.lib.utils', 'kallithea.model.db'),
 
('kallithea.lib.utils', 'kallithea.model.scm'),
 
('kallithea.model.async_tasks', 'kallithea.lib.helpers'),
 
('kallithea.model.async_tasks', 'kallithea.lib.hooks'),
 
('kallithea.model.async_tasks', 'kallithea.lib.indexers'),
 
('kallithea.model.async_tasks', 'kallithea.model'),
 
('kallithea.model', 'kallithea.lib.auth'),  # auth.HasXXX
 
('kallithea.model', 'kallithea.lib.auth_modules'),  # validators
 
('kallithea.model', 'kallithea.lib.helpers'),
 
('kallithea.model', 'kallithea.lib.hooks'),  # clean up hooks
 
('kallithea.model', 'kallithea.model.scm'),
 
('kallithea.model.scm', 'kallithea.lib.hooks'),
 
]
 

	
 
extra_edges = [
 
('kallithea.config', 'kallithea.controllers'),  # through TG
 
('kallithea.lib.auth', 'kallithea.lib.auth_modules'),  # custom loader
 
]
 

	
 

	
 
def normalize(s):
 
    """Given a string with dot path, return the string it should be shown as."""
 
    parts = s.replace('.__init__', '').split('.')
 
    short_2 = '.'.join(parts[:2])
 
    short_3 = '.'.join(parts[:3])
 
    short_4 = '.'.join(parts[:4])
 
    if parts[0] in ['scripts', 'contributor_data', 'i18n_utils']:
 
        return 'scripts'
 
    if short_3 == 'kallithea.model.meta':
 
        return 'kallithea.model.db'
 
    if parts[:4] == ['kallithea', 'lib', 'vcs', 'ssh']:
 
        return 'kallithea.lib.vcs.ssh'
 
    if short_4 in shown_modules:
 
        return short_4
 
    if short_3 in shown_modules:
 
        return short_3
 
    if short_2 in shown_modules:
 
        return short_2
 
    if short_2 == 'kallithea.tests':
 
        return None
 
    if parts[0] in ignored_modules:
 
        return None
 
    assert parts[0] in bottom_external_modules, parts
 
    return parts[0]
 

	
 

	
 
def main(filenames):
 
    if not filenames or filenames[0].startswith('-'):
 
        print('''\
 
Usage:
 
    hg files 'set:!binary()&grep("^#!.*python")' 'set:**.py' | xargs scripts/deps.py
 
    dot -Tsvg deps.dot > deps.svg
 
        ''')
 
        raise SystemExit(1)
 

	
 
    files_imports = dict()  # map filenames to its imports
 
    import_deps = set()  # set of tuples with module name and its imports
0 comments (0 inline, 0 general)