chore: Move initial avatar upload to background worker (#3727)
* chore: Async user avatar upload processor * chore: Async team avatar upload * Refactor to task for retries * Docs Include avatarUrl in task props to prevent race condition Remove transaction around upload fetch request
This commit is contained in:
@@ -156,6 +156,7 @@ class Event extends IdModel {
|
||||
"shares.create",
|
||||
"shares.update",
|
||||
"shares.revoke",
|
||||
"teams.create",
|
||||
"teams.update",
|
||||
"users.create",
|
||||
"users.update",
|
||||
|
||||
@@ -11,18 +11,14 @@ import {
|
||||
Table,
|
||||
Unique,
|
||||
IsIn,
|
||||
BeforeSave,
|
||||
HasMany,
|
||||
Scopes,
|
||||
Is,
|
||||
DataType,
|
||||
} from "sequelize-typescript";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { getBaseDomain, RESERVED_SUBDOMAINS } from "@shared/utils/domains";
|
||||
import env from "@server/env";
|
||||
import Logger from "@server/logging/Logger";
|
||||
import { generateAvatarUrl } from "@server/utils/avatars";
|
||||
import { publicS3Endpoint, uploadToS3FromUrl } from "@server/utils/s3";
|
||||
import AuthenticationProvider from "./AuthenticationProvider";
|
||||
import Collection from "./Collection";
|
||||
import Document from "./Document";
|
||||
@@ -242,34 +238,6 @@ class Team extends ParanoidModel {
|
||||
|
||||
@HasMany(() => TeamDomain)
|
||||
allowedDomains: TeamDomain[];
|
||||
|
||||
// hooks
|
||||
@BeforeSave
|
||||
static uploadAvatar = async (model: Team) => {
|
||||
const endpoint = publicS3Endpoint();
|
||||
const { avatarUrl } = model;
|
||||
|
||||
if (
|
||||
avatarUrl &&
|
||||
!avatarUrl.startsWith("/api") &&
|
||||
!avatarUrl.startsWith(endpoint)
|
||||
) {
|
||||
try {
|
||||
const newUrl = await uploadToS3FromUrl(
|
||||
avatarUrl,
|
||||
`avatars/${model.id}/${uuidv4()}`,
|
||||
"public-read"
|
||||
);
|
||||
if (newUrl) {
|
||||
model.avatarUrl = newUrl;
|
||||
}
|
||||
} catch (err) {
|
||||
Logger.error("Error uploading avatar to S3", err, {
|
||||
url: avatarUrl,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default Team;
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
Default,
|
||||
IsIn,
|
||||
BeforeDestroy,
|
||||
BeforeSave,
|
||||
BeforeCreate,
|
||||
AfterCreate,
|
||||
BelongsTo,
|
||||
@@ -19,12 +18,9 @@ import {
|
||||
HasMany,
|
||||
Scopes,
|
||||
} from "sequelize-typescript";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { languages } from "@shared/i18n";
|
||||
import { stringToColor } from "@shared/utils/color";
|
||||
import env from "@server/env";
|
||||
import Logger from "@server/logging/Logger";
|
||||
import { publicS3Endpoint, uploadToS3FromUrl } from "@server/utils/s3";
|
||||
import { ValidationError } from "../errors";
|
||||
import ApiKey from "./ApiKey";
|
||||
import Collection from "./Collection";
|
||||
@@ -463,34 +459,6 @@ class User extends ParanoidModel {
|
||||
});
|
||||
};
|
||||
|
||||
@BeforeSave
|
||||
static uploadAvatar = async (model: User) => {
|
||||
const endpoint = publicS3Endpoint();
|
||||
const { avatarUrl } = model;
|
||||
|
||||
if (
|
||||
avatarUrl &&
|
||||
!avatarUrl.startsWith("/api") &&
|
||||
!avatarUrl.startsWith(endpoint) &&
|
||||
!avatarUrl.startsWith(env.DEFAULT_AVATAR_HOST)
|
||||
) {
|
||||
try {
|
||||
const newUrl = await uploadToS3FromUrl(
|
||||
avatarUrl,
|
||||
`avatars/${model.id}/${uuidv4()}`,
|
||||
"public-read"
|
||||
);
|
||||
if (newUrl) {
|
||||
model.avatarUrl = newUrl;
|
||||
}
|
||||
} catch (err) {
|
||||
Logger.error("Couldn't upload user avatar image to S3", err, {
|
||||
url: avatarUrl,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@BeforeCreate
|
||||
static setRandomJwtSecret = (model: User) => {
|
||||
model.jwtSecret = crypto.randomBytes(64).toString("hex");
|
||||
|
||||
Reference in New Issue
Block a user