summaryrefslogtreecommitdiff
path: root/gitlab
diff options
context:
space:
mode:
authorGauvain Pocentek <gauvain@pocentek.net>2018-05-21 10:30:46 +0200
committerGauvain Pocentek <gauvain@pocentek.net>2018-05-21 10:30:46 +0200
commit174185bd45abb7c99cf28432a227660023d53632 (patch)
tree6aca21979a07d1c0a5e50a767c760240049d43d7 /gitlab
parent175abe950c9f08dc9f66de21b20e7f4df5454517 (diff)
downloadgitlab-174185bd45abb7c99cf28432a227660023d53632.tar.gz
Add support for user avatar upload
Fixes #308
Diffstat (limited to 'gitlab')
-rw-r--r--gitlab/__init__.py21
-rw-r--r--gitlab/mixins.py39
-rw-r--r--gitlab/types.py10
-rw-r--r--gitlab/v4/objects.py9
4 files changed, 60 insertions, 19 deletions
diff --git a/gitlab/__init__.py b/gitlab/__init__.py
index af38680..3a36bf2 100644
--- a/gitlab/__init__.py
+++ b/gitlab/__init__.py
@@ -356,20 +356,25 @@ class Gitlab(object):
opts = self._get_session_opts(content_type='application/json')
- # don't set the content-type header when uploading files
- if files is not None:
- del opts["headers"]["Content-type"]
-
verify = opts.pop('verify')
timeout = opts.pop('timeout')
+ # We need to deal with json vs. data when uploading files
+ if files:
+ data = post_data
+ json = None
+ del opts["headers"]["Content-type"]
+ else:
+ json = post_data
+ data = None
+
# Requests assumes that `.` should not be encoded as %2E and will make
# changes to urls using this encoding. Using a prepped request we can
# get the desired behavior.
# The Requests behavior is right but it seems that web servers don't
# always agree with this decision (this is the case with a default
# gitlab installation)
- req = requests.Request(verb, url, json=post_data, params=params,
+ req = requests.Request(verb, url, json=json, data=data, params=params,
files=files, **opts)
prepped = self.session.prepare_request(req)
prepped.url = sanitized_url(prepped.url)
@@ -506,7 +511,8 @@ class Gitlab(object):
error_message="Failed to parse the server message")
return result
- def http_put(self, path, query_data={}, post_data={}, **kwargs):
+ def http_put(self, path, query_data={}, post_data={}, files=None,
+ **kwargs):
"""Make a PUT request to the Gitlab server.
Args:
@@ -515,6 +521,7 @@ class Gitlab(object):
query_data (dict): Data to send as query parameters
post_data (dict): Data to send in the body (will be converted to
json)
+ files (dict): The files to send to the server
**kwargs: Extra data to make the query (e.g. sudo, per_page, page)
Returns:
@@ -525,7 +532,7 @@ class Gitlab(object):
GitlabParsingError: If the json data could not be parsed
"""
result = self.http_request('put', path, query_data=query_data,
- post_data=post_data, **kwargs)
+ post_data=post_data, files=files, **kwargs)
try:
return result.json()
except Exception:
diff --git a/gitlab/mixins.py b/gitlab/mixins.py
index f940d60..17f1196 100644
--- a/gitlab/mixins.py
+++ b/gitlab/mixins.py
@@ -18,6 +18,7 @@
import gitlab
from gitlab import base
from gitlab import cli
+from gitlab import types as g_types
from gitlab import exceptions as exc
@@ -171,21 +172,29 @@ class CreateMixin(object):
GitlabCreateError: If the server cannot perform the request
"""
self._check_missing_create_attrs(data)
+ files = {}
# We get the attributes that need some special transformation
types = getattr(self, '_types', {})
-
if types:
# Duplicate data to avoid messing with what the user sent us
data = data.copy()
for attr_name, type_cls in types.items():
if attr_name in data.keys():
type_obj = type_cls(data[attr_name])
- data[attr_name] = type_obj.get_for_api()
+
+ # if the type if FileAttribute we need to pass the data as
+ # file
+ if issubclass(type_cls, g_types.FileAttribute):
+ k = type_obj.get_file_name(attr_name)
+ files[attr_name] = (k, data.pop(attr_name))
+ else:
+ data[attr_name] = type_obj.get_for_api()
# Handle specific URL for creation
path = kwargs.pop('path', self.path)
- server_data = self.gitlab.http_post(path, post_data=data, **kwargs)
+ server_data = self.gitlab.http_post(path, post_data=data, files=files,
+ **kwargs)
return self._obj_cls(self, server_data)
@@ -232,15 +241,27 @@ class UpdateMixin(object):
path = '%s/%s' % (self.path, id)
self._check_missing_update_attrs(new_data)
+ files = {}
# We get the attributes that need some special transformation
types = getattr(self, '_types', {})
- for attr_name, type_cls in types.items():
- if attr_name in new_data.keys():
- type_obj = type_cls(new_data[attr_name])
- new_data[attr_name] = type_obj.get_for_api()
-
- return self.gitlab.http_put(path, post_data=new_data, **kwargs)
+ if types:
+ # Duplicate data to avoid messing with what the user sent us
+ new_data = new_data.copy()
+ for attr_name, type_cls in types.items():
+ if attr_name in new_data.keys():
+ type_obj = type_cls(new_data[attr_name])
+
+ # if the type if FileAttribute we need to pass the data as
+ # file
+ if issubclass(type_cls, g_types.FileAttribute):
+ k = type_obj.get_file_name(attr_name)
+ files[attr_name] = (k, new_data.pop(attr_name))
+ else:
+ new_data[attr_name] = type_obj.get_for_api()
+
+ return self.gitlab.http_put(path, post_data=new_data, files=files,
+ **kwargs)
class SetMixin(object):
diff --git a/gitlab/types.py b/gitlab/types.py
index d361222..b32409f 100644
--- a/gitlab/types.py
+++ b/gitlab/types.py
@@ -44,3 +44,13 @@ class ListAttribute(GitlabAttribute):
class LowercaseStringAttribute(GitlabAttribute):
def get_for_api(self):
return str(self._value).lower()
+
+
+class FileAttribute(GitlabAttribute):
+ def get_file_name(self, attr_name=None):
+ return attr_name
+
+
+class ImageAttribute(FileAttribute):
+ def get_file_name(self, attr_name=None):
+ return '%s.png' % attr_name if attr_name else 'image.png'
diff --git a/gitlab/v4/objects.py b/gitlab/v4/objects.py
index 14bad5a..2d9a6bf 100644
--- a/gitlab/v4/objects.py
+++ b/gitlab/v4/objects.py
@@ -307,16 +307,19 @@ class UserManager(CRUDMixin, RESTManager):
('email', 'username', 'name', 'password', 'reset_password', 'skype',
'linkedin', 'twitter', 'projects_limit', 'extern_uid', 'provider',
'bio', 'admin', 'can_create_group', 'website_url',
- 'skip_confirmation', 'external', 'organization', 'location')
+ 'skip_confirmation', 'external', 'organization', 'location', 'avatar')
)
_update_attrs = (
('email', 'username', 'name'),
('password', 'skype', 'linkedin', 'twitter', 'projects_limit',
'extern_uid', 'provider', 'bio', 'admin', 'can_create_group',
'website_url', 'skip_confirmation', 'external', 'organization',
- 'location')
+ 'location', 'avatar')
)
- _types = {'confirm': types.LowercaseStringAttribute}
+ _types = {
+ 'confirm': types.LowercaseStringAttribute,
+ 'avatar': types.ImageAttribute,
+ }
class CurrentUserEmail(ObjectDeleteMixin, RESTObject):