Пример #1
0
    def test_Optional_object(self):

        option1 = Optional(None)
        assert '<Optional:%s>' % (None, ) == repr(option1)
        assert option1() is None

        assert 1 == Optional.extract(Optional(1))
        assert 'example' == Optional.extract('example')
Пример #2
0
def changeset_comment(request,
                      apiuser,
                      repoid,
                      revision,
                      message,
                      userid=Optional(OAttr('apiuser')),
                      status=Optional(None)):
    """
    Set a changeset comment, and optionally change the status of the
    changeset.

    This command can only be run using an |authtoken| with admin
    permissions on the |repo|.

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param repoid: Set the repository name or repository ID.
    :type repoid: str or int
    :param revision: Specify the revision for which to set a comment.
    :type revision: str
    :param message: The comment text.
    :type message: str
    :param userid: Set the user name of the comment creator.
    :type userid: Optional(str or int)
    :param status: Set the comment status. The following are valid options:
        * not_reviewed
        * approved
        * rejected
        * under_review
    :type status: str

    Example error output:

    .. code-block:: json

        {
            "id" : <id_given_in_input>,
            "result" : {
                "msg": "Commented on commit `<revision>` for repository `<repoid>`",
                "status_change": null or <status>,
                "success": true
            },
            "error" : null
        }

    """
    from .repo_api import comment_commit

    return comment_commit(request=request,
                          apiuser=apiuser,
                          repoid=repoid,
                          commit_id=revision,
                          message=message,
                          userid=userid,
                          status=status)
Пример #3
0
def rescan_repos(request, apiuser, remove_obsolete=Optional(False)):
    """
    Triggers a rescan of the specified repositories.

    * If the ``remove_obsolete`` option is set, it also deletes repositories
      that are found in the database but not on the file system, so called
      "clean zombies".

    This command can only be run using an |authtoken| with admin rights to
    the specified repository.

    This command takes the following options:

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param remove_obsolete: Deletes repositories from the database that
        are not found on the filesystem.
    :type remove_obsolete: Optional(``True`` | ``False``)

    Example output:

    .. code-block:: bash

      id : <id_given_in_input>
      result : {
        'added': [<added repository name>,...]
        'removed': [<removed repository name>,...]
      }
      error :  null

    Example error output:

    .. code-block:: bash

      id : <id_given_in_input>
      result : null
      error :  {
        'Error occurred during rescan repositories action'
      }

    """
    if not has_superadmin_permission(apiuser):
        raise JSONRPCForbidden()

    try:
        rm_obsolete = Optional.extract(remove_obsolete)
        added, removed = repo2db_mapper(ScmModel().repo_scan(),
                                        remove_obsolete=rm_obsolete)
        return {'added': added, 'removed': removed}
    except Exception:
        log.exception('Failed to run repo rescann')
        raise JSONRPCError(
            'Error occurred during rescan repositories action'
        )
Пример #4
0
def test_params_opt(request,
                    apiuser,
                    params,
                    opt1=False,
                    opt2=Optional(True),
                    opt3=Optional(OAttr('apiuser'))):
    opt2 = Optional.extract(opt2)
    opt3 = Optional.extract(opt3, evaluate_locals=locals())

    return u'hello apiuser:{} params:{}, opt:[{},{},{}]'.format(
        apiuser, params, opt1, opt2, opt3)
Пример #5
0
def update_repo_group(
        request, apiuser, repogroupid, group_name=Optional(''),
        description=Optional(''), owner=Optional(OAttr('apiuser')),
        parent=Optional(None), enable_locking=Optional(False)):
    """
    Updates repository group with the details given.

    This command can only be run using an |authtoken| with admin
    permissions.

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param repogroupid: Set the ID of repository group.
    :type repogroupid: str or int
    :param group_name: Set the name of the |repo| group.
    :type group_name: str
    :param description: Set a description for the group.
    :type description: str
    :param owner: Set the |repo| group owner.
    :type owner: str
    :param parent: Set the |repo| group parent.
    :type parent: str or int
    :param enable_locking: Enable |repo| locking. The default is false.
    :type enable_locking: bool
    """

    repo_group = get_repo_group_or_error(repogroupid)
    if not has_superadmin_permission(apiuser):
        # check if we have admin permission for this repo group !
        _perms = ('group.admin',)
        if not HasRepoGroupPermissionAnyApi(*_perms)(
                user=apiuser, group_name=repo_group.group_name):
            raise JSONRPCError(
                'repository group `%s` does not exist' % (repogroupid,))

    updates = {}
    try:
        store_update(updates, group_name, 'group_name')
        store_update(updates, description, 'group_description')
        store_update(updates, owner, 'user')
        store_update(updates, parent, 'group_parent_id')
        store_update(updates, enable_locking, 'enable_locking')
        repo_group = RepoGroupModel().update(repo_group, updates)
        Session().commit()
        return {
            'msg': 'updated repository group ID:%s %s' % (
                repo_group.group_id, repo_group.group_name),
            'repo_group': repo_group.get_api_data()
        }
    except Exception:
        log.exception("Exception occurred while trying update repo group")
        raise JSONRPCError('failed to update repository group `%s`'
                           % (repogroupid,))
Пример #6
0
def get_user_locks(request, apiuser, userid=Optional(OAttr('apiuser'))):
    """
    Displays all repositories locked by the specified user.

    * If this command is run by a non-admin user, it returns
      a list of |repos| locked by that user.

    This command takes the following options:

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param userid: Sets the userid whose list of locked |repos| will be
        displayed.
    :type userid: Optional(str or int)

    Example output:

    .. code-block:: bash

        id : <id_given_in_input>
        result : {
            [repo_object, repo_object,...]
        }
        error :  null
    """

    include_secrets = False
    if not has_superadmin_permission(apiuser):
        # make sure normal user does not pass someone else userid,
        # he is not allowed to do that
        if not isinstance(userid, Optional) and userid != apiuser.user_id:
            raise JSONRPCError('userid is not the same as your user')
    else:
        include_secrets = True

    userid = Optional.extract(userid, evaluate_locals=locals())
    userid = getattr(userid, 'user_id', userid)
    user = get_user_or_error(userid)

    ret = []

    # show all locks
    for r in Repository.getAll():
        _user_id, _time, _reason = r.locked
        if _user_id and _time:
            _api_data = r.get_api_data(include_secrets=include_secrets)
            # if we use user filter just show the locks for this user
            if safe_int(_user_id) == user.user_id:
                ret.append(_api_data)

    return ret
Пример #7
0
def get_ip(request, apiuser, userid=Optional(OAttr('apiuser'))):
    """
    Displays the IP Address as seen from the |RCE| server.

    * This command displays the IP Address, as well as all the defined IP
      addresses for the specified user. If the ``userid`` is not set, the
      data returned is for the user calling the method.

    This command can only be run using an |authtoken| with admin rights to
    the specified repository.

    This command takes the following options:

    :param apiuser: This is filled automatically from |authtoken|.
    :type apiuser: AuthUser
    :param userid: Sets the userid for which associated IP Address data
        is returned.
    :type userid: Optional(str or int)

    Example output:

    .. code-block:: bash

        id : <id_given_in_input>
        result : {
                     "server_ip_addr": "<ip_from_clien>",
                     "user_ips": [
                                    {
                                       "ip_addr": "<ip_with_mask>",
                                       "ip_range": ["<start_ip>", "<end_ip>"],
                                    },
                                    ...
                                 ]
        }

    """
    if not has_superadmin_permission(apiuser):
        raise JSONRPCForbidden()

    userid = Optional.extract(userid, evaluate_locals=locals())
    userid = getattr(userid, 'user_id', userid)

    user = get_user_or_error(userid)
    ips = UserIpMap.query().filter(UserIpMap.user == user).all()
    return {
        'server_ip_addr': request.rpc_ip_addr,
        'user_ips': ips
    }
Пример #8
0
def get_gists(request, apiuser, userid=Optional(OAttr('apiuser'))):
    """
    Get all gists for given user. If userid is empty returned gists
    are for user who called the api

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param userid: user to get gists for
    :type userid: Optional(str or int)
    """

    if not has_superadmin_permission(apiuser):
        # make sure normal user does not pass someone else userid,
        # he is not allowed to do that
        if not isinstance(userid, Optional) and userid != apiuser.user_id:
            raise JSONRPCError(
                'userid is not the same as your user'
            )

    if isinstance(userid, Optional):
        user_id = apiuser.user_id
    else:
        user_id = get_user_or_error(userid).user_id

    gists = []
    _gists = Gist().query() \
        .filter(or_(
        Gist.gist_expires == -1, Gist.gist_expires >= time.time())) \
        .filter(Gist.gist_owner == user_id) \
        .order_by(Gist.created_on.desc())
    for gist in _gists:
        gists.append(gist.get_api_data())
    return gists
def close_pull_request(request,
                       apiuser,
                       repoid,
                       pullrequestid,
                       userid=Optional(OAttr('apiuser'))):
    """
    Close the pull request specified by `pullrequestid`.

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param repoid: Repository name or repository ID to which the pull
        request belongs.
    :type repoid: str or int
    :param pullrequestid: ID of the pull request to be closed.
    :type pullrequestid: int
    :param userid: Close the pull request as this user.
    :type userid: Optional(str or int)

    Example output:

    .. code-block:: bash

      "id": <id_given_in_input>,
      "result":
        {
            "pull_request_id":  "<int>",
            "closed":           "<bool>"
        },
      "error": null

    """
    repo = get_repo_or_error(repoid)
    if not isinstance(userid, Optional):
        if (has_superadmin_permission(apiuser)
                or HasRepoPermissionAnyApi('repository.admin')(
                    user=apiuser, repo_name=repo.repo_name)):
            apiuser = get_user_or_error(userid)
        else:
            raise JSONRPCError('userid is not the same as your user')

    pull_request = get_pull_request_or_error(pullrequestid)
    if not PullRequestModel().check_user_update(
            pull_request, apiuser, api=True):
        raise JSONRPCError(
            'pull request `%s` close failed, no permission to close.' %
            (pullrequestid, ))
    if pull_request.is_closed():
        raise JSONRPCError('pull request `%s` is already closed' %
                           (pullrequestid, ))

    PullRequestModel().close_pull_request(pull_request.pull_request_id,
                                          apiuser)
    Session.commit()
    data = {
        'pull_request_id': pull_request.pull_request_id,
        'closed': True,
    }
    return data
Пример #10
0
def get_gist(request, apiuser, gistid, content=Optional(False)):
    """
    Get the specified gist, based on the gist ID.

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param gistid: Set the id of the private or public gist
    :type gistid: str
    :param content: Return the gist content. Default is false.
    :type content: Optional(bool)
    """

    gist = get_gist_or_error(gistid)
    content = Optional.extract(content)
    if not has_superadmin_permission(apiuser):
        if gist.gist_owner != apiuser.user_id:
            raise JSONRPCError('gist `%s` does not exist' % (gistid,))
    data = gist.get_api_data()
    if content:
        from rhodecode.model.gist import GistModel
        rev, gist_files = GistModel().get_gist_files(gistid)
        data['content'] = dict([(x.path, x.content) for x in gist_files])
    return data
Пример #11
0
def get_user(request, apiuser, userid=Optional(OAttr('apiuser'))):
    """
    Returns the information associated with a username or userid.

    * If the ``userid`` is not set, this command returns the information
      for the ``userid`` calling the method.

    .. note::

       Normal users may only run this command against their ``userid``. For
       full privileges you must run this command using an |authtoken| with
       admin rights.

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param userid: Sets the userid for which data will be returned.
    :type userid: Optional(str or int)

    Example output:

    .. code-block:: bash

        {
          "error": null,
          "id": <id>,
          "result": {
            "active": true,
            "admin": false,
            "api_key": "api-key",
            "api_keys": [ list of keys ],
            "email": "*****@*****.**",
            "emails": [
              "*****@*****.**"
            ],
            "extern_name": "rhodecode",
            "extern_type": "rhodecode",
            "firstname": "username",
            "ip_addresses": [],
            "language": null,
            "last_login": "******",
            "lastname": "surnae",
            "permissions": {
              "global": [
                "hg.inherit_default_perms.true",
                "usergroup.read",
                "hg.repogroup.create.false",
                "hg.create.none",
                "hg.extern_activate.manual",
                "hg.create.write_on_repogroup.false",
                "hg.usergroup.create.false",
                "group.none",
                "repository.none",
                "hg.register.none",
                "hg.fork.repository"
              ],
              "repositories": { "username/example": "repository.write"},
              "repositories_groups": { "user-group/repo": "group.none" },
              "user_groups": { "user_group_name": "usergroup.read" }
            },
            "user_id": 32,
            "username": "******"
          }
        }
    """

    if not has_superadmin_permission(apiuser):
        # make sure normal user does not pass someone else userid,
        # he is not allowed to do that
        if not isinstance(userid, Optional) and userid != apiuser.user_id:
            raise JSONRPCError('userid is not the same as your user')

    userid = Optional.extract(userid, evaluate_locals=locals())
    userid = getattr(userid, 'user_id', userid)

    user = get_user_or_error(userid)
    data = user.get_api_data(include_secrets=True)
    data['permissions'] = AuthUser(user_id=user.user_id).permissions
    return data
Пример #12
0
def update_user(
        request,
        apiuser,
        userid,
        username=Optional(None),
        email=Optional(None),
        password=Optional(None),
        firstname=Optional(None),
        lastname=Optional(None),
        active=Optional(None),
        admin=Optional(None),
        extern_type=Optional(None),
        extern_name=Optional(None),
):
    """
    Updates the details for the specified user, if that user exists.

    This command can only be run using an |authtoken| with admin rights to
    the specified repository.

    This command takes the following options:

    :param apiuser: This is filled automatically from |authtoken|.
    :type apiuser: AuthUser
    :param userid: Set the ``userid`` to update.
    :type userid: str or int
    :param username: Set the new username.
    :type username: str or int
    :param email: Set the new email.
    :type email: str
    :param password: Set the new password.
    :type password: Optional(str)
    :param firstname: Set the new first name.
    :type firstname: Optional(str)
    :param lastname: Set the new surname.
    :type lastname: Optional(str)
    :param active: Set the new user as active.
    :type active: Optional(``True`` | ``False``)
    :param admin: Give the user admin rights.
    :type admin: Optional(``True`` | ``False``)
    :param extern_name: Set the authentication plugin user name.
        Using LDAP this is filled with LDAP UID.
    :type extern_name: Optional(str)
    :param extern_type: Set the authentication plugin type.
    :type extern_type: Optional(str)


    Example output:

    .. code-block:: bash

        id : <id_given_in_input>
        result: {
                  "msg" : "updated user ID:<userid> <username>",
                  "user": <user_object>,
                }
        error:  null

    Example error output:

    .. code-block:: bash

      id : <id_given_in_input>
      result : null
      error :  {
        "failed to update user `<username>`"
      }

    """
    if not has_superadmin_permission(apiuser):
        raise JSONRPCForbidden()

    user = get_user_or_error(userid)

    # only non optional arguments will be stored in updates
    updates = {}

    try:

        store_update(updates, username, 'username')
        store_update(updates, password, 'password')
        store_update(updates, email, 'email')
        store_update(updates, firstname, 'name')
        store_update(updates, lastname, 'lastname')
        store_update(updates, active, 'active')
        store_update(updates, admin, 'admin')
        store_update(updates, extern_name, 'extern_name')
        store_update(updates, extern_type, 'extern_type')

        user = UserModel().update_user(user, **updates)
        Session().commit()
        return {
            'msg': 'updated user ID:%s %s' % (user.user_id, user.username),
            'user': user.get_api_data(include_secrets=True)
        }
    except DefaultUserException:
        log.exception("Default user edit exception")
        raise JSONRPCError('editing default user is forbidden')
    except Exception:
        log.exception("Error occurred during update of user")
        raise JSONRPCError('failed to update user `%s`' % (userid, ))
Пример #13
0
def create_user(request,
                apiuser,
                username,
                email,
                password=Optional(''),
                firstname=Optional(''),
                lastname=Optional(''),
                active=Optional(True),
                admin=Optional(False),
                extern_name=Optional('rhodecode'),
                extern_type=Optional('rhodecode'),
                force_password_change=Optional(False)):
    """
    Creates a new user and returns the new user object.

    This command can only be run using an |authtoken| with admin rights to
    the specified repository.

    This command takes the following options:

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param username: Set the new username.
    :type username: str or int
    :param email: Set the user email address.
    :type email: str
    :param password: Set the new user password.
    :type password: Optional(str)
    :param firstname: Set the new user firstname.
    :type firstname: Optional(str)
    :param lastname: Set the new user surname.
    :type lastname: Optional(str)
    :param active: Set the user as active.
    :type active: Optional(``True`` | ``False``)
    :param admin: Give the new user admin rights.
    :type admin: Optional(``True`` | ``False``)
    :param extern_name: Set the authentication plugin name.
        Using LDAP this is filled with LDAP UID.
    :type extern_name: Optional(str)
    :param extern_type: Set the new user authentication plugin.
    :type extern_type: Optional(str)
    :param force_password_change: Force the new user to change password
        on next login.
    :type force_password_change: Optional(``True`` | ``False``)

    Example output:

    .. code-block:: bash

        id : <id_given_in_input>
        result: {
                  "msg" : "created new user `<username>`",
                  "user": <user_obj>
                }
        error:  null

    Example error output:

    .. code-block:: bash

      id : <id_given_in_input>
      result : null
      error :  {
        "user `<username>` already exist"
        or
        "email `<email>` already exist"
        or
        "failed to create user `<username>`"
      }

    """
    if not has_superadmin_permission(apiuser):
        raise JSONRPCForbidden()

    if UserModel().get_by_username(username):
        raise JSONRPCError("user `%s` already exist" % (username, ))

    if UserModel().get_by_email(email, case_insensitive=True):
        raise JSONRPCError("email `%s` already exist" % (email, ))

    # generate random password if we actually given the
    # extern_name and it's not rhodecode
    if (not isinstance(extern_name, Optional)
            and Optional.extract(extern_name) != 'rhodecode'):
        # generate temporary password if user is external
        password = PasswordGenerator().gen_password(length=16)

    try:
        user = UserModel().create_or_update(
            username=Optional.extract(username),
            password=Optional.extract(password),
            email=Optional.extract(email),
            firstname=Optional.extract(firstname),
            lastname=Optional.extract(lastname),
            active=Optional.extract(active),
            admin=Optional.extract(admin),
            extern_type=Optional.extract(extern_type),
            extern_name=Optional.extract(extern_name),
            force_password_change=Optional.extract(force_password_change),
        )
        Session().commit()
        return {
            'msg': 'created new user `%s`' % username,
            'user': user.get_api_data(include_secrets=True)
        }
    except Exception:
        log.exception('Error occurred during creation of user')
        raise JSONRPCError('failed to create user `%s`' % (username, ))
Пример #14
0
def create_gist(
        request, apiuser, files, owner=Optional(OAttr('apiuser')),
        gist_type=Optional(Gist.GIST_PUBLIC), lifetime=Optional(-1),
        acl_level=Optional(Gist.ACL_LEVEL_PUBLIC),
        description=Optional('')):
    """
    Creates a new Gist.

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param files: files to be added to the gist. The data structure has
        to match the following example::

          {'filename': {'content':'...', 'lexer': null},
           'filename2': {'content':'...', 'lexer': null}}

    :type files: dict
    :param owner: Set the gist owner, defaults to api method caller
    :type owner: Optional(str or int)
    :param gist_type: type of gist ``public`` or ``private``
    :type gist_type: Optional(str)
    :param lifetime: time in minutes of gist lifetime
    :type lifetime: Optional(int)
    :param acl_level: acl level for this gist, can be
        ``acl_public`` or ``acl_private`` If the value is set to
        ``acl_private`` only logged in users are able to access this gist.
        If not set it defaults to ``acl_public``.
    :type acl_level: Optional(str)
    :param description: gist description
    :type description: Optional(str)

    Example  output:

    .. code-block:: bash

      id : <id_given_in_input>
      result : {
        "msg": "created new gist",
        "gist": {}
      }
      error :  null

    Example error output:

    .. code-block:: bash

      id : <id_given_in_input>
      result : null
      error :  {
        "failed to create gist"
      }

    """

    try:
        if isinstance(owner, Optional):
            owner = apiuser.user_id

        owner = get_user_or_error(owner)
        description = Optional.extract(description)
        gist_type = Optional.extract(gist_type)
        lifetime = Optional.extract(lifetime)
        acl_level = Optional.extract(acl_level)

        gist = GistModel().create(description=description,
                                  owner=owner,
                                  gist_mapping=files,
                                  gist_type=gist_type,
                                  lifetime=lifetime,
                                  gist_acl_level=acl_level)
        Session().commit()
        return {
            'msg': 'created new gist',
            'gist': gist.get_api_data()
        }
    except Exception:
        log.exception('Error occurred during creation of gist')
        raise JSONRPCError('failed to create gist')
Пример #15
0
def create_repo_group(request, apiuser, group_name, description=Optional(''),
                      owner=Optional(OAttr('apiuser')),
                      copy_permissions=Optional(False)):
    """
    Creates a repository group.

    * If the repository group name contains "/", all the required repository
      groups will be created.

      For example "foo/bar/baz" will create |repo| groups "foo" and "bar"
      (with "foo" as parent). It will also create the "baz" repository
      with "bar" as |repo| group.

    This command can only be run using an |authtoken| with admin
    permissions.

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param group_name: Set the repository group name.
    :type group_name: str
    :param description: Set the |repo| group description.
    :type description: str
    :param owner: Set the |repo| group owner.
    :type owner: str
    :param copy_permissions:
    :type copy_permissions:

    Example output:

    .. code-block:: bash

      id : <id_given_in_input>
      result : {
          "msg": "Created new repo group `<repo_group_name>`"
          "repo_group": <repogroup_object>
      }
      error :  null


    Example error output:

    .. code-block:: bash

      id : <id_given_in_input>
      result : null
      error :  {
        failed to create repo group `<repogroupid>`
      }

    """

    schema = RepoGroupSchema()
    try:
        data = schema.deserialize({
            'group_name': group_name
        })
    except colander.Invalid as e:
        raise JSONRPCError("Validation failed: %s" % (e.asdict(),))
    group_name = data['group_name']

    if isinstance(owner, Optional):
        owner = apiuser.user_id

    group_description = Optional.extract(description)
    copy_permissions = Optional.extract(copy_permissions)

    # get by full name with parents, check if it already exist
    if RepoGroup.get_by_group_name(group_name):
        raise JSONRPCError("repo group `%s` already exist" % (group_name,))

    (group_name_cleaned,
     parent_group_name) = RepoGroupModel()._get_group_name_and_parent(
        group_name)

    parent_group = None
    if parent_group_name:
        parent_group = get_repo_group_or_error(parent_group_name)

    if not HasPermissionAnyApi(
            'hg.admin', 'hg.repogroup.create.true')(user=apiuser):
        # check if we have admin permission for this parent repo group !
        # users without admin or hg.repogroup.create can only create other
        # groups in groups they own so this is a required, but can be empty
        parent_group = getattr(parent_group, 'group_name', '')
        _perms = ('group.admin',)
        if not HasRepoGroupPermissionAnyApi(*_perms)(
                user=apiuser, group_name=parent_group):
            raise JSONRPCForbidden()

    try:
        repo_group = RepoGroupModel().create(
            group_name=group_name,
            group_description=group_description,
            owner=owner,
            copy_permissions=copy_permissions)
        Session().commit()
        return {
            'msg': 'Created new repo group `%s`' % group_name,
            'repo_group': repo_group.get_api_data()
        }
    except Exception:
        log.exception("Exception occurred while trying create repo group")
        raise JSONRPCError(
            'failed to create repo group `%s`' % (group_name,))
def update_user_group(request, apiuser, usergroupid, group_name=Optional(''),
                      description=Optional(''), owner=Optional(None),
                      active=Optional(True)):
    """
    Updates the specified `user group` with the details provided.

    This command can only be run using an |authtoken| with admin rights to
    the specified repository.

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param usergroupid: Set the id of the `user group` to update.
    :type usergroupid: str or int
    :param group_name: Set the new name the `user group`
    :type group_name: str
    :param description: Give a description for the `user group`
    :type description: str
    :param owner: Set the owner of the `user group`.
    :type owner: Optional(str or int)
    :param active: Set the group as active.
    :type active: Optional(``True`` | ``False``)

    Example output:

    .. code-block:: bash

      id : <id_given_in_input>
      result : {
        "msg": 'updated user group ID:<user group id> <user group name>',
        "user_group": <user_group_object>
      }
      error :  null

    Example error output:

    .. code-block:: bash

      id : <id_given_in_input>
      result : null
      error :  {
        "failed to update user group `<user group name>`"
      }

    """

    user_group = get_user_group_or_error(usergroupid)
    include_secrets = False
    if not has_superadmin_permission(apiuser):
        # check if we have admin permission for this user group !
        _perms = ('usergroup.admin',)
        if not HasUserGroupPermissionAnyApi(*_perms)(
                user=apiuser, user_group_name=user_group.users_group_name):
            raise JSONRPCError(
                'user group `%s` does not exist' % (usergroupid,))
    else:
        include_secrets = True

    if not isinstance(owner, Optional):
        owner = get_user_or_error(owner)

    updates = {}
    store_update(updates, group_name, 'users_group_name')
    store_update(updates, description, 'user_group_description')
    store_update(updates, owner, 'user')
    store_update(updates, active, 'users_group_active')
    try:
        UserGroupModel().update(user_group, updates)
        Session().commit()
        return {
            'msg': 'updated user group ID:%s %s' % (
                user_group.users_group_id, user_group.users_group_name),
            'user_group': user_group.get_api_data(
                include_secrets=include_secrets)
        }
    except Exception:
        log.exception("Error occurred during update of user group")
        raise JSONRPCError(
            'failed to update user group `%s`' % (usergroupid,))
def comment_pull_request(request,
                         apiuser,
                         repoid,
                         pullrequestid,
                         message=Optional(None),
                         status=Optional(None),
                         userid=Optional(OAttr('apiuser'))):
    """
    Comment on the pull request specified with the `pullrequestid`,
    in the |repo| specified by the `repoid`, and optionally change the
    review status.

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param repoid: The repository name or repository ID.
    :type repoid: str or int
    :param pullrequestid: The pull request ID.
    :type pullrequestid: int
    :param message: The text content of the comment.
    :type message: str
    :param status: (**Optional**) Set the approval status of the pull
        request. Valid options are:
        * not_reviewed
        * approved
        * rejected
        * under_review
    :type status: str
    :param userid: Comment on the pull request as this user
    :type userid: Optional(str or int)

    Example output:

    .. code-block:: bash

      id : <id_given_in_input>
      result :
        {
            "pull_request_id":  "<Integer>",
            "comment_id":       "<Integer>"
        }
      error :  null
    """
    repo = get_repo_or_error(repoid)
    if not isinstance(userid, Optional):
        if (has_superadmin_permission(apiuser)
                or HasRepoPermissionAnyApi('repository.admin')(
                    user=apiuser, repo_name=repo.repo_name)):
            apiuser = get_user_or_error(userid)
        else:
            raise JSONRPCError('userid is not the same as your user')

    pull_request = get_pull_request_or_error(pullrequestid)
    if not PullRequestModel().check_user_read(pull_request, apiuser, api=True):
        raise JSONRPCError('repository `%s` does not exist' % (repoid, ))
    message = Optional.extract(message)
    status = Optional.extract(status)
    if not message and not status:
        raise JSONRPCError('message and status parameter missing')

    if (status not in (st[0] for st in ChangesetStatus.STATUSES)
            and status is not None):
        raise JSONRPCError('unknown comment status`%s`' % status)

    allowed_to_change_status = PullRequestModel().check_user_change_status(
        pull_request, apiuser)
    text = message
    if status and allowed_to_change_status:
        st_message = (('Status change %(transition_icon)s %(status)s') % {
            'transition_icon': '>',
            'status': ChangesetStatus.get_status_lbl(status)
        })
        text = message or st_message

    rc_config = SettingsModel().get_all_settings()
    renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
    comment = ChangesetCommentsModel().create(
        text=text,
        repo=pull_request.target_repo.repo_id,
        user=apiuser.user_id,
        pull_request=pull_request.pull_request_id,
        f_path=None,
        line_no=None,
        status_change=(ChangesetStatus.get_status_lbl(status)
                       if status and allowed_to_change_status else None),
        closing_pr=False,
        renderer=renderer)

    if allowed_to_change_status and status:
        ChangesetStatusModel().set_status(
            pull_request.target_repo.repo_id,
            status,
            apiuser.user_id,
            comment,
            pull_request=pull_request.pull_request_id)
        Session().flush()

    Session().commit()
    data = {
        'pull_request_id': pull_request.pull_request_id,
        'comment_id': comment.comment_id,
        'status': status
    }
    return data
Пример #18
0
def get_locks(request, apiuser, userid=Optional(OAttr('apiuser'))):
    from .user_api import get_user_locks
    return get_user_locks(request=request, apiuser=apiuser, userid=userid)
def merge_pull_request(request,
                       apiuser,
                       repoid,
                       pullrequestid,
                       userid=Optional(OAttr('apiuser'))):
    """
    Merge the pull request specified by `pullrequestid` into its target
    repository.

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param repoid: The Repository name or repository ID of the
        target repository to which the |pr| is to be merged.
    :type repoid: str or int
    :param pullrequestid: ID of the pull request which shall be merged.
    :type pullrequestid: int
    :param userid: Merge the pull request as this user.
    :type userid: Optional(str or int)

    Example output:

    .. code-block:: bash

      "id": <id_given_in_input>,
      "result":
        {
            "executed":         "<bool>",
            "failure_reason":   "<int>",
            "merge_commit_id":  "<merge_commit_id>",
            "possible":         "<bool>"
        },
      "error": null

    """
    repo = get_repo_or_error(repoid)
    if not isinstance(userid, Optional):
        if (has_superadmin_permission(apiuser)
                or HasRepoPermissionAnyApi('repository.admin')(
                    user=apiuser, repo_name=repo.repo_name)):
            apiuser = get_user_or_error(userid)
        else:
            raise JSONRPCError('userid is not the same as your user')

    pull_request = get_pull_request_or_error(pullrequestid)
    if not PullRequestModel().check_user_merge(pull_request, apiuser,
                                               api=True):
        raise JSONRPCError('repository `%s` does not exist' % (repoid, ))
    if pull_request.is_closed():
        raise JSONRPCError(
            'pull request `%s` merge failed, pull request is closed' %
            (pullrequestid, ))

    target_repo = pull_request.target_repo
    extras = vcs_operation_context(request.environ,
                                   repo_name=target_repo.repo_name,
                                   username=apiuser.username,
                                   action='push',
                                   scm=target_repo.repo_type)
    data = PullRequestModel().merge(pull_request, apiuser, extras=extras)
    if data.executed:
        PullRequestModel().close_pull_request(pull_request.pull_request_id,
                                              apiuser)

        Session.commit()
    return data
def create_pull_request(request,
                        apiuser,
                        source_repo,
                        target_repo,
                        source_ref,
                        target_ref,
                        title,
                        description=Optional(''),
                        reviewers=Optional(None)):
    """
    Creates a new pull request.

    Accepts refs in the following formats:

        * branch:<branch_name>:<sha>
        * branch:<branch_name>
        * bookmark:<bookmark_name>:<sha> (Mercurial only)
        * bookmark:<bookmark_name> (Mercurial only)

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param source_repo: Set the source repository name.
    :type source_repo: str
    :param target_repo: Set the target repository name.
    :type target_repo: str
    :param source_ref: Set the source ref name.
    :type source_ref: str
    :param target_ref: Set the target ref name.
    :type target_ref: str
    :param title: Set the pull request title.
    :type title: str
    :param description: Set the pull request description.
    :type description: Optional(str)
    :param reviewers: Set the new pull request reviewers list.
    :type reviewers: Optional(list)
    """
    source = get_repo_or_error(source_repo)
    target = get_repo_or_error(target_repo)
    if not has_superadmin_permission(apiuser):
        _perms = (
            'repository.admin',
            'repository.write',
            'repository.read',
        )
        has_repo_permissions(apiuser, source_repo, source, _perms)

    full_source_ref = resolve_ref_or_error(source_ref, source)
    full_target_ref = resolve_ref_or_error(target_ref, target)
    source_commit = get_commit_or_error(full_source_ref, source)
    target_commit = get_commit_or_error(full_target_ref, target)
    source_scm = source.scm_instance()
    target_scm = target.scm_instance()

    commit_ranges = target_scm.compare(target_commit.raw_id,
                                       source_commit.raw_id,
                                       source_scm,
                                       merge=True,
                                       pre_load=[])

    ancestor = target_scm.get_common_ancestor(target_commit.raw_id,
                                              source_commit.raw_id, source_scm)

    if not commit_ranges:
        raise JSONRPCError('no commits found')

    if not ancestor:
        raise JSONRPCError('no common ancestor found')

    reviewer_names = Optional.extract(reviewers) or []
    if not isinstance(reviewer_names, list):
        raise JSONRPCError('reviewers should be specified as a list')

    reviewer_users = [get_user_or_error(n) for n in reviewer_names]
    reviewer_ids = [u.user_id for u in reviewer_users]

    pull_request_model = PullRequestModel()
    pull_request = pull_request_model.create(
        created_by=apiuser.user_id,
        source_repo=source_repo,
        source_ref=full_source_ref,
        target_repo=target_repo,
        target_ref=full_target_ref,
        revisions=reversed(
            [commit.raw_id for commit in reversed(commit_ranges)]),
        reviewers=reviewer_ids,
        title=title,
        description=Optional.extract(description))

    Session().commit()
    data = {
        'msg': 'Created new pull request `{}`'.format(title),
        'pull_request_id': pull_request.pull_request_id,
    }
    return data
Пример #21
0
def revoke_user_group_permission_from_repo_group(
        request, apiuser, repogroupid, usergroupid,
        apply_to_children=Optional('none')):
    """
    Revoke permission for user group on given repository.

    This command can only be run using an |authtoken| with admin
    permissions on the |repo| group.

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param repogroupid: name or id of repository group
    :type repogroupid: str or int
    :param usergroupid:
    :param apply_to_children: 'none', 'repos', 'groups', 'all'
    :type apply_to_children: str

    Example output:

    .. code-block:: bash

        id : <id_given_in_input>
        result: {
                  "msg" : "Revoked perm (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
                  "success": true
                }
        error:  null

    Example error output:

    .. code-block:: bash

      id : <id_given_in_input>
      result : null
      error :  {
        "failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`"
      }


    """

    repo_group = get_repo_group_or_error(repogroupid)
    user_group = get_user_group_or_error(usergroupid)
    if not has_superadmin_permission(apiuser):
        # check if we have admin permission for this repo group !
        _perms = ('group.admin',)
        if not HasRepoGroupPermissionAnyApi(*_perms)(
                user=apiuser, group_name=repo_group.group_name):
            raise JSONRPCError(
                'repository group `%s` does not exist' % (repogroupid,))

        # check if we have at least read permission for this user group !
        _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
        if not HasUserGroupPermissionAnyApi(*_perms)(
                user=apiuser, user_group_name=user_group.users_group_name):
            raise JSONRPCError(
                'user group `%s` does not exist' % (usergroupid,))

    apply_to_children = Optional.extract(apply_to_children)

    perm_deletions = [[user_group.users_group_id, None, "user_group"]]
    try:
        RepoGroupModel().update_permissions(repo_group=repo_group,
                                            perm_deletions=perm_deletions,
                                            recursive=apply_to_children,
                                            cur_user=apiuser)
        Session().commit()
        return {
            'msg': 'Revoked perm (recursive:%s) for user group: '
                   '`%s` in repo group: `%s`' % (
                       apply_to_children, user_group.users_group_name,
                       repo_group.name
                   ),
            'success': True
        }
    except Exception:
        log.exception("Exception occurred while trying revoke user group "
                      "permissions from repo group")
        raise JSONRPCError(
            'failed to edit permission for user group: '
            '`%s` in repo group: `%s`' % (
                user_group.users_group_name, repo_group.name
            )
        )
Пример #22
0
def grant_user_group_permission_to_repo_group(
        request, apiuser, repogroupid, usergroupid, perm,
        apply_to_children=Optional('none'), ):
    """
    Grant permission for a user group on given repository group, or update
    existing permissions if found.

    This command can only be run using an |authtoken| with admin
    permissions on the |repo| group.

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param repogroupid: Set the name or id of repository group
    :type repogroupid: str or int
    :param usergroupid: id of usergroup
    :type usergroupid: str or int
    :param perm: (group.(none|read|write|admin))
    :type perm: str
    :param apply_to_children: 'none', 'repos', 'groups', 'all'
    :type apply_to_children: str

    Example output:

    .. code-block:: bash

      id : <id_given_in_input>
      result : {
        "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
        "success": true

      }
      error :  null

    Example error output:

    .. code-block:: bash

      id : <id_given_in_input>
      result : null
      error :  {
        "failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`"
      }

    """

    repo_group = get_repo_group_or_error(repogroupid)
    perm = get_perm_or_error(perm, prefix='group.')
    user_group = get_user_group_or_error(usergroupid)
    if not has_superadmin_permission(apiuser):
        # check if we have admin permission for this repo group !
        _perms = ('group.admin',)
        if not HasRepoGroupPermissionAnyApi(*_perms)(
                user=apiuser, group_name=repo_group.group_name):
            raise JSONRPCError(
                'repository group `%s` does not exist' % (repogroupid,))

        # check if we have at least read permission for this user group !
        _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
        if not HasUserGroupPermissionAnyApi(*_perms)(
                user=apiuser, user_group_name=user_group.users_group_name):
            raise JSONRPCError(
                'user group `%s` does not exist' % (usergroupid,))

    apply_to_children = Optional.extract(apply_to_children)

    perm_additions = [[user_group.users_group_id, perm, "user_group"]]
    try:
        RepoGroupModel().update_permissions(repo_group=repo_group,
                                            perm_additions=perm_additions,
                                            recursive=apply_to_children,
                                            cur_user=apiuser)
        Session().commit()
        return {
            'msg': 'Granted perm: `%s` (recursive:%s) '
                   'for user group: `%s` in repo group: `%s`' % (
                       perm.permission_name, apply_to_children,
                       user_group.users_group_name, repo_group.name
                   ),
            'success': True
        }
    except Exception:
        log.exception("Exception occurred while trying to grant user "
                      "group permissions to repo group")
        raise JSONRPCError(
            'failed to edit permission for user group: `%s` in '
            'repo group: `%s`' % (
                usergroupid, repo_group.name
            )
        )
def update_pull_request(request,
                        apiuser,
                        repoid,
                        pullrequestid,
                        title=Optional(''),
                        description=Optional(''),
                        reviewers=Optional(None),
                        update_commits=Optional(None),
                        close_pull_request=Optional(None)):
    """
    Updates a pull request.

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param repoid: The repository name or repository ID.
    :type repoid: str or int
    :param pullrequestid: The pull request ID.
    :type pullrequestid: int
    :param title: Set the pull request title.
    :type title: str
    :param description: Update pull request description.
    :type description: Optional(str)
    :param reviewers: Update pull request reviewers list with new value.
    :type reviewers: Optional(list)
    :param update_commits: Trigger update of commits for this pull request
    :type: update_commits: Optional(bool)
    :param close_pull_request: Close this pull request with rejected state
    :type: close_pull_request: Optional(bool)

    Example output:

    .. code-block:: bash

      id : <id_given_in_input>
      result :
        {
            "msg": "Updated pull request `63`",
            "pull_request": <pull_request_object>,
            "updated_reviewers": {
              "added": [
                "username"
              ],
              "removed": []
            },
            "updated_commits": {
              "added": [
                "<sha1_hash>"
              ],
              "common": [
                "<sha1_hash>",
                "<sha1_hash>",
              ],
              "removed": []
            }
        }
      error :  null
    """

    repo = get_repo_or_error(repoid)
    pull_request = get_pull_request_or_error(pullrequestid)
    if not PullRequestModel().check_user_update(
            pull_request, apiuser, api=True):
        raise JSONRPCError(
            'pull request `%s` update failed, no permission to update.' %
            (pullrequestid, ))
    if pull_request.is_closed():
        raise JSONRPCError(
            'pull request `%s` update failed, pull request is closed' %
            (pullrequestid, ))

    reviewer_names = Optional.extract(reviewers) or []
    if not isinstance(reviewer_names, list):
        raise JSONRPCError('reviewers should be specified as a list')

    reviewer_users = [get_user_or_error(n) for n in reviewer_names]
    reviewer_ids = [u.user_id for u in reviewer_users]

    title = Optional.extract(title)
    description = Optional.extract(description)
    if title or description:
        PullRequestModel().edit(pull_request, title or pull_request.title,
                                description or pull_request.description)
        Session().commit()

    commit_changes = {"added": [], "common": [], "removed": []}
    if str2bool(Optional.extract(update_commits)):
        if PullRequestModel().has_valid_update_type(pull_request):
            _version, _commit_changes = PullRequestModel().update_commits(
                pull_request)
            commit_changes = _commit_changes or commit_changes
        Session().commit()

    reviewers_changes = {"added": [], "removed": []}
    if reviewer_ids:
        added_reviewers, removed_reviewers = \
            PullRequestModel().update_reviewers(pull_request, reviewer_ids)

        reviewers_changes['added'] = sorted(
            [get_user_or_error(n).username for n in added_reviewers])
        reviewers_changes['removed'] = sorted(
            [get_user_or_error(n).username for n in removed_reviewers])
        Session().commit()

    if str2bool(Optional.extract(close_pull_request)):
        PullRequestModel().close_pull_request_with_comment(
            pull_request, apiuser, repo)
        Session().commit()

    data = {
        'msg':
        'Updated pull request `{}`'.format(pull_request.pull_request_id),
        'pull_request': pull_request.get_api_data(),
        'updated_commits': commit_changes,
        'updated_reviewers': reviewers_changes
    }
    return data
def create_user_group(
        request, apiuser, group_name, description=Optional(''),
        owner=Optional(OAttr('apiuser')), active=Optional(True)):
    """
    Creates a new user group.

    This command can only be run using an |authtoken| with admin rights to
    the specified repository.

    This command takes the following options:

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param group_name: Set the name of the new user group.
    :type group_name: str
    :param description: Give a description of the new user group.
    :type description: str
    :param owner: Set the owner of the new user group.
        If not set, the owner is the |authtoken| user.
    :type owner: Optional(str or int)
    :param active: Set this group as active.
    :type active: Optional(``True`` | ``False``)

    Example output:

    .. code-block:: bash

        id : <id_given_in_input>
        result: {
                  "msg": "created new user group `<groupname>`",
                  "user_group": <user_group_object>
                }
        error:  null

    Example error output:

    .. code-block:: bash

      id : <id_given_in_input>
      result : null
      error :  {
        "user group `<group name>` already exist"
        or
        "failed to create group `<group name>`"
      }

    """

    if not has_superadmin_permission(apiuser):
        if not HasPermissionAnyApi('hg.usergroup.create.true')(user=apiuser):
            raise JSONRPCForbidden()

    if UserGroupModel().get_by_name(group_name):
        raise JSONRPCError("user group `%s` already exist" % (group_name,))

    try:
        if isinstance(owner, Optional):
            owner = apiuser.user_id

        owner = get_user_or_error(owner)
        active = Optional.extract(active)
        description = Optional.extract(description)
        ug = UserGroupModel().create(
            name=group_name, description=description, owner=owner,
            active=active)
        Session().commit()
        return {
            'msg': 'created new user group `%s`' % group_name,
            'user_group': ug.get_api_data()
        }
    except Exception:
        log.exception("Error occurred during creation of user group")
        raise JSONRPCError('failed to create group `%s`' % (group_name,))
Пример #25
0
def show_ip(request, apiuser, userid=Optional(OAttr('apiuser'))):
    from .server_api import get_ip
    return get_ip(request=request, apiuser=apiuser, userid=userid)
def get_pull_requests(request, apiuser, repoid, status=Optional('new')):
    """
    Get all pull requests from the repository specified in `repoid`.

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param repoid: Repository name or repository ID.
    :type repoid: str or int
    :param status: Only return pull requests with the specified status.
        Valid options are.
        * ``new`` (default)
        * ``open``
        * ``closed``
    :type status: str

    Example output:

    .. code-block:: bash

      "id": <id_given_in_input>,
      "result":
        [
            ...
            {
                "pull_request_id":   "<pull_request_id>",
                "url":               "<url>",
                "title" :            "<title>",
                "description":       "<description>",
                "status":            "<status>",
                "created_on":        "<date_time_created>",
                "updated_on":        "<date_time_updated>",
                "commit_ids":        [
                                         ...
                                         "<commit_id>",
                                         "<commit_id>",
                                         ...
                                     ],
                "review_status":    "<review_status>",
                "mergeable":         {
                                        "status":      "<bool>",
                                        "message:      "<message>",
                                     },
                "source":            {
                                         "clone_url":     "<clone_url>",
                                         "reference":
                                         {
                                             "name":      "<name>",
                                             "type":      "<type>",
                                             "commit_id": "<commit_id>",
                                         }
                                     },
                "target":            {
                                         "clone_url":   "<clone_url>",
                                         "reference":
                                         {
                                             "name":      "<name>",
                                             "type":      "<type>",
                                             "commit_id": "<commit_id>",
                                         }
                                     },
               "author":             <user_obj>,
               "reviewers":          [
                                         ...
                                         {
                                            "user":          "******",
                                            "review_status": "<review_status>",
                                         }
                                         ...
                                     ]
            }
            ...
        ],
      "error": null

    """
    repo = get_repo_or_error(repoid)
    if not has_superadmin_permission(apiuser):
        _perms = (
            'repository.admin',
            'repository.write',
            'repository.read',
        )
        has_repo_permissions(apiuser, repoid, repo, _perms)

    status = Optional.extract(status)
    pull_requests = PullRequestModel().get_all(repo, statuses=[status])
    data = [pr.get_api_data() for pr in pull_requests]
    return data
Пример #27
0
 def test_Optional_OAttr(self):
     option1 = Optional(OAttr('apiuser'))
     assert 'apiuser' == Optional.extract(option1)