계정 아이콘 등록과 목록 내리기 제한을 조정한다
This commit is contained in:
@@ -434,13 +434,14 @@ export const createInMemoryUserRepository = (hasher: PasswordHasher = createPass
|
||||
updatedAt: Date,
|
||||
dayStart: Date,
|
||||
consumeDailyQuota: boolean,
|
||||
allowCutoffEquality = false
|
||||
allowCutoffEquality = false,
|
||||
enforceCooldown = true
|
||||
): Promise<string | null> {
|
||||
for (const user of usersByName.values()) {
|
||||
if (user.id !== userId) {
|
||||
continue;
|
||||
}
|
||||
if (user.picture !== 'default.jpg' && user.iconUpdatedAt) {
|
||||
if (enforceCooldown && user.picture !== 'default.jpg' && user.iconUpdatedAt) {
|
||||
const previousUpdate = new Date(user.iconUpdatedAt);
|
||||
if (allowCutoffEquality ? previousUpdate > dayStart : previousUpdate >= dayStart) {
|
||||
return null;
|
||||
@@ -468,12 +469,9 @@ export const createInMemoryUserRepository = (hasher: PasswordHasher = createPass
|
||||
.filter((icon) => icon.userId === userId && (includeRetired || !icon.retiredAt))
|
||||
.sort((a, b) => a.createdAt.localeCompare(b.createdAt) || a.id.localeCompare(b.id));
|
||||
},
|
||||
async addIconForWindow(userId, picture, imageServer, now, uploadCutoff, maxActive) {
|
||||
async addIconForWindow(userId, picture, imageServer, now, maxActive) {
|
||||
const user = [...usersByName.values()].find((candidate) => candidate.id === userId);
|
||||
if (!user) return { ok: false, reason: 'NOT_FOUND' };
|
||||
if (user.iconUpdatedAt && new Date(user.iconUpdatedAt) > uploadCutoff) {
|
||||
return { ok: false, reason: 'COOLDOWN' };
|
||||
}
|
||||
const active = [...iconsById.values()].filter((icon) => icon.userId === userId && !icon.retiredAt);
|
||||
if (active.length >= maxActive) return { ok: false, reason: 'LIMIT' };
|
||||
const revision = nextRevision(user, now);
|
||||
|
||||
@@ -607,7 +607,8 @@ export const createPostgresUserRepository = (
|
||||
updatedAt: Date,
|
||||
dayStart: Date,
|
||||
consumeDailyQuota: boolean,
|
||||
allowCutoffEquality = false
|
||||
allowCutoffEquality = false,
|
||||
enforceCooldown = true
|
||||
): Promise<string | null> {
|
||||
const rows = await prisma.$queryRaw<Array<{ iconRevision: Date }>>(GatewayPrisma.sql`
|
||||
UPDATE "app_user"
|
||||
@@ -623,7 +624,7 @@ export const createPostgresUserRepository = (
|
||||
COALESCE("icon_revision", "icon_updated_at", "created_at") + INTERVAL '1 millisecond'
|
||||
)
|
||||
WHERE "id" = ${userId}
|
||||
AND (
|
||||
AND (NOT ${enforceCooldown} OR
|
||||
"picture" = 'default.jpg'
|
||||
OR "icon_updated_at" IS NULL
|
||||
OR "icon_updated_at" < ${dayStart}
|
||||
@@ -640,20 +641,16 @@ export const createPostgresUserRepository = (
|
||||
});
|
||||
return rows.map(mapIcon);
|
||||
},
|
||||
async addIconForWindow(userId, picture, imageServer, now, uploadCutoff, maxActive) {
|
||||
async addIconForWindow(userId, picture, imageServer, now, maxActive) {
|
||||
return prisma.$transaction(async (tx) => {
|
||||
const users = await tx.$queryRaw<
|
||||
Array<{ createdAt: Date; iconUpdatedAt: Date | null; iconRevision: Date | null }>
|
||||
Array<{ createdAt: Date; iconRevision: Date | null }>
|
||||
>(GatewayPrisma.sql`
|
||||
SELECT "created_at" AS "createdAt", "icon_updated_at" AS "iconUpdatedAt",
|
||||
"icon_revision" AS "iconRevision"
|
||||
SELECT "created_at" AS "createdAt", "icon_revision" AS "iconRevision"
|
||||
FROM "app_user" WHERE "id" = ${userId} FOR UPDATE
|
||||
`);
|
||||
const user = users[0];
|
||||
if (!user) return { ok: false as const, reason: 'NOT_FOUND' as const };
|
||||
if (user.iconUpdatedAt && user.iconUpdatedAt > uploadCutoff) {
|
||||
return { ok: false as const, reason: 'COOLDOWN' as const };
|
||||
}
|
||||
const activeCount = await tx.userIcon.count({ where: { userId, retiredAt: null } });
|
||||
if (activeCount >= maxActive) return { ok: false as const, reason: 'LIMIT' as const };
|
||||
const revision = new Date(
|
||||
|
||||
@@ -63,7 +63,7 @@ export interface SpecialAccountAccessGrantRecord {
|
||||
}
|
||||
|
||||
export type AddUserIconResult =
|
||||
{ ok: true; icon: UserIconRecord; revision: string } | { ok: false; reason: 'COOLDOWN' | 'LIMIT' | 'NOT_FOUND' };
|
||||
{ ok: true; icon: UserIconRecord; revision: string } | { ok: false; reason: 'LIMIT' | 'NOT_FOUND' };
|
||||
|
||||
export type RetireUserIconResult =
|
||||
| { ok: true; icon: UserIconRecord; revision: string; preferredChanged: boolean }
|
||||
@@ -233,7 +233,8 @@ export interface UserRepository {
|
||||
updatedAt: Date,
|
||||
dayStart: Date,
|
||||
consumeDailyQuota: boolean,
|
||||
allowCutoffEquality?: boolean
|
||||
allowCutoffEquality?: boolean,
|
||||
enforceCooldown?: boolean
|
||||
): Promise<string | null>;
|
||||
listIcons(userId: string, includeRetired?: boolean): Promise<UserIconRecord[]>;
|
||||
addIconForWindow(
|
||||
@@ -241,7 +242,6 @@ export interface UserRepository {
|
||||
picture: string,
|
||||
imageServer: number,
|
||||
now: Date,
|
||||
uploadCutoff: Date,
|
||||
maxActive: number
|
||||
): Promise<AddUserIconResult>;
|
||||
setPreferredIcon(userId: string, iconId: string, now: Date): Promise<string | null>;
|
||||
|
||||
Reference in New Issue
Block a user