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
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)
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)
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,))
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
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 }
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
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')
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 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 test_OAttr_object(self): oattr1 = OAttr('apiuser') assert '<OptionalAttr:apiuser>' == repr(oattr1) assert oattr1() == oattr1
def test_Optional_OAttr(self): option1 = Optional(OAttr('apiuser')) assert 'apiuser' == Optional.extract(option1)
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
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,))
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