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:
syuilo
2023-01-05 13:59:48 +09:00
committed by GitHub
parent 5d904b05dd
commit ebe340d510
45 changed files with 2465 additions and 93 deletions

View 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);
});
}
}

View 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);
});
}
}

View 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);
});
}
}

View 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);
});
}
}

View 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);
});
}
}

View 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);
});
}
}

View 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);
});
}
}

View 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);
});
}
}

View 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,
});
});
}
}