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 * 🎨 * wip * ✌️
This commit is contained in:
		@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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],
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										66
									
								
								packages/backend/src/server/api/endpoints/flash/create.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								packages/backend/src/server/api/endpoints/flash/create.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										56
									
								
								packages/backend/src/server/api/endpoints/flash/delete.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								packages/backend/src/server/api/endpoints/flash/delete.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								packages/backend/src/server/api/endpoints/flash/featured.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								packages/backend/src/server/api/endpoints/flash/featured.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										87
									
								
								packages/backend/src/server/api/endpoints/flash/like.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								packages/backend/src/server/api/endpoints/flash/like.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								packages/backend/src/server/api/endpoints/flash/my-likes.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								packages/backend/src/server/api/endpoints/flash/my-likes.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								packages/backend/src/server/api/endpoints/flash/my.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								packages/backend/src/server/api/endpoints/flash/my.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										60
									
								
								packages/backend/src/server/api/endpoints/flash/show.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								packages/backend/src/server/api/endpoints/flash/show.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								packages/backend/src/server/api/endpoints/flash/unlike.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								packages/backend/src/server/api/endpoints/flash/unlike.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										78
									
								
								packages/backend/src/server/api/endpoints/flash/update.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								packages/backend/src/server/api/endpoints/flash/update.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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,
 | 
			
		||||
			});
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user