mirror of
https://iceshrimp.dev/crimekillz/iceshrimp-161sh.git
synced 2024-11-25 05:29:07 +01:00
[backend] Include avatar & banner url and blurhash in the user table
This drastically improves timeline performance due to the many (2-6 per query) database joins that are now no longer required
This commit is contained in:
parent
6e82e18eea
commit
302b112f05
@ -0,0 +1,32 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class UserAvatarBannerRefactor1700517975122 implements MigrationInterface {
|
||||
name = 'UserAvatarBannerRefactor1700517975122'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "user" ADD "avatarUrl" character varying(512)`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."avatarUrl" IS 'The URL of the avatar DriveFile'`);
|
||||
await queryRunner.query(`ALTER TABLE "user" ADD "avatarBlurhash" character varying(128)`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."avatarBlurhash" IS 'The blurhash of the avatar DriveFile'`);
|
||||
await queryRunner.query(`ALTER TABLE "user" ADD "bannerUrl" character varying(512)`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."bannerUrl" IS 'The URL of the banner DriveFile'`);
|
||||
await queryRunner.query(`ALTER TABLE "user" ADD "bannerBlurhash" character varying(128)`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."bannerBlurhash" IS 'The blurhash of the banner DriveFile'`);
|
||||
|
||||
await queryRunner.query(`UPDATE "user" SET "avatarUrl" = (SELECT COALESCE("thumbnailUrl", "webpublicUrl", "url") FROM "drive_file" WHERE "id" = "user"."avatarId") WHERE "avatarId" IS NOT NULL`);
|
||||
await queryRunner.query(`UPDATE "user" SET "avatarBlurhash" = (SELECT "blurhash" FROM "drive_file" WHERE "id" = "user"."avatarId") WHERE "avatarId" IS NOT NULL`);
|
||||
await queryRunner.query(`UPDATE "user" SET "bannerUrl" = (SELECT COALESCE("webpublicUrl", "url") FROM "drive_file" WHERE "id" = "user"."bannerId") WHERE "bannerId" IS NOT NULL`);
|
||||
await queryRunner.query(`UPDATE "user" SET "bannerBlurhash" = (SELECT "blurhash" FROM "drive_file" WHERE "id" = "user"."bannerId") WHERE "bannerId" IS NOT NULL`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."bannerBlurhash" IS 'The blurhash of the banner DriveFile'`);
|
||||
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "bannerBlurhash"`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."bannerUrl" IS 'The URL of the banner DriveFile'`);
|
||||
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "bannerUrl"`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."avatarBlurhash" IS 'The blurhash of the avatar DriveFile'`);
|
||||
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "avatarBlurhash"`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."avatarUrl" IS 'The URL of the avatar DriveFile'`);
|
||||
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "avatarUrl"`);
|
||||
}
|
||||
}
|
@ -103,6 +103,20 @@ export class User {
|
||||
})
|
||||
public avatarId: DriveFile["id"] | null;
|
||||
|
||||
@Column("varchar", {
|
||||
length: 512,
|
||||
nullable: true,
|
||||
comment: "The URL of the avatar DriveFile",
|
||||
})
|
||||
public avatarUrl: string | null;
|
||||
|
||||
@Column("varchar", {
|
||||
length: 128,
|
||||
nullable: true,
|
||||
comment: "The blurhash of the avatar DriveFile",
|
||||
})
|
||||
public avatarBlurhash: string | null;
|
||||
|
||||
@OneToOne((type) => DriveFile, {
|
||||
onDelete: "SET NULL",
|
||||
})
|
||||
@ -116,6 +130,20 @@ export class User {
|
||||
})
|
||||
public bannerId: DriveFile["id"] | null;
|
||||
|
||||
@Column("varchar", {
|
||||
length: 512,
|
||||
nullable: true,
|
||||
comment: "The URL of the banner DriveFile",
|
||||
})
|
||||
public bannerUrl: string | null;
|
||||
|
||||
@Column("varchar", {
|
||||
length: 128,
|
||||
nullable: true,
|
||||
comment: "The blurhash of the banner DriveFile",
|
||||
})
|
||||
public bannerBlurhash: string | null;
|
||||
|
||||
@OneToOne((type) => DriveFile, {
|
||||
onDelete: "SET NULL",
|
||||
})
|
||||
|
@ -2,13 +2,11 @@ import { db } from "@/db/postgre.js";
|
||||
import { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
import { awaitAll, Promiseable } from "@/prelude/await-all.js";
|
||||
import { awaitAll } from "@/prelude/await-all.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
import config from "@/config/index.js";
|
||||
import { query, appendQuery } from "@/prelude/url.js";
|
||||
import { Meta } from "@/models/entities/meta.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { Users, DriveFolders } from "../index.js";
|
||||
import { appendQuery, query } from "@/prelude/url.js";
|
||||
import { DriveFolders, Users } from "../index.js";
|
||||
import { deepClone } from "@/misc/clone.js";
|
||||
|
||||
type PackOptions = {
|
||||
@ -44,6 +42,19 @@ export const DriveFileRepository = db.getRepository(DriveFile).extend({
|
||||
return file.properties;
|
||||
},
|
||||
|
||||
isImage(file: DriveFile): boolean {
|
||||
return !!file.type &&
|
||||
[
|
||||
"image/png",
|
||||
"image/apng",
|
||||
"image/gif",
|
||||
"image/jpeg",
|
||||
"image/webp",
|
||||
"image/svg+xml",
|
||||
"image/avif",
|
||||
].includes(file.type);
|
||||
},
|
||||
|
||||
getPublicUrl(file: DriveFile, thumbnail = false): string | null {
|
||||
// リモートかつメディアプロキシ
|
||||
if (
|
||||
@ -70,23 +81,17 @@ export const DriveFileRepository = db.getRepository(DriveFile).extend({
|
||||
}
|
||||
}
|
||||
|
||||
const isImage =
|
||||
file.type &&
|
||||
[
|
||||
"image/png",
|
||||
"image/apng",
|
||||
"image/gif",
|
||||
"image/jpeg",
|
||||
"image/webp",
|
||||
"image/svg+xml",
|
||||
"image/avif",
|
||||
].includes(file.type);
|
||||
|
||||
return thumbnail
|
||||
? file.thumbnailUrl || (isImage ? file.webpublicUrl || file.url : null)
|
||||
? file.thumbnailUrl || (this.isImage(file) ? file.webpublicUrl || file.url : null)
|
||||
: file.webpublicUrl || file.url;
|
||||
},
|
||||
|
||||
getDatabasePrefetchUrl(file: DriveFile, thumbnail = false): string | null {
|
||||
return thumbnail
|
||||
? file.thumbnailUrl ?? file.webpublicUrl ?? file.url
|
||||
: file.webpublicUrl ?? file.url;
|
||||
},
|
||||
|
||||
async calcDriveUsageOf(
|
||||
user: User["id"] | { id: User["id"] },
|
||||
): Promise<number> {
|
||||
|
@ -339,6 +339,7 @@ export const UserRepository = db.getRepository(User).extend({
|
||||
this.getIdenticonUrl(user.id)
|
||||
);
|
||||
} else if (user.avatarId) {
|
||||
if (user.avatarUrl) return user.avatarUrl;
|
||||
const avatar = await DriveFiles.findOneByOrFail({ id: user.avatarId });
|
||||
return (
|
||||
DriveFiles.getPublicUrl(avatar, true) || this.getIdenticonUrl(user.id)
|
||||
@ -349,7 +350,9 @@ export const UserRepository = db.getRepository(User).extend({
|
||||
},
|
||||
|
||||
getAvatarUrlSync(user: User): string {
|
||||
if (user.avatar) {
|
||||
if (user.avatarId && user.avatarUrl) {
|
||||
return user.avatarUrl;
|
||||
} else if (user.avatar) {
|
||||
return (
|
||||
DriveFiles.getPublicUrl(user.avatar, true) ||
|
||||
this.getIdenticonUrl(user.id)
|
||||
@ -388,17 +391,9 @@ export const UserRepository = db.getRepository(User).extend({
|
||||
|
||||
if (typeof src === "object") {
|
||||
user = src;
|
||||
if (src.avatar === undefined && src.avatarId)
|
||||
src.avatar = (await DriveFiles.findOneBy({ id: src.avatarId })) ?? null;
|
||||
if (src.banner === undefined && src.bannerId)
|
||||
src.banner = (await DriveFiles.findOneBy({ id: src.bannerId })) ?? null;
|
||||
} else {
|
||||
user = await this.findOneOrFail({
|
||||
where: { id: src },
|
||||
relations: {
|
||||
avatar: true,
|
||||
banner: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -474,7 +469,7 @@ export const UserRepository = db.getRepository(User).extend({
|
||||
username: user.username,
|
||||
host: user.host,
|
||||
avatarUrl: this.getAvatarUrlSync(user),
|
||||
avatarBlurhash: user.avatar?.blurhash || null,
|
||||
avatarBlurhash: user.avatarId ? (user.avatarBlurhash ?? user.avatar?.blurhash ?? null) : null,
|
||||
avatarColor: null, // 後方互換性のため
|
||||
isAdmin: user.isAdmin || falsy,
|
||||
isModerator: user.isModerator || falsy,
|
||||
@ -519,10 +514,10 @@ export const UserRepository = db.getRepository(User).extend({
|
||||
lastFetchedAt: user.lastFetchedAt
|
||||
? user.lastFetchedAt.toISOString()
|
||||
: null,
|
||||
bannerUrl: user.banner
|
||||
bannerUrl: user.bannerId ? (user.bannerUrl ?? (user.banner
|
||||
? DriveFiles.getPublicUrl(user.banner, false)
|
||||
: null,
|
||||
bannerBlurhash: user.banner?.blurhash || null,
|
||||
: null)) : null,
|
||||
bannerBlurhash: user.bannerId ? (user.bannerBlurhash ?? user.banner?.blurhash ?? null) : null,
|
||||
bannerColor: null, // 後方互換性のため
|
||||
isSilenced: user.isSilenced || falsy,
|
||||
isSuspended: user.isSuspended || falsy,
|
||||
|
@ -409,16 +409,28 @@ export async function createPerson(
|
||||
),
|
||||
);
|
||||
|
||||
const avatarId = avatar ? avatar.id : null;
|
||||
const bannerId = banner ? banner.id : null;
|
||||
const avatarId = avatar?.id ?? null;
|
||||
const avatarBlurhash = avatar?.blurhash ?? null;
|
||||
const avatarUrl = avatar ? DriveFiles.getDatabasePrefetchUrl(avatar, true) : null;
|
||||
const bannerId = banner?.id ?? null;
|
||||
const bannerBlurhash = banner?.blurhash ?? null;
|
||||
const bannerUrl = banner ? DriveFiles.getDatabasePrefetchUrl(banner, false) : null;
|
||||
|
||||
await Users.update(user!.id, {
|
||||
avatarId,
|
||||
avatarBlurhash,
|
||||
avatarUrl,
|
||||
bannerId,
|
||||
bannerBlurhash,
|
||||
bannerUrl,
|
||||
});
|
||||
|
||||
user!.avatarId = avatarId;
|
||||
user!.avatarBlurhash = avatarBlurhash;
|
||||
user!.avatarUrl = avatarUrl;
|
||||
user!.bannerId = bannerId;
|
||||
user!.bannerBlurhash = bannerBlurhash;
|
||||
user!.bannerUrl = bannerUrl;
|
||||
//#endregion
|
||||
|
||||
//#region Get custom emoji
|
||||
@ -576,10 +588,14 @@ export async function updatePerson(
|
||||
|
||||
if (avatar) {
|
||||
updates.avatarId = avatar.id;
|
||||
updates.avatarUrl = DriveFiles.getDatabasePrefetchUrl(avatar, true);
|
||||
updates.avatarBlurhash = avatar.blurhash;
|
||||
}
|
||||
|
||||
if (banner) {
|
||||
updates.bannerId = banner.id;
|
||||
updates.bannerUrl = DriveFiles.getDatabasePrefetchUrl(banner, false);
|
||||
updates.bannerBlurhash = banner.blurhash;
|
||||
}
|
||||
|
||||
if (host) {
|
||||
|
@ -97,16 +97,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||
const query = makePaginationQuery(Notes.createQueryBuilder("note"))
|
||||
.where("note.id IN (:...noteIds)", { noteIds: noteIds })
|
||||
.innerJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner")
|
||||
.andWhere("note.visibility != 'home'");
|
||||
|
||||
generateVisibilityQuery(query, user);
|
||||
|
@ -62,16 +62,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||
)
|
||||
.andWhere("note.channelId = :channelId", { channelId: channel.id })
|
||||
.innerJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner")
|
||||
.leftJoinAndSelect("note.channel", "channel");
|
||||
//#endregion
|
||||
|
||||
|
@ -70,16 +70,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||
"clipNote.noteId = note.id",
|
||||
)
|
||||
.innerJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner")
|
||||
.andWhere("clipNote.clipId = :clipId", { clipId: clip.id });
|
||||
|
||||
if (user) {
|
||||
|
@ -100,16 +100,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||
.leftJoinAndSelect("notifier.avatar", "notifierAvatar")
|
||||
.leftJoinAndSelect("notifier.banner", "notifierBanner")
|
||||
.leftJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner");
|
||||
.leftJoinAndSelect("renote.user", "renoteUser");
|
||||
|
||||
// muted users
|
||||
query.andWhere(
|
||||
|
@ -215,22 +215,27 @@ export default define(meta, paramDef, async (ps, _user, token) => {
|
||||
if (ps.emailNotificationTypes !== undefined)
|
||||
profileUpdates.emailNotificationTypes = ps.emailNotificationTypes;
|
||||
|
||||
if (ps.avatarId) {
|
||||
const avatar = await DriveFiles.findOneBy({ id: ps.avatarId });
|
||||
const avatar = ps.avatarId ? await DriveFiles.findOneBy({ id: ps.avatarId }) : null;
|
||||
const banner = ps.bannerId ? await DriveFiles.findOneBy({ id: ps.bannerId }) : null;
|
||||
|
||||
if (ps.avatarId) {
|
||||
if (avatar == null || avatar.userId !== user.id)
|
||||
throw new ApiError(meta.errors.noSuchAvatar);
|
||||
if (!avatar.type.startsWith("image/"))
|
||||
throw new ApiError(meta.errors.avatarNotAnImage);
|
||||
|
||||
updates.avatarUrl = DriveFiles.getDatabasePrefetchUrl(avatar, true);
|
||||
updates.avatarBlurhash = avatar.blurhash;
|
||||
}
|
||||
|
||||
if (ps.bannerId) {
|
||||
const banner = await DriveFiles.findOneBy({ id: ps.bannerId });
|
||||
|
||||
if (banner == null || banner.userId !== user.id)
|
||||
throw new ApiError(meta.errors.noSuchBanner);
|
||||
if (!banner.type.startsWith("image/"))
|
||||
throw new ApiError(meta.errors.bannerNotAnImage);
|
||||
|
||||
updates.bannerUrl = DriveFiles.getDatabasePrefetchUrl(banner, false);
|
||||
updates.bannerBlurhash = banner.blurhash;
|
||||
}
|
||||
|
||||
if (ps.pinnedPageId) {
|
||||
|
@ -43,16 +43,10 @@ export default define(meta, paramDef, async (ps) => {
|
||||
.andWhere("note.visibility = 'public'")
|
||||
.andWhere("note.localOnly = FALSE")
|
||||
.innerJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner");
|
||||
.leftJoinAndSelect("renote.user", "renoteUser");
|
||||
|
||||
if (ps.local) {
|
||||
query.andWhere("note.userHost IS NULL");
|
||||
|
@ -47,9 +47,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||
"note.id IN (SELECT id FROM note_replies(:noteId, :depth, :limit))",
|
||||
{ noteId: ps.noteId, depth: ps.depth, limit: ps.limit },
|
||||
)
|
||||
.innerJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner");
|
||||
.innerJoinAndSelect("note.user", "user");
|
||||
|
||||
generateVisibilityQuery(query, user);
|
||||
if (user) {
|
||||
|
@ -47,16 +47,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||
.andWhere("note.createdAt > :date", { date: new Date(Date.now() - day) })
|
||||
.andWhere("note.visibility = 'public'")
|
||||
.innerJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner");
|
||||
.leftJoinAndSelect("renote.user", "renoteUser");
|
||||
|
||||
switch (ps.origin) {
|
||||
case "local":
|
||||
|
@ -81,16 +81,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||
.andWhere("note.visibility = 'public'")
|
||||
.andWhere("note.channelId IS NULL")
|
||||
.innerJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner");
|
||||
.leftJoinAndSelect("renote.user", "renoteUser");
|
||||
|
||||
generateRepliesQuery(query, ps.withReplies, user);
|
||||
if (user) {
|
||||
|
@ -97,16 +97,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||
}),
|
||||
)
|
||||
.innerJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner")
|
||||
.setParameters(followingQuery.getParameters());
|
||||
|
||||
generateListQuery(query, user);
|
||||
|
@ -91,16 +91,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||
.andWhere("note.visibility = 'public'")
|
||||
.andWhere("note.userHost IS NULL")
|
||||
.innerJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner");
|
||||
.leftJoinAndSelect("renote.user", "renoteUser");
|
||||
|
||||
generateChannelQuery(query, user);
|
||||
generateRepliesQuery(query, ps.withReplies, user);
|
||||
|
@ -56,16 +56,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||
}),
|
||||
)
|
||||
.innerJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner");
|
||||
.leftJoinAndSelect("renote.user", "renoteUser");
|
||||
|
||||
generateVisibilityQuery(query, user);
|
||||
generateMutedUserQuery(query, user);
|
||||
|
@ -91,16 +91,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||
.andWhere(`note.userHost IN (:...instances)`, { instances: m.recommendedInstances })
|
||||
.andWhere("note.visibility = 'public'")
|
||||
.innerJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner");
|
||||
.leftJoinAndSelect("renote.user", "renoteUser");
|
||||
|
||||
generateChannelQuery(query, user);
|
||||
generateRepliesQuery(query, ps.withReplies, user);
|
||||
|
@ -66,16 +66,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||
}
|
||||
|
||||
query
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner");
|
||||
.leftJoinAndSelect("renote.user", "renoteUser");
|
||||
|
||||
generateVisibilityQuery(query, user);
|
||||
if (user) generateMutedUserQuery(query, user);
|
||||
|
@ -43,16 +43,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||
)
|
||||
.andWhere("note.replyId = :replyId", { replyId: ps.noteId })
|
||||
.innerJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner");
|
||||
.leftJoinAndSelect("renote.user", "renoteUser");
|
||||
|
||||
generateVisibilityQuery(query, user);
|
||||
if (user) generateMutedUserQuery(query, user);
|
||||
|
@ -76,16 +76,10 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||
ps.untilId,
|
||||
)
|
||||
.innerJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner");
|
||||
.leftJoinAndSelect("renote.user", "renoteUser");
|
||||
|
||||
generateVisibilityQuery(query, me);
|
||||
if (me) generateMutedUserQuery(query, me);
|
||||
|
@ -75,16 +75,10 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||
|
||||
query
|
||||
.innerJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner");
|
||||
.leftJoinAndSelect("renote.user", "renoteUser");
|
||||
|
||||
generateFtsQuery(query, ps.query);
|
||||
generateVisibilityQuery(query, me);
|
||||
|
@ -75,16 +75,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||
ps.untilDate,
|
||||
)
|
||||
.innerJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner");
|
||||
.leftJoinAndSelect("renote.user", "renoteUser");
|
||||
|
||||
await generateFollowingQuery(query, user);
|
||||
generateListQuery(query, user);
|
||||
|
@ -80,16 +80,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||
"userListJoining.userId = note.userId",
|
||||
)
|
||||
.innerJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner")
|
||||
.andWhere("userListJoining.userListId = :userListId", {
|
||||
userListId: list.id,
|
||||
});
|
||||
|
@ -76,16 +76,10 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||
)
|
||||
.andWhere("note.userId = :userId", { userId: user.id })
|
||||
.innerJoinAndSelect("note.user", "user")
|
||||
.leftJoinAndSelect("user.avatar", "avatar")
|
||||
.leftJoinAndSelect("user.banner", "banner")
|
||||
.leftJoinAndSelect("note.reply", "reply")
|
||||
.leftJoinAndSelect("note.renote", "renote")
|
||||
.leftJoinAndSelect("reply.user", "replyUser")
|
||||
.leftJoinAndSelect("replyUser.avatar", "replyUserAvatar")
|
||||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner");
|
||||
.leftJoinAndSelect("renote.user", "renoteUser");
|
||||
|
||||
generateVisibilityQuery(query, me);
|
||||
if (me) {
|
||||
|
@ -35,11 +35,11 @@ export class UserConverter {
|
||||
const profile = UserProfiles.findOneBy({ userId: u.id });
|
||||
const bio = profile.then(profile => MfmHelpers.toHtml(mfm.parse(profile?.description ?? ""), profile?.mentions, u.host).then(p => p ?? escapeMFM(profile?.description ?? "")));
|
||||
const avatar = u.avatarId
|
||||
? (DriveFiles.findOneBy({ id: u.avatarId }))
|
||||
? u.avatarUrl ?? (DriveFiles.findOneBy({ id: u.avatarId }))
|
||||
.then(p => p?.url ?? Users.getIdenticonUrl(u.id))
|
||||
: Users.getIdenticonUrl(u.id);
|
||||
const banner = u.bannerId
|
||||
? (DriveFiles.findOneBy({ id: u.bannerId }))
|
||||
? u.bannerUrl ?? (DriveFiles.findOneBy({ id: u.bannerId }))
|
||||
.then(p => p?.url ?? `${config.url}/static-assets/transparent.png`)
|
||||
: `${config.url}/static-assets/transparent.png`;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Note } from "@/models/entities/note.js";
|
||||
import { ILocalUser, IRemoteUser, User } from "@/models/entities/user.js";
|
||||
import {
|
||||
Blockings,
|
||||
Blockings, DriveFiles,
|
||||
Followings,
|
||||
FollowRequests,
|
||||
Mutings,
|
||||
@ -173,11 +173,15 @@ export class UserHelpers {
|
||||
if (avatar) {
|
||||
const file = await MediaHelpers.uploadMediaBasic(avatar, ctx);
|
||||
updates.avatarId = file.id;
|
||||
updates.avatarBlurhash = file.blurhash;
|
||||
updates.avatarUrl = DriveFiles.getDatabasePrefetchUrl(file, true);
|
||||
}
|
||||
|
||||
if (header) {
|
||||
const file = await MediaHelpers.uploadMediaBasic(header, ctx);
|
||||
updates.bannerId = file.id;
|
||||
updates.bannerBlurhash = file.blurhash;
|
||||
updates.bannerUrl = DriveFiles.getDatabasePrefetchUrl(file, false);
|
||||
}
|
||||
|
||||
if (formData.fields_attributes) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import { InternalStorage } from "./internal-storage.js";
|
||||
import { DriveFiles, Instances } from "@/models/index.js";
|
||||
import { DriveFiles, Instances, Users } from "@/models/index.js";
|
||||
import {
|
||||
driveChart,
|
||||
perUserDriveChart,
|
||||
@ -81,6 +81,8 @@ async function postProcess(file: DriveFile, isExpired = false) {
|
||||
thumbnailAccessKey: `thumbnail-${uuid()}`,
|
||||
webpublicAccessKey: `webpublic-${uuid()}`,
|
||||
});
|
||||
Users.update({ avatarId: file.id }, { avatarUrl: file.uri });
|
||||
Users.update({ bannerId: file.id }, { bannerUrl: file.uri });
|
||||
} else {
|
||||
DriveFiles.delete(file.id);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user