File: 0002-add-put-multipart-support-edit_project.patch

package info (click to toggle)
libgitlab-api-v4-perl 0.26-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,860 kB
  • sloc: perl: 5,830; sh: 835; python: 63; makefile: 12
file content (153 lines) | stat: -rwxr-xr-x 5,724 bytes parent folder | download
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 );
     }