1//
2// Copyright 2021, Sander van Harmelen
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17package gitlab
18
19import (
20	"bytes"
21	"fmt"
22	"io"
23	"mime/multipart"
24	"net/http"
25	"os"
26	"path/filepath"
27	"strconv"
28)
29
30// GroupImportExportService handles communication with the group import export
31// related methods of the GitLab API.
32//
33// GitLab API docs: https://docs.gitlab.com/ce/api/group_import_export.html
34type GroupImportExportService struct {
35	client *Client
36}
37
38// ScheduleExport starts a new group export.
39//
40// GitLab API docs:
41// https://docs.gitlab.com/ce/api/group_import_export.html#schedule-new-export
42func (s *GroupImportExportService) ScheduleExport(gid interface{}, options ...RequestOptionFunc) (*Response, error) {
43	group, err := parseID(gid)
44	if err != nil {
45		return nil, err
46	}
47	u := fmt.Sprintf("groups/%s/export", pathEscape(group))
48
49	req, err := s.client.NewRequest(http.MethodPost, u, nil, options)
50	if err != nil {
51		return nil, err
52	}
53
54	return s.client.Do(req, nil)
55}
56
57// ExportDownload downloads the finished export.
58//
59// GitLab API docs:
60// https://docs.gitlab.com/ce/api/group_import_export.html#export-download
61func (s *GroupImportExportService) ExportDownload(gid interface{}, options ...RequestOptionFunc) (*bytes.Reader, *Response, error) {
62	group, err := parseID(gid)
63	if err != nil {
64		return nil, nil, err
65	}
66	u := fmt.Sprintf("groups/%s/export/download", pathEscape(group))
67
68	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
69	if err != nil {
70		return nil, nil, err
71	}
72
73	exportDownload := new(bytes.Buffer)
74	resp, err := s.client.Do(req, exportDownload)
75	if err != nil {
76		return nil, resp, err
77	}
78
79	return bytes.NewReader(exportDownload.Bytes()), resp, err
80}
81
82// GroupImportFileOptions represents the available ImportFile() options.
83//
84// GitLab API docs:
85// https://docs.gitlab.com/ce/api/group_import_export.html#import-a-file
86type GroupImportFileOptions struct {
87	Name     *string `url:"name,omitempty" json:"name,omitempty"`
88	Path     *string `url:"path,omitempty" json:"path,omitempty"`
89	File     *string `url:"file,omitempty" json:"file,omitempty"`
90	ParentID *int    `url:"parent_id,omitempty" json:"parent_id,omitempty"`
91}
92
93// ImportFile imports a file.
94//
95// GitLab API docs:
96// https://docs.gitlab.com/ce/api/group_import_export.html#import-a-file
97func (s *GroupImportExportService) ImportFile(opt *GroupImportFileOptions, options ...RequestOptionFunc) (*Response, error) {
98	// First check if we got all required options.
99	if opt.Name == nil || *opt.Name == "" {
100		return nil, fmt.Errorf("Missing required option: Name")
101	}
102	if opt.Path == nil || *opt.Path == "" {
103		return nil, fmt.Errorf("Missing required option: Path")
104	}
105	if opt.File == nil || *opt.File == "" {
106		return nil, fmt.Errorf("Missing required option: File")
107	}
108
109	f, err := os.Open(*opt.File)
110	if err != nil {
111		return nil, err
112	}
113	defer f.Close()
114
115	b := &bytes.Buffer{}
116	w := multipart.NewWriter(b)
117
118	_, filename := filepath.Split(*opt.File)
119	fw, err := w.CreateFormFile("file", filename)
120	if err != nil {
121		return nil, err
122	}
123
124	_, err = io.Copy(fw, f)
125	if err != nil {
126		return nil, err
127	}
128
129	// Populate the additional fields.
130	fw, err = w.CreateFormField("name")
131	if err != nil {
132		return nil, err
133	}
134
135	_, err = fw.Write([]byte(*opt.Name))
136	if err != nil {
137		return nil, err
138	}
139
140	fw, err = w.CreateFormField("path")
141	if err != nil {
142		return nil, err
143	}
144
145	_, err = fw.Write([]byte(*opt.Path))
146	if err != nil {
147		return nil, err
148	}
149
150	if opt.ParentID != nil {
151		fw, err = w.CreateFormField("parent_id")
152		if err != nil {
153			return nil, err
154		}
155
156		_, err = fw.Write([]byte(strconv.Itoa(*opt.ParentID)))
157		if err != nil {
158			return nil, err
159		}
160	}
161
162	if err = w.Close(); err != nil {
163		return nil, err
164	}
165
166	req, err := s.client.NewRequest(http.MethodPost, "groups/import", nil, options)
167	if err != nil {
168		return nil, err
169	}
170
171	// Set the buffer as the request body.
172	if err = req.SetBody(b); err != nil {
173		return nil, err
174	}
175
176	// Overwrite the default content type.
177	req.Header.Set("Content-Type", w.FormDataContentType())
178
179	return s.client.Do(req, nil)
180}
181