1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
Description:
Using GitLab's API v4, it is possible to change a project's avatar.
However the request needs to be submitted via PUT with `Content-Type: multipart/form-data` header set.
REF: https://docs.gitlab.com/ee/api/projects.html#upload-a-project-avatar
Author: g0t mi1k <have.you.g0tmi1k@gmail.com>
Last-Update: Mon, 23 Jan 2023 06:10:02 +0000
Forwarded: https://github.com/bluefeet/GitLab-API-v4/pull/54
---
author/generate.pl | 6 ++++++
author/sections/projects.yml | 4 ++++
lib/GitLab/API/v4.pm | 26 ++++++++++++++++++++++
lib/GitLab/API/v4/RESTClient.pm | 48 ++++++++++++++++++++++++++++++-----------
4 files changed, 72 insertions(+), 12 deletions(-)
diff --git a/author/generate.pl b/author/generate.pl
index 76096ed..341dbb3 100755
--- a/author/generate.pl
+++ b/author/generate.pl
@@ -121,6 +121,12 @@ foreach my $section_name (keys %$section_pack) {
print " \$options->{$params_key} = \$params if defined \$params;\n";
}
+ my @code;
+ @code = split /\n/, $endpoint->{code} if $endpoint->{code};
+ foreach my $line (@code) {
+ print " $line\n";
+ }
+
print ' ';
print 'return ' if $return;
print "\$self->_call_rest_client( '$verb', '$path', [\@_], \$options );\n";
diff --git a/author/sections/projects.yml b/author/sections/projects.yml
index 5ed0990..4e149f9 100644
--- a/author/sections/projects.yml
+++ b/author/sections/projects.yml
@@ -6,6 +6,10 @@
- create_project: project = POST projects?
- create_project_for_user: POST projects/user/:user_id?
- edit_project: PUT projects/:project_id?
+- method: edit_project_multipart
+ spec: PUT projects/:project_id?
+ note: The request will have "multipart/form-data" header set for uploading files.
+ code: $options->{content}->{file} = $params;
- fork_project: POST projects/:project_id/fork?
- project_forks: forks = GET projects/:project_id/forks?
- start_project: project = POST projects/:project_id/star
diff --git a/lib/GitLab/API/v4.pm b/lib/GitLab/API/v4.pm
index 87ba571..6ad83ce 100644
--- a/lib/GitLab/API/v4.pm
+++ b/lib/GitLab/API/v4.pm
@@ -7340,6 +7340,32 @@ sub edit_project {
return;
}
+=item edit_project_multipart
+
+ $api->edit_project_multipart(
+ $project_id,
+ \%params,
+ );
+
+Sends a C<PUT> request to C<projects/:project_id>.
+
+The request will have "multipart/form-data" header set for uploading files.
+=cut
+
+sub edit_project_multipart {
+ my $self = shift;
+ croak 'edit_project_multipart must be called with 1 to 2 arguments' if @_ < 1 or @_ > 2;
+ croak 'The #1 argument ($project_id) to edit_project_multipart must be a scalar' if ref($_[0]) or (!defined $_[0]);
+ croak 'The last argument (\%params) to edit_project_multipart must be a hash ref' if defined($_[1]) and ref($_[1]) ne 'HASH';
+ my $params = (@_ == 2) ? pop() : undef;
+ my $options = {};
+ $options->{decode} = 0;
+ $options->{content} = $params if defined $params;
+ $options->{content}->{file} = $params;
+ $self->_call_rest_client( 'PUT', 'projects/:project_id', [@_], $options );
+ return;
+}
+
=item fork_project
$api->fork_project(
diff --git a/lib/GitLab/API/v4/RESTClient.pm b/lib/GitLab/API/v4/RESTClient.pm
index 471dae5..045663b 100644
--- a/lib/GitLab/API/v4/RESTClient.pm
+++ b/lib/GitLab/API/v4/RESTClient.pm
@@ -162,10 +162,18 @@ sub request {
my $req_method = 'request';
my $req = [ $verb, $url, $options ];
+ my $boundary;
- if ($verb eq 'POST' and ref($content) eq 'HASH' and $content->{file}) {
+ if (($verb eq 'POST' or $verb eq 'PUT' ) and ref($content) eq 'HASH' and $content->{file}) {
$content = { %$content };
- my $file = path( delete $content->{file} );
+ my $file = delete $content->{file};
+
+ my $key = (keys %$file)[0]
+ if (ref $file);
+
+ $file = (ref $file)
+ ? path( $file->{$key} )
+ : path( $file );
unless (-f $file and -r $file) {
local $Carp::Internal{ 'GitLab::API::v4' } = 1;
@@ -183,18 +191,34 @@ sub request {
},
};
- $req->[0] = $req->[1]; # Replace method with url.
- $req->[1] = $data; # Put data where url was.
- # So, req went from [$verb,$url,$options] to [$url,$data,$options],
- # per the post_multipart interface.
-
- $req_method = 'post_multipart';
- $content = undef if ! %$content;
+ if ($verb eq 'POST') {
+ $req->[0] = $req->[1]; # Replace method with url.
+ $req->[1] = $data; # Put data where url was.
+ # So, req went from [$verb,$url,$options] to [$url,$data,$options],
+ # per the post_multipart interface.
+
+ $req_method = 'post_multipart';
+ $content = undef if ! %$content;
+ } elsif ($verb eq 'PUT') {
+ $boundary .= sprintf("%x", rand 16) for 1..16;
+ $content = <<"EOL";
+--------------------------$boundary
+Content-Disposition: form-data; name="$key"; filename="$data->{file}->{filename}"
+
+$data->{file}->{content}
+--------------------------$boundary--
+EOL
+ }
}
- if (ref $content) {
- $content = $self->json->encode( $content );
- $headers->{'content-type'} = 'application/json';
+ if (defined $boundary or ref $content) {
+ $content = $self->json->encode( $content )
+ if (ref $content);
+
+ $headers->{'content-type'} = (defined $boundary)
+ ? "multipart/form-data; boundary=------------------------$boundary"
+ : 'application/json';
+
$headers->{'content-length'} = length( $content );
}
|