Add usageHint field to DriveFile, and fill accordingly when operating on Persons

This commit is contained in:
yumeko 2024-04-19 03:34:25 +03:00
parent c6e2776298
commit 4823abd3a9
No known key found for this signature in database
GPG key ID: 31A48AD2758B1B53
7 changed files with 51 additions and 9 deletions

View file

@ -0,0 +1,15 @@
import type { MigrationInterface, QueryRunner } from "typeorm";
export class AddDriveFileUsage1713451569342 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "drive_file" ADD "usageHint" character varying(16) DEFAULT NULL`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "drive_file" DROP COLUMN "usageHint"`
);
}
}

View file

@ -177,6 +177,13 @@ export class DriveFile {
}) })
public isSensitive: boolean; public isSensitive: boolean;
@Column("varchar", {
length: 16,
nullable: true,
comment: "Hint for what the file is used for.",
})
public usageHint: string | null;
/** /**
* ()URLへの直リンクか否か * ()URLへの直リンクか否か
*/ */

View file

@ -16,6 +16,7 @@ const logger = apLogger;
export async function createImage( export async function createImage(
actor: CacheableRemoteUser, actor: CacheableRemoteUser,
value: any, value: any,
usage: 'avatar' | 'banner' | null
): Promise<DriveFile> { ): Promise<DriveFile> {
// Skip if author is frozen. // Skip if author is frozen.
if (actor.isSuspended) { if (actor.isSuspended) {
@ -43,6 +44,7 @@ export async function createImage(
sensitive: image.sensitive, sensitive: image.sensitive,
isLink: !instance.cacheRemoteFiles, isLink: !instance.cacheRemoteFiles,
comment: truncate(image.name, DB_MAX_IMAGE_COMMENT_LENGTH), comment: truncate(image.name, DB_MAX_IMAGE_COMMENT_LENGTH),
usageHint: usage
}); });
if (file.isLink) { if (file.isLink) {
@ -73,9 +75,10 @@ export async function createImage(
export async function resolveImage( export async function resolveImage(
actor: CacheableRemoteUser, actor: CacheableRemoteUser,
value: any, value: any,
usage: 'avatar' | 'banner' | null,
): Promise<DriveFile> { ): Promise<DriveFile> {
// TODO // TODO
// Fetch from remote server and register // Fetch from remote server and register
return await createImage(actor, value); return await createImage(actor, value, usage);
} }

View file

@ -213,7 +213,7 @@ export async function createNote(
? ( ? (
await Promise.all( await Promise.all(
note.attachment.map( note.attachment.map(
(x) => limit(() => resolveImage(actor, x)) as Promise<DriveFile>, (x) => limit(() => resolveImage(actor, x, null)) as Promise<DriveFile>,
), ),
) )
).filter((image) => image != null) ).filter((image) => image != null)
@ -616,7 +616,7 @@ export async function updateNote(value: string | IObject, resolver?: Resolver) {
fileList.map( fileList.map(
(x) => (x) =>
limit(async () => { limit(async () => {
const file = await resolveImage(actor, x); const file = await resolveImage(actor, x, null);
const update: Partial<DriveFile> = {}; const update: Partial<DriveFile> = {};
const altText = truncate(x.name, DB_MAX_IMAGE_COMMENT_LENGTH); const altText = truncate(x.name, DB_MAX_IMAGE_COMMENT_LENGTH);

View file

@ -362,10 +362,10 @@ export async function createPerson(
//#region Fetch avatar and header image //#region Fetch avatar and header image
const [avatar, banner] = await Promise.all( const [avatar, banner] = await Promise.all(
[person.icon, person.image].map((img) => [person.icon, person.image].map((img, index) =>
img == null img == null
? Promise.resolve(null) ? Promise.resolve(null)
: resolveImage(user!, img).catch(() => null), : resolveImage(user!, img, index === 0 ? "avatar" : index === 1 ? "banner" : null).catch(() => null),
), ),
); );
@ -438,10 +438,10 @@ export async function updatePerson(
// Fetch avatar and header image // Fetch avatar and header image
const [avatar, banner] = await Promise.all( const [avatar, banner] = await Promise.all(
[person.icon, person.image].map((img) => [person.icon, person.image].map((img, index) =>
img == null img == null
? Promise.resolve(null) ? Promise.resolve(null)
: resolveImage(user, img).catch(() => null), : resolveImage(user, img, index === 0 ? "avatar" : index === 1 ? "banner" : null).catch(() => null),
), ),
); );

View file

@ -65,6 +65,7 @@ function urlPathJoin(
* @param type Content-Type for original * @param type Content-Type for original
* @param hash Hash for original * @param hash Hash for original
* @param size Size for original * @param size Size for original
* @param usage Optional usage hint for file (f.e. "avatar")
*/ */
async function save( async function save(
file: DriveFile, file: DriveFile,
@ -73,6 +74,7 @@ async function save(
type: string, type: string,
hash: string, hash: string,
size: number, size: number,
usage: string | null = null
): Promise<DriveFile> { ): Promise<DriveFile> {
// thunbnail, webpublic を必要なら生成 // thunbnail, webpublic を必要なら生成
const alts = await generateAlts(path, type, !file.uri); const alts = await generateAlts(path, type, !file.uri);
@ -161,6 +163,7 @@ async function save(
file.md5 = hash; file.md5 = hash;
file.size = size; file.size = size;
file.storedInternal = false; file.storedInternal = false;
file.usageHint = usage ?? null;
return await DriveFiles.insert(file).then((x) => return await DriveFiles.insert(file).then((x) =>
DriveFiles.findOneByOrFail(x.identifiers[0]), DriveFiles.findOneByOrFail(x.identifiers[0]),
@ -204,6 +207,7 @@ async function save(
file.type = type; file.type = type;
file.md5 = hash; file.md5 = hash;
file.size = size; file.size = size;
file.usageHint = usage ?? null;
return await DriveFiles.insert(file).then((x) => return await DriveFiles.insert(file).then((x) =>
DriveFiles.findOneByOrFail(x.identifiers[0]), DriveFiles.findOneByOrFail(x.identifiers[0]),
@ -450,6 +454,9 @@ type AddFileArgs = {
requestIp?: string | null; requestIp?: string | null;
requestHeaders?: Record<string, string> | null; requestHeaders?: Record<string, string> | null;
/** Whether this file has a known use case, like user avatar or instance icon */
usageHint?: string | null;
}; };
/** /**
@ -469,6 +476,7 @@ export async function addFile({
sensitive = null, sensitive = null,
requestIp = null, requestIp = null,
requestHeaders = null, requestHeaders = null,
usageHint = null,
}: AddFileArgs): Promise<DriveFile> { }: AddFileArgs): Promise<DriveFile> {
const info = await getFileInfo(path); const info = await getFileInfo(path);
logger.info(`${JSON.stringify(info)}`); logger.info(`${JSON.stringify(info)}`);
@ -581,6 +589,7 @@ export async function addFile({
file.isLink = isLink; file.isLink = isLink;
file.requestIp = requestIp; file.requestIp = requestIp;
file.requestHeaders = requestHeaders; file.requestHeaders = requestHeaders;
file.usageHint = usageHint;
file.isSensitive = user file.isSensitive = user
? Users.isLocalUser(user) && ? Users.isLocalUser(user) &&
(instance!.markLocalFilesNsfwByDefault || profile!.alwaysMarkNsfw) (instance!.markLocalFilesNsfwByDefault || profile!.alwaysMarkNsfw)
@ -639,6 +648,7 @@ export async function addFile({
info.type.mime, info.type.mime,
info.md5, info.md5,
info.size, info.size,
usageHint
); );
} }

View file

@ -13,7 +13,11 @@ const logger = driveLogger.createSubLogger("downloader");
type Args = { type Args = {
url: string; url: string;
user: { id: User["id"]; host: User["host"] } | null; user: {
id: User["id"];
host: User["host"];
driveCapacityOverrideMb: User["driveCapacityOverrideMb"];
} | null;
folderId?: DriveFolder["id"] | null; folderId?: DriveFolder["id"] | null;
uri?: string | null; uri?: string | null;
sensitive?: boolean; sensitive?: boolean;
@ -22,6 +26,7 @@ type Args = {
comment?: string | null; comment?: string | null;
requestIp?: string | null; requestIp?: string | null;
requestHeaders?: Record<string, string> | null; requestHeaders?: Record<string, string> | null;
usageHint?: string | null;
}; };
export async function uploadFromUrl({ export async function uploadFromUrl({
@ -35,6 +40,7 @@ export async function uploadFromUrl({
comment = null, comment = null,
requestIp = null, requestIp = null,
requestHeaders = null, requestHeaders = null,
usageHint = null
}: Args): Promise<DriveFile> { }: Args): Promise<DriveFile> {
const parsedUrl = new URL(url); const parsedUrl = new URL(url);
if ( if (
@ -75,9 +81,10 @@ export async function uploadFromUrl({
sensitive, sensitive,
requestIp, requestIp,
requestHeaders, requestHeaders,
usageHint
}); });
logger.succ(`Got: ${driveFile.id}`); logger.succ(`Got: ${driveFile.id}`);
return driveFile!; return driveFile;
} catch (e) { } catch (e) {
logger.error(`Failed to create drive file:\n${inspect(e)}`); logger.error(`Failed to create drive file:\n${inspect(e)}`);
throw e; throw e;