diff --git a/server/models/Team.ts b/server/models/Team.ts index f26248247b60..b09aa1a5d77a 100644 --- a/server/models/Team.ts +++ b/server/models/Team.ts @@ -16,6 +16,8 @@ import { Is, DataType, IsUUID, + IsUrl, + AllowNull, } from "sequelize-typescript"; import { getBaseDomain, RESERVED_SUBDOMAINS } from "@shared/utils/domains"; import env from "@server/env"; @@ -82,6 +84,8 @@ class Team extends ParanoidModel { @Column(DataType.UUID) defaultCollectionId: string | null; + @AllowNull + @IsUrl @Length({ max: 255, msg: "avatarUrl must be 255 characters or less" }) @Column avatarUrl: string | null; diff --git a/server/models/User.ts b/server/models/User.ts index aae09cecb05e..7459dab27db3 100644 --- a/server/models/User.ts +++ b/server/models/User.ts @@ -18,6 +18,8 @@ import { HasMany, Scopes, IsDate, + IsUrl, + AllowNull, } from "sequelize-typescript"; import { languages } from "@shared/i18n"; import { stringToColor } from "@shared/utils/color"; @@ -154,6 +156,8 @@ class User extends ParanoidModel { @Column language: string; + @AllowNull + @IsUrl @Length({ max: 1000, msg: "avatarUrl must be less than 1000 characters" }) @Column(DataType.STRING) get avatarUrl() { diff --git a/server/routes/api/attachments.ts b/server/routes/api/attachments.ts index 8959bf8f6a00..4ae074f19026 100644 --- a/server/routes/api/attachments.ts +++ b/server/routes/api/attachments.ts @@ -51,10 +51,11 @@ router.post("attachments.create", auth(), async (ctx) => { const acl = isPublic === undefined ? AWS_S3_ACL : isPublic ? "public-read" : "private"; const bucket = acl === "public-read" ? "public" : "uploads"; - const key = `${bucket}/${user.id}/${s3Key}/${name}`; + const keyPrefix = `${bucket}/${user.id}/${s3Key}`; + const key = `${keyPrefix}/${name}`; const presignedPost = await getPresignedPost(key, acl, contentType); const endpoint = publicS3Endpoint(); - const url = `${endpoint}/${key}`; + const url = `${endpoint}/${keyPrefix}/${encodeURIComponent(name)}`; if (documentId !== undefined) { assertUuid(documentId, "documentId must be a uuid");