summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGauvain Pocentek <gauvain@pocentek.net>2017-05-28 10:53:54 +0200
committerGauvain Pocentek <gauvain@pocentek.net>2017-06-02 15:41:37 +0200
commita50690288f9c03ec37ff374839d1f465c74ecf0a (patch)
tree35f9e07f1c36cd50bcc4bcf791a1294bb50c2028
parent9fbdb9461a660181a3a268cd398865cafd0b4a89 (diff)
downloadgitlab-a50690288f9c03ec37ff374839d1f465c74ecf0a.tar.gz
Add support for managers in objects for new API
Convert User* to the new REST* API.
-rw-r--r--gitlab/base.py33
-rw-r--r--gitlab/mixins.py14
-rw-r--r--gitlab/v4/objects.py160
3 files changed, 119 insertions, 88 deletions
diff --git a/gitlab/base.py b/gitlab/base.py
index 2ecf1d2..afbcd38 100644
--- a/gitlab/base.py
+++ b/gitlab/base.py
@@ -575,8 +575,14 @@ class RESTObject(object):
'manager': manager,
'_attrs': attrs,
'_updated_attrs': {},
+ '_module': importlib.import_module(self.__module__)
})
+ # TODO(gpocentek): manage the creation of new objects from the received
+ # data (_constructor_types)
+
+ self._create_managers()
+
def __getattr__(self, name):
try:
return self.__dict__['_updated_attrs'][name]
@@ -602,6 +608,16 @@ class RESTObject(object):
else:
return '<%s>' % self.__class__.__name__
+ def _create_managers(self):
+ managers = getattr(self, '_managers', None)
+ if managers is None:
+ return
+
+ for attr, cls_name in self._managers:
+ cls = getattr(self._module, cls_name)
+ manager = cls(self.manager.gitlab, parent=self)
+ self.__dict__[attr] = manager
+
def get_id(self):
if self._id_attr is None:
return None
@@ -653,6 +669,19 @@ class RESTManager(object):
_path = None
_obj_cls = None
- def __init__(self, gl, parent_attrs={}):
+ def __init__(self, gl, parent=None):
self.gitlab = gl
- self._parent_attrs = {} # for nested managers
+ self._parent = parent # for nested managers
+ self._computed_path = self._compute_path()
+
+ def _compute_path(self):
+ if self._parent is None or not hasattr(self, '_from_parent_attrs'):
+ return self._path
+
+ data = {self_attr: getattr(self._parent, parent_attr)
+ for self_attr, parent_attr in self._from_parent_attrs.items()}
+ return self._path % data
+
+ @property
+ def path(self):
+ return self._computed_path
diff --git a/gitlab/mixins.py b/gitlab/mixins.py
index a81b2ae..80ce6c9 100644
--- a/gitlab/mixins.py
+++ b/gitlab/mixins.py
@@ -32,7 +32,7 @@ class GetMixin(object):
Raises:
GitlabGetError: If the server cannot perform the request.
"""
- path = '%s/%s' % (self._path, id)
+ path = '%s/%s' % (self.path, id)
server_data = self.gitlab.http_get(path, **kwargs)
return self._obj_cls(self, server_data)
@@ -50,7 +50,7 @@ class GetWithoutIdMixin(object):
Raises:
GitlabGetError: If the server cannot perform the request.
"""
- server_data = self.gitlab.http_get(self._path, **kwargs)
+ server_data = self.gitlab.http_get(self.path, **kwargs)
return self._obj_cls(self, server_data)
@@ -70,7 +70,7 @@ class ListMixin(object):
list(RESTObjectList).
"""
- obj = self.gitlab.http_list(self._path, **kwargs)
+ obj = self.gitlab.http_list(self.path, **kwargs)
if isinstance(obj, list):
return [self._obj_cls(self, item) for item in obj]
else:
@@ -139,7 +139,7 @@ class CreateMixin(object):
self._check_missing_attrs(data)
if hasattr(self, '_sanitize_data'):
data = self._sanitize_data(data, 'create')
- server_data = self.gitlab.http_post(self._path, post_data=data,
+ server_data = self.gitlab.http_post(self.path, post_data=data,
**kwargs)
return self._obj_cls(self, server_data)
@@ -180,9 +180,9 @@ class UpdateMixin(object):
"""
if id is None:
- path = self._path
+ path = self.path
else:
- path = '%s/%s' % (self._path, id)
+ path = '%s/%s' % (self.path, id)
self._check_missing_attrs(new_data)
if hasattr(self, '_sanitize_data'):
@@ -199,7 +199,7 @@ class DeleteMixin(object):
id: ID of the object to delete
**kwargs: Extra data to send to the Gitlab server (e.g. sudo)
"""
- path = '%s/%s' % (self._path, id)
+ path = '%s/%s' % (self.path, id)
self.gitlab.http_delete(path, **kwargs)
diff --git a/gitlab/v4/objects.py b/gitlab/v4/objects.py
index 9f16a50..34100d8 100644
--- a/gitlab/v4/objects.py
+++ b/gitlab/v4/objects.py
@@ -77,105 +77,107 @@ class SidekiqManager(RESTManager):
return self._simple_get('/sidekiq/compound_metrics', **kwargs)
-class UserEmail(GitlabObject):
- _url = '/users/%(user_id)s/emails'
- canUpdate = False
- shortPrintAttr = 'email'
- requiredUrlAttrs = ['user_id']
- requiredCreateAttrs = ['email']
+class UserEmail(RESTObject):
+ _short_print_attr = 'email'
-class UserEmailManager(BaseManager):
- obj_cls = UserEmail
+class UserEmailManager(RetrieveMixin, CreateMixin, DeleteMixin, RESTManager):
+ _path = '/users/%(user_id)s/emails'
+ _obj_cls = UserEmail
+ _from_parent_attrs = {'user_id': 'id'}
+ _create_attrs = {'required': ('email', ), 'optional': tuple()}
-class UserKey(GitlabObject):
- _url = '/users/%(user_id)s/keys'
- canGet = 'from_list'
- canUpdate = False
- requiredUrlAttrs = ['user_id']
- requiredCreateAttrs = ['title', 'key']
+class UserKey(RESTObject):
+ pass
-class UserKeyManager(BaseManager):
- obj_cls = UserKey
+class UserKeyManager(GetFromListMixin, CreateMixin, DeleteMixin, RESTManager):
+ _path = '/users/%(user_id)s/emails'
+ _obj_cls = UserKey
+ _from_parent_attrs = {'user_id': 'id'}
+ _create_attrs = {'required': ('title', 'key'), 'optional': tuple()}
-class UserProject(GitlabObject):
- _url = '/projects/user/%(user_id)s'
- _constructorTypes = {'owner': 'User', 'namespace': 'Group'}
- canUpdate = False
- canDelete = False
- canList = False
- canGet = False
- requiredUrlAttrs = ['user_id']
- requiredCreateAttrs = ['name']
- optionalCreateAttrs = ['default_branch', 'issues_enabled', 'wall_enabled',
- 'merge_requests_enabled', 'wiki_enabled',
- 'snippets_enabled', 'public', 'visibility',
- 'description', 'builds_enabled', 'public_builds',
- 'import_url', 'only_allow_merge_if_build_succeeds']
+class UserProject(RESTObject):
+ _constructor_types = {'owner': 'User', 'namespace': 'Group'}
-class UserProjectManager(BaseManager):
- obj_cls = UserProject
+class UserProjectManager(CreateMixin, RESTManager):
+ _path = '/projects/user/%(user_id)s'
+ _obj_cls = UserProject
+ _from_parent_attrs = {'user_id': 'id'}
+ _create_attrs = {
+ 'required': ('name', ),
+ 'optional': ('default_branch', 'issues_enabled', 'wall_enabled',
+ 'merge_requests_enabled', 'wiki_enabled',
+ 'snippets_enabled', 'public', 'visibility', 'description',
+ 'builds_enabled', 'public_builds', 'import_url',
+ 'only_allow_merge_if_build_succeeds')
+ }
-class User(GitlabObject):
- _url = '/users'
- shortPrintAttr = 'username'
- optionalListAttrs = ['active', 'blocked', 'username', 'extern_uid',
- 'provider', 'external']
- requiredCreateAttrs = ['email', 'username', 'name']
- optionalCreateAttrs = ['password', 'reset_password', 'skype', 'linkedin',
- 'twitter', 'projects_limit', 'extern_uid',
- 'provider', 'bio', 'admin', 'can_create_group',
- 'website_url', 'skip_confirmation', 'external',
- 'organization', 'location']
- requiredUpdateAttrs = ['email', 'username', 'name']
- optionalUpdateAttrs = ['password', 'skype', 'linkedin', 'twitter',
- 'projects_limit', 'extern_uid', 'provider', 'bio',
- 'admin', 'can_create_group', 'website_url',
- 'skip_confirmation', 'external', 'organization',
- 'location']
- managers = (
- ('emails', 'UserEmailManager', [('user_id', 'id')]),
- ('keys', 'UserKeyManager', [('user_id', 'id')]),
- ('projects', 'UserProjectManager', [('user_id', 'id')]),
+class User(SaveMixin, RESTObject):
+ _short_print_attr = 'username'
+ _managers = (
+ ('emails', 'UserEmailManager'),
+ ('keys', 'UserKeyManager'),
+ ('projects', 'UserProjectManager'),
)
- def _data_for_gitlab(self, extra_parameters={}, update=False,
- as_json=True):
- if hasattr(self, 'confirm'):
- self.confirm = str(self.confirm).lower()
- return super(User, self)._data_for_gitlab(extra_parameters)
-
def block(self, **kwargs):
- """Blocks the user."""
- url = '/users/%s/block' % self.id
- r = self.gitlab._raw_post(url, **kwargs)
- raise_error_from_response(r, GitlabBlockError, 201)
- self.state = 'blocked'
+ """Blocks the user.
+
+ Returns:
+ bool: whether the user status has been changed.
+ """
+ path = '/users/%s/block' % self.id
+ server_data = self.manager.gitlab.http_post(path, **kwargs)
+ if server_data is True:
+ self._attrs['state'] = 'blocked'
+ return server_data
def unblock(self, **kwargs):
- """Unblocks the user."""
- url = '/users/%s/unblock' % self.id
- r = self.gitlab._raw_post(url, **kwargs)
- raise_error_from_response(r, GitlabUnblockError, 201)
- self.state = 'active'
+ """Unblocks the user.
+
+ Returns:
+ bool: whether the user status has been changed.
+ """
+ path = '/users/%s/unblock' % self.id
+ server_data = self.manager.gitlab.http_post(path, **kwargs)
+ if server_data is True:
+ self._attrs['state'] = 'active'
+ return server_data
- def __eq__(self, other):
- if type(other) is type(self):
- selfdict = self.as_dict()
- otherdict = other.as_dict()
- selfdict.pop('password', None)
- otherdict.pop('password', None)
- return selfdict == otherdict
- return False
+class UserManager(CRUDMixin, RESTManager):
+ _path = '/users'
+ _obj_cls = User
-class UserManager(BaseManager):
- obj_cls = User
+ _list_filters = ('active', 'blocked', 'username', 'extern_uid', 'provider',
+ 'external')
+ _create_attrs = {
+ 'required': ('email', 'username', 'name'),
+ 'optional': ('password', 'reset_password', 'skype', 'linkedin',
+ 'twitter', 'projects_limit', 'extern_uid', 'provider',
+ 'bio', 'admin', 'can_create_group', 'website_url',
+ 'skip_confirmation', 'external', 'organization',
+ 'location')
+ }
+ _update_attrs = {
+ 'required': ('email', 'username', 'name'),
+ 'optional': ('password', 'skype', 'linkedin', 'twitter',
+ 'projects_limit', 'extern_uid', 'provider', 'bio',
+ 'admin', 'can_create_group', 'website_url',
+ 'skip_confirmation', 'external', 'organization',
+ 'location')
+ }
+
+ def _sanitize_data(self, data, action):
+ new_data = data.copy()
+ if 'confirm' in data:
+ new_data['confirm'] = str(new_data['confirm']).lower()
+ return new_data
class CurrentUserEmail(GitlabObject):