Changeset - 17893d61792a
[Not reviewed]
beta
0 10 0
Marcin Kuzminski - 13 years ago 2012-07-01 12:44:54
marcin@python-works.com
Added associated classes into child models
10 files changed with 23 insertions and 0 deletions:
0 comments (0 inline, 0 general)
rhodecode/model/changeset_status.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.changeset_status
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 

	
 
    :created_on: Apr 30, 2012
 
    :author: marcink
 
    :copyright: (C) 2011-2012 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, 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/>.
 

	
 

	
 
import logging
 
from collections import  defaultdict
 

	
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import ChangesetStatus, PullRequest
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class ChangesetStatusModel(BaseModel):
 

	
 
    cls = ChangesetStatus
 

	
 
    def __get_changeset_status(self, changeset_status):
 
        return self._get_instance(ChangesetStatus, changeset_status)
 

	
 
    def __get_pull_request(self, pull_request):
 
        return self._get_instance(PullRequest, pull_request)
 

	
 
    def _get_status_query(self, repo, revision, pull_request,
 
                          with_revisions=False):
 
        repo = self._get_repo(repo)
 

	
 
        q = ChangesetStatus.query()\
 
            .filter(ChangesetStatus.repo == repo)
 
        if not with_revisions:
 
            q = q.filter(ChangesetStatus.version == 0)
 

	
 
        if revision:
 
            q = q.filter(ChangesetStatus.revision == revision)
 
        elif pull_request:
 
            pull_request = self.__get_pull_request(pull_request)
 
            q = q.filter(ChangesetStatus.pull_request == pull_request)
 
        else:
 
            raise Exception('Please specify revision or pull_request')
 
        q.order_by(ChangesetStatus.version.asc())
 
        return q
 

	
 
    def calculate_status(self, statuses_by_reviewers):
 
        """
 
        leading one wins, if number of occurences are equal than weaker wins
 

	
 
        :param statuses_by_reviewers:
 
        """
 
        status = None
 
        votes = defaultdict(int)
 
        reviewers_number = len(statuses_by_reviewers)
 
        for user, statuses in statuses_by_reviewers:
 
            if statuses:
 
                ver, latest = statuses[0]
 
                votes[latest.status] += 1
 
            else:
 
                votes[ChangesetStatus.DEFAULT] += 1
 

	
 
        if votes.get(ChangesetStatus.STATUS_APPROVED) == reviewers_number:
 
            return ChangesetStatus.STATUS_APPROVED
 
        else:
 
            return ChangesetStatus.STATUS_UNDER_REVIEW
 

	
 
    def get_statuses(self, repo, revision=None, pull_request=None,
 
                     with_revisions=False):
 
        q = self._get_status_query(repo, revision, pull_request,
 
                                   with_revisions)
 
        return q.all()
 

	
 
    def get_status(self, repo, revision=None, pull_request=None):
 
        """
 
        Returns latest status of changeset for given revision or for given
 
        pull request. Statuses are versioned inside a table itself and
 
        version == 0 is always the current one
 

	
 
        :param repo:
 
        :type repo:
 
        :param revision: 40char hash or None
 
        :type revision: str
 
        :param pull_request: pull_request reference
 
        :type:
 
        """
 
        q = self._get_status_query(repo, revision, pull_request)
 

	
 
        # need to use first here since there can be multiple statuses
 
        # returned from pull_request
 
        status = q.first()
 
        status = status.status if status else status
 
        st = status or ChangesetStatus.DEFAULT
 
        return str(st)
 

	
 
    def set_status(self, repo, status, user, comment, revision=None,
 
                   pull_request=None):
 
        """
 
        Creates new status for changeset or updates the old ones bumping their
 
        version, leaving the current status at
 

	
 
        :param repo:
 
        :type repo:
 
        :param revision:
 
        :type revision:
 
        :param status:
 
        :type status:
 
        :param user:
 
        :type user:
 
        :param comment:
 
        :type comment:
 
        """
 
        repo = self._get_repo(repo)
 

	
 
        q = ChangesetStatus.query()
 

	
 
        if revision:
rhodecode/model/comment.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.comment
 
    ~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    comments model for RhodeCode
 

	
 
    :created_on: Nov 11, 2011
 
    :author: marcink
 
    :copyright: (C) 2011-2012 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, 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/>.
 

	
 
import logging
 
import traceback
 

	
 
from pylons.i18n.translation import _
 
from sqlalchemy.util.compat import defaultdict
 

	
 
from rhodecode.lib.utils2 import extract_mentioned_users, safe_unicode
 
from rhodecode.lib import helpers as h
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import ChangesetComment, User, Repository, \
 
    Notification, PullRequest
 
from rhodecode.model.notification import NotificationModel
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class ChangesetCommentsModel(BaseModel):
 

	
 
    cls = ChangesetComment
 

	
 
    def __get_changeset_comment(self, changeset_comment):
 
        return self._get_instance(ChangesetComment, changeset_comment)
 

	
 
    def __get_pull_request(self, pull_request):
 
        return self._get_instance(PullRequest, pull_request)
 

	
 
    def _extract_mentions(self, s):
 
        user_objects = []
 
        for username in extract_mentioned_users(s):
 
            user_obj = User.get_by_username(username, case_insensitive=True)
 
            if user_obj:
 
                user_objects.append(user_obj)
 
        return user_objects
 

	
 
    def create(self, text, repo_id, user_id, revision=None, pull_request=None,
 
               f_path=None, line_no=None, status_change=None):
 
        """
 
        Creates new comment for changeset or pull request.
 
        IF status_change is not none this comment is associated with a
 
        status change of changeset or changesets associated with pull request
 

	
 
        :param text:
 
        :param repo_id:
 
        :param user_id:
 
        :param revision:
 
        :param pull_request:
 
        :param f_path:
 
        :param line_no:
 
        :param status_change:
 
        """
 
        if not text:
 
            return
 

	
 
        repo = Repository.get(repo_id)
 
        comment = ChangesetComment()
 
        comment.repo = repo
 
        comment.user_id = user_id
 
        comment.text = text
 
        comment.f_path = f_path
 
        comment.line_no = line_no
 

	
 
        if revision:
 
            cs = repo.scm_instance.get_changeset(revision)
 
            desc = "%s - %s" % (cs.short_id, h.shorter(cs.message, 256))
 
            author_email = cs.author_email
 
            comment.revision = revision
 
        elif pull_request:
 
            pull_request = self.__get_pull_request(pull_request)
 
            comment.pull_request = pull_request
 
            desc = ''
 
        else:
 
            raise Exception('Please specify revision or pull_request_id')
 

	
 
        self.sa.add(comment)
 
        self.sa.flush()
 

	
 
        # make notification
 
        line = ''
 
        body = text
 

	
 
        #changeset
 
        if revision:
 
            if line_no:
 
                line = _('on line %s') % line_no
 
            subj = safe_unicode(
 
                h.link_to('Re commit: %(commit_desc)s %(line)s' % \
 
                          {'commit_desc': desc, 'line': line},
 
                          h.url('changeset_home', repo_name=repo.repo_name,
 
                                revision=revision,
 
                                anchor='comment-%s' % comment.comment_id,
 
                                qualified=True,
 
                          )
 
                )
 
            )
 
            notification_type = Notification.TYPE_CHANGESET_COMMENT
 
            # get the current participants of this changeset
 
            recipients = ChangesetComment.get_users(revision=revision)
 
            # add changeset author if it's in rhodecode system
 
            recipients += [User.get_by_email(author_email)]
 
        #pull request
 
        elif pull_request:
 
            #TODO: make this something usefull
 
            subj = 'commented on pull request something...'
 
            notification_type = Notification.TYPE_PULL_REQUEST_COMMENT
 
            # get the current participants of this pull request
 
            recipients = ChangesetComment.get_users(pull_request_id=
 
                                                pull_request.pull_request_id)
 
            # add pull request author
 
            recipients += [pull_request.author]
 

	
 
        # create notification objects, and emails
 
        NotificationModel().create(
 
          created_by=user_id, subject=subj, body=body,
 
          recipients=recipients, type_=notification_type,
 
          email_kwargs={'status_change': status_change}
 
        )
rhodecode/model/notification.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.notification
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Model for notifications
 

	
 

	
 
    :created_on: Nov 20, 2011
 
    :author: marcink
 
    :copyright: (C) 2010-2012 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, 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/>.
 

	
 
import os
 
import logging
 
import traceback
 

	
 
from pylons.i18n.translation import _
 

	
 
import rhodecode
 
from rhodecode.lib import helpers as h
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import Notification, User, UserNotification
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class NotificationModel(BaseModel):
 

	
 
    cls = Notification
 

	
 
    def __get_notification(self, notification):
 
        if isinstance(notification, Notification):
 
            return notification
 
        elif isinstance(notification, (int, long)):
 
            return Notification.get(notification)
 
        else:
 
            if notification:
 
                raise Exception('notification must be int, long or Instance'
 
                                ' of Notification got %s' % type(notification))
 

	
 
    def create(self, created_by, subject, body, recipients=None,
 
               type_=Notification.TYPE_MESSAGE, with_email=True,
 
               email_kwargs={}):
 
        """
 

	
 
        Creates notification of given type
 

	
 
        :param created_by: int, str or User instance. User who created this
 
            notification
 
        :param subject:
 
        :param body:
 
        :param recipients: list of int, str or User objects, when None
 
            is given send to all admins
 
        :param type_: type of notification
 
        :param with_email: send email with this notification
 
        :param email_kwargs: additional dict to pass as args to email template
 
        """
 
        from rhodecode.lib.celerylib import tasks, run_task
 

	
 
        if recipients and not getattr(recipients, '__iter__', False):
 
            raise Exception('recipients must be a list of iterable')
 

	
 
        created_by_obj = self._get_user(created_by)
 

	
 
        if recipients:
 
            recipients_objs = []
 
            for u in recipients:
 
                obj = self._get_user(u)
 
                if obj:
 
                    recipients_objs.append(obj)
 
            recipients_objs = set(recipients_objs)
 
            log.debug('sending notifications %s to %s' % (
 
                type_, recipients_objs)
 
            )
 
        else:
 
            # empty recipients means to all admins
 
            recipients_objs = User.query().filter(User.admin == True).all()
 
            log.debug('sending notifications %s to admins: %s' % (
 
                type_, recipients_objs)
 
            )
 
        notif = Notification.create(
 
            created_by=created_by_obj, subject=subject,
 
            body=body, recipients=recipients_objs, type_=type_
 
        )
 

	
 
        if with_email is False:
 
            return notif
 

	
 
        #don't send email to person who created this comment
 
        rec_objs = set(recipients_objs).difference(set([created_by_obj]))
 

	
 
        # send email with notification to all other participants
 
        for rec in rec_objs:
 
            email_subject = NotificationModel().make_description(notif, False)
 
            type_ = type_
 
            email_body = body
 
            ## this is passed into template
 
            kwargs = {'subject': subject, 'body': h.rst_w_mentions(body)}
 
            kwargs.update(email_kwargs)
 
            email_body_html = EmailNotificationModel()\
 
                                .get_email_tmpl(type_, **kwargs)
 

	
 
            run_task(tasks.send_email, rec.email, email_subject, email_body,
 
                     email_body_html)
 

	
 
        return notif
 

	
 
    def delete(self, user, notification):
 
        # we don't want to remove actual notification just the assignment
 
        try:
 
            notification = self.__get_notification(notification)
 
            user = self._get_user(user)
 
            if notification and user:
 
                obj = UserNotification.query()\
 
                        .filter(UserNotification.user == user)\
 
                        .filter(UserNotification.notification
 
                                == notification)\
 
                        .one()
 
                self.sa.delete(obj)
 
                return True
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
    def get_for_user(self, user, filter_=None):
 
        """
rhodecode/model/permission.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.permission
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    permissions model for RhodeCode
 

	
 
    :created_on: Aug 20, 2010
 
    :author: marcink
 
    :copyright: (C) 2010-2012 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, 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/>.
 

	
 
import logging
 
import traceback
 

	
 
from sqlalchemy.exc import DatabaseError
 

	
 
from rhodecode.lib.caching_query import FromCache
 

	
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import User, Permission, UserToPerm, UserRepoToPerm,\
 
    UserRepoGroupToPerm
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class PermissionModel(BaseModel):
 
    """
 
    Permissions model for RhodeCode
 
    """
 

	
 
    cls = Permission
 

	
 
    def get_permission(self, permission_id, cache=False):
 
        """
 
        Get's permissions by id
 

	
 
        :param permission_id: id of permission to get from database
 
        :param cache: use Cache for this query
 
        """
 
        perm = self.sa.query(Permission)
 
        if cache:
 
            perm = perm.options(FromCache("sql_cache_short",
 
                                          "get_permission_%s" % permission_id))
 
        return perm.get(permission_id)
 

	
 
    def get_permission_by_name(self, name, cache=False):
 
        """
 
        Get's permissions by given name
 

	
 
        :param name: name to fetch
 
        :param cache: Use cache for this query
 
        """
 
        perm = self.sa.query(Permission)\
 
            .filter(Permission.permission_name == name)
 
        if cache:
 
            perm = perm.options(FromCache("sql_cache_short",
 
                                          "get_permission_%s" % name))
 
        return perm.scalar()
 

	
 
    def update(self, form_result):
 
        perm_user = self.sa.query(User)\
 
                        .filter(User.username ==
 
                                form_result['perm_user_name']).scalar()
 
        u2p = self.sa.query(UserToPerm).filter(UserToPerm.user ==
 
                                               perm_user).all()
 
        if len(u2p) != 3:
 
            raise Exception('Defined: %s should be 3  permissions for default'
 
                            ' user. This should not happen please verify'
 
                            ' your database' % len(u2p))
 

	
 
        try:
 
            # stage 1 change defaults
 
            for p in u2p:
 
                if p.permission.permission_name.startswith('repository.'):
 
                    p.permission = self.get_permission_by_name(
 
                                       form_result['default_perm'])
 
                    self.sa.add(p)
 

	
 
                elif p.permission.permission_name.startswith('hg.register.'):
 
                    p.permission = self.get_permission_by_name(
 
                                       form_result['default_register'])
 
                    self.sa.add(p)
 

	
 
                elif p.permission.permission_name.startswith('hg.create.'):
 
                    p.permission = self.get_permission_by_name(
 
                                        form_result['default_create'])
 
                    self.sa.add(p)
 

	
 
            _def_name = form_result['default_perm'].split('repository.')[-1]
 
            #stage 2 update all default permissions for repos if checked
 
            if form_result['overwrite_default'] == True:
 
                _def = self.get_permission_by_name('repository.' + _def_name)
 
                # repos
 
                for r2p in self.sa.query(UserRepoToPerm)\
 
                               .filter(UserRepoToPerm.user == perm_user)\
 
                               .all():
 
                    r2p.permission = _def
 
                    self.sa.add(r2p)
 
                # groups
 
                _def = self.get_permission_by_name('group.' + _def_name)
 
                for g2p in self.sa.query(UserRepoGroupToPerm)\
 
                               .filter(UserRepoGroupToPerm.user == perm_user)\
 
                               .all():
 
                    g2p.permission = _def
 
                    self.sa.add(g2p)
 

	
 
            # stage 3 set anonymous access
 
            if perm_user.username == 'default':
 
                perm_user.active = bool(form_result['anonymous'])
 
                self.sa.add(perm_user)
 

	
 
        except (DatabaseError,):
 
            log.error(traceback.format_exc())
 
            raise
rhodecode/model/pull_request.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.pull_reuquest
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    pull request model for RhodeCode
 

	
 
    :created_on: Jun 6, 2012
 
    :author: marcink
 
    :copyright: (C) 2012-2012 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, 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/>.
 

	
 
import logging
 
import binascii
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.lib import helpers as h
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import PullRequest, PullRequestReviewers, Notification
 
from rhodecode.model.notification import NotificationModel
 
from rhodecode.lib.utils2 import safe_unicode
 

	
 
from rhodecode.lib.vcs.utils.hgcompat import discovery
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class PullRequestModel(BaseModel):
 

	
 
    cls = PullRequest
 

	
 
    def get_all(self, repo):
 
        repo = self._get_repo(repo)
 
        return PullRequest.query().filter(PullRequest.other_repo == repo).all()
 

	
 
    def create(self, created_by, org_repo, org_ref, other_repo,
 
               other_ref, revisions, reviewers, title, description=None):
 
        created_by_user = self._get_user(created_by)
 

	
 
        new = PullRequest()
 
        new.org_repo = self._get_repo(org_repo)
 
        new.org_ref = org_ref
 
        new.other_repo = self._get_repo(other_repo)
 
        new.other_ref = other_ref
 
        new.revisions = revisions
 
        new.title = title
 
        new.description = description
 
        new.author = created_by_user
 
        self.sa.add(new)
 

	
 
        #members
 
        for member in reviewers:
 
            _usr = self._get_user(member)
 
            reviewer = PullRequestReviewers(_usr, new)
 
            self.sa.add(reviewer)
 

	
 
        #notification to reviewers
 
        notif = NotificationModel()
 

	
 
        subject = safe_unicode(
 
            h.link_to(
 
              _('%(user)s wants you to review pull request #%(pr_id)s') % \
 
                {'user': created_by_user.username,
 
                 'pr_id': new.pull_request_id},
 
              h.url('pullrequest_show', repo_name=other_repo,
 
                    pull_request_id=new.pull_request_id,
 
                    qualified=True,
 
              )
 
            )
 
        )
 
        body = description
 
        notif.create(created_by=created_by, subject=subject, body=body,
 
                     recipients=reviewers,
 
                     type_=Notification.TYPE_PULL_REQUEST,)
 

	
 
        return new
 

	
 
    def _get_changesets(self, org_repo, org_ref, other_repo, other_ref,
 
                        discovery_data):
 
        """
 
        Returns a list of changesets that are incoming from org_repo@org_ref
 
        to other_repo@other_ref
 

	
 
        :param org_repo:
 
        :type org_repo:
 
        :param org_ref:
 
        :type org_ref:
 
        :param other_repo:
 
        :type other_repo:
 
        :param other_ref:
 
        :type other_ref:
 
        :param tmp:
 
        :type tmp:
 
        """
 
        changesets = []
 
        #case two independent repos
 
        if org_repo != other_repo:
 
            common, incoming, rheads = discovery_data
 

	
 
            if not incoming:
 
                revs = []
 
            else:
 
                revs = org_repo._repo.changelog.findmissing(common, rheads)
 

	
 
            for cs in reversed(map(binascii.hexlify, revs)):
 
                changesets.append(org_repo.get_changeset(cs))
 
        else:
 
            revs = ['ancestors(%s) and not ancestors(%s)' % (org_ref[1],
 
                                                             other_ref[1])]
 
            from mercurial import scmutil
 
            out = scmutil.revrange(org_repo._repo, revs)
 
            for cs in reversed(out):
 
                changesets.append(org_repo.get_changeset(cs))
 

	
 
        return changesets
 

	
 
    def _get_discovery(self, org_repo, org_ref, other_repo, other_ref):
 
        """
 
        Get's mercurial discovery data used to calculate difference between
 
        repos and refs
 

	
 
        :param org_repo:
 
        :type org_repo:
 
        :param org_ref:
 
        :type org_ref:
 
        :param other_repo:
 
        :type other_repo:
rhodecode/model/repo.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.repo
 
    ~~~~~~~~~~~~~~~~~~~~
 

	
 
    Repository model for rhodecode
 

	
 
    :created_on: Jun 5, 2010
 
    :author: marcink
 
    :copyright: (C) 2010-2012 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, 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/>.
 
from __future__ import with_statement
 
import os
 
import shutil
 
import logging
 
import traceback
 
import pkg_resources
 
from os.path import dirname as dn, join as jn
 
from datetime import datetime
 

	
 
from rhodecode.lib.vcs.backends import get_backend
 
from rhodecode.lib.compat import json
 
from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode
 
from rhodecode.lib.caching_query import FromCache
 
from rhodecode.lib.hooks import log_create_repository
 

	
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
 
    Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup
 
from rhodecode.lib import helpers as h
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class RepoModel(BaseModel):
 

	
 
    cls = Repository
 

	
 
    def __get_users_group(self, users_group):
 
        return self._get_instance(UsersGroup, users_group,
 
                                  callback=UsersGroup.get_by_group_name)
 

	
 
    def __get_repos_group(self, repos_group):
 
        return self._get_instance(RepoGroup, repos_group,
 
                                  callback=RepoGroup.get_by_group_name)
 

	
 
    @LazyProperty
 
    def repos_path(self):
 
        """
 
        Get's the repositories root path from database
 
        """
 

	
 
        q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
 
        return q.ui_value
 

	
 
    def get(self, repo_id, cache=False):
 
        repo = self.sa.query(Repository)\
 
            .filter(Repository.repo_id == repo_id)
 

	
 
        if cache:
 
            repo = repo.options(FromCache("sql_cache_short",
 
                                          "get_repo_%s" % repo_id))
 
        return repo.scalar()
 

	
 
    def get_repo(self, repository):
 
        return self._get_repo(repository)
 

	
 
    def get_by_repo_name(self, repo_name, cache=False):
 
        repo = self.sa.query(Repository)\
 
            .filter(Repository.repo_name == repo_name)
 

	
 
        if cache:
 
            repo = repo.options(FromCache("sql_cache_short",
 
                                          "get_repo_%s" % repo_name))
 
        return repo.scalar()
 

	
 
    def get_users_js(self):
 
        users = self.sa.query(User).filter(User.active == True).all()
 
        return json.dumps([
 
            {
 
             'id': u.user_id,
 
             'fname': u.name,
 
             'lname': u.lastname,
 
             'nname': u.username,
 
             'gravatar_lnk': h.gravatar_url(u.email, 14)
 
            } for u in users]
 
        )
 

	
 
    def get_users_groups_js(self):
 
        users_groups = self.sa.query(UsersGroup)\
 
            .filter(UsersGroup.users_group_active == True).all()
 

	
 
        return json.dumps([
 
            {
 
             'id': gr.users_group_id,
 
             'grname': gr.users_group_name,
 
             'grmembers': len(gr.members),
 
            } for gr in users_groups]
 
        )
 

	
 
    def _get_defaults(self, repo_name):
 
        """
 
        Get's information about repository, and returns a dict for
 
        usage in forms
 

	
 
        :param repo_name:
 
        """
 

	
 
        repo_info = Repository.get_by_repo_name(repo_name)
 

	
 
        if repo_info is None:
 
            return None
 

	
 
        defaults = repo_info.get_dict()
 
        group, repo_name = repo_info.groups_and_repo
 
        defaults['repo_name'] = repo_name
 
        defaults['repo_group'] = getattr(group[-1] if group else None,
 
                                         'group_id', None)
 

	
 
        # fill owner
 
        if repo_info.user:
 
            defaults.update({'user': repo_info.user.username})
 
        else:
 
            replacement_user = User.query().filter(User.admin ==
 
                                                   True).first().username
 
            defaults.update({'user': replacement_user})
 

	
 
        # fill repository users
 
        for p in repo_info.repo_to_perm:
 
            defaults.update({'u_perm_%s' % p.user.username:
 
                             p.permission.permission_name})
 

	
 
        # fill repository groups
 
        for p in repo_info.users_group_to_perm:
rhodecode/model/repo_permission.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.users_group
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    repository permission model for RhodeCode
 

	
 
    :created_on: Oct 1, 2011
 
    :author: nvinot, marcink
 
    :copyright: (C) 2011-2011 Nicolas Vinot <aeris@imirhil.fr>
 
    :copyright: (C) 2011-2012 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, 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/>.
 

	
 
import logging
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import UserRepoToPerm, UsersGroupRepoToPerm, \
 
    Permission
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class RepositoryPermissionModel(BaseModel):
 

	
 
    cls = UserRepoToPerm
 

	
 
    def get_user_permission(self, repository, user):
 
        repository = self._get_repo(repository)
 
        user = self._get_user(user)
 

	
 
        return UserRepoToPerm.query() \
 
                .filter(UserRepoToPerm.user == user) \
 
                .filter(UserRepoToPerm.repository == repository) \
 
                .scalar()
 

	
 
    def update_user_permission(self, repository, user, permission):
 
        permission = Permission.get_by_key(permission)
 
        current = self.get_user_permission(repository, user)
 
        if current:
 
            if not current.permission is permission:
 
                current.permission = permission
 
        else:
 
            p = UserRepoToPerm()
 
            p.user = user
 
            p.repository = repository
 
            p.permission = permission
 
            self.sa.add(p)
 

	
 
    def delete_user_permission(self, repository, user):
 
        current = self.get_user_permission(repository, user)
 
        if current:
 
            self.sa.delete(current)
 

	
 
    def get_users_group_permission(self, repository, users_group):
 
        return UsersGroupRepoToPerm.query() \
 
                .filter(UsersGroupRepoToPerm.users_group == users_group) \
 
                .filter(UsersGroupRepoToPerm.repository == repository) \
 
                .scalar()
 

	
 
    def update_users_group_permission(self, repository, users_group,
 
                                      permission):
 
        permission = Permission.get_by_key(permission)
 
        current = self.get_users_group_permission(repository, users_group)
 
        if current:
 
            if not current.permission is permission:
 
                current.permission = permission
 
        else:
 
            p = UsersGroupRepoToPerm()
 
            p.users_group = users_group
 
            p.repository = repository
 
            p.permission = permission
 
            self.sa.add(p)
 

	
 
    def delete_users_group_permission(self, repository, users_group):
 
        current = self.get_users_group_permission(repository, users_group)
 
        if current:
 
            self.sa.delete(current)
 

	
 
    def update_or_delete_user_permission(self, repository, user, permission):
 
        if permission:
 
            self.update_user_permission(repository, user, permission)
 
        else:
 
            self.delete_user_permission(repository, user)
 

	
 
    def update_or_delete_users_group_permission(self, repository, user_group,
 
                                              permission):
 
        if permission:
 
            self.update_users_group_permission(repository, user_group,
 
                                               permission)
 
        else:
 
            self.delete_users_group_permission(repository, user_group)
rhodecode/model/repos_group.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.user_group
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    users groups model for RhodeCode
 

	
 
    :created_on: Jan 25, 2011
 
    :author: marcink
 
    :copyright: (C) 2011-2012 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, 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/>.
 

	
 
import os
 
import logging
 
import traceback
 
import shutil
 

	
 
from rhodecode.lib.utils2 import LazyProperty
 

	
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \
 
    User, Permission, UsersGroupRepoGroupToPerm, UsersGroup
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class ReposGroupModel(BaseModel):
 

	
 
    cls = RepoGroup
 

	
 
    def __get_users_group(self, users_group):
 
        return self._get_instance(UsersGroup, users_group,
 
                                  callback=UsersGroup.get_by_group_name)
 

	
 
    def __get_repos_group(self, repos_group):
 
        return self._get_instance(RepoGroup, repos_group,
 
                                  callback=RepoGroup.get_by_group_name)
 

	
 
    @LazyProperty
 
    def repos_path(self):
 
        """
 
        Get's the repositories root path from database
 
        """
 

	
 
        q = RhodeCodeUi.get_by_key('/').one()
 
        return q.ui_value
 

	
 
    def _create_default_perms(self, new_group):
 
        # create default permission
 
        repo_group_to_perm = UserRepoGroupToPerm()
 
        default_perm = 'group.read'
 
        for p in User.get_by_username('default').user_perms:
 
            if p.permission.permission_name.startswith('group.'):
 
                default_perm = p.permission.permission_name
 
                break
 

	
 
        repo_group_to_perm.permission_id = self.sa.query(Permission)\
 
                .filter(Permission.permission_name == default_perm)\
 
                .one().permission_id
 

	
 
        repo_group_to_perm.group = new_group
 
        repo_group_to_perm.user_id = User.get_by_username('default').user_id
 

	
 
        self.sa.add(repo_group_to_perm)
 

	
 
    def __create_group(self, group_name):
 
        """
 
        makes repositories group on filesystem
 

	
 
        :param repo_name:
 
        :param parent_id:
 
        """
 

	
 
        create_path = os.path.join(self.repos_path, group_name)
 
        log.debug('creating new group in %s' % create_path)
 

	
 
        if os.path.isdir(create_path):
 
            raise Exception('That directory already exists !')
 

	
 
        os.makedirs(create_path)
 

	
 
    def __rename_group(self, old, new):
 
        """
 
        Renames a group on filesystem
 

	
 
        :param group_name:
 
        """
 

	
 
        if old == new:
 
            log.debug('skipping group rename')
 
            return
 

	
 
        log.debug('renaming repos group from %s to %s' % (old, new))
 

	
 
        old_path = os.path.join(self.repos_path, old)
 
        new_path = os.path.join(self.repos_path, new)
 

	
 
        log.debug('renaming repos paths from %s to %s' % (old_path, new_path))
 

	
 
        if os.path.isdir(new_path):
 
            raise Exception('Was trying to rename to already '
 
                            'existing dir %s' % new_path)
 
        shutil.move(old_path, new_path)
 

	
 
    def __delete_group(self, group):
 
        """
 
        Deletes a group from a filesystem
 

	
 
        :param group: instance of group from database
 
        """
 
        paths = group.full_path.split(RepoGroup.url_sep())
 
        paths = os.sep.join(paths)
 

	
 
        rm_path = os.path.join(self.repos_path, paths)
 
        if os.path.isdir(rm_path):
 
            # delete only if that path really exists
 
            os.rmdir(rm_path)
 

	
 
    def create(self, group_name, group_description, parent, just_db=False):
 
        try:
 
            new_repos_group = RepoGroup()
 
            new_repos_group.group_description = group_description
 
            new_repos_group.parent_group = self.__get_repos_group(parent)
 
            new_repos_group.group_name = new_repos_group.get_new_name(group_name)
 

	
 
            self.sa.add(new_repos_group)
rhodecode/model/user.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.user
 
    ~~~~~~~~~~~~~~~~~~~~
 

	
 
    users model for RhodeCode
 

	
 
    :created_on: Apr 9, 2010
 
    :author: marcink
 
    :copyright: (C) 2010-2012 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, 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/>.
 

	
 
import logging
 
import traceback
 

	
 
from pylons import url
 
from pylons.i18n.translation import _
 

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

	
 
from rhodecode.lib.utils2 import safe_unicode, generate_api_key
 
from rhodecode.lib.caching_query import FromCache
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
 
    UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \
 
    Notification, RepoGroup, UserRepoGroupToPerm, UsersGroupRepoGroupToPerm, \
 
    UserEmailMap
 
from rhodecode.lib.exceptions import DefaultUserException, \
 
    UserOwnsReposException
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
PERM_WEIGHTS = {
 
    'repository.none': 0,
 
    'repository.read': 1,
 
    'repository.write': 3,
 
    'repository.admin': 4,
 
    'group.none': 0,
 
    'group.read': 1,
 
    'group.write': 3,
 
    'group.admin': 4,
 
}
 

	
 

	
 
class UserModel(BaseModel):
 
    cls = User
 

	
 
    def get(self, user_id, cache=False):
 
        user = self.sa.query(User)
 
        if cache:
 
            user = user.options(FromCache("sql_cache_short",
 
                                          "get_user_%s" % user_id))
 
        return user.get(user_id)
 

	
 
    def get_user(self, user):
 
        return self._get_user(user)
 

	
 
    def get_by_username(self, username, cache=False, case_insensitive=False):
 

	
 
        if case_insensitive:
 
            user = self.sa.query(User).filter(User.username.ilike(username))
 
        else:
 
            user = self.sa.query(User)\
 
                .filter(User.username == username)
 
        if cache:
 
            user = user.options(FromCache("sql_cache_short",
 
                                          "get_user_%s" % username))
 
        return user.scalar()
 

	
 
    def get_by_email(self, email, cache=False, case_insensitive=False):
 
        return User.get_by_email(email, case_insensitive, cache)
 

	
 
    def get_by_api_key(self, api_key, cache=False):
 
        return User.get_by_api_key(api_key, cache)
 

	
 
    def create(self, form_data):
 
        from rhodecode.lib.auth import get_crypt_password
 
        try:
 
            new_user = User()
 
            for k, v in form_data.items():
 
                if k == 'password':
 
                    v = get_crypt_password(v)
 
                setattr(new_user, k, v)
 

	
 
            new_user.api_key = generate_api_key(form_data['username'])
 
            self.sa.add(new_user)
 
            return new_user
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
    def create_or_update(self, username, password, email, firstname='',
 
                         lastname='', active=True, admin=False, ldap_dn=None):
 
        """
 
        Creates a new instance if not found, or updates current one
 

	
 
        :param username:
 
        :param password:
 
        :param email:
 
        :param active:
 
        :param firstname:
 
        :param lastname:
 
        :param active:
 
        :param admin:
 
        :param ldap_dn:
 
        """
 

	
 
        from rhodecode.lib.auth import get_crypt_password
 

	
 
        log.debug('Checking for %s account in RhodeCode database' % username)
 
        user = User.get_by_username(username, case_insensitive=True)
 
        if user is None:
 
            log.debug('creating new user %s' % username)
 
            new_user = User()
 
            edit = False
 
        else:
 
            log.debug('updating user %s' % username)
 
            new_user = user
 
            edit = True
 

	
 
        try:
 
            new_user.username = username
 
            new_user.admin = admin
 
            # set password only if creating an user or password is changed
 
            if edit is False or user.password != password:
 
                new_user.password = get_crypt_password(password)
 
                new_user.api_key = generate_api_key(username)
 
            new_user.email = email
 
            new_user.active = active
 
            new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None
 
            new_user.name = firstname
 
            new_user.lastname = lastname
 
            self.sa.add(new_user)
 
            return new_user
 
        except (DatabaseError,):
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
    def create_for_container_auth(self, username, attrs):
 
        """
 
        Creates the given user if it's not already in the database
 

	
 
        :param username:
 
        :param attrs:
 
        """
 
        if self.get_by_username(username, case_insensitive=True) is None:
 

	
 
            # autogenerate email for container account without one
 
            generate_email = lambda usr: '%s@container_auth.account' % usr
 

	
 
            try:
 
                new_user = User()
 
                new_user.username = username
 
                new_user.password = None
 
                new_user.api_key = generate_api_key(username)
 
                new_user.email = attrs['email']
 
                new_user.active = attrs.get('active', True)
 
                new_user.name = attrs['name'] or generate_email(username)
 
                new_user.lastname = attrs['lastname']
 

	
 
                self.sa.add(new_user)
 
                return new_user
 
            except (DatabaseError,):
 
                log.error(traceback.format_exc())
 
                self.sa.rollback()
 
                raise
 
        log.debug('User %s already exists. Skipping creation of account'
 
                  ' for container auth.', username)
rhodecode/model/users_group.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.users_group
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    users group model for RhodeCode
 

	
 
    :created_on: Oct 1, 2011
 
    :author: nvinot
 
    :copyright: (C) 2011-2011 Nicolas Vinot <aeris@imirhil.fr>
 
    :copyright: (C) 2010-2012 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, 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/>.
 

	
 
import logging
 
import traceback
 

	
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import UsersGroupMember, UsersGroup,\
 
    UsersGroupRepoToPerm, Permission, UsersGroupToPerm, User
 
from rhodecode.lib.exceptions import UsersGroupsAssignedException
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class UsersGroupModel(BaseModel):
 

	
 
    def __get_users_group(self, users_group):
 
        return self._get_instance(UsersGroup, users_group,
 
                                  callback=UsersGroup.get_by_group_name)
 

	
 
    def get(self, users_group_id, cache=False):
 
        return UsersGroup.get(users_group_id)
 

	
 
    def get_group(self, users_group):
 
        return self.__get_users_group(users_group)
 

	
 
    def get_by_name(self, name, cache=False, case_insensitive=False):
 
        return UsersGroup.get_by_group_name(name, cache, case_insensitive)
 

	
 
    def create(self, name, active=True):
 
        try:
 
            new = UsersGroup()
 
            new.users_group_name = name
 
            new.users_group_active = active
 
            self.sa.add(new)
 
            return new
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
    def update(self, users_group, form_data):
 

	
 
        try:
 
            users_group = self.__get_users_group(users_group)
 

	
 
            for k, v in form_data.items():
 
                if k == 'users_group_members':
 
                    users_group.members = []
 
                    self.sa.flush()
 
                    members_list = []
 
                    if v:
 
                        v = [v] if isinstance(v, basestring) else v
 
                        for u_id in set(v):
 
                            member = UsersGroupMember(users_group.users_group_id, u_id)
 
                            members_list.append(member)
 
                    setattr(users_group, 'members', members_list)
 
                setattr(users_group, k, v)
 

	
 
            self.sa.add(users_group)
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
    def delete(self, users_group, force=False):
 
        """
 
        Deletes repos group, unless force flag is used
 
        raises exception if there are members in that group, else deletes
 
        group and users
 

	
 
        :param users_group:
 
        :param force:
 
        """
 
        try:
 
            users_group = self.__get_users_group(users_group)
 

	
 
            # check if this group is not assigned to repo
 
            assigned_groups = UsersGroupRepoToPerm.query()\
 
                .filter(UsersGroupRepoToPerm.users_group == users_group).all()
 

	
 
            if assigned_groups and force is False:
 
                raise UsersGroupsAssignedException('RepoGroup assigned to %s' %
 
                                                   assigned_groups)
 

	
 
            self.sa.delete(users_group)
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
    def add_user_to_group(self, users_group, user):
 
        users_group = self.__get_users_group(users_group)
 
        user = self._get_user(user)
 

	
 
        for m in users_group.members:
 
            u = m.user
 
            if u.user_id == user.user_id:
 
                return True
 

	
 
        try:
 
            users_group_member = UsersGroupMember()
 
            users_group_member.user = user
 
            users_group_member.users_group = users_group
 

	
 
            users_group.members.append(users_group_member)
 
            user.group_member.append(users_group_member)
 

	
 
            self.sa.add(users_group_member)
 
            return users_group_member
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
    def remove_user_from_group(self, users_group, user):
 
        users_group = self.__get_users_group(users_group)
 
        user = self._get_user(user)
 

	
 
        users_group_member = None
 
        for m in users_group.members:
 
            if m.user.user_id == user.user_id:
 
                # Found this user's membership row
 
                users_group_member = m
 
                break
 

	
0 comments (0 inline, 0 general)