@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export class Userannouncement1688647797135 {
|
||||
name = 'Userannouncement1688647797135'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "announcement" ADD COLUMN "userId" character varying(32)`);
|
||||
await queryRunner.query(`ALTER TABLE "announcement" ADD COLUMN "closeDuration" integer NOT NULL DEFAULT 0`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_fd25dfe3da37df1715f11ba6ec" ON "announcement" ("userId") `);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_fd25dfe3da37df1715f11ba6ec"`);
|
||||
await queryRunner.query(`ALTER TABLE "announcement" DROP COLUMN "userId"`);
|
||||
await queryRunner.query(`ALTER TABLE "announcement" DROP COLUMN "closeDuration"`);
|
||||
}
|
||||
}
|
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { In, IsNull, Not } from 'typeorm';
|
||||
import { In, Not } from 'typeorm';
|
||||
import * as Redis from 'ioredis';
|
||||
import _Ajv from 'ajv';
|
||||
import { ModuleRef } from '@nestjs/core';
|
||||
@@ -250,11 +250,9 @@ export class UserEntityService implements OnModuleInit {
|
||||
userId: userId,
|
||||
});
|
||||
|
||||
const id = reads.length > 0 ? Not(In(reads.map(read => read.announcementId))) : undefined;
|
||||
const count = await this.announcementsRepository.countBy([
|
||||
{ id, userId: IsNull() },
|
||||
{ id, userId: userId },
|
||||
]);
|
||||
const count = await this.announcementsRepository.countBy(reads.length > 0 ? {
|
||||
id: Not(In(reads.map(read => read.announcementId))),
|
||||
} : {});
|
||||
|
||||
return count > 0;
|
||||
}
|
||||
|
@@ -38,19 +38,6 @@ export class Announcement {
|
||||
})
|
||||
public imageUrl: string | null;
|
||||
|
||||
@Index()
|
||||
@Column('varchar', {
|
||||
...id(),
|
||||
nullable: true,
|
||||
})
|
||||
public userId: string | null;
|
||||
|
||||
@Column('integer', {
|
||||
nullable: false,
|
||||
default: 0,
|
||||
})
|
||||
public closeDuration: number;
|
||||
|
||||
constructor(data: Partial<Announcement>) {
|
||||
if (data == null) return;
|
||||
|
||||
|
@@ -47,14 +47,6 @@ export const meta = {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
closeDuration: {
|
||||
type: 'number',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
@@ -65,8 +57,6 @@ export const paramDef = {
|
||||
title: { type: 'string', minLength: 1 },
|
||||
text: { type: 'string', minLength: 1 },
|
||||
imageUrl: { type: 'string', nullable: true, minLength: 1 },
|
||||
userId: { type: 'string', nullable: true, format: 'misskey:id' },
|
||||
closeDuration: { type: 'number', nullable: false },
|
||||
},
|
||||
required: ['title', 'text', 'imageUrl'],
|
||||
} as const;
|
||||
@@ -88,8 +78,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
title: ps.title,
|
||||
text: ps.text,
|
||||
imageUrl: ps.imageUrl,
|
||||
userId: ps.userId ?? null,
|
||||
closeDuration: ps.closeDuration,
|
||||
}).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0]));
|
||||
|
||||
return Object.assign({}, announcement, { createdAt: announcement.createdAt.toISOString(), updatedAt: null });
|
||||
|
@@ -4,12 +4,10 @@
|
||||
*/
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { In } from 'typeorm';
|
||||
import type { AnnouncementsRepository, AnnouncementReadsRepository, UsersRepository } from '@/models/index.js';
|
||||
import type { AnnouncementsRepository, AnnouncementReadsRepository } from '@/models/index.js';
|
||||
import type { Announcement } from '@/models/entities/Announcement.js';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { QueryService } from '@/core/QueryService.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
|
||||
export const meta = {
|
||||
@@ -53,23 +51,10 @@ export const meta = {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
user: {
|
||||
type: 'object',
|
||||
optional: true, nullable: false,
|
||||
ref: 'UserLite',
|
||||
},
|
||||
reads: {
|
||||
type: 'number',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
closeDuration: {
|
||||
type: 'number',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -81,7 +66,6 @@ export const paramDef = {
|
||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||
sinceId: { type: 'string', format: 'misskey:id' },
|
||||
untilId: { type: 'string', format: 'misskey:id' },
|
||||
userId: { type: 'string', format: 'misskey:id' },
|
||||
},
|
||||
required: [],
|
||||
} as const;
|
||||
@@ -96,21 +80,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
@Inject(DI.announcementReadsRepository)
|
||||
private announcementReadsRepository: AnnouncementReadsRepository,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
private queryService: QueryService,
|
||||
private userEntityService: UserEntityService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const builder = this.announcementsRepository.createQueryBuilder('announcement');
|
||||
if (ps.userId) {
|
||||
builder.where('"userId" = :userId', { userId: ps.userId });
|
||||
} else {
|
||||
builder.where('"userId" IS NULL');
|
||||
}
|
||||
|
||||
const query = this.queryService.makePaginationQuery(builder, ps.sinceId, ps.untilId);
|
||||
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId);
|
||||
|
||||
const announcements = await query.limit(ps.limit).getMany();
|
||||
|
||||
@@ -122,13 +95,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
}));
|
||||
}
|
||||
|
||||
const users = await this.usersRepository.findBy({
|
||||
id: In(announcements.map(a => a.userId).filter(id => id != null)),
|
||||
});
|
||||
const packedUsers = await this.userEntityService.packMany(users, me, {
|
||||
detail: false,
|
||||
});
|
||||
|
||||
return announcements.map(announcement => ({
|
||||
id: announcement.id,
|
||||
createdAt: announcement.createdAt.toISOString(),
|
||||
@@ -136,10 +102,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
title: announcement.title,
|
||||
text: announcement.text,
|
||||
imageUrl: announcement.imageUrl,
|
||||
userId: announcement.userId,
|
||||
user: packedUsers.find(user => user.id === announcement.userId),
|
||||
reads: reads.get(announcement)!,
|
||||
closeDuration: announcement.closeDuration,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import type { AnnouncementReadsRepository, AnnouncementsRepository } from '@/models/index.js';
|
||||
import type { AnnouncementsRepository } from '@/models/index.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
@@ -31,10 +31,8 @@ export const paramDef = {
|
||||
title: { type: 'string', minLength: 1 },
|
||||
text: { type: 'string', minLength: 1 },
|
||||
imageUrl: { type: 'string', nullable: true, minLength: 0 },
|
||||
userId: { type: 'string', nullable: true, format: 'misskey:id' },
|
||||
closeDuration: { type: 'number', nullable: false },
|
||||
},
|
||||
required: ['id', 'title', 'text', 'imageUrl', 'closeDuration'],
|
||||
required: ['id', 'title', 'text', 'imageUrl'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
@@ -43,27 +41,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
constructor(
|
||||
@Inject(DI.announcementsRepository)
|
||||
private announcementsRepository: AnnouncementsRepository,
|
||||
|
||||
@Inject(DI.announcementReadsRepository)
|
||||
private announcementsReadsRepository: AnnouncementReadsRepository,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const announcement = await this.announcementsRepository.findOneBy({ id: ps.id });
|
||||
|
||||
if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement);
|
||||
|
||||
if (announcement.userId && announcement.userId !== ps.userId) {
|
||||
await this.announcementsReadsRepository.delete({ id: announcement.id, userId: announcement.userId });
|
||||
}
|
||||
|
||||
await this.announcementsRepository.update(announcement.id, {
|
||||
updatedAt: new Date(),
|
||||
title: ps.title,
|
||||
text: ps.text,
|
||||
/* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- 空の文字列の場合、nullを渡すようにするため */
|
||||
imageUrl: ps.imageUrl || null,
|
||||
userId: ps.userId ?? null,
|
||||
closeDuration: ps.closeDuration,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@@ -53,14 +53,6 @@ export const meta = {
|
||||
type: 'boolean',
|
||||
optional: true, nullable: false,
|
||||
},
|
||||
isPrivate: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
closeDuration: {
|
||||
type: 'number',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -73,7 +65,6 @@ export const paramDef = {
|
||||
withUnreads: { type: 'boolean', default: false },
|
||||
sinceId: { type: 'string', format: 'misskey:id' },
|
||||
untilId: { type: 'string', format: 'misskey:id' },
|
||||
privateOnly: { type: 'boolean', default: false },
|
||||
},
|
||||
required: [],
|
||||
} as const;
|
||||
@@ -91,19 +82,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
private queryService: QueryService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const builder = this.announcementsRepository.createQueryBuilder('announcement');
|
||||
if (me) {
|
||||
if (ps.privateOnly) {
|
||||
builder.where('"userId" = :userId', { userId: me.id });
|
||||
} else {
|
||||
builder.where('"userId" IS NULL');
|
||||
builder.orWhere('"userId" = :userId', { userId: me.id });
|
||||
}
|
||||
} else {
|
||||
builder.where('"userId" IS NULL');
|
||||
}
|
||||
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId);
|
||||
|
||||
const query = this.queryService.makePaginationQuery(builder, ps.sinceId, ps.untilId);
|
||||
const announcements = await query.limit(ps.limit).getMany();
|
||||
|
||||
if (me) {
|
||||
@@ -120,7 +100,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
...a,
|
||||
createdAt: a.createdAt.toISOString(),
|
||||
updatedAt: a.updatedAt?.toISOString() ?? null,
|
||||
isPrivate: !!a.userId,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
@@ -4,7 +4,6 @@
|
||||
*/
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { IsNull } from 'typeorm';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import type { AnnouncementReadsRepository, AnnouncementsRepository } from '@/models/index.js';
|
||||
@@ -53,18 +52,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
// Check if announcement exists
|
||||
const announcementExist = await this.announcementsRepository.exist({
|
||||
where: [
|
||||
{
|
||||
id: ps.announcementId,
|
||||
userId: IsNull(),
|
||||
},
|
||||
{
|
||||
id: ps.announcementId,
|
||||
userId: me.id,
|
||||
}
|
||||
]
|
||||
});
|
||||
const announcementExist = await this.announcementsRepository.exist({ where: { id: ps.announcementId } });
|
||||
|
||||
if (!announcementExist) {
|
||||
throw new ApiError(meta.errors.noSuchAnnouncement);
|
||||
|
Reference in New Issue
Block a user