Changeset - b84c83b651de
[Not reviewed]
beta
0 9 0
Marcin Kuzminski - 12 years ago 2013-05-22 03:15:44
marcin@python-works.com
replace equality comparision to None
9 files changed with 11 insertions and 11 deletions:
0 comments (0 inline, 0 general)
rhodecode/bin/ldap_sync.py
Show inline comments
 
# 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 ldap
 
import urllib2
 
import uuid
 

	
 
try:
 
    from rhodecode.lib.compat import json
 
except ImportError:
 
    try:
 
        import simplejson as json
 
    except ImportError:
 
        import json
 

	
 
from ConfigParser import ConfigParser
 

	
 
config = ConfigParser()
 
config.read('ldap_sync.conf')
 

	
 

	
 
class InvalidResponseIDError(Exception):
 
    """ Request and response don't have the same UUID. """
 

	
 

	
 
class RhodecodeResponseError(Exception):
 
    """ Response has an error, something went wrong with request execution. """
 

	
 

	
 
class UserAlreadyInGroupError(Exception):
 
    """ User is already a member of the target group. """
 

	
 

	
 
class UserNotInGroupError(Exception):
 
    """ User is not a member of the target group. """
 

	
 

	
 
class RhodecodeAPI():
 

	
 
    def __init__(self, url, key):
 
        self.url = url
 
        self.key = key
 

	
 
    def get_api_data(self, uid, method, args):
 
        """Prepare dict for API post."""
 
        return {
 
            "id": uid,
 
            "api_key": self.key,
 
            "method": method,
 
            "args": args
 
        }
 

	
 
    def rhodecode_api_post(self, method, args):
 
        """Send a generic API post to Rhodecode.
 

	
 
        This will generate the UUID for validation check after the
 
        response is returned. Handle errors and get the result back.
 
        """
 
        uid = str(uuid.uuid1())
 
        data = self.get_api_data(uid, method, args)
 

	
 
        data = json.dumps(data)
 
        headers = {'content-type': 'text/plain'}
 
        req = urllib2.Request(self.url, data, headers)
 

	
 
        response = urllib2.urlopen(req)
 
        response = json.load(response)
 

	
 
        if uid != response["id"]:
 
            raise InvalidResponseIDError("UUID does not match.")
 

	
 
        if response["error"] != None:
 
        if response["error"] is not None:
 
            raise RhodecodeResponseError(response["error"])
 

	
 
        return response["result"]
 

	
 
    def create_group(self, name, active=True):
 
        """Create the Rhodecode user group."""
 
        args = {
 
            "group_name": name,
 
            "active": str(active)
 
        }
 
        self.rhodecode_api_post("create_users_group", args)
 

	
 
    def add_membership(self, group, username):
 
        """Add specific user to a group."""
 
        args = {
 
            "usersgroupid": group,
 
            "userid": username
 
        }
 
        result = self.rhodecode_api_post("add_user_to_users_group", args)
 
        if not result["success"]:
 
            raise UserAlreadyInGroupError("User %s already in group %s." %
 
                                          (username, group))
 

	
 
    def remove_membership(self, group, username):
 
        """Remove specific user from a group."""
 
        args = {
 
            "usersgroupid": group,
 
            "userid": username
 
        }
 
        result = self.rhodecode_api_post("remove_user_from_users_group", args)
 
        if not result["success"]:
 
            raise UserNotInGroupError("User %s not in group %s." %
 
                                      (username, group))
 

	
 
    def get_group_members(self, name):
 
        """Get the list of member usernames from a user group."""
 
        args = {"usersgroupid": name}
 
        members = self.rhodecode_api_post("get_users_group", args)['members']
 
        member_list = []
 
        for member in members:
 
            member_list.append(member["username"])
 
        return member_list
 

	
 
    def get_group(self, name):
 
        """Return group info."""
 
        args = {"usersgroupid": name}
 
        return self.rhodecode_api_post("get_users_group", args)
 

	
 
    def get_user(self, username):
 
        """Return user info."""
 
        args = {"userid": username}
 
        return self.rhodecode_api_post("get_user", args)
 

	
 

	
 
class LdapClient():
 

	
 
    def __init__(self, uri, user, key, base_dn):
 
        self.client = ldap.initialize(uri, trace_level=0)
 
        self.client.set_option(ldap.OPT_REFERRALS, 0)
 
        self.client.simple_bind(user, key)
 
        self.base_dn = base_dn
 

	
 
    def __del__(self):
 
        self.client.unbind()
 

	
 
    def get_groups(self):
 
        """Get all the groups in form of dict {group_name: group_info,...}."""
 
        searchFilter = "objectClass=groupOfUniqueNames"
 
        result = self.client.search_s(self.base_dn, ldap.SCOPE_SUBTREE,
 
                                      searchFilter)
 

	
 
        groups = {}
 
        for group in result:
 
            groups[group[1]['cn'][0]] = group[1]
 

	
 
        return groups
 

	
 
    def get_group_users(self, groups, group):
 
        """Returns all the users belonging to a single group.
 

	
 
        Based on the list of groups and memberships, returns all the
 
        users belonging to a single group, searching recursively.
 
        """
 
        users = []
 
        for member in groups[group]["uniqueMember"]:
 
            member = self.parse_member_string(member)
 
            if member[0] == "uid":
 
                users.append(member[1])
 
            elif member[0] == "cn":
 
                users += self.get_group_users(groups, member[1])
 

	
 
        return users
 

	
 
    def parse_member_string(self, member):
 
        """Parses the member string and returns a touple of type and name.
 

	
rhodecode/controllers/changeset.py
Show inline comments
 
@@ -141,193 +141,193 @@ def _context_url(GET, fileid=None):
 
    ln_ctx = (get_line_ctx(fileid, GET) or 3) * 2
 

	
 
    params = defaultdict(list)
 
    _update_with_GET(params, GET)
 

	
 
    # global option
 
    if fileid is None:
 
        if ln_ctx > 0:
 
            params['context'] += [ln_ctx]
 

	
 
        if ig_ws:
 
            ig_ws_key = 'ignorews'
 
            ig_ws_val = 1
 

	
 
    # per file option
 
    else:
 
        params[fileid] += ['C:%s' % ln_ctx]
 
        ig_ws_key = fileid
 
        ig_ws_val = 'WS:%s' % 1
 

	
 
    if ig_ws:
 
        params[ig_ws_key] += [ig_ws_val]
 

	
 
    lbl = _('%s line context') % ln_ctx
 

	
 
    params['anchor'] = fileid
 
    img = h.image(h.url('/images/icons/table_add.png'), lbl, class_='icon')
 
    return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
 

	
 

	
 
class ChangesetController(BaseRepoController):
 

	
 
    def __before__(self):
 
        super(ChangesetController, self).__before__()
 
        c.affected_files_cut_off = 60
 
        repo_model = RepoModel()
 
        c.users_array = repo_model.get_users_js()
 
        c.users_groups_array = repo_model.get_users_groups_js()
 

	
 
    def _index(self, revision, method):
 
        c.anchor_url = anchor_url
 
        c.ignorews_url = _ignorews_url
 
        c.context_url = _context_url
 
        c.fulldiff = fulldiff = request.GET.get('fulldiff')
 
        #get ranges of revisions if preset
 
        rev_range = revision.split('...')[:2]
 
        enable_comments = True
 
        try:
 
            if len(rev_range) == 2:
 
                enable_comments = False
 
                rev_start = rev_range[0]
 
                rev_end = rev_range[1]
 
                rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
 
                                                             end=rev_end)
 
            else:
 
                rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
 

	
 
            c.cs_ranges = list(rev_ranges)
 
            if not c.cs_ranges:
 
                raise RepositoryError('Changeset range returned empty result')
 

	
 
        except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
 
            log.error(traceback.format_exc())
 
            h.flash(str(e), category='error')
 
            raise HTTPNotFound()
 

	
 
        c.changes = OrderedDict()
 

	
 
        c.lines_added = 0  # count of lines added
 
        c.lines_deleted = 0  # count of lines removes
 

	
 
        c.changeset_statuses = ChangesetStatus.STATUSES
 
        c.comments = []
 
        c.statuses = []
 
        c.inline_comments = []
 
        c.inline_cnt = 0
 

	
 
        # Iterate over ranges (default changeset view is always one changeset)
 
        for changeset in c.cs_ranges:
 
            inlines = []
 
            if method == 'show':
 
                c.statuses.extend([ChangesetStatusModel().get_status(
 
                            c.rhodecode_db_repo.repo_id, changeset.raw_id)])
 

	
 
                c.comments.extend(ChangesetCommentsModel()\
 
                                  .get_comments(c.rhodecode_db_repo.repo_id,
 
                                                revision=changeset.raw_id))
 

	
 
                #comments from PR
 
                st = ChangesetStatusModel().get_statuses(
 
                            c.rhodecode_db_repo.repo_id, changeset.raw_id,
 
                            with_revisions=True)
 
                # from associated statuses, check the pull requests, and
 
                # show comments from them
 

	
 
                prs = set([x.pull_request for x in
 
                           filter(lambda x: x.pull_request != None, st)])
 
                           filter(lambda x: x.pull_request is not None, st)])
 

	
 
                for pr in prs:
 
                    c.comments.extend(pr.comments)
 
                inlines = ChangesetCommentsModel()\
 
                            .get_inline_comments(c.rhodecode_db_repo.repo_id,
 
                                                 revision=changeset.raw_id)
 
                c.inline_comments.extend(inlines)
 

	
 
            c.changes[changeset.raw_id] = []
 

	
 
            cs2 = changeset.raw_id
 
            cs1 = changeset.parents[0].raw_id if changeset.parents else EmptyChangeset()
 
            context_lcl = get_line_ctx('', request.GET)
 
            ign_whitespace_lcl = ign_whitespace_lcl = get_ignore_ws('', request.GET)
 

	
 
            _diff = c.rhodecode_repo.get_diff(cs1, cs2,
 
                ignore_whitespace=ign_whitespace_lcl, context=context_lcl)
 
            diff_limit = self.cut_off_limit if not fulldiff else None
 
            diff_processor = diffs.DiffProcessor(_diff,
 
                                                 vcs=c.rhodecode_repo.alias,
 
                                                 format='gitdiff',
 
                                                 diff_limit=diff_limit)
 
            cs_changes = OrderedDict()
 
            if method == 'show':
 
                _parsed = diff_processor.prepare()
 
                c.limited_diff = False
 
                if isinstance(_parsed, LimitedDiffContainer):
 
                    c.limited_diff = True
 
                for f in _parsed:
 
                    st = f['stats']
 
                    c.lines_added += st['added']
 
                    c.lines_deleted += st['deleted']
 
                    fid = h.FID(changeset.raw_id, f['filename'])
 
                    diff = diff_processor.as_html(enable_comments=enable_comments,
 
                                                  parsed_lines=[f])
 
                    cs_changes[fid] = [cs1, cs2, f['operation'], f['filename'],
 
                                       diff, st]
 
            else:
 
                # downloads/raw we only need RAW diff nothing else
 
                diff = diff_processor.as_raw()
 
                cs_changes[''] = [None, None, None, None, diff, None]
 
            c.changes[changeset.raw_id] = cs_changes
 

	
 
        #sort comments by how they were generated
 
        c.comments = sorted(c.comments, key=lambda x: x.comment_id)
 

	
 
        # count inline comments
 
        for __, lines in c.inline_comments:
 
            for comments in lines.values():
 
                c.inline_cnt += len(comments)
 

	
 
        if len(c.cs_ranges) == 1:
 
            c.changeset = c.cs_ranges[0]
 
            c.parent_tmpl = ''.join(['# Parent  %s\n' % x.raw_id
 
                                     for x in c.changeset.parents])
 
        if method == 'download':
 
            response.content_type = 'text/plain'
 
            response.content_disposition = 'attachment; filename=%s.diff' \
 
                                            % revision[:12]
 
            return diff
 
        elif method == 'patch':
 
            response.content_type = 'text/plain'
 
            c.diff = safe_unicode(diff)
 
            return render('changeset/patch_changeset.html')
 
        elif method == 'raw':
 
            response.content_type = 'text/plain'
 
            return diff
 
        elif method == 'show':
 
            if len(c.cs_ranges) == 1:
 
                return render('changeset/changeset.html')
 
            else:
 
                return render('changeset/changeset_range.html')
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def index(self, revision, method='show'):
 
        return self._index(revision, method=method)
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def changeset_raw(self, revision):
 
        return self._index(revision, method='raw')
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def changeset_patch(self, revision):
 
        return self._index(revision, method='patch')
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def changeset_download(self, revision):
 
        return self._index(revision, method='download')
rhodecode/lib/db_manage.py
Show inline comments
 
@@ -421,209 +421,209 @@ class DbManage(object):
 
            TEST_USER_REGULAR2_PASS, TEST_USER_REGULAR2_EMAIL
 

	
 
            self.create_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS,
 
                             TEST_USER_ADMIN_EMAIL, True)
 

	
 
            self.create_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,
 
                             TEST_USER_REGULAR_EMAIL, False)
 

	
 
            self.create_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS,
 
                             TEST_USER_REGULAR2_EMAIL, False)
 

	
 
    def create_ui_settings(self):
 
        """
 
        Creates ui settings, fills out hooks
 
        and disables dotencode
 
        """
 

	
 
        #HOOKS
 
        hooks1_key = RhodeCodeUi.HOOK_UPDATE
 
        hooks1_ = self.sa.query(RhodeCodeUi)\
 
            .filter(RhodeCodeUi.ui_key == hooks1_key).scalar()
 

	
 
        hooks1 = RhodeCodeUi() if hooks1_ is None else hooks1_
 
        hooks1.ui_section = 'hooks'
 
        hooks1.ui_key = hooks1_key
 
        hooks1.ui_value = 'hg update >&2'
 
        hooks1.ui_active = False
 
        self.sa.add(hooks1)
 

	
 
        hooks2_key = RhodeCodeUi.HOOK_REPO_SIZE
 
        hooks2_ = self.sa.query(RhodeCodeUi)\
 
            .filter(RhodeCodeUi.ui_key == hooks2_key).scalar()
 
        hooks2 = RhodeCodeUi() if hooks2_ is None else hooks2_
 
        hooks2.ui_section = 'hooks'
 
        hooks2.ui_key = hooks2_key
 
        hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
 
        self.sa.add(hooks2)
 

	
 
        hooks3 = RhodeCodeUi()
 
        hooks3.ui_section = 'hooks'
 
        hooks3.ui_key = RhodeCodeUi.HOOK_PUSH
 
        hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
 
        self.sa.add(hooks3)
 

	
 
        hooks4 = RhodeCodeUi()
 
        hooks4.ui_section = 'hooks'
 
        hooks4.ui_key = RhodeCodeUi.HOOK_PRE_PUSH
 
        hooks4.ui_value = 'python:rhodecode.lib.hooks.pre_push'
 
        self.sa.add(hooks4)
 

	
 
        hooks5 = RhodeCodeUi()
 
        hooks5.ui_section = 'hooks'
 
        hooks5.ui_key = RhodeCodeUi.HOOK_PULL
 
        hooks5.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
 
        self.sa.add(hooks5)
 

	
 
        hooks6 = RhodeCodeUi()
 
        hooks6.ui_section = 'hooks'
 
        hooks6.ui_key = RhodeCodeUi.HOOK_PRE_PULL
 
        hooks6.ui_value = 'python:rhodecode.lib.hooks.pre_pull'
 
        self.sa.add(hooks6)
 

	
 
        # enable largefiles
 
        largefiles = RhodeCodeUi()
 
        largefiles.ui_section = 'extensions'
 
        largefiles.ui_key = 'largefiles'
 
        largefiles.ui_value = ''
 
        self.sa.add(largefiles)
 

	
 
        # enable hgsubversion disabled by default
 
        hgsubversion = RhodeCodeUi()
 
        hgsubversion.ui_section = 'extensions'
 
        hgsubversion.ui_key = 'hgsubversion'
 
        hgsubversion.ui_value = ''
 
        hgsubversion.ui_active = False
 
        self.sa.add(hgsubversion)
 

	
 
        # enable hggit disabled by default
 
        hggit = RhodeCodeUi()
 
        hggit.ui_section = 'extensions'
 
        hggit.ui_key = 'hggit'
 
        hggit.ui_value = ''
 
        hggit.ui_active = False
 
        self.sa.add(hggit)
 

	
 
    def create_ldap_options(self, skip_existing=False):
 
        """Creates ldap settings"""
 

	
 
        for k, v in [('ldap_active', 'false'), ('ldap_host', ''),
 
                    ('ldap_port', '389'), ('ldap_tls_kind', 'PLAIN'),
 
                    ('ldap_tls_reqcert', ''), ('ldap_dn_user', ''),
 
                    ('ldap_dn_pass', ''), ('ldap_base_dn', ''),
 
                    ('ldap_filter', ''), ('ldap_search_scope', ''),
 
                    ('ldap_attr_login', ''), ('ldap_attr_firstname', ''),
 
                    ('ldap_attr_lastname', ''), ('ldap_attr_email', '')]:
 

	
 
            if skip_existing and RhodeCodeSetting.get_by_name(k) != None:
 
            if skip_existing and RhodeCodeSetting.get_by_name(k) is not None:
 
                log.debug('Skipping option %s' % k)
 
                continue
 
            setting = RhodeCodeSetting(k, v)
 
            self.sa.add(setting)
 

	
 
    def create_default_options(self, skip_existing=False):
 
        """Creates default settings"""
 

	
 
        for k, v in [
 
            ('default_repo_enable_locking',  False),
 
            ('default_repo_enable_downloads', False),
 
            ('default_repo_enable_statistics', False),
 
            ('default_repo_private', False),
 
            ('default_repo_type', 'hg')]:
 

	
 
            if skip_existing and RhodeCodeSetting.get_by_name(k) != None:
 
            if skip_existing and RhodeCodeSetting.get_by_name(k) is not None:
 
                log.debug('Skipping option %s' % k)
 
                continue
 
            setting = RhodeCodeSetting(k, v)
 
            self.sa.add(setting)
 

	
 
    def fixup_groups(self):
 
        def_usr = User.get_default_user()
 
        for g in RepoGroup.query().all():
 
            g.group_name = g.get_new_name(g.name)
 
            self.sa.add(g)
 
            # get default perm
 
            default = UserRepoGroupToPerm.query()\
 
                .filter(UserRepoGroupToPerm.group == g)\
 
                .filter(UserRepoGroupToPerm.user == def_usr)\
 
                .scalar()
 

	
 
            if default is None:
 
                log.debug('missing default permission for group %s adding' % g)
 
                perm_obj = ReposGroupModel()._create_default_perms(g)
 
                self.sa.add(perm_obj)
 

	
 
    def reset_permissions(self, username):
 
        """
 
        Resets permissions to default state, usefull when old systems had
 
        bad permissions, we must clean them up
 

	
 
        :param username:
 
        """
 
        default_user = User.get_by_username(username)
 
        if not default_user:
 
            return
 

	
 
        u2p = UserToPerm.query()\
 
            .filter(UserToPerm.user == default_user).all()
 
        fixed = False
 
        if len(u2p) != len(Permission.DEFAULT_USER_PERMISSIONS):
 
            for p in u2p:
 
                Session().delete(p)
 
            fixed = True
 
            self.populate_default_permissions()
 
        return fixed
 

	
 
    def update_repo_info(self):
 
        RepoModel.update_repoinfo()
 

	
 
    def config_prompt(self, test_repo_path='', retries=3):
 
        defaults = self.cli_args
 
        _path = defaults.get('repos_location')
 
        if retries == 3:
 
            log.info('Setting up repositories config')
 

	
 
        if _path is not None:
 
            path = _path
 
        elif not self.tests and not test_repo_path:
 
            path = raw_input(
 
                 'Enter a valid absolute path to store repositories. '
 
                 'All repositories in that path will be added automatically:'
 
            )
 
        else:
 
            path = test_repo_path
 
        path_ok = True
 

	
 
        # check proper dir
 
        if not os.path.isdir(path):
 
            path_ok = False
 
            log.error('Given path %s is not a valid directory' % path)
 

	
 
        elif not os.path.isabs(path):
 
            path_ok = False
 
            log.error('Given path %s is not an absolute path' % path)
 

	
 
        # check write access
 
        elif not os.access(path, os.W_OK) and path_ok:
 
            path_ok = False
 
            log.error('No write permission to given path %s' % path)
 

	
 
        if retries == 0:
 
            sys.exit('max retries reached')
 
        if not path_ok:
 
            retries -= 1
 
            return self.config_prompt(test_repo_path, retries)
 

	
 
        real_path = os.path.normpath(os.path.realpath(path))
 

	
 
        if real_path != os.path.normpath(path):
 
            if not ask_ok(('Path looks like a symlink, Rhodecode will store '
 
                           'given path as %s ? [y/n]') % (real_path)):
 
                log.error('Canceled by user')
 
                sys.exit(-1)
 

	
 
        return real_path
 

	
 
    def create_settings(self, path):
 

	
 
        self.create_ui_settings()
 

	
rhodecode/lib/middleware/simplegit.py
Show inline comments
 
@@ -4,193 +4,193 @@
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    SimpleGit middleware for handling git protocol request (push/clone etc.)
 
    It's implemented with basic auth function
 

	
 
    :created_on: Apr 28, 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 os
 
import re
 
import logging
 
import traceback
 

	
 
from dulwich import server as dulserver
 
from dulwich.web import LimitedInputFilter, GunzipFilter
 
from rhodecode.lib.exceptions import HTTPLockedRC
 
from rhodecode.lib.hooks import pre_pull
 

	
 

	
 
class SimpleGitUploadPackHandler(dulserver.UploadPackHandler):
 

	
 
    def handle(self):
 
        write = lambda x: self.proto.write_sideband(1, x)
 

	
 
        graph_walker = dulserver.ProtocolGraphWalker(self,
 
                                                     self.repo.object_store,
 
                                                     self.repo.get_peeled)
 
        objects_iter = self.repo.fetch_objects(
 
          graph_walker.determine_wants, graph_walker, self.progress,
 
          get_tagged=self.get_tagged)
 

	
 
        # Did the process short-circuit (e.g. in a stateless RPC call)? Note
 
        # that the client still expects a 0-object pack in most cases.
 
        if objects_iter is None:
 
            return
 

	
 
        self.progress("counting objects: %d, done.\n" % len(objects_iter))
 
        dulserver.write_pack_objects(dulserver.ProtocolFile(None, write),
 
                                     objects_iter)
 
        messages = []
 
        messages.append('thank you for using rhodecode')
 

	
 
        for msg in messages:
 
            self.progress(msg + "\n")
 
        # we are done
 
        self.proto.write("0000")
 

	
 

	
 
dulserver.DEFAULT_HANDLERS = {
 
  #git-ls-remote, git-clone, git-fetch and git-pull
 
  'git-upload-pack': SimpleGitUploadPackHandler,
 
  #git-push
 
  'git-receive-pack': dulserver.ReceivePackHandler,
 
}
 

	
 
# not used for now until dulwich get's fixed
 
#from dulwich.repo import Repo
 
#from dulwich.web import make_wsgi_chain
 

	
 
from paste.httpheaders import REMOTE_USER, AUTH_TYPE
 
from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \
 
    HTTPBadRequest, HTTPNotAcceptable
 

	
 
from rhodecode.lib.utils2 import safe_str, fix_PATH, get_server_url,\
 
    _set_extras
 
from rhodecode.lib.base import BaseVCSController
 
from rhodecode.lib.auth import get_container_username
 
from rhodecode.lib.utils import is_valid_repo, make_ui
 
from rhodecode.lib.compat import json
 
from rhodecode.model.db import User, RhodeCodeUi
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
GIT_PROTO_PAT = re.compile(r'^/(.+)/(info/refs|git-upload-pack|git-receive-pack)')
 

	
 

	
 
def is_git(environ):
 
    path_info = environ['PATH_INFO']
 
    isgit_path = GIT_PROTO_PAT.match(path_info)
 
    log.debug('pathinfo: %s detected as GIT %s' % (
 
        path_info, isgit_path != None)
 
        path_info, isgit_path is not None)
 
    )
 
    return isgit_path
 

	
 

	
 
class SimpleGit(BaseVCSController):
 

	
 
    def _handle_request(self, environ, start_response):
 
        if not is_git(environ):
 
            return self.application(environ, start_response)
 
        if not self._check_ssl(environ, start_response):
 
            return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response)
 

	
 
        ip_addr = self._get_ip_addr(environ)
 
        username = None
 
        self._git_first_op = False
 
        # skip passing error to error controller
 
        environ['pylons.status_code_redirect'] = True
 

	
 
        #======================================================================
 
        # EXTRACT REPOSITORY NAME FROM ENV
 
        #======================================================================
 
        try:
 
            repo_name = self.__get_repository(environ)
 
            log.debug('Extracted repo name is %s' % repo_name)
 
        except Exception:
 
            return HTTPInternalServerError()(environ, start_response)
 

	
 
        # quick check if that dir exists...
 
        if not is_valid_repo(repo_name, self.basepath, 'git'):
 
            return HTTPNotFound()(environ, start_response)
 

	
 
        #======================================================================
 
        # GET ACTION PULL or PUSH
 
        #======================================================================
 
        action = self.__get_action(environ)
 

	
 
        #======================================================================
 
        # CHECK ANONYMOUS PERMISSION
 
        #======================================================================
 
        if action in ['pull', 'push']:
 
            anonymous_user = self.__get_user('default')
 
            username = anonymous_user.username
 
            anonymous_perm = self._check_permission(action, anonymous_user,
 
                                                    repo_name, ip_addr)
 

	
 
            if not anonymous_perm or not anonymous_user.active:
 
                if not anonymous_perm:
 
                    log.debug('Not enough credentials to access this '
 
                              'repository as anonymous user')
 
                if not anonymous_user.active:
 
                    log.debug('Anonymous access is disabled, running '
 
                              'authentication')
 
                #==============================================================
 
                # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
 
                # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
 
                #==============================================================
 

	
 
                # Attempting to retrieve username from the container
 
                username = get_container_username(environ, self.config)
 

	
 
                # If not authenticated by the container, running basic auth
 
                if not username:
 
                    self.authenticate.realm = \
 
                        safe_str(self.config['rhodecode_realm'])
 
                    result = self.authenticate(environ)
 
                    if isinstance(result, str):
 
                        AUTH_TYPE.update(environ, 'basic')
 
                        REMOTE_USER.update(environ, result)
 
                        username = result
 
                    else:
 
                        return result.wsgi_application(environ, start_response)
 

	
 
                #==============================================================
 
                # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
 
                #==============================================================
 
                try:
 
                    user = self.__get_user(username)
 
                    if user is None or not user.active:
 
                        return HTTPForbidden()(environ, start_response)
 
                    username = user.username
 
                except Exception:
 
                    log.error(traceback.format_exc())
 
                    return HTTPInternalServerError()(environ, start_response)
 

	
 
                #check permissions for this repository
 
                perm = self._check_permission(action, user, repo_name, ip_addr)
 
                if not perm:
 
                    return HTTPForbidden()(environ, start_response)
 

	
 
        # extras are injected into UI object and later available
 
        # in hooks executed by rhodecode
 
        from rhodecode import CONFIG
 
        server_url = get_server_url(environ)
 
        extras = {
 
            'ip': ip_addr,
 
            'username': username,
rhodecode/lib/rcmail/response.py
Show inline comments
 
# The code in this module is entirely lifted from the Lamson project
 
# (http://lamsonproject.org/).  Its copyright is:
 

	
 
# Copyright (c) 2008, Zed A. Shaw
 
# All rights reserved.
 

	
 
# It is provided under this license:
 

	
 
# Redistribution and use in source and binary forms, with or without
 
# modification, are permitted provided that the following conditions are met:
 

	
 
# * Redistributions of source code must retain the above copyright notice, this
 
#   list of conditions and the following disclaimer.
 

	
 
# * Redistributions in binary form must reproduce the above copyright notice,
 
#   this list of conditions and the following disclaimer in the documentation
 
#   and/or other materials provided with the distribution.
 

	
 
# * Neither the name of the Zed A. Shaw nor the names of its contributors may
 
#   be used to endorse or promote products derived from this software without
 
#   specific prior written permission.
 

	
 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
# POSSIBILITY OF SUCH DAMAGE.
 

	
 
import os
 
import mimetypes
 
import string
 
from email import encoders
 
from email.charset import Charset
 
from email.utils import parseaddr
 
from email.mime.base import MIMEBase
 

	
 
ADDRESS_HEADERS_WHITELIST = ['From', 'To', 'Delivered-To', 'Cc']
 
DEFAULT_ENCODING = "utf-8"
 
VALUE_IS_EMAIL_ADDRESS = lambda v: '@' in v
 

	
 

	
 
def normalize_header(header):
 
    return string.capwords(header.lower(), '-')
 

	
 

	
 
class EncodingError(Exception):
 
    """Thrown when there is an encoding error."""
 
    pass
 

	
 

	
 
class MailBase(object):
 
    """MailBase is used as the basis of lamson.mail and contains the basics of
 
    encoding an email.  You actually can do all your email processing with this
 
    class, but it's more raw.
 
    """
 
    def __init__(self, items=()):
 
        self.headers = dict(items)
 
        self.parts = []
 
        self.body = None
 
        self.content_encoding = {'Content-Type': (None, {}),
 
                                 'Content-Disposition': (None, {}),
 
                                 'Content-Transfer-Encoding': (None, {})}
 

	
 
    def __getitem__(self, key):
 
        return self.headers.get(normalize_header(key), None)
 

	
 
    def __len__(self):
 
        return len(self.headers)
 

	
 
    def __iter__(self):
 
        return iter(self.headers)
 

	
 
    def __contains__(self, key):
 
        return normalize_header(key) in self.headers
 

	
 
    def __setitem__(self, key, value):
 
        self.headers[normalize_header(key)] = value
 

	
 
    def __delitem__(self, key):
 
        del self.headers[normalize_header(key)]
 

	
 
    def __nonzero__(self):
 
        return self.body != None or len(self.headers) > 0 or len(self.parts) > 0
 
        return self.body is not None or len(self.headers) > 0 or len(self.parts) > 0
 

	
 
    def keys(self):
 
        """Returns the sorted keys."""
 
        return sorted(self.headers.keys())
 

	
 
    def attach_file(self, filename, data, ctype, disposition):
 
        """
 
        A file attachment is a raw attachment with a disposition that
 
        indicates the file name.
 
        """
 
        assert filename, "You can't attach a file without a filename."
 
        ctype = ctype.lower()
 

	
 
        part = MailBase()
 
        part.body = data
 
        part.content_encoding['Content-Type'] = (ctype, {'name': filename})
 
        part.content_encoding['Content-Disposition'] = (disposition,
 
                                                        {'filename': filename})
 
        self.parts.append(part)
 

	
 
    def attach_text(self, data, ctype):
 
        """
 
        This attaches a simpler text encoded part, which doesn't have a
 
        filename.
 
        """
 
        ctype = ctype.lower()
 

	
 
        part = MailBase()
 
        part.body = data
 
        part.content_encoding['Content-Type'] = (ctype, {})
 
        self.parts.append(part)
 

	
 
    def walk(self):
 
        for p in self.parts:
 
            yield p
 
            for x in p.walk():
 
                yield x
 

	
 

	
 
class MailResponse(object):
 
    """
 
    You are given MailResponse objects from the lamson.view methods, and
 
    whenever you want to generate an email to send to someone.  It has the
 
    same basic functionality as MailRequest, but it is designed to be written
 
    to, rather than read from (although you can do both).
 

	
 
    You can easily set a Body or Html during creation or after by passing it
 
    as __init__ parameters, or by setting those attributes.
 

	
 
    You can initially set the From, To, and Subject, but they are headers so
 
    use the dict notation to change them: msg['From'] = 'joe@test.com'.
 

	
 
    The message is not fully crafted until right when you convert it with
 
    MailResponse.to_message.  This lets you change it and work with it, then
 
    send it out when it's ready.
 
    """
 
    def __init__(self, To=None, From=None, Subject=None, Body=None, Html=None,
 
                 separator="; "):
 
        self.Body = Body
 
        self.Html = Html
 
        self.base = MailBase([('To', To), ('From', From), ('Subject', Subject)])
 
        self.multipart = self.Body and self.Html
 
        self.attachments = []
 
        self.separator = separator
 

	
 
    def __contains__(self, key):
 
        return self.base.__contains__(key)
 

	
 
    def __getitem__(self, key):
 
        return self.base.__getitem__(key)
 

	
 
    def __setitem__(self, key, val):
 
        return self.base.__setitem__(key, val)
 

	
 
    def __delitem__(self, name):
 
        del self.base[name]
 

	
 
    def attach(self, filename=None, content_type=None, data=None,
 
               disposition=None):
 
        """
 

	
 
        Simplifies attaching files from disk or data as files.  To attach
 
        simple text simple give data and a content_type.  To attach a file,
 
        give the data/content_type/filename/disposition combination.
 

	
 
        For convenience, if you don't give data and only a filename, then it
 
        will read that file's contents when you call to_message() later.  If
 
        you give data and filename then it will assume you've filled data
 
        with what the file's contents are and filename is just the name to
 
        use.
 
        """
 

	
 
        assert filename or data, ("You must give a filename or some data to "
 
                                  "attach.")
 
        assert data or os.path.exists(filename), ("File doesn't exist, and no "
 
                                                  "data given.")
 
@@ -295,159 +295,159 @@ class MailResponse(object):
 
            for args in self.attachments:
 
                self._encode_attachment(**args)
 

	
 
        elif self.Body:
 
            self.base.body = self.Body
 
            self.base.content_encoding['Content-Type'] = ('text/plain', {})
 

	
 
        elif self.Html:
 
            self.base.body = self.Html
 
            self.base.content_encoding['Content-Type'] = ('text/html', {})
 

	
 
        return to_message(self.base, separator=self.separator)
 

	
 
    def all_parts(self):
 
        """
 
        Returns all the encoded parts.  Only useful for debugging
 
        or inspecting after calling to_message().
 
        """
 
        return self.base.parts
 

	
 
    def keys(self):
 
        return self.base.keys()
 

	
 

	
 
def to_message(mail, separator="; "):
 
    """
 
    Given a MailBase message, this will construct a MIMEPart
 
    that is canonicalized for use with the Python email API.
 
    """
 
    ctype, params = mail.content_encoding['Content-Type']
 

	
 
    if not ctype:
 
        if mail.parts:
 
            ctype = 'multipart/mixed'
 
        else:
 
            ctype = 'text/plain'
 
    else:
 
        if mail.parts:
 
            assert ctype.startswith(("multipart", "message")), \
 
                   "Content type should be multipart or message, not %r" % ctype
 

	
 
    # adjust the content type according to what it should be now
 
    mail.content_encoding['Content-Type'] = (ctype, params)
 

	
 
    try:
 
        out = MIMEPart(ctype, **params)
 
    except TypeError, exc:  # pragma: no cover
 
        raise EncodingError("Content-Type malformed, not allowed: %r; "
 
                            "%r (Python ERROR: %s" %
 
                            (ctype, params, exc.message))
 

	
 
    for k in mail.keys():
 
        if k in ADDRESS_HEADERS_WHITELIST:
 
            out[k.encode('ascii')] = header_to_mime_encoding(
 
                                         mail[k],
 
                                         not_email=False,
 
                                         separator=separator
 
                                     )
 
        else:
 
            out[k.encode('ascii')] = header_to_mime_encoding(
 
                                         mail[k],
 
                                         not_email=True
 
                                    )
 

	
 
    out.extract_payload(mail)
 

	
 
    # go through the children
 
    for part in mail.parts:
 
        out.attach(to_message(part))
 

	
 
    return out
 

	
 

	
 
class MIMEPart(MIMEBase):
 
    """
 
    A reimplementation of nearly everything in email.mime to be more useful
 
    for actually attaching things.  Rather than one class for every type of
 
    thing you'd encode, there's just this one, and it figures out how to
 
    encode what you ask it.
 
    """
 
    def __init__(self, type, **params):
 
        self.maintype, self.subtype = type.split('/')
 
        MIMEBase.__init__(self, self.maintype, self.subtype, **params)
 

	
 
    def add_text(self, content):
 
        # this is text, so encode it in canonical form
 
        try:
 
            encoded = content.encode('ascii')
 
            charset = 'ascii'
 
        except UnicodeError:
 
            encoded = content.encode('utf-8')
 
            charset = 'utf-8'
 

	
 
        self.set_payload(encoded, charset=charset)
 

	
 
    def extract_payload(self, mail):
 
        if mail.body == None:
 
        if mail.body is None:
 
            return  # only None, '' is still ok
 

	
 
        ctype, ctype_params = mail.content_encoding['Content-Type']
 
        cdisp, cdisp_params = mail.content_encoding['Content-Disposition']
 

	
 
        assert ctype, ("Extract payload requires that mail.content_encoding "
 
                       "have a valid Content-Type.")
 

	
 
        if ctype.startswith("text/"):
 
            self.add_text(mail.body)
 
        else:
 
            if cdisp:
 
                # replicate the content-disposition settings
 
                self.add_header('Content-Disposition', cdisp, **cdisp_params)
 

	
 
            self.set_payload(mail.body)
 
            encoders.encode_base64(self)
 

	
 
    def __repr__(self):
 
        return "<MIMEPart '%s/%s': %r, %r, multipart=%r>" % (
 
            self.subtype,
 
            self.maintype,
 
            self['Content-Type'],
 
            self['Content-Disposition'],
 
            self.is_multipart())
 

	
 

	
 
def header_to_mime_encoding(value, not_email=False, separator=", "):
 
    if not value:
 
        return ""
 

	
 
    encoder = Charset(DEFAULT_ENCODING)
 
    if type(value) == list:
 
        return separator.join(properly_encode_header(
 
            v, encoder, not_email) for v in value)
 
    else:
 
        return properly_encode_header(value, encoder, not_email)
 

	
 

	
 
def properly_encode_header(value, encoder, not_email):
 
    """
 
    The only thing special (weird) about this function is that it tries
 
    to do a fast check to see if the header value has an email address in
 
    it.  Since random headers could have an email address, and email addresses
 
    have weird special formatting rules, we have to check for it.
 

	
 
    Normally this works fine, but in Librelist, we need to "obfuscate" email
 
    addresses by changing the '@' to '-AT-'.  This is where
 
    VALUE_IS_EMAIL_ADDRESS exists.  It's a simple lambda returning True/False
 
    to check if a header value has an email address.  If you need to make this
 
    check different, then change this.
 
    """
 
    try:
 
        return value.encode("ascii")
 
    except UnicodeEncodeError:
 
        if not not_email and VALUE_IS_EMAIL_ADDRESS(value):
 
            # this could have an email address, make sure we don't screw it up
 
            name, address = parseaddr(value)
 
            return '"%s" <%s>' % (
 
                encoder.header_encode(name.encode("utf-8")), address)
 

	
 
        return encoder.header_encode(value.encode("utf-8"))
rhodecode/lib/vcs/subprocessio.py
Show inline comments
 
@@ -275,141 +275,141 @@ class BufferedGenerator():
 
        self.data.append(x)
 

	
 
    def extend(self, o):
 
        self.data.extend(o)
 

	
 
    def __getitem__(self, i):
 
        return self.data[i]
 

	
 

	
 
class SubprocessIOChunker(object):
 
    """
 
    Processor class wrapping handling of subprocess IO.
 

	
 
    In a way, this is a "communicate()" replacement with a twist.
 

	
 
    - We are multithreaded. Writing in and reading out, err are all sep threads.
 
    - We support concurrent (in and out) stream processing.
 
    - The output is not a stream. It's a queue of read string (bytes, not unicode)
 
      chunks. The object behaves as an iterable. You can "for chunk in obj:" us.
 
    - We are non-blocking in more respects than communicate()
 
      (reading from subprocess out pauses when internal buffer is full, but
 
       does not block the parent calling code. On the flip side, reading from
 
       slow-yielding subprocess may block the iteration until data shows up. This
 
       does not block the parallel inpipe reading occurring parallel thread.)
 

	
 
    The purpose of the object is to allow us to wrap subprocess interactions into
 
    and interable that can be passed to a WSGI server as the application's return
 
    value. Because of stream-processing-ability, WSGI does not have to read ALL
 
    of the subprocess's output and buffer it, before handing it to WSGI server for
 
    HTTP response. Instead, the class initializer reads just a bit of the stream
 
    to figure out if error ocurred or likely to occur and if not, just hands the
 
    further iteration over subprocess output to the server for completion of HTTP
 
    response.
 

	
 
    The real or perceived subprocess error is trapped and raised as one of
 
    EnvironmentError family of exceptions
 

	
 
    Example usage:
 
    #    try:
 
    #        answer = SubprocessIOChunker(
 
    #            cmd,
 
    #            input,
 
    #            buffer_size = 65536,
 
    #            chunk_size = 4096
 
    #            )
 
    #    except (EnvironmentError) as e:
 
    #        print str(e)
 
    #        raise e
 
    #
 
    #    return answer
 

	
 

	
 
    """
 
    def __init__(self, cmd, inputstream=None, buffer_size=65536,
 
                 chunk_size=4096, starting_values=[], **kwargs):
 
        """
 
        Initializes SubprocessIOChunker
 

	
 
        :param cmd: A Subprocess.Popen style "cmd". Can be string or array of strings
 
        :param inputstream: (Default: None) A file-like, string, or file pointer.
 
        :param buffer_size: (Default: 65536) A size of total buffer per stream in bytes.
 
        :param chunk_size: (Default: 4096) A max size of a chunk. Actual chunk may be smaller.
 
        :param starting_values: (Default: []) An array of strings to put in front of output que.
 
        """
 

	
 
        if inputstream:
 
            input_streamer = StreamFeeder(inputstream)
 
            input_streamer.start()
 
            inputstream = input_streamer.output
 

	
 
        _shell = kwargs.get('shell', True)
 
        if isinstance(cmd, (list, tuple)):
 
            cmd = ' '.join(cmd)
 

	
 
        kwargs['shell'] = _shell
 
        _p = subprocess.Popen(cmd,
 
            bufsize=-1,
 
            stdin=inputstream,
 
            stdout=subprocess.PIPE,
 
            stderr=subprocess.PIPE,
 
            **kwargs
 
        )
 

	
 
        bg_out = BufferedGenerator(_p.stdout, buffer_size, chunk_size, starting_values)
 
        bg_err = BufferedGenerator(_p.stderr, 16000, 1, bottomless=True)
 

	
 
        while not bg_out.done_reading and not bg_out.reading_paused and not bg_err.length:
 
            # doing this until we reach either end of file, or end of buffer.
 
            bg_out.data_added_event.wait(1)
 
            bg_out.data_added_event.clear()
 

	
 
        # at this point it's still ambiguous if we are done reading or just full buffer.
 
        # Either way, if error (returned by ended process, or implied based on
 
        # presence of stuff in stderr output) we error out.
 
        # Else, we are happy.
 
        _returncode = _p.poll()
 
        if _returncode or (_returncode == None and bg_err.length):
 
        if _returncode or (_returncode is None and bg_err.length):
 
            try:
 
                _p.terminate()
 
            except:
 
                pass
 
            bg_out.stop()
 
            bg_err.stop()
 
            err = '%s' % ''.join(bg_err)
 
            if err:
 
                raise EnvironmentError("Subprocess exited due to an error:\n" + err)
 
            raise EnvironmentError("Subprocess exited with non 0 ret code:%s" % _returncode)
 

	
 
        self.process = _p
 
        self.output = bg_out
 
        self.error = bg_err
 

	
 
    def __iter__(self):
 
        return self
 

	
 
    def next(self):
 
        if self.process.poll():
 
            err = '%s' % ''.join(self.error)
 
            raise EnvironmentError("Subprocess exited due to an error:\n" + err)
 
        return self.output.next()
 

	
 
    def throw(self, type, value=None, traceback=None):
 
        if self.output.length or not self.output.done_reading:
 
            raise type(value)
 

	
 
    def close(self):
 
        try:
 
            self.process.terminate()
 
        except:
 
            pass
 
        try:
 
            self.output.close()
 
        except:
 
            pass
 
        try:
 
            self.error.close()
 
        except:
 
            pass
 

	
 
    def __del__(self):
 
        self.close()
rhodecode/tests/functional/test_admin_settings.py
Show inline comments
 
@@ -159,107 +159,107 @@ class TestAdminSettingsController(TestCo
 
            params['last_login'] = updated_params['last_login']
 
            if name == 'email':
 
                params['emails'] = [expected]
 
            if name == 'ldap_dn':
 
                #cannot update this via form
 
                params['ldap_dn'] = None
 
            if name == 'active':
 
                #my account cannot deactivate account
 
                params['active'] = True
 
            if name == 'admin':
 
                #my account cannot make you an admin !
 
                params['admin'] = False
 

	
 
            self.assertEqual(params, updated_params)
 

	
 
        finally:
 
            UserModel().delete('testme')
 

	
 
    def test_my_account_update_err_email_exists(self):
 
        self.log_user()
 

	
 
        new_email = 'test_regular@mail.com'  # already exisitn email
 
        response = self.app.put(url('admin_settings_my_account_update'),
 
                                params=dict(
 
                                    username='test_admin',
 
                                    new_password='test12',
 
                                    password_confirmation='test122',
 
                                    firstname='NewName',
 
                                    lastname='NewLastname',
 
                                    email=new_email,)
 
                                )
 

	
 
        response.mustcontain('This e-mail address is already taken')
 

	
 
    def test_my_account_update_err(self):
 
        self.log_user('test_regular2', 'test12')
 

	
 
        new_email = 'newmail.pl'
 
        response = self.app.post(url('admin_settings_my_account_update'),
 
                                 params=dict(
 
                                            _method='put',
 
                                            username='test_admin',
 
                                            new_password='test12',
 
                                            password_confirmation='test122',
 
                                            firstname='NewName',
 
                                            lastname='NewLastname',
 
                                            email=new_email,)
 
                                 )
 

	
 
        response.mustcontain('An email address must contain a single @')
 
        from rhodecode.model import validators
 
        msg = validators.ValidUsername(edit=False,
 
                                    old_data={})._messages['username_exists']
 
        msg = h.html_escape(msg % {'username': 'test_admin'})
 
        response.mustcontain(u"%s" % msg)
 

	
 
    def test_set_repo_fork_has_no_self_id(self):
 
        self.log_user()
 
        repo = Repository.get_by_repo_name(HG_REPO)
 
        response = self.app.get(url('edit_repo', repo_name=HG_REPO))
 
        opt = """<option value="%s">vcs_test_git</option>""" % repo.repo_id
 
        response.mustcontain(no=[opt])
 

	
 
    def test_set_fork_of_repo(self):
 
        self.log_user()
 
        repo = Repository.get_by_repo_name(HG_REPO)
 
        repo2 = Repository.get_by_repo_name(GIT_REPO)
 
        response = self.app.put(url('repo_as_fork', repo_name=HG_REPO),
 
                                 params=dict(
 
                                    id_fork_of=repo2.repo_id
 
                                 ))
 
        repo = Repository.get_by_repo_name(HG_REPO)
 
        repo2 = Repository.get_by_repo_name(GIT_REPO)
 
        self.checkSessionFlash(response,
 
        'Marked repo %s as fork of %s' % (repo.repo_name, repo2.repo_name))
 

	
 
        assert repo.fork == repo2
 
        response = response.follow()
 
        # check if given repo is selected
 

	
 
        opt = """<option value="%s" selected="selected">%s</option>""" % (
 
                                                repo2.repo_id, repo2.repo_name)
 
        response.mustcontain(opt)
 

	
 
        # clean session flash
 
        #response = self.app.get(url('edit_repo', repo_name=HG_REPO))
 

	
 
        ## mark it as None
 
        response = self.app.put(url('repo_as_fork', repo_name=HG_REPO),
 
                                 params=dict(
 
                                    id_fork_of=None
 
                                 ))
 
        repo = Repository.get_by_repo_name(HG_REPO)
 
        repo2 = Repository.get_by_repo_name(GIT_REPO)
 
        self.checkSessionFlash(response,
 
        'Marked repo %s as fork of %s' % (repo.repo_name, "Nothing"))
 
        assert repo.fork == None
 
        assert repo.fork is None
 

	
 
    def test_set_fork_of_same_repo(self):
 
        self.log_user()
 
        repo = Repository.get_by_repo_name(HG_REPO)
 
        response = self.app.put(url('repo_as_fork', repo_name=HG_REPO),
 
                                 params=dict(
 
                                    id_fork_of=repo.repo_id
 
                                 ))
 
        self.checkSessionFlash(response,
 
                               'An error occurred during this operation')
rhodecode/tests/other/test_validators.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
import formencode
 

	
 
from rhodecode.tests import *
 

	
 
from rhodecode.model import validators as v
 
from rhodecode.model.users_group import UserGroupModel
 

	
 
from rhodecode.model.meta import Session
 
from rhodecode.model.repos_group import ReposGroupModel
 
from rhodecode.model.db import ChangesetStatus, Repository
 
from rhodecode.model.changeset_status import ChangesetStatusModel
 
from rhodecode.tests.fixture import Fixture
 

	
 
fixture = Fixture()
 

	
 

	
 
class TestReposGroups(BaseTestCase):
 

	
 
    def setUp(self):
 
        pass
 

	
 
    def tearDown(self):
 
        Session.remove()
 

	
 
    def test_Message_extractor(self):
 
        validator = v.ValidUsername()
 
        self.assertRaises(formencode.Invalid, validator.to_python, 'default')
 

	
 
        class StateObj(object):
 
            pass
 

	
 
        self.assertRaises(formencode.Invalid,
 
                          validator.to_python, 'default', StateObj)
 

	
 
    def test_ValidUsername(self):
 
        validator = v.ValidUsername()
 

	
 
        self.assertRaises(formencode.Invalid, validator.to_python, 'default')
 
        self.assertRaises(formencode.Invalid, validator.to_python, 'new_user')
 
        self.assertRaises(formencode.Invalid, validator.to_python, '.,')
 
        self.assertRaises(formencode.Invalid, validator.to_python,
 
                          TEST_USER_ADMIN_LOGIN)
 
        self.assertEqual('test', validator.to_python('test'))
 

	
 
        validator = v.ValidUsername(edit=True, old_data={'user_id': 1})
 

	
 
    def test_ValidRepoUser(self):
 
        validator = v.ValidRepoUser()
 
        self.assertRaises(formencode.Invalid, validator.to_python, 'nouser')
 
        self.assertEqual(TEST_USER_ADMIN_LOGIN,
 
                         validator.to_python(TEST_USER_ADMIN_LOGIN))
 

	
 
    def test_ValidUserGroup(self):
 
        validator = v.ValidUserGroup()
 
        self.assertRaises(formencode.Invalid, validator.to_python, 'default')
 
        self.assertRaises(formencode.Invalid, validator.to_python, '.,')
 

	
 
        gr = fixture.create_user_group('test')
 
        gr2 = fixture.create_user_group('tes2')
 
        Session().commit()
 
        self.assertRaises(formencode.Invalid, validator.to_python, 'test')
 
        assert gr.users_group_id != None
 
        assert gr.users_group_id is not None
 
        validator = v.ValidUserGroup(edit=True,
 
                                    old_data={'users_group_id':
 
                                              gr2.users_group_id})
 

	
 
        self.assertRaises(formencode.Invalid, validator.to_python, 'test')
 
        self.assertRaises(formencode.Invalid, validator.to_python, 'TesT')
 
        self.assertRaises(formencode.Invalid, validator.to_python, 'TEST')
 
        UserGroupModel().delete(gr)
 
        UserGroupModel().delete(gr2)
 
        Session().commit()
 

	
 
    def test_ValidReposGroup(self):
 
        validator = v.ValidReposGroup()
 
        model = ReposGroupModel()
 
        self.assertRaises(formencode.Invalid, validator.to_python,
 
                          {'group_name': HG_REPO, })
 
        gr = model.create(group_name='test_gr', group_description='desc',
 
                          parent=None,
 
                          just_db=True,
 
                          owner=TEST_USER_ADMIN_LOGIN)
 
        self.assertRaises(formencode.Invalid,
 
                          validator.to_python, {'group_name': gr.group_name, })
 

	
 
        validator = v.ValidReposGroup(edit=True,
 
                                      old_data={'group_id':  gr.group_id})
 
        self.assertRaises(formencode.Invalid,
 
                          validator.to_python, {
 
                                        'group_name': gr.group_name + 'n',
 
                                        'group_parent_id': gr.group_id
 
                                        })
 
        model.delete(gr)
 

	
 
    def test_ValidPassword(self):
 
        validator = v.ValidPassword()
 
        self.assertEqual('lol', validator.to_python('lol'))
 
        self.assertEqual(None, validator.to_python(None))
 
        self.assertRaises(formencode.Invalid, validator.to_python, 'ąćżź')
 

	
 
    def test_ValidPasswordsMatch(self):
 
        validator = v.ValidPasswordsMatch()
 
        self.assertRaises(formencode.Invalid,
 
                    validator.to_python, {'password': 'pass',
 
                                          'password_confirmation': 'pass2'})
 

	
 
        self.assertRaises(formencode.Invalid,
 
                    validator.to_python, {'new_password': 'pass',
 
                                          'password_confirmation': 'pass2'})
 

	
 
        self.assertEqual({'new_password': 'pass',
 
                          'password_confirmation': 'pass'},
 
                    validator.to_python({'new_password': 'pass',
 
                                         'password_confirmation': 'pass'}))
 

	
 
        self.assertEqual({'password': 'pass',
 
                          'password_confirmation': 'pass'},
 
                    validator.to_python({'password': 'pass',
 
                                         'password_confirmation': 'pass'}))
 

	
 
    def test_ValidAuth(self):
 
        validator = v.ValidAuth()
 
        valid_creds = {
 
            'username': TEST_USER_REGULAR2_LOGIN,
 
            'password': TEST_USER_REGULAR2_PASS,
 
        }
 
        invalid_creds = {
 
            'username': 'err',
 
            'password': 'err',
 
        }
 
        self.assertEqual(valid_creds, validator.to_python(valid_creds))
 
        self.assertRaises(formencode.Invalid,
 
                          validator.to_python, invalid_creds)
 

	
 
    def test_ValidAuthToken(self):
 
        validator = v.ValidAuthToken()
 
        # this is untestable without a threadlocal
 
#        self.assertRaises(formencode.Invalid,
 
#                          validator.to_python, 'BadToken')
 
        validator
 

	
 
    def test_ValidRepoName(self):
 
        validator = v.ValidRepoName()
 

	
 
        self.assertRaises(formencode.Invalid,
 
                          validator.to_python, {'repo_name': ''})
 

	
 
        self.assertRaises(formencode.Invalid,
 
                          validator.to_python, {'repo_name': HG_REPO})
 

	
 
        gr = ReposGroupModel().create(group_name='group_test',
 
                                      group_description='desc',
 
                                      parent=None,
 
                                      owner=TEST_USER_ADMIN_LOGIN)
 
        self.assertRaises(formencode.Invalid,
 
                          validator.to_python, {'repo_name': gr.group_name})
 

	
 
        #TODO: write an error case for that ie. create a repo withinh a group
rhodecode/tests/scripts/test_concurency.py
Show inline comments
 
@@ -68,153 +68,153 @@ class Command(object):
 
    def execute(self, cmd, *args):
 
        """Runs command on the system with given ``args``.
 
        """
 

	
 
        command = cmd + ' ' + ' '.join(args)
 
        log.debug('Executing %s' % command)
 
        if DEBUG:
 
            print command
 
        p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd)
 
        stdout, stderr = p.communicate()
 
        if DEBUG:
 
            print stdout, stderr
 
        return stdout, stderr
 

	
 

	
 
def get_session():
 
    engine = engine_from_config(conf, 'sqlalchemy.db1.')
 
    init_model(engine)
 
    sa = meta.Session
 
    return sa
 

	
 

	
 
def create_test_user(force=True):
 
    print 'creating test user'
 
    sa = get_session()
 

	
 
    user = sa.query(User).filter(User.username == USER).scalar()
 

	
 
    if force and user is not None:
 
        print 'removing current user'
 
        for repo in sa.query(Repository).filter(Repository.user == user).all():
 
            sa.delete(repo)
 
        sa.delete(user)
 
        sa.commit()
 

	
 
    if user is None or force:
 
        print 'creating new one'
 
        new_usr = User()
 
        new_usr.username = USER
 
        new_usr.password = get_crypt_password(PASS)
 
        new_usr.email = 'mail@mail.com'
 
        new_usr.name = 'test'
 
        new_usr.lastname = 'lasttestname'
 
        new_usr.active = True
 
        new_usr.admin = True
 
        sa.add(new_usr)
 
        sa.commit()
 

	
 
    print 'done'
 

	
 

	
 
def create_test_repo(force=True):
 
    print 'creating test repo'
 
    from rhodecode.model.repo import RepoModel
 
    sa = get_session()
 

	
 
    user = sa.query(User).filter(User.username == USER).scalar()
 
    if user is None:
 
        raise Exception('user not found')
 

	
 
    repo = sa.query(Repository).filter(Repository.repo_name == HG_REPO).scalar()
 

	
 
    if repo is None:
 
        print 'repo not found creating'
 

	
 
        form_data = {'repo_name': HG_REPO,
 
                     'repo_type': 'hg',
 
                     'private':False,
 
                     'clone_uri': '' }
 
        rm = RepoModel(sa)
 
        rm.base_path = '/home/hg'
 
        rm.create(form_data, user)
 

	
 
    print 'done'
 

	
 

	
 
def set_anonymous_access(enable=True):
 
    sa = get_session()
 
    user = sa.query(User).filter(User.username == 'default').one()
 
    user.active = enable
 
    sa.add(user)
 
    sa.commit()
 

	
 

	
 
def get_anonymous_access():
 
    sa = get_session()
 
    return sa.query(User).filter(User.username == 'default').one().active
 

	
 

	
 
#==============================================================================
 
# TESTS
 
#==============================================================================
 
def test_clone_with_credentials(no_errors=False, repo=HG_REPO, method=METHOD,
 
                                seq=None, backend='hg'):
 
    cwd = path = jn(TESTS_TMP_PATH, repo)
 

	
 
    if seq == None:
 
    if seq is None:
 
        seq = _RandomNameSequence().next()
 

	
 
    try:
 
        shutil.rmtree(path, ignore_errors=True)
 
        os.makedirs(path)
 
        #print 'made dirs %s' % jn(path)
 
    except OSError:
 
        raise
 

	
 
    clone_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s' % \
 
                  {'user': USER,
 
                   'pass': PASS,
 
                   'host': HOST,
 
                   'cloned_repo': repo, }
 

	
 
    dest = path + seq
 
    if method == 'pull':
 
        stdout, stderr = Command(cwd).execute(backend, method, '--cwd', dest, clone_url)
 
    else:
 
        stdout, stderr = Command(cwd).execute(backend, method, clone_url, dest)
 
        print stdout,'sdasdsadsa'
 
        if not no_errors:
 
            if backend == 'hg':
 
                assert """adding file changes""" in stdout, 'no messages about cloning'
 
                assert """abort""" not in stderr , 'got error from clone'
 
            elif backend == 'git':
 
                assert """Cloning into""" in stdout, 'no messages about cloning'
 

	
 
if __name__ == '__main__':
 
    try:
 
        create_test_user(force=False)
 
        seq = None
 
        import time
 

	
 
        try:
 
            METHOD = sys.argv[3]
 
        except Exception:
 
            pass
 

	
 
        try:
 
            backend = sys.argv[4]
 
        except Exception:
 
            backend = 'hg'
 

	
 
        if METHOD == 'pull':
 
            seq = _RandomNameSequence().next()
 
            test_clone_with_credentials(repo=sys.argv[1], method='clone',
 
                                        seq=seq, backend=backend)
 
        s = time.time()
 
        for i in range(1, int(sys.argv[2]) + 1):
 
            print 'take', i
 
            test_clone_with_credentials(repo=sys.argv[1], method=METHOD,
 
                                        seq=seq, backend=backend)
 
        print 'time taken %.3f' % (time.time() - s)
 
    except Exception, e:
 
        sys.exit('stop on %s' % e)
0 comments (0 inline, 0 general)