wip gallery

This commit is contained in:
tamaina 2023-07-03 08:57:13 +00:00
parent a97d379c84
commit 41250d997b
10 changed files with 279 additions and 292 deletions

View file

@ -4,38 +4,17 @@ import type { GalleryPostsRepository } from '@/models/index.js';
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js'; import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
export const meta = {
tags: ['gallery'],
requireCredential: false,
res: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
ref: 'GalleryPost',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { export default class extends Endpoint<'gallery/featured'> {
name = 'gallery/featured' as const;
constructor( constructor(
@Inject(DI.galleryPostsRepository) @Inject(DI.galleryPostsRepository)
private galleryPostsRepository: GalleryPostsRepository, private galleryPostsRepository: GalleryPostsRepository,
private galleryPostEntityService: GalleryPostEntityService, private galleryPostEntityService: GalleryPostEntityService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(async (ps, me) => {
const query = this.galleryPostsRepository.createQueryBuilder('post') const query = this.galleryPostsRepository.createQueryBuilder('post')
.andWhere('post.createdAt > :date', { date: new Date(Date.now() - (1000 * 60 * 60 * 24 * 3)) }) .andWhere('post.createdAt > :date', { date: new Date(Date.now() - (1000 * 60 * 60 * 24 * 3)) })
.andWhere('post.likedCount > 0') .andWhere('post.likedCount > 0')

View file

@ -4,38 +4,17 @@ import type { GalleryPostsRepository } from '@/models/index.js';
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js'; import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
export const meta = {
tags: ['gallery'],
requireCredential: false,
res: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
ref: 'GalleryPost',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { export default class extends Endpoint<'gallery/popular'> {
name = 'gallery/popular' as const;
constructor( constructor(
@Inject(DI.galleryPostsRepository) @Inject(DI.galleryPostsRepository)
private galleryPostsRepository: GalleryPostsRepository, private galleryPostsRepository: GalleryPostsRepository,
private galleryPostEntityService: GalleryPostEntityService, private galleryPostEntityService: GalleryPostEntityService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(async (ps, me) => {
const query = this.galleryPostsRepository.createQueryBuilder('post') const query = this.galleryPostsRepository.createQueryBuilder('post')
.andWhere('post.likedCount > 0') .andWhere('post.likedCount > 0')
.orderBy('post.likedCount', 'DESC'); .orderBy('post.likedCount', 'DESC');

View file

@ -5,33 +5,10 @@ import { QueryService } from '@/core/QueryService.js';
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js'; import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
export const meta = {
tags: ['gallery'],
res: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
ref: 'GalleryPost',
},
},
} 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 // eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { export default class extends Endpoint<'gallery/posts'> {
name = 'gallery/posts' as const;
constructor( constructor(
@Inject(DI.galleryPostsRepository) @Inject(DI.galleryPostsRepository)
private galleryPostsRepository: GalleryPostsRepository, private galleryPostsRepository: GalleryPostsRepository,
@ -39,7 +16,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private galleryPostEntityService: GalleryPostEntityService, private galleryPostEntityService: GalleryPostEntityService,
private queryService: QueryService, private queryService: QueryService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.galleryPostsRepository.createQueryBuilder('post'), ps.sinceId, ps.untilId) const query = this.queryService.makePaginationQuery(this.galleryPostsRepository.createQueryBuilder('post'), ps.sinceId, ps.untilId)
.innerJoinAndSelect('post.user', 'user'); .innerJoinAndSelect('post.user', 'user');

View file

@ -8,47 +8,10 @@ import { IdService } from '@/core/IdService.js';
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js'; import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
export const meta = {
tags: ['gallery'],
requireCredential: true,
prohibitMoved: true,
kind: 'write:gallery',
limit: {
duration: ms('1hour'),
max: 20,
},
res: {
type: 'object',
optional: false, nullable: false,
ref: 'GalleryPost',
},
errors: {
},
} as const;
export const paramDef = {
type: 'object',
properties: {
title: { type: 'string', minLength: 1 },
description: { type: 'string', nullable: true },
fileIds: { type: 'array', uniqueItems: true, minItems: 1, maxItems: 32, items: {
type: 'string', format: 'misskey:id',
} },
isSensitive: { type: 'boolean', default: false },
},
required: ['title', 'fileIds'],
} as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { export default class extends Endpoint<'gallery/posts/create'> {
name = 'gallery/posts/create' as const;
constructor( constructor(
@Inject(DI.galleryPostsRepository) @Inject(DI.galleryPostsRepository)
private galleryPostsRepository: GalleryPostsRepository, private galleryPostsRepository: GalleryPostsRepository,
@ -59,7 +22,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private galleryPostEntityService: GalleryPostEntityService, private galleryPostEntityService: GalleryPostEntityService,
private idService: IdService, private idService: IdService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(async (ps, me) => {
const files = (await Promise.all(ps.fileIds.map(fileId => const files = (await Promise.all(ps.fileIds.map(fileId =>
this.driveFilesRepository.findOneBy({ this.driveFilesRepository.findOneBy({
id: fileId, id: fileId,

View file

@ -4,45 +4,22 @@ import type { GalleryPostsRepository } from '@/models/index.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js'; import { ApiError } from '../../../error.js';
export const meta = {
tags: ['gallery'],
requireCredential: true,
kind: 'write:gallery',
errors: {
noSuchPost: {
message: 'No such post.',
code: 'NO_SUCH_POST',
id: 'ae52f367-4bd7-4ecd-afc6-5672fff427f5',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
postId: { type: 'string', format: 'misskey:id' },
},
required: ['postId'],
} as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { export default class extends Endpoint<'gallery/posts/delete'> {
name = 'gallery/posts/delete' as const;
constructor( constructor(
@Inject(DI.galleryPostsRepository) @Inject(DI.galleryPostsRepository)
private galleryPostsRepository: GalleryPostsRepository, private galleryPostsRepository: GalleryPostsRepository,
) { ) {
super(meta, paramDef, async (ps, me) => { super(async (ps, me) => {
const post = await this.galleryPostsRepository.findOneBy({ const post = await this.galleryPostsRepository.findOneBy({
id: ps.postId, id: ps.postId,
userId: me.id, userId: me.id,
}); });
if (post == null) { if (post == null) {
throw new ApiError(meta.errors.noSuchPost); throw new ApiError(this.meta.errors.noSuchPost);
} }
await this.galleryPostsRepository.delete(post.id); await this.galleryPostsRepository.delete(post.id);

View file

@ -5,47 +5,10 @@ import { IdService } from '@/core/IdService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js'; import { ApiError } from '../../../error.js';
export const meta = {
tags: ['gallery'],
requireCredential: true,
prohibitMoved: true,
kind: 'write:gallery-likes',
errors: {
noSuchPost: {
message: 'No such post.',
code: 'NO_SUCH_POST',
id: '56c06af3-1287-442f-9701-c93f7c4a62ff',
},
yourPost: {
message: 'You cannot like your post.',
code: 'YOUR_POST',
id: 'f78f1511-5ebc-4478-a888-1198d752da68',
},
alreadyLiked: {
message: 'The post has already been liked.',
code: 'ALREADY_LIKED',
id: '40e9ed56-a59c-473a-bf3f-f289c54fb5a7',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
postId: { type: 'string', format: 'misskey:id' },
},
required: ['postId'],
} as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { export default class extends Endpoint<'gallery/posts/like'> {
name = 'gallery/posts/like' as const;
constructor( constructor(
@Inject(DI.galleryPostsRepository) @Inject(DI.galleryPostsRepository)
private galleryPostsRepository: GalleryPostsRepository, private galleryPostsRepository: GalleryPostsRepository,
@ -55,14 +18,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private idService: IdService, private idService: IdService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(async (ps, me) => {
const post = await this.galleryPostsRepository.findOneBy({ id: ps.postId }); const post = await this.galleryPostsRepository.findOneBy({ id: ps.postId });
if (post == null) { if (post == null) {
throw new ApiError(meta.errors.noSuchPost); throw new ApiError(this.meta.errors.noSuchPost);
} }
if (post.userId === me.id) { if (post.userId === me.id) {
throw new ApiError(meta.errors.yourPost); throw new ApiError(this.meta.errors.yourPost);
} }
// if already liked // if already liked
@ -72,7 +35,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}); });
if (exist != null) { if (exist != null) {
throw new ApiError(meta.errors.alreadyLiked); throw new ApiError(this.meta.errors.alreadyLiked);
} }
// Create like // Create like

View file

@ -5,50 +5,23 @@ import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityServi
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js'; import { ApiError } from '../../../error.js';
export const meta = {
tags: ['gallery'],
requireCredential: false,
errors: {
noSuchPost: {
message: 'No such post.',
code: 'NO_SUCH_POST',
id: '1137bf14-c5b0-4604-85bb-5b5371b1cd45',
},
},
res: {
type: 'object',
optional: false, nullable: false,
ref: 'GalleryPost',
},
} as const;
export const paramDef = {
type: 'object',
properties: {
postId: { type: 'string', format: 'misskey:id' },
},
required: ['postId'],
} as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { export default class extends Endpoint<'gallery/posts/show'> {
name = 'gallery/posts/show' as const;
constructor( constructor(
@Inject(DI.galleryPostsRepository) @Inject(DI.galleryPostsRepository)
private galleryPostsRepository: GalleryPostsRepository, private galleryPostsRepository: GalleryPostsRepository,
private galleryPostEntityService: GalleryPostEntityService, private galleryPostEntityService: GalleryPostEntityService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(async (ps, me) => {
const post = await this.galleryPostsRepository.findOneBy({ const post = await this.galleryPostsRepository.findOneBy({
id: ps.postId, id: ps.postId,
}); });
if (post == null) { if (post == null) {
throw new ApiError(meta.errors.noSuchPost); throw new ApiError(this.meta.errors.noSuchPost);
} }
return await this.galleryPostEntityService.pack(post, me); return await this.galleryPostEntityService.pack(post, me);

View file

@ -4,41 +4,10 @@ import type { GalleryPostsRepository, GalleryLikesRepository } from '@/models/in
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js'; import { ApiError } from '../../../error.js';
export const meta = {
tags: ['gallery'],
requireCredential: true,
prohibitMoved: true,
kind: 'write:gallery-likes',
errors: {
noSuchPost: {
message: 'No such post.',
code: 'NO_SUCH_POST',
id: 'c32e6dd0-b555-4413-925e-b3757d19ed84',
},
notLiked: {
message: 'You have not liked that post.',
code: 'NOT_LIKED',
id: 'e3e8e06e-be37-41f7-a5b4-87a8250288f0',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
postId: { type: 'string', format: 'misskey:id' },
},
required: ['postId'],
} as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { export default class extends Endpoint<'gallery/posts/unlike'> {
name = 'gallery/posts/unlike' as const;
constructor( constructor(
@Inject(DI.galleryPostsRepository) @Inject(DI.galleryPostsRepository)
private galleryPostsRepository: GalleryPostsRepository, private galleryPostsRepository: GalleryPostsRepository,
@ -46,10 +15,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
@Inject(DI.galleryLikesRepository) @Inject(DI.galleryLikesRepository)
private galleryLikesRepository: GalleryLikesRepository, private galleryLikesRepository: GalleryLikesRepository,
) { ) {
super(meta, paramDef, async (ps, me) => { super(async (ps, me) => {
const post = await this.galleryPostsRepository.findOneBy({ id: ps.postId }); const post = await this.galleryPostsRepository.findOneBy({ id: ps.postId });
if (post == null) { if (post == null) {
throw new ApiError(meta.errors.noSuchPost); throw new ApiError(this.meta.errors.noSuchPost);
} }
const exist = await this.galleryLikesRepository.findOneBy({ const exist = await this.galleryLikesRepository.findOneBy({
@ -58,7 +27,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}); });
if (exist == null) { if (exist == null) {
throw new ApiError(meta.errors.notLiked); throw new ApiError(this.meta.errors.notLiked);
} }
// Delete like // Delete like

View file

@ -6,48 +6,10 @@ import type { DriveFile } from '@/models/entities/DriveFile.js';
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js'; import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
export const meta = {
tags: ['gallery'],
requireCredential: true,
prohibitMoved: true,
kind: 'write:gallery',
limit: {
duration: ms('1hour'),
max: 300,
},
res: {
type: 'object',
optional: false, nullable: false,
ref: 'GalleryPost',
},
errors: {
},
} as const;
export const paramDef = {
type: 'object',
properties: {
postId: { type: 'string', format: 'misskey:id' },
title: { type: 'string', minLength: 1 },
description: { type: 'string', nullable: true },
fileIds: { type: 'array', uniqueItems: true, minItems: 1, maxItems: 32, items: {
type: 'string', format: 'misskey:id',
} },
isSensitive: { type: 'boolean', default: false },
},
required: ['postId', 'title', 'fileIds'],
} as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { export default class extends Endpoint<'gallery/posts/update'> {
name = 'gallery/posts/update' as const;
constructor( constructor(
@Inject(DI.galleryPostsRepository) @Inject(DI.galleryPostsRepository)
private galleryPostsRepository: GalleryPostsRepository, private galleryPostsRepository: GalleryPostsRepository,
@ -57,7 +19,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private galleryPostEntityService: GalleryPostEntityService, private galleryPostEntityService: GalleryPostEntityService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(async (ps, me) => {
const files = (await Promise.all(ps.fileIds.map(fileId => const files = (await Promise.all(ps.fileIds.map(fileId =>
this.driveFilesRepository.findOneBy({ this.driveFilesRepository.findOneBy({
id: fileId, id: fileId,

View file

@ -4972,6 +4972,251 @@ export const endpoints = {
}], }],
}, },
//#endregion //#endregion
//#region gallery
'gallery/posts/create': {
tags: ['gallery'],
requireCredential: true,
prohibitMoved: true,
kind: 'write:gallery',
limit: {
duration: ms('1hour'),
max: 20,
},
defines: [{
req: {
type: 'object',
properties: {
title: { type: 'string', minLength: 1 },
description: { type: ['string', 'null'] },
fileIds: { type: 'array', uniqueItems: true, minItems: 1, maxItems: 32, items: {
type: 'string', format: 'misskey:id',
} },
isSensitive: { type: 'boolean', default: false },
},
required: ['title', 'fileIds'],
},
res: {
$ref: 'https://misskey-hub.net/api/schemas/GalleryPost',
},
}],
},
'gallery/posts/delete': {
tags: ['gallery'],
requireCredential: true,
kind: 'write:gallery',
errors: {
noSuchPost: {
message: 'No such post.',
code: 'NO_SUCH_POST',
id: 'ae52f367-4bd7-4ecd-afc6-5672fff427f5',
},
},
defines: [{
req: {
type: 'object',
properties: {
postId: { type: 'string', format: 'misskey:id' },
},
required: ['postId'],
},
res: undefined,
}],
},
'gallery/posts/like': {
tags: ['gallery'],
requireCredential: true,
prohibitMoved: true,
kind: 'write:gallery-likes',
errors: {
noSuchPost: {
message: 'No such post.',
code: 'NO_SUCH_POST',
id: '56c06af3-1287-442f-9701-c93f7c4a62ff',
},
yourPost: {
message: 'You cannot like your post.',
code: 'YOUR_POST',
id: 'f78f1511-5ebc-4478-a888-1198d752da68',
},
alreadyLiked: {
message: 'The post has already been liked.',
code: 'ALREADY_LIKED',
id: '40e9ed56-a59c-473a-bf3f-f289c54fb5a7',
},
},
defines: [{
req: {
type: 'object',
properties: {
postId: { type: 'string', format: 'misskey:id' },
},
required: ['postId'],
},
res: undefined,
}],
},
'gallery/posts/show': {
tags: ['gallery'],
requireCredential: false,
errors: {
noSuchPost: {
message: 'No such post.',
code: 'NO_SUCH_POST',
id: '1137bf14-c5b0-4604-85bb-5b5371b1cd45',
},
},
defines: [{
req: {
type: 'object',
properties: {
postId: { type: 'string', format: 'misskey:id' },
},
required: ['postId'],
},
res: {
$ref: 'https://misskey-hub.net/api/schemas/GalleryPost',
},
}],
},
'gallery/posts/unlike': {
tags: ['gallery'],
requireCredential: true,
prohibitMoved: true,
kind: 'write:gallery-likes',
errors: {
noSuchPost: {
message: 'No such post.',
code: 'NO_SUCH_POST',
id: 'c32e6dd0-b555-4413-925e-b3757d19ed84',
},
notLiked: {
message: 'You have not liked that post.',
code: 'NOT_LIKED',
id: 'e3e8e06e-be37-41f7-a5b4-87a8250288f0',
},
},
defines: [{
req: {
type: 'object',
properties: {
postId: { type: 'string', format: 'misskey:id' },
},
required: ['postId'],
},
res: undefined,
}]
},
'gallery/posts/update': {
tags: ['gallery'],
requireCredential: true,
prohibitMoved: true,
kind: 'write:gallery',
limit: {
duration: ms('1hour'),
max: 300,
},
defines: [{
req: {
type: 'object',
properties: {
postId: { type: 'string', format: 'misskey:id' },
title: { type: 'string', minLength: 1 },
description: { type: ['string', 'null'] },
fileIds: { type: 'array', uniqueItems: true, minItems: 1, maxItems: 32, items: {
type: 'string', format: 'misskey:id',
} },
isSensitive: { type: 'boolean', default: false },
},
required: ['postId', 'title', 'fileIds'],
},
res: {
$ref: 'https://misskey-hub.net/api/schemas/GalleryPost',
},
}],
},
'gallery/featured': {
tags: ['gallery'],
requireCredential: false,
defines: [{
req: undefined,
res: {
type: 'array',
items: {
$ref: 'https://misskey-hub.net/api/schemas/GalleryPost',
},
},
}],
},
'gallery/popular': {
tags: ['gallery'],
requireCredential: false,
defines: [{
req: undefined,
res: {
type: 'array',
items: {
$ref: 'https://misskey-hub.net/api/schemas/GalleryPost',
},
},
}],
},
'gallery/posts': {
tags: ['gallery'],
defines: [{
req: {
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: [],
},
res: {
type: 'array',
items: {
$ref: 'https://misskey-hub.net/api/schemas/GalleryPost',
},
},
}],
},
//#endregion
} as const satisfies { [x: string]: IEndpointMeta; }; } as const satisfies { [x: string]: IEndpointMeta; };
/** /**