Skip to content

Commit b4c6f8d

Browse files
committed
Add PUT multipart support
To use GitLab's API v4, in order to change a project's avatar, the request needs to be submitted via PUT with `Content-Type: multipart/form-data` header. REF: https://docs.gitlab.com/ee/api/projects.html#upload-a-project-avatar
1 parent 4f111b8 commit b4c6f8d

File tree

2 files changed

+47
-15
lines changed

2 files changed

+47
-15
lines changed

lib/GitLab/API/v4.pm

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7321,6 +7321,7 @@ sub create_project_for_user {
73217321
$api->edit_project(
73227322
$project_id,
73237323
\%params,
7324+
\%params_multipart,
73247325
);
73257326
73267327
Sends a C<PUT> request to C<projects/:project_id>.
@@ -7329,14 +7330,21 @@ Sends a C<PUT> request to C<projects/:project_id>.
73297330

73307331
sub edit_project {
73317332
my $self = shift;
7332-
croak 'edit_project must be called with 1 to 2 arguments' if @_ < 1 or @_ > 2;
7333+
croak 'edit_project must be called with 1 to 3 arguments' if @_ < 1 or @_ > 3;
73337334
croak 'The #1 argument ($project_id) to edit_project must be a scalar' if ref($_[0]) or (!defined $_[0]);
7334-
croak 'The last argument (\%params) to edit_project must be a hash ref' if defined($_[1]) and ref($_[1]) ne 'HASH';
7335+
croak 'The #2 argument (\%params) to edit_project must be a hash ref' if defined($_[1]) and ref($_[1]) ne 'HASH';
7336+
croak 'The last argument (\%params_multipart) to edit_project must be a hash ref' if defined($_[2]) and ref($_[2]) ne 'HASH';
7337+
my $params_multipart = (@_ == 3) ? pop() : undef;
73357338
my $params = (@_ == 2) ? pop() : undef;
73367339
my $options = {};
73377340
$options->{decode} = 0;
73387341
$options->{content} = $params if defined $params;
7339-
$self->_call_rest_client( 'PUT', 'projects/:project_id', [@_], $options );
7342+
$self->_call_rest_client( 'PUT', 'projects/:project_id', [$_[0]], $options );
7343+
7344+
if (keys %$params_multipart) {
7345+
$options->{content}->{file} = $params_multipart ;
7346+
$self->_call_rest_client( 'PUT', 'projects/:project_id', [$_[0]], $options );
7347+
}
73407348
return;
73417349
}
73427350

lib/GitLab/API/v4/RESTClient.pm

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,18 @@ sub request {
162162

163163
my $req_method = 'request';
164164
my $req = [ $verb, $url, $options ];
165+
my $boundary;
165166

166-
if ($verb eq 'POST' and ref($content) eq 'HASH' and $content->{file}) {
167+
if (($verb eq 'POST' or $verb eq 'PUT' ) and ref($content) eq 'HASH' and $content->{file}) {
167168
$content = { %$content };
168-
my $file = path( delete $content->{file} );
169+
my $file = delete $content->{file};
170+
171+
my $key = (keys %$file)[0]
172+
if (ref $file);
173+
174+
$file = (ref $file)
175+
? path( $file->{$key} )
176+
: path( $file );
169177

170178
unless (-f $file and -r $file) {
171179
local $Carp::Internal{ 'GitLab::API::v4' } = 1;
@@ -183,18 +191,34 @@ sub request {
183191
},
184192
};
185193

186-
$req->[0] = $req->[1]; # Replace method with url.
187-
$req->[1] = $data; # Put data where url was.
188-
# So, req went from [$verb,$url,$options] to [$url,$data,$options],
189-
# per the post_multipart interface.
190-
191-
$req_method = 'post_multipart';
192-
$content = undef if ! %$content;
194+
if ($verb eq 'POST') {
195+
$req->[0] = $req->[1]; # Replace method with url.
196+
$req->[1] = $data; # Put data where url was.
197+
# So, req went from [$verb,$url,$options] to [$url,$data,$options],
198+
# per the post_multipart interface.
199+
200+
$req_method = 'post_multipart';
201+
$content = undef if ! %$content;
202+
} elsif ($verb eq 'PUT') {
203+
$boundary .= sprintf("%x", rand 16) for 1..16;
204+
$content = <<"EOL";
205+
--------------------------$boundary
206+
Content-Disposition: form-data; name="$key"; filename="$data->{file}->{filename}"
207+
208+
$data->{file}->{content}
209+
--------------------------$boundary--
210+
EOL
211+
}
193212
}
194213

195-
if (ref $content) {
196-
$content = $self->json->encode( $content );
197-
$headers->{'content-type'} = 'application/json';
214+
if (defined $boundary or ref $content) {
215+
$content = $self->json->encode( $content )
216+
if (ref $content);
217+
218+
$headers->{'content-type'} = (defined $boundary)
219+
? "multipart/form-data; boundary=------------------------$boundary"
220+
: 'application/json';
221+
198222
$headers->{'content-length'} = length( $content );
199223
}
200224

0 commit comments

Comments
 (0)