mirror of
https://github.com/outline/outline.git
synced 2026-05-05 17:19:47 -05:00
fix: Store Linear workspace logo in storage (#9061)
* fix: Store Linear workspace logo in Outline * use async task * Move task into plugin --------- Co-authored-by: Tom Moor <tom@getoutline.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import validate from "@server/middlewares/validate";
|
||||
import { IntegrationAuthentication, Integration, Team } from "@server/models";
|
||||
import { APIContext } from "@server/types";
|
||||
import { Linear } from "../linear";
|
||||
import UploadLinearWorkspaceLogoTask from "../tasks/UploadLinearWorkspaceLogoTask";
|
||||
import * as T from "./schema";
|
||||
import { LinearUtils } from "plugins/linear/shared/LinearUtils";
|
||||
|
||||
@@ -82,7 +83,9 @@ router.get(
|
||||
},
|
||||
{ transaction }
|
||||
);
|
||||
await Integration.create<Integration<IntegrationType.Embed>>(
|
||||
const integration = await Integration.create<
|
||||
Integration<IntegrationType.Embed>
|
||||
>(
|
||||
{
|
||||
service: IntegrationService.Linear,
|
||||
type: IntegrationType.Embed,
|
||||
@@ -103,6 +106,13 @@ router.get(
|
||||
{ transaction }
|
||||
);
|
||||
|
||||
transaction.afterCommit(async () => {
|
||||
await UploadLinearWorkspaceLogoTask.schedule({
|
||||
integrationId: integration.id,
|
||||
logoUrl: workspace.logoUrl,
|
||||
});
|
||||
});
|
||||
|
||||
ctx.redirect(LinearUtils.successUrl());
|
||||
}
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@ import config from "../plugin.json";
|
||||
import router from "./api/linear";
|
||||
import env from "./env";
|
||||
import { Linear } from "./linear";
|
||||
import UploadLinearWorkspaceLogoTask from "./tasks/UploadLinearWorkspaceLogoTask";
|
||||
import { uninstall } from "./uninstall";
|
||||
|
||||
const enabled = !!env.LINEAR_CLIENT_ID && !!env.LINEAR_CLIENT_SECRET;
|
||||
@@ -15,6 +16,10 @@ if (enabled) {
|
||||
type: Hook.API,
|
||||
value: router,
|
||||
},
|
||||
{
|
||||
type: Hook.Task,
|
||||
value: UploadLinearWorkspaceLogoTask,
|
||||
},
|
||||
{
|
||||
type: Hook.UnfurlProvider,
|
||||
value: { unfurl: Linear.unfurl, cacheExpiry: Minute.seconds },
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { IntegrationService, IntegrationType } from "@shared/types";
|
||||
import { Integration } from "@server/models";
|
||||
import { Buckets } from "@server/models/helpers/AttachmentHelper";
|
||||
import BaseTask, { TaskPriority } from "@server/queues/tasks/BaseTask";
|
||||
import FileStorage from "@server/storage/files";
|
||||
|
||||
type Props = {
|
||||
/** The integrationId to operate on */
|
||||
integrationId: string;
|
||||
/** The original logoUrl from Linear */
|
||||
logoUrl: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* A task that uploads the provided logoUrl to storage and updates the
|
||||
* Linear integration record with the new url.
|
||||
*/
|
||||
export default class UploadLinearWorkspaceLogoTask extends BaseTask<Props> {
|
||||
public async perform(props: Props) {
|
||||
const integration = await Integration.scope("withAuthentication").findByPk<
|
||||
Integration<IntegrationType.Embed>
|
||||
>(props.integrationId);
|
||||
if (!integration || integration.service !== IntegrationService.Linear) {
|
||||
return;
|
||||
}
|
||||
|
||||
const res = await FileStorage.storeFromUrl(
|
||||
props.logoUrl,
|
||||
`${Buckets.avatars}/${integration.teamId}/${uuidv4()}`,
|
||||
"public-read",
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${integration.authentication.token}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (res?.url) {
|
||||
integration.settings.linear!.workspace.logoUrl = res.url;
|
||||
integration.changed("settings", true);
|
||||
await integration.save();
|
||||
}
|
||||
}
|
||||
|
||||
public get options() {
|
||||
return {
|
||||
attempts: 3,
|
||||
priority: TaskPriority.Normal,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Blob } from "buffer";
|
||||
import { Readable } from "stream";
|
||||
import { PresignedPost } from "@aws-sdk/s3-presigned-post";
|
||||
import omit from "lodash/omit";
|
||||
import FileHelper from "@shared/editor/lib/FileHelper";
|
||||
import { isBase64Url, isInternalUrl } from "@shared/utils/urls";
|
||||
import env from "@server/env";
|
||||
@@ -162,6 +163,12 @@ export default abstract class BaseStorage {
|
||||
buffer = Buffer.from(match[2], "base64");
|
||||
} else {
|
||||
try {
|
||||
const headers = {
|
||||
"User-Agent": chromeUserAgent,
|
||||
...init?.headers,
|
||||
};
|
||||
const initWithoutHeaders = omit(init, ["headers"]);
|
||||
|
||||
const res = await fetch(url, {
|
||||
follow: 3,
|
||||
redirect: "follow",
|
||||
@@ -169,11 +176,9 @@ export default abstract class BaseStorage {
|
||||
options?.maxUploadSize ?? Infinity,
|
||||
env.FILE_STORAGE_UPLOAD_MAX_SIZE
|
||||
),
|
||||
headers: {
|
||||
"User-Agent": chromeUserAgent,
|
||||
},
|
||||
headers,
|
||||
timeout: 10000,
|
||||
...init,
|
||||
...initWithoutHeaders,
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
|
||||
Reference in New Issue
Block a user