summaryrefslogtreecommitdiff
path: root/packages/backend
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2023-01-05 13:59:48 +0900
committerGitHub <noreply@github.com>2023-01-05 13:59:48 +0900
commitebe340d5105595abe2406e8f386c3ab69703b73b (patch)
tree36eb93333667353fb71a430b7d5e1a700d0e904e /packages/backend
parentUpdate CHANGELOG.md (diff)
downloadmisskey-ebe340d5105595abe2406e8f386c3ab69703b73b.tar.gz
misskey-ebe340d5105595abe2406e8f386c3ab69703b73b.tar.bz2
misskey-ebe340d5105595abe2406e8f386c3ab69703b73b.zip
MisskeyPlay (#9467)
* wip * wip * wip * wip * wip * Update ui.ts * wip * wip * wip * wip * wip * wip * wip * wip * Update CHANGELOG.md * wip * wip * wip * wip * :art: * wip * :v:
Diffstat (limited to '')
-rw-r--r--packages/backend/migration/1672822262496-Flash.js29
-rw-r--r--packages/backend/src/core/CoreModule.ts12
-rw-r--r--packages/backend/src/core/entities/FlashEntityService.ts55
-rw-r--r--packages/backend/src/core/entities/FlashLikeEntityService.ts44
-rw-r--r--packages/backend/src/di-symbols.ts2
-rw-r--r--packages/backend/src/models/RepositoryModule.ts18
-rw-r--r--packages/backend/src/models/entities/Flash.ts60
-rw-r--r--packages/backend/src/models/entities/FlashLike.ts33
-rw-r--r--packages/backend/src/models/index.ts6
-rw-r--r--packages/backend/src/postgre.ts4
-rw-r--r--packages/backend/src/server/api/EndpointsModule.ts36
-rw-r--r--packages/backend/src/server/api/endpoints.ts18
-rw-r--r--packages/backend/src/server/api/endpoints/flash/create.ts66
-rw-r--r--packages/backend/src/server/api/endpoints/flash/delete.ts56
-rw-r--r--packages/backend/src/server/api/endpoints/flash/featured.ts48
-rw-r--r--packages/backend/src/server/api/endpoints/flash/like.ts87
-rw-r--r--packages/backend/src/server/api/endpoints/flash/my-likes.ts68
-rw-r--r--packages/backend/src/server/api/endpoints/flash/my.ts57
-rw-r--r--packages/backend/src/server/api/endpoints/flash/show.ts60
-rw-r--r--packages/backend/src/server/api/endpoints/flash/unlike.ts68
-rw-r--r--packages/backend/src/server/api/endpoints/flash/update.ts78
21 files changed, 904 insertions, 1 deletions
diff --git a/packages/backend/migration/1672822262496-Flash.js b/packages/backend/migration/1672822262496-Flash.js
new file mode 100644
index 0000000000..6c2338fab2
--- /dev/null
+++ b/packages/backend/migration/1672822262496-Flash.js
@@ -0,0 +1,29 @@
+export class Flash1672822262496 {
+ name = 'Flash1672822262496'
+
+ async up(queryRunner) {
+ await queryRunner.query(`CREATE TABLE "flash" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, "title" character varying(256) NOT NULL, "summary" character varying(1024) NOT NULL, "userId" character varying(32) NOT NULL, "script" character varying(16384) NOT NULL, "permissions" character varying(256) array NOT NULL DEFAULT '{}', "likedCount" integer NOT NULL DEFAULT '0', CONSTRAINT "PK_0c01a2c1c5f2266942dd1b3fdbc" PRIMARY KEY ("id")); COMMENT ON COLUMN "flash"."createdAt" IS 'The created date of the Flash.'; COMMENT ON COLUMN "flash"."updatedAt" IS 'The updated date of the Flash.'; COMMENT ON COLUMN "flash"."userId" IS 'The ID of author.'`);
+ await queryRunner.query(`CREATE INDEX "IDX_149d2e44785707548c82999b01" ON "flash" ("createdAt") `);
+ await queryRunner.query(`CREATE INDEX "IDX_3aa8ea9a8f15214ad91638c0a7" ON "flash" ("updatedAt") `);
+ await queryRunner.query(`CREATE INDEX "IDX_9b88250fc2fd009b8f1b5623ed" ON "flash" ("userId") `);
+ await queryRunner.query(`CREATE TABLE "flash_like" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "flashId" character varying(32) NOT NULL, CONSTRAINT "PK_d110109ee310588d63d6183b233" PRIMARY KEY ("id"))`);
+ await queryRunner.query(`CREATE INDEX "IDX_60c4af1c19a7a75f1592f93b28" ON "flash_like" ("userId") `);
+ await queryRunner.query(`CREATE UNIQUE INDEX "IDX_cfbfeeccb0cbedcd660b17eb07" ON "flash_like" ("userId", "flashId") `);
+ await queryRunner.query(`ALTER TABLE "flash" ADD CONSTRAINT "FK_9b88250fc2fd009b8f1b5623ed5" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
+ await queryRunner.query(`ALTER TABLE "flash_like" ADD CONSTRAINT "FK_60c4af1c19a7a75f1592f93b287" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
+ await queryRunner.query(`ALTER TABLE "flash_like" ADD CONSTRAINT "FK_6c16fe0e93b7a1951eca624b76a" FOREIGN KEY ("flashId") REFERENCES "flash"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
+ }
+
+ async down(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "flash_like" DROP CONSTRAINT "FK_6c16fe0e93b7a1951eca624b76a"`);
+ await queryRunner.query(`ALTER TABLE "flash_like" DROP CONSTRAINT "FK_60c4af1c19a7a75f1592f93b287"`);
+ await queryRunner.query(`ALTER TABLE "flash" DROP CONSTRAINT "FK_9b88250fc2fd009b8f1b5623ed5"`);
+ await queryRunner.query(`DROP INDEX "public"."IDX_cfbfeeccb0cbedcd660b17eb07"`);
+ await queryRunner.query(`DROP INDEX "public"."IDX_60c4af1c19a7a75f1592f93b28"`);
+ await queryRunner.query(`DROP TABLE "flash_like"`);
+ await queryRunner.query(`DROP INDEX "public"."IDX_9b88250fc2fd009b8f1b5623ed"`);
+ await queryRunner.query(`DROP INDEX "public"."IDX_3aa8ea9a8f15214ad91638c0a7"`);
+ await queryRunner.query(`DROP INDEX "public"."IDX_149d2e44785707548c82999b01"`);
+ await queryRunner.query(`DROP TABLE "flash"`);
+ }
+}
diff --git a/packages/backend/src/core/CoreModule.ts b/packages/backend/src/core/CoreModule.ts
index 7c6d12abf8..2f17fa389a 100644
--- a/packages/backend/src/core/CoreModule.ts
+++ b/packages/backend/src/core/CoreModule.ts
@@ -95,6 +95,8 @@ import { UserEntityService } from './entities/UserEntityService.js';
import { UserGroupEntityService } from './entities/UserGroupEntityService.js';
import { UserGroupInvitationEntityService } from './entities/UserGroupInvitationEntityService.js';
import { UserListEntityService } from './entities/UserListEntityService.js';
+import { FlashEntityService } from './entities/FlashEntityService.js';
+import { FlashLikeEntityService } from './entities/FlashLikeEntityService.js';
import { ApAudienceService } from './activitypub/ApAudienceService.js';
import { ApDbResolverService } from './activitypub/ApDbResolverService.js';
import { ApDeliverManagerService } from './activitypub/ApDeliverManagerService.js';
@@ -216,6 +218,8 @@ const $UserEntityService: Provider = { provide: 'UserEntityService', useExisting
const $UserGroupEntityService: Provider = { provide: 'UserGroupEntityService', useExisting: UserGroupEntityService };
const $UserGroupInvitationEntityService: Provider = { provide: 'UserGroupInvitationEntityService', useExisting: UserGroupInvitationEntityService };
const $UserListEntityService: Provider = { provide: 'UserListEntityService', useExisting: UserListEntityService };
+const $FlashEntityService: Provider = { provide: 'FlashEntityService', useExisting: FlashEntityService };
+const $FlashLikeEntityService: Provider = { provide: 'FlashLikeEntityService', useExisting: FlashLikeEntityService };
const $ApAudienceService: Provider = { provide: 'ApAudienceService', useExisting: ApAudienceService };
const $ApDbResolverService: Provider = { provide: 'ApDbResolverService', useExisting: ApDbResolverService };
@@ -338,6 +342,8 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
UserGroupEntityService,
UserGroupInvitationEntityService,
UserListEntityService,
+ FlashEntityService,
+ FlashLikeEntityService,
ApAudienceService,
ApDbResolverService,
ApDeliverManagerService,
@@ -455,6 +461,8 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$UserGroupEntityService,
$UserGroupInvitationEntityService,
$UserListEntityService,
+ $FlashEntityService,
+ $FlashLikeEntityService,
$ApAudienceService,
$ApDbResolverService,
$ApDeliverManagerService,
@@ -572,6 +580,8 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
UserGroupEntityService,
UserGroupInvitationEntityService,
UserListEntityService,
+ FlashEntityService,
+ FlashLikeEntityService,
ApAudienceService,
ApDbResolverService,
ApDeliverManagerService,
@@ -688,6 +698,8 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$UserGroupEntityService,
$UserGroupInvitationEntityService,
$UserListEntityService,
+ $FlashEntityService,
+ $FlashLikeEntityService,
$ApAudienceService,
$ApDbResolverService,
$ApDeliverManagerService,
diff --git a/packages/backend/src/core/entities/FlashEntityService.ts b/packages/backend/src/core/entities/FlashEntityService.ts
new file mode 100644
index 0000000000..61bd18c04f
--- /dev/null
+++ b/packages/backend/src/core/entities/FlashEntityService.ts
@@ -0,0 +1,55 @@
+import { Inject, Injectable } from '@nestjs/common';
+import { DI } from '@/di-symbols.js';
+import type { FlashsRepository, FlashLikesRepository } from '@/models/index.js';
+import { awaitAll } from '@/misc/prelude/await-all.js';
+import type { Packed } from '@/misc/schema.js';
+import type { } from '@/models/entities/Blocking.js';
+import type { User } from '@/models/entities/User.js';
+import type { Flash } from '@/models/entities/Flash.js';
+import { bindThis } from '@/decorators.js';
+import { UserEntityService } from './UserEntityService.js';
+
+@Injectable()
+export class FlashEntityService {
+ constructor(
+ @Inject(DI.flashsRepository)
+ private flashsRepository: FlashsRepository,
+
+ @Inject(DI.flashLikesRepository)
+ private flashLikesRepository: FlashLikesRepository,
+
+ private userEntityService: UserEntityService,
+ ) {
+ }
+
+ @bindThis
+ public async pack(
+ src: Flash['id'] | Flash,
+ me?: { id: User['id'] } | null | undefined,
+ ): Promise<Packed<'Flash'>> {
+ const meId = me ? me.id : null;
+ const flash = typeof src === 'object' ? src : await this.flashsRepository.findOneByOrFail({ id: src });
+
+ return await awaitAll({
+ id: flash.id,
+ createdAt: flash.createdAt.toISOString(),
+ updatedAt: flash.updatedAt.toISOString(),
+ userId: flash.userId,
+ user: this.userEntityService.pack(flash.user ?? flash.userId, me), // { detail: true } すると無限ループするので注意
+ title: flash.title,
+ summary: flash.summary,
+ script: flash.script,
+ likedCount: flash.likedCount,
+ isLiked: meId ? await this.flashLikesRepository.findOneBy({ flashId: flash.id, userId: meId }).then(x => x != null) : undefined,
+ });
+ }
+
+ @bindThis
+ public packMany(
+ flashs: Flash[],
+ me?: { id: User['id'] } | null | undefined,
+ ) {
+ return Promise.all(flashs.map(x => this.pack(x, me)));
+ }
+}
+
diff --git a/packages/backend/src/core/entities/FlashLikeEntityService.ts b/packages/backend/src/core/entities/FlashLikeEntityService.ts
new file mode 100644
index 0000000000..dcf12d53ea
--- /dev/null
+++ b/packages/backend/src/core/entities/FlashLikeEntityService.ts
@@ -0,0 +1,44 @@
+import { Inject, Injectable } from '@nestjs/common';
+import { DI } from '@/di-symbols.js';
+import type { FlashLikesRepository } from '@/models/index.js';
+import { awaitAll } from '@/misc/prelude/await-all.js';
+import type { Packed } from '@/misc/schema.js';
+import type { } from '@/models/entities/Blocking.js';
+import type { User } from '@/models/entities/User.js';
+import type { FlashLike } from '@/models/entities/FlashLike.js';
+import { bindThis } from '@/decorators.js';
+import { UserEntityService } from './UserEntityService.js';
+import { FlashEntityService } from './FlashEntityService.js';
+
+@Injectable()
+export class FlashLikeEntityService {
+ constructor(
+ @Inject(DI.flashLikesRepository)
+ private flashLikesRepository: FlashLikesRepository,
+
+ private flashEntityService: FlashEntityService,
+ ) {
+ }
+
+ @bindThis
+ public async pack(
+ src: FlashLike['id'] | FlashLike,
+ me?: { id: User['id'] } | null | undefined,
+ ) {
+ const like = typeof src === 'object' ? src : await this.flashLikesRepository.findOneByOrFail({ id: src });
+
+ return {
+ id: like.id,
+ flash: await this.flashEntityService.pack(like.flash ?? like.flashId, me),
+ };
+ }
+
+ @bindThis
+ public packMany(
+ likes: any[],
+ me: { id: User['id'] },
+ ) {
+ return Promise.all(likes.map(x => this.pack(x, me)));
+ }
+}
+
diff --git a/packages/backend/src/di-symbols.ts b/packages/backend/src/di-symbols.ts
index d2a361405f..9719d773ca 100644
--- a/packages/backend/src/di-symbols.ts
+++ b/packages/backend/src/di-symbols.ts
@@ -69,5 +69,7 @@ export const DI = {
adsRepository: Symbol('adsRepository'),
passwordResetRequestsRepository: Symbol('passwordResetRequestsRepository'),
retentionAggregationsRepository: Symbol('retentionAggregationsRepository'),
+ flashsRepository: Symbol('flashsRepository'),
+ flashLikesRepository: Symbol('flashLikesRepository'),
//#endregion
};
diff --git a/packages/backend/src/models/RepositoryModule.ts b/packages/backend/src/models/RepositoryModule.ts
index e22f0517ca..a5d5a63931 100644
--- a/packages/backend/src/models/RepositoryModule.ts
+++ b/packages/backend/src/models/RepositoryModule.ts
@@ -1,6 +1,6 @@
import { Module } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
-import { User, Note, Announcement, AnnouncementRead, App, NoteFavorite, NoteThreadMuting, NoteReaction, NoteUnread, Notification, Poll, PollVote, UserProfile, UserKeypair, UserPending, AttestationChallenge, UserSecurityKey, UserPublickey, UserList, UserListJoining, UserGroup, UserGroupJoining, UserGroupInvitation, UserNotePining, UserIp, UsedUsername, Following, FollowRequest, Instance, Emoji, DriveFile, DriveFolder, Meta, Muting, Blocking, SwSubscription, Hashtag, AbuseUserReport, RegistrationTicket, AuthSession, AccessToken, Signin, MessagingMessage, Page, PageLike, GalleryPost, GalleryLike, ModerationLog, Clip, ClipNote, Antenna, AntennaNote, PromoNote, PromoRead, Relay, MutedNote, Channel, ChannelFollowing, ChannelNotePining, RegistryItem, Webhook, Ad, PasswordResetRequest, RetentionAggregation } from './index.js';
+import { User, Note, Announcement, AnnouncementRead, App, NoteFavorite, NoteThreadMuting, NoteReaction, NoteUnread, Notification, Poll, PollVote, UserProfile, UserKeypair, UserPending, AttestationChallenge, UserSecurityKey, UserPublickey, UserList, UserListJoining, UserGroup, UserGroupJoining, UserGroupInvitation, UserNotePining, UserIp, UsedUsername, Following, FollowRequest, Instance, Emoji, DriveFile, DriveFolder, Meta, Muting, Blocking, SwSubscription, Hashtag, AbuseUserReport, RegistrationTicket, AuthSession, AccessToken, Signin, MessagingMessage, Page, PageLike, GalleryPost, GalleryLike, ModerationLog, Clip, ClipNote, Antenna, AntennaNote, PromoNote, PromoRead, Relay, MutedNote, Channel, ChannelFollowing, ChannelNotePining, RegistryItem, Webhook, Ad, PasswordResetRequest, RetentionAggregation, FlashLike, Flash } from './index.js';
import type { DataSource } from 'typeorm';
import type { Provider } from '@nestjs/common';
@@ -388,6 +388,18 @@ const $retentionAggregationsRepository: Provider = {
inject: [DI.db],
};
+const $flashsRepository: Provider = {
+ provide: DI.flashsRepository,
+ useFactory: (db: DataSource) => db.getRepository(Flash),
+ inject: [DI.db],
+};
+
+const $flashLikesRepository: Provider = {
+ provide: DI.flashLikesRepository,
+ useFactory: (db: DataSource) => db.getRepository(FlashLike),
+ inject: [DI.db],
+};
+
@Module({
imports: [
],
@@ -456,6 +468,8 @@ const $retentionAggregationsRepository: Provider = {
$adsRepository,
$passwordResetRequestsRepository,
$retentionAggregationsRepository,
+ $flashsRepository,
+ $flashLikesRepository,
],
exports: [
$usersRepository,
@@ -522,6 +536,8 @@ const $retentionAggregationsRepository: Provider = {
$adsRepository,
$passwordResetRequestsRepository,
$retentionAggregationsRepository,
+ $flashsRepository,
+ $flashLikesRepository,
],
})
export class RepositoryModule {}
diff --git a/packages/backend/src/models/entities/Flash.ts b/packages/backend/src/models/entities/Flash.ts
new file mode 100644
index 0000000000..d9a6ac987c
--- /dev/null
+++ b/packages/backend/src/models/entities/Flash.ts
@@ -0,0 +1,60 @@
+import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm';
+import { id } from '../id.js';
+import { User } from './User.js';
+import { DriveFile } from './DriveFile.js';
+
+@Entity()
+export class Flash {
+ @PrimaryColumn(id())
+ public id: string;
+
+ @Index()
+ @Column('timestamp with time zone', {
+ comment: 'The created date of the Flash.',
+ })
+ public createdAt: Date;
+
+ @Index()
+ @Column('timestamp with time zone', {
+ comment: 'The updated date of the Flash.',
+ })
+ public updatedAt: Date;
+
+ @Column('varchar', {
+ length: 256,
+ })
+ public title: string;
+
+ @Column('varchar', {
+ length: 1024,
+ })
+ public summary: string;
+
+ @Index()
+ @Column({
+ ...id(),
+ comment: 'The ID of author.',
+ })
+ public userId: User['id'];
+
+ @ManyToOne(type => User, {
+ onDelete: 'CASCADE',
+ })
+ @JoinColumn()
+ public user: User | null;
+
+ @Column('varchar', {
+ length: 16384,
+ })
+ public script: string;
+
+ @Column('varchar', {
+ length: 256, array: true, default: '{}',
+ })
+ public permissions: string[];
+
+ @Column('integer', {
+ default: 0,
+ })
+ public likedCount: number;
+}
diff --git a/packages/backend/src/models/entities/FlashLike.ts b/packages/backend/src/models/entities/FlashLike.ts
new file mode 100644
index 0000000000..81d39191ca
--- /dev/null
+++ b/packages/backend/src/models/entities/FlashLike.ts
@@ -0,0 +1,33 @@
+import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm';
+import { id } from '../id.js';
+import { User } from './User.js';
+import { Flash } from './Flash.js';
+
+@Entity()
+@Index(['userId', 'flashId'], { unique: true })
+export class FlashLike {
+ @PrimaryColumn(id())
+ public id: string;
+
+ @Column('timestamp with time zone')
+ public createdAt: Date;
+
+ @Index()
+ @Column(id())
+ public userId: User['id'];
+
+ @ManyToOne(type => User, {
+ onDelete: 'CASCADE',
+ })
+ @JoinColumn()
+ public user: User | null;
+
+ @Column(id())
+ public flashId: Flash['id'];
+
+ @ManyToOne(type => Flash, {
+ onDelete: 'CASCADE',
+ })
+ @JoinColumn()
+ public flash: Flash | null;
+}
diff --git a/packages/backend/src/models/index.ts b/packages/backend/src/models/index.ts
index ca7a7c9e56..b132475747 100644
--- a/packages/backend/src/models/index.ts
+++ b/packages/backend/src/models/index.ts
@@ -62,6 +62,8 @@ import { UserSecurityKey } from '@/models/entities/UserSecurityKey.js';
import { Webhook } from '@/models/entities/Webhook.js';
import { Channel } from '@/models/entities/Channel.js';
import { RetentionAggregation } from '@/models/entities/RetentionAggregation.js';
+import { Flash } from '@/models/entities/Flash.js';
+import { FlashLike } from '@/models/entities/FlashLike.js';
import type { Repository } from 'typeorm';
export {
@@ -129,6 +131,8 @@ export {
Webhook,
Channel,
RetentionAggregation,
+ Flash,
+ FlashLike,
};
export type AbuseUserReportsRepository = Repository<AbuseUserReport>;
@@ -195,3 +199,5 @@ export type UserSecurityKeysRepository = Repository<UserSecurityKey>;
export type WebhooksRepository = Repository<Webhook>;
export type ChannelsRepository = Repository<Channel>;
export type RetentionAggregationsRepository = Repository<RetentionAggregation>;
+export type FlashsRepository = Repository<Flash>;
+export type FlashLikesRepository = Repository<FlashLike>;
diff --git a/packages/backend/src/postgre.ts b/packages/backend/src/postgre.ts
index 4b4490a0c3..4f6b157d80 100644
--- a/packages/backend/src/postgre.ts
+++ b/packages/backend/src/postgre.ts
@@ -70,6 +70,8 @@ import { UserSecurityKey } from '@/models/entities/UserSecurityKey.js';
import { Webhook } from '@/models/entities/Webhook.js';
import { Channel } from '@/models/entities/Channel.js';
import { RetentionAggregation } from '@/models/entities/RetentionAggregation.js';
+import { Flash } from '@/models/entities/Flash.js';
+import { FlashLike } from '@/models/entities/FlashLike.js';
import { Config } from '@/config.js';
import MisskeyLogger from '@/logger.js';
@@ -184,6 +186,8 @@ export const entities = [
Webhook,
UserIp,
RetentionAggregation,
+ Flash,
+ FlashLike,
...charts,
];
diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts
index 32eff7f312..60beca4f47 100644
--- a/packages/backend/src/server/api/EndpointsModule.ts
+++ b/packages/backend/src/server/api/EndpointsModule.ts
@@ -266,6 +266,15 @@ import * as ep___pages_like from './endpoints/pages/like.js';
import * as ep___pages_show from './endpoints/pages/show.js';
import * as ep___pages_unlike from './endpoints/pages/unlike.js';
import * as ep___pages_update from './endpoints/pages/update.js';
+import * as ep___flash_create from './endpoints/flash/create.js';
+import * as ep___flash_delete from './endpoints/flash/delete.js';
+import * as ep___flash_featured from './endpoints/flash/featured.js';
+import * as ep___flash_like from './endpoints/flash/like.js';
+import * as ep___flash_show from './endpoints/flash/show.js';
+import * as ep___flash_unlike from './endpoints/flash/unlike.js';
+import * as ep___flash_update from './endpoints/flash/update.js';
+import * as ep___flash_my from './endpoints/flash/my.js';
+import * as ep___flash_myLikes from './endpoints/flash/my-likes.js';
import * as ep___ping from './endpoints/ping.js';
import * as ep___pinnedUsers from './endpoints/pinned-users.js';
import * as ep___promo_read from './endpoints/promo/read.js';
@@ -587,6 +596,15 @@ const $pages_like: Provider = { provide: 'ep:pages/like', useClass: ep___pages_l
const $pages_show: Provider = { provide: 'ep:pages/show', useClass: ep___pages_show.default };
const $pages_unlike: Provider = { provide: 'ep:pages/unlike', useClass: ep___pages_unlike.default };
const $pages_update: Provider = { provide: 'ep:pages/update', useClass: ep___pages_update.default };
+const $flash_create: Provider = { provide: 'ep:flash/create', useClass: ep___flash_create.default };
+const $flash_delete: Provider = { provide: 'ep:flash/delete', useClass: ep___flash_delete.default };
+const $flash_featured: Provider = { provide: 'ep:flash/featured', useClass: ep___flash_featured.default };
+const $flash_like: Provider = { provide: 'ep:flash/like', useClass: ep___flash_like.default };
+const $flash_show: Provider = { provide: 'ep:flash/show', useClass: ep___flash_show.default };
+const $flash_unlike: Provider = { provide: 'ep:flash/unlike', useClass: ep___flash_unlike.default };
+const $flash_update: Provider = { provide: 'ep:flash/update', useClass: ep___flash_update.default };
+const $flash_my: Provider = { provide: 'ep:flash/my', useClass: ep___flash_my.default };
+const $flash_myLikes: Provider = { provide: 'ep:flash/my-likes', useClass: ep___flash_myLikes.default };
const $ping: Provider = { provide: 'ep:ping', useClass: ep___ping.default };
const $pinnedUsers: Provider = { provide: 'ep:pinned-users', useClass: ep___pinnedUsers.default };
const $promo_read: Provider = { provide: 'ep:promo/read', useClass: ep___promo_read.default };
@@ -912,6 +930,15 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$pages_show,
$pages_unlike,
$pages_update,
+ $flash_create,
+ $flash_delete,
+ $flash_featured,
+ $flash_like,
+ $flash_show,
+ $flash_unlike,
+ $flash_update,
+ $flash_my,
+ $flash_myLikes,
$ping,
$pinnedUsers,
$promo_read,
@@ -1231,6 +1258,15 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$pages_show,
$pages_unlike,
$pages_update,
+ $flash_create,
+ $flash_delete,
+ $flash_featured,
+ $flash_like,
+ $flash_show,
+ $flash_unlike,
+ $flash_update,
+ $flash_my,
+ $flash_myLikes,
$ping,
$pinnedUsers,
$promo_read,
diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts
index 49dc3b224f..d4f8be5b85 100644
--- a/packages/backend/src/server/api/endpoints.ts
+++ b/packages/backend/src/server/api/endpoints.ts
@@ -265,6 +265,15 @@ import * as ep___pages_like from './endpoints/pages/like.js';
import * as ep___pages_show from './endpoints/pages/show.js';
import * as ep___pages_unlike from './endpoints/pages/unlike.js';
import * as ep___pages_update from './endpoints/pages/update.js';
+import * as ep___flash_create from './endpoints/flash/create.js';
+import * as ep___flash_delete from './endpoints/flash/delete.js';
+import * as ep___flash_featured from './endpoints/flash/featured.js';
+import * as ep___flash_like from './endpoints/flash/like.js';
+import * as ep___flash_show from './endpoints/flash/show.js';
+import * as ep___flash_unlike from './endpoints/flash/unlike.js';
+import * as ep___flash_update from './endpoints/flash/update.js';
+import * as ep___flash_my from './endpoints/flash/my.js';
+import * as ep___flash_myLikes from './endpoints/flash/my-likes.js';
import * as ep___ping from './endpoints/ping.js';
import * as ep___pinnedUsers from './endpoints/pinned-users.js';
import * as ep___promo_read from './endpoints/promo/read.js';
@@ -584,6 +593,15 @@ const eps = [
['pages/show', ep___pages_show],
['pages/unlike', ep___pages_unlike],
['pages/update', ep___pages_update],
+ ['flash/create', ep___flash_create],
+ ['flash/delete', ep___flash_delete],
+ ['flash/featured', ep___flash_featured],
+ ['flash/like', ep___flash_like],
+ ['flash/show', ep___flash_show],
+ ['flash/unlike', ep___flash_unlike],
+ ['flash/update', ep___flash_update],
+ ['flash/my', ep___flash_my],
+ ['flash/my-likes', ep___flash_myLikes],
['ping', ep___ping],
['pinned-users', ep___pinnedUsers],
['promo/read', ep___promo_read],
diff --git a/packages/backend/src/server/api/endpoints/flash/create.ts b/packages/backend/src/server/api/endpoints/flash/create.ts
new file mode 100644
index 0000000000..a652047d98
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/flash/create.ts
@@ -0,0 +1,66 @@
+import ms from 'ms';
+import { Inject, Injectable } from '@nestjs/common';
+import type { DriveFilesRepository, FlashsRepository, PagesRepository } from '@/models/index.js';
+import { IdService } from '@/core/IdService.js';
+import { Page } from '@/models/entities/Page.js';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { PageEntityService } from '@/core/entities/PageEntityService.js';
+import { DI } from '@/di-symbols.js';
+import { FlashEntityService } from '@/core/entities/FlashEntityService.js';
+import { ApiError } from '../../error.js';
+
+export const meta = {
+ tags: ['flash'],
+
+ requireCredential: true,
+
+ kind: 'write:flash',
+
+ limit: {
+ duration: ms('1hour'),
+ max: 10,
+ },
+
+ errors: {
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ title: { type: 'string' },
+ summary: { type: 'string' },
+ script: { type: 'string' },
+ permissions: { type: 'array', items: {
+ type: 'string',
+ } },
+ },
+ required: ['title', 'summary', 'script', 'permissions'],
+} as const;
+
+// eslint-disable-next-line import/no-default-export
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> {
+ constructor(
+ @Inject(DI.flashsRepository)
+ private flashsRepository: FlashsRepository,
+
+ private flashEntityService: FlashEntityService,
+ private idService: IdService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ const flash = await this.flashsRepository.insert({
+ id: this.idService.genId(),
+ userId: me.id,
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ title: ps.title,
+ summary: ps.summary,
+ script: ps.script,
+ permissions: ps.permissions,
+ }).then(x => this.flashsRepository.findOneByOrFail(x.identifiers[0]));
+
+ return await this.flashEntityService.pack(flash);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/flash/delete.ts b/packages/backend/src/server/api/endpoints/flash/delete.ts
new file mode 100644
index 0000000000..e94ede9f68
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/flash/delete.ts
@@ -0,0 +1,56 @@
+import { Inject, Injectable } from '@nestjs/common';
+import type { FlashsRepository } from '@/models/index.js';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { DI } from '@/di-symbols.js';
+import { ApiError } from '../../error.js';
+
+export const meta = {
+ tags: ['flashs'],
+
+ requireCredential: true,
+
+ kind: 'write:flash',
+
+ errors: {
+ noSuchFlash: {
+ message: 'No such flash.',
+ code: 'NO_SUCH_FLASH',
+ id: 'de1623ef-bbb3-4289-a71e-14cfa83d9740',
+ },
+
+ accessDenied: {
+ message: 'Access denied.',
+ code: 'ACCESS_DENIED',
+ id: '1036ad7b-9f92-4fff-89c3-0e50dc941704',
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ flashId: { type: 'string', format: 'misskey:id' },
+ },
+ required: ['flashId'],
+} as const;
+
+// eslint-disable-next-line import/no-default-export
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> {
+ constructor(
+ @Inject(DI.flashsRepository)
+ private flashsRepository: FlashsRepository,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ const flash = await this.flashsRepository.findOneBy({ id: ps.flashId });
+ if (flash == null) {
+ throw new ApiError(meta.errors.noSuchFlash);
+ }
+ if (flash.userId !== me.id) {
+ throw new ApiError(meta.errors.accessDenied);
+ }
+
+ await this.flashsRepository.delete(flash.id);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/flash/featured.ts b/packages/backend/src/server/api/endpoints/flash/featured.ts
new file mode 100644
index 0000000000..570aef96d2
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/flash/featured.ts
@@ -0,0 +1,48 @@
+import { Inject, Injectable } from '@nestjs/common';
+import type { FlashsRepository } from '@/models/index.js';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { FlashEntityService } from '@/core/entities/FlashEntityService.js';
+import { DI } from '@/di-symbols.js';
+
+export const meta = {
+ tags: ['flash'],
+
+ requireCredential: false,
+
+ res: {
+ type: 'array',
+ optional: false, nullable: false,
+ items: {
+ type: 'object',
+ optional: false, nullable: false,
+ ref: 'Flash',
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {},
+ required: [],
+} as const;
+
+// eslint-disable-next-line import/no-default-export
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> {
+ constructor(
+ @Inject(DI.flashsRepository)
+ private flashsRepository: FlashsRepository,
+
+ private flashEntityService: FlashEntityService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ const query = this.flashsRepository.createQueryBuilder('flash')
+ .andWhere('flash.likedCount > 0')
+ .orderBy('flash.likedCount', 'DESC');
+
+ const flashs = await query.take(10).getMany();
+
+ return await this.flashEntityService.packMany(flashs, me);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/flash/like.ts b/packages/backend/src/server/api/endpoints/flash/like.ts
new file mode 100644
index 0000000000..5581b8ec60
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/flash/like.ts
@@ -0,0 +1,87 @@
+import { Inject, Injectable } from '@nestjs/common';
+import type { FlashsRepository, FlashLikesRepository } from '@/models/index.js';
+import { IdService } from '@/core/IdService.js';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { DI } from '@/di-symbols.js';
+import { ApiError } from '../../error.js';
+
+export const meta = {
+ tags: ['flash'],
+
+ requireCredential: true,
+
+ kind: 'write:flash-likes',
+
+ errors: {
+ noSuchFlash: {
+ message: 'No such flash.',
+ code: 'NO_SUCH_FLASH',
+ id: 'c07c1491-9161-4c5c-9d75-01906f911f73',
+ },
+
+ yourFlash: {
+ message: 'You cannot like your flash.',
+ code: 'YOUR_FLASH',
+ id: '3fd8a0e7-5955-4ba9-85bb-bf3e0c30e13b',
+ },
+
+ alreadyLiked: {
+ message: 'The flash has already been liked.',
+ code: 'ALREADY_LIKED',
+ id: '010065cf-ad43-40df-8067-abff9f4686e3',
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ flashId: { type: 'string', format: 'misskey:id' },
+ },
+ required: ['flashId'],
+} as const;
+
+// eslint-disable-next-line import/no-default-export
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> {
+ constructor(
+ @Inject(DI.flashsRepository)
+ private flashsRepository: FlashsRepository,
+
+ @Inject(DI.flashLikesRepository)
+ private flashLikesRepository: FlashLikesRepository,
+
+ private idService: IdService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ const flash = await this.flashsRepository.findOneBy({ id: ps.flashId });
+ if (flash == null) {
+ throw new ApiError(meta.errors.noSuchFlash);
+ }
+
+ if (flash.userId === me.id) {
+ throw new ApiError(meta.errors.yourFlash);
+ }
+
+ // if already liked
+ const exist = await this.flashLikesRepository.findOneBy({
+ flashId: flash.id,
+ userId: me.id,
+ });
+
+ if (exist != null) {
+ throw new ApiError(meta.errors.alreadyLiked);
+ }
+
+ // Create like
+ await this.flashLikesRepository.insert({
+ id: this.idService.genId(),
+ createdAt: new Date(),
+ flashId: flash.id,
+ userId: me.id,
+ });
+
+ this.flashsRepository.increment({ id: flash.id }, 'likedCount', 1);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/flash/my-likes.ts b/packages/backend/src/server/api/endpoints/flash/my-likes.ts
new file mode 100644
index 0000000000..f7716ea74a
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/flash/my-likes.ts
@@ -0,0 +1,68 @@
+import { Inject, Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import type { FlashLikesRepository } from '@/models/index.js';
+import { QueryService } from '@/core/QueryService.js';
+import { FlashLikeEntityService } from '@/core/entities/FlashLikeEntityService.js';
+import { DI } from '@/di-symbols.js';
+
+export const meta = {
+ tags: ['account', 'flash'],
+
+ requireCredential: true,
+
+ kind: 'read:flash-likes',
+
+ res: {
+ type: 'array',
+ optional: false, nullable: false,
+ items: {
+ type: 'object',
+ properties: {
+ id: {
+ type: 'string',
+ optional: false, nullable: false,
+ format: 'id',
+ },
+ flash: {
+ type: 'object',
+ optional: false, nullable: false,
+ ref: 'Flash',
+ },
+ },
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
+ sinceId: { type: 'string', format: 'misskey:id' },
+ untilId: { type: 'string', format: 'misskey:id' },
+ },
+ required: [],
+} as const;
+
+// eslint-disable-next-line import/no-default-export
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> {
+ constructor(
+ @Inject(DI.flashLikesRepository)
+ private flashLikesRepository: FlashLikesRepository,
+
+ private flashLikeEntityService: FlashLikeEntityService,
+ private queryService: QueryService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ const query = this.queryService.makePaginationQuery(this.flashLikesRepository.createQueryBuilder('like'), ps.sinceId, ps.untilId)
+ .andWhere('like.userId = :meId', { meId: me.id })
+ .leftJoinAndSelect('like.flash', 'flash');
+
+ const likes = await query
+ .take(ps.limit)
+ .getMany();
+
+ return this.flashLikeEntityService.packMany(likes, me);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/flash/my.ts b/packages/backend/src/server/api/endpoints/flash/my.ts
new file mode 100644
index 0000000000..baed7f000f
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/flash/my.ts
@@ -0,0 +1,57 @@
+import { Inject, Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import type { FlashsRepository } from '@/models/index.js';
+import { QueryService } from '@/core/QueryService.js';
+import { FlashEntityService } from '@/core/entities/FlashEntityService.js';
+import { DI } from '@/di-symbols.js';
+
+export const meta = {
+ tags: ['account', 'flash'],
+
+ requireCredential: true,
+
+ kind: 'read:flash',
+
+ res: {
+ type: 'array',
+ optional: false, nullable: false,
+ items: {
+ type: 'object',
+ optional: false, nullable: false,
+ ref: 'Flash',
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
+ sinceId: { type: 'string', format: 'misskey:id' },
+ untilId: { type: 'string', format: 'misskey:id' },
+ },
+ required: [],
+} as const;
+
+// eslint-disable-next-line import/no-default-export
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> {
+ constructor(
+ @Inject(DI.flashsRepository)
+ private flashsRepository: FlashsRepository,
+
+ private flashEntityService: FlashEntityService,
+ private queryService: QueryService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ const query = this.queryService.makePaginationQuery(this.flashsRepository.createQueryBuilder('flash'), ps.sinceId, ps.untilId)
+ .andWhere('flash.userId = :meId', { meId: me.id });
+
+ const flashs = await query
+ .take(ps.limit)
+ .getMany();
+
+ return await this.flashEntityService.packMany(flashs);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/flash/show.ts b/packages/backend/src/server/api/endpoints/flash/show.ts
new file mode 100644
index 0000000000..48114c5a60
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/flash/show.ts
@@ -0,0 +1,60 @@
+import { IsNull } from 'typeorm';
+import { Inject, Injectable } from '@nestjs/common';
+import type { UsersRepository, FlashsRepository } from '@/models/index.js';
+import type { Flash } from '@/models/entities/Flash.js';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { FlashEntityService } from '@/core/entities/FlashEntityService.js';
+import { DI } from '@/di-symbols.js';
+import { ApiError } from '../../error.js';
+
+export const meta = {
+ tags: ['flashs'],
+
+ requireCredential: false,
+
+ res: {
+ type: 'object',
+ optional: false, nullable: false,
+ ref: 'Flash',
+ },
+
+ errors: {
+ noSuchFlash: {
+ message: 'No such flash.',
+ code: 'NO_SUCH_FLASH',
+ id: 'f0d34a1a-d29a-401d-90ba-1982122b5630',
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ flashId: { type: 'string', format: 'misskey:id' },
+ },
+ required: ['flashId'],
+} as const;
+
+// eslint-disable-next-line import/no-default-export
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> {
+ constructor(
+ @Inject(DI.usersRepository)
+ private usersRepository: UsersRepository,
+
+ @Inject(DI.flashsRepository)
+ private flashsRepository: FlashsRepository,
+
+ private flashEntityService: FlashEntityService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ const flash = await this.flashsRepository.findOneBy({ id: ps.flashId });
+
+ if (flash == null) {
+ throw new ApiError(meta.errors.noSuchFlash);
+ }
+
+ return await this.flashEntityService.pack(flash, me);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/flash/unlike.ts b/packages/backend/src/server/api/endpoints/flash/unlike.ts
new file mode 100644
index 0000000000..b994f5d347
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/flash/unlike.ts
@@ -0,0 +1,68 @@
+import { Inject, Injectable } from '@nestjs/common';
+import type { FlashsRepository, FlashLikesRepository } from '@/models/index.js';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { DI } from '@/di-symbols.js';
+import { ApiError } from '../../error.js';
+
+export const meta = {
+ tags: ['flash'],
+
+ requireCredential: true,
+
+ kind: 'write:flash-likes',
+
+ errors: {
+ noSuchFlash: {
+ message: 'No such flash.',
+ code: 'NO_SUCH_FLASH',
+ id: 'afe8424a-a69e-432d-a5f2-2f0740c62410',
+ },
+
+ notLiked: {
+ message: 'You have not liked that flash.',
+ code: 'NOT_LIKED',
+ id: '755f25a7-9871-4f65-9f34-51eaad9ae0ac',
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ flashId: { type: 'string', format: 'misskey:id' },
+ },
+ required: ['flashId'],
+} as const;
+
+// eslint-disable-next-line import/no-default-export
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> {
+ constructor(
+ @Inject(DI.flashsRepository)
+ private flashsRepository: FlashsRepository,
+
+ @Inject(DI.flashLikesRepository)
+ private flashLikesRepository: FlashLikesRepository,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ const flash = await this.flashsRepository.findOneBy({ id: ps.flashId });
+ if (flash == null) {
+ throw new ApiError(meta.errors.noSuchFlash);
+ }
+
+ const exist = await this.flashLikesRepository.findOneBy({
+ flashId: flash.id,
+ userId: me.id,
+ });
+
+ if (exist == null) {
+ throw new ApiError(meta.errors.notLiked);
+ }
+
+ // Delete like
+ await this.flashLikesRepository.delete(exist.id);
+
+ this.flashsRepository.decrement({ id: flash.id }, 'likedCount', 1);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/flash/update.ts b/packages/backend/src/server/api/endpoints/flash/update.ts
new file mode 100644
index 0000000000..9ab17a61e8
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/flash/update.ts
@@ -0,0 +1,78 @@
+import ms from 'ms';
+import { Not } from 'typeorm';
+import { Inject, Injectable } from '@nestjs/common';
+import type { FlashsRepository, DriveFilesRepository } from '@/models/index.js';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { DI } from '@/di-symbols.js';
+import { ApiError } from '../../error.js';
+
+export const meta = {
+ tags: ['flash'],
+
+ requireCredential: true,
+
+ kind: 'write:flash',
+
+ limit: {
+ duration: ms('1hour'),
+ max: 300,
+ },
+
+ errors: {
+ noSuchFlash: {
+ message: 'No such flash.',
+ code: 'NO_SUCH_FLASH',
+ id: '611e13d2-309e-419a-a5e4-e0422da39b02',
+ },
+
+ accessDenied: {
+ message: 'Access denied.',
+ code: 'ACCESS_DENIED',
+ id: '08e60c88-5948-478e-a132-02ec701d67b2',
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ flashId: { type: 'string', format: 'misskey:id' },
+ title: { type: 'string' },
+ summary: { type: 'string' },
+ script: { type: 'string' },
+ permissions: { type: 'array', items: {
+ type: 'string',
+ } },
+ },
+ required: ['flashId', 'title', 'summary', 'script', 'permissions'],
+} as const;
+
+// eslint-disable-next-line import/no-default-export
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> {
+ constructor(
+ @Inject(DI.flashsRepository)
+ private flashsRepository: FlashsRepository,
+
+ @Inject(DI.driveFilesRepository)
+ private driveFilesRepository: DriveFilesRepository,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ const flash = await this.flashsRepository.findOneBy({ id: ps.flashId });
+ if (flash == null) {
+ throw new ApiError(meta.errors.noSuchFlash);
+ }
+ if (flash.userId !== me.id) {
+ throw new ApiError(meta.errors.accessDenied);
+ }
+
+ await this.flashsRepository.update(flash.id, {
+ updatedAt: new Date(),
+ title: ps.title,
+ summary: ps.summary,
+ script: ps.script,
+ permissions: ps.permissions,
+ });
+ });
+ }
+}