From 7c632c8bc2dbfbdd910c3c39aae3a949e5b76495 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Wed, 31 Jul 2024 13:35:26 +0200 Subject: [PATCH] Add basic support for GitLab (#100) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * First stab at adding support for GitLab * Add support for put() * Pass options * Add localization phrases * Rename: apiCall → fileCall * Move phrases up * Encode id on URL parsing * Add support for uploading files * Encode all needed components --- backends/gitlab/index.js | 80 ++++++++++++++++++++++++++++++++++++++++ backends/index-fn.js | 1 + 2 files changed, 81 insertions(+) create mode 100644 backends/gitlab/index.js diff --git a/backends/gitlab/index.js b/backends/gitlab/index.js new file mode 100644 index 0000000..4ef3d94 --- /dev/null +++ b/backends/gitlab/index.js @@ -0,0 +1,80 @@ +import OAuthBackend from "../../src/oauth-backend.js"; +import { readFile } from "../../src/util.js"; + +/** + * @category GitLab + */ +export default class Gitlab extends OAuthBackend { + static capabilities = { auth: true, put: true, upload: true }; + static defaultPermissions = { read: true }; + + static fileBased = true; + + static urls = [ + "http{s}?://gitlab.com/:id(.+)/-/blob/:branch/:path(.+)", + ]; + + static userCall = "user"; + static userSchema = { + username: "username", + name: ["name", "username"], + avatar: "avatar_url", + url: "web_url", + }; + + static apiDomain = "https://gitlab.com/api/v4/"; + static oAuth = "https://gitlab.com/oauth/authorize"; + + static phrases = { + "updated_file": (name = "file") => "Updated " + name, + "uploaded_file": (name = "file") => "Uploaded " + name, + }; + + static parseURL (source) { + let ret = super.parseURL(source); + ["id", "path"].forEach(key => ret[key] = encodeURIComponent(ret[key])); + ret.fileCall = `projects/${ ret.id }/repository/files/${ ret.path }`; + return ret; + } + + get (ref = this.ref) { + let { fileCall, branch } = ref; + return this.request(`${ fileCall }/raw?ref=${ branch }`); + } + + async put (data, {ref = this.ref} = {}) { + let { fileCall, path, branch } = ref; + let body = { + branch, + content: await this.stringify(data, {ref}), + commit_message: this.constructor.phrase("updated_file", path), + }; + return this.request(fileCall, body, "PUT"); + } + + async upload (file, path = file.name) { + let { id, branch } = this.ref; + let fileCall = `projects/${ id }/repository/files/${ encodeURIComponent(path) }`; + + let type = file.type; + let isText = type.startsWith("text/") || type.startsWith("application/") && !type.endsWith("pdf"); + let content; + if (isText) { + content = await readFile(file, "Text"); + } + else { + content = await readFile(file); + content = content.slice(5); // remove “data:” + type = type.replace("+", "\\+"); // escape “+” in, e.g., “image/svg+xml” + content = content.replace(RegExp(`^${type}(;base64)?,`), ""); + } + + let body = { + branch, + content, + commit_message: this.constructor.phrase("uploaded_file", path), + encoding: isText ? "text" : "base64", + }; + return this.request(fileCall, body, "POST"); + } +} diff --git a/backends/index-fn.js b/backends/index-fn.js index a348b11..b38b8cd 100644 --- a/backends/index-fn.js +++ b/backends/index-fn.js @@ -9,3 +9,4 @@ export {default as Dropbox} from "./dropbox/index.js"; export * from "./google/index.js"; export * from "./coda/index.js"; export {default as Firebase} from "./firebase/index.js"; +export {default as Gitlab} from "./gitlab/index.js";