backend: remove galleries
This commit is contained in:
parent
70fb1e9a5c
commit
2bbb85b472
25 changed files with 3 additions and 897 deletions
|
@ -50,8 +50,6 @@ import { UserSecurityKey } from '@/models/entities/user-security-key.js';
|
|||
import { AttestationChallenge } from '@/models/entities/attestation-challenge.js';
|
||||
import { Page } from '@/models/entities/page.js';
|
||||
import { PageLike } from '@/models/entities/page-like.js';
|
||||
import { GalleryPost } from '@/models/entities/gallery-post.js';
|
||||
import { GalleryLike } from '@/models/entities/gallery-like.js';
|
||||
import { ModerationLog } from '@/models/entities/moderation-log.js';
|
||||
import { UsedUsername } from '@/models/entities/used-username.js';
|
||||
import { Announcement } from '@/models/entities/announcement.js';
|
||||
|
@ -143,8 +141,6 @@ export const entities = [
|
|||
NoteUnread,
|
||||
Page,
|
||||
PageLike,
|
||||
GalleryPost,
|
||||
GalleryLike,
|
||||
DriveFile,
|
||||
DriveFolder,
|
||||
Poll,
|
||||
|
|
|
@ -27,9 +27,5 @@ export const kinds = [
|
|||
'write:user-groups',
|
||||
'read:channels',
|
||||
'write:channels',
|
||||
'read:gallery',
|
||||
'write:gallery',
|
||||
'read:gallery-likes',
|
||||
'write:gallery-likes',
|
||||
];
|
||||
// IF YOU ADD KINDS(PERMISSIONS), YOU MUST ADD TRANSLATIONS (under _permissions).
|
||||
|
|
|
@ -28,7 +28,6 @@ import { packedAntennaSchema } from '@/models/schema/antenna.js';
|
|||
import { packedClipSchema } from '@/models/schema/clip.js';
|
||||
import { packedFederationInstanceSchema } from '@/models/schema/federation-instance.js';
|
||||
import { packedQueueCountSchema } from '@/models/schema/queue.js';
|
||||
import { packedGalleryPostSchema } from '@/models/schema/gallery-post.js';
|
||||
import { packedEmojiSchema } from '@/models/schema/emoji.js';
|
||||
|
||||
export const refs = {
|
||||
|
@ -61,7 +60,6 @@ export const refs = {
|
|||
Antenna: packedAntennaSchema,
|
||||
Clip: packedClipSchema,
|
||||
FederationInstance: packedFederationInstanceSchema,
|
||||
GalleryPost: packedGalleryPostSchema,
|
||||
Emoji: packedEmojiSchema,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { id } from '../id.js';
|
||||
import { User } from './user.js';
|
||||
import { GalleryPost } from './gallery-post.js';
|
||||
|
||||
@Entity()
|
||||
@Index(['userId', 'postId'], { unique: true })
|
||||
export class GalleryLike {
|
||||
@PrimaryColumn(id())
|
||||
public id: string;
|
||||
|
||||
@Column('timestamp with time zone')
|
||||
public createdAt: Date;
|
||||
|
||||
@Index()
|
||||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
public user: User | null;
|
||||
|
||||
@Column(id())
|
||||
public postId: GalleryPost['id'];
|
||||
|
||||
@ManyToOne(() => GalleryPost, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
public post: GalleryPost | null;
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm';
|
||||
import { id } from '../id.js';
|
||||
import { User } from './user.js';
|
||||
import { DriveFile } from './drive-file.js';
|
||||
|
||||
@Entity()
|
||||
export class GalleryPost {
|
||||
@PrimaryColumn(id())
|
||||
public id: string;
|
||||
|
||||
@Index()
|
||||
@Column('timestamp with time zone', {
|
||||
comment: 'The created date of the GalleryPost.',
|
||||
})
|
||||
public createdAt: Date;
|
||||
|
||||
@Index()
|
||||
@Column('timestamp with time zone', {
|
||||
comment: 'The updated date of the GalleryPost.',
|
||||
})
|
||||
public updatedAt: Date;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 256,
|
||||
})
|
||||
public title: string;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 2048, nullable: true,
|
||||
})
|
||||
public description: string | null;
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
...id(),
|
||||
comment: 'The ID of author.',
|
||||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
public user: User | null;
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
...id(),
|
||||
array: true, default: '{}',
|
||||
})
|
||||
public fileIds: DriveFile['id'][];
|
||||
|
||||
@Index()
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
comment: 'Whether the post is sensitive.',
|
||||
})
|
||||
public isSensitive: boolean;
|
||||
|
||||
@Index()
|
||||
@Column('integer', {
|
||||
default: 0,
|
||||
})
|
||||
public likedCount: number;
|
||||
|
||||
@Index()
|
||||
@Column('varchar', {
|
||||
length: 128, array: true, default: '{}',
|
||||
})
|
||||
public tags: string[];
|
||||
|
||||
constructor(data: Partial<GalleryPost>) {
|
||||
if (data == null) return;
|
||||
|
||||
for (const [k, v] of Object.entries(data)) {
|
||||
(this as any)[k] = v;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -42,8 +42,6 @@ import { UserSecurityKey } from './entities/user-security-key.js';
|
|||
import { HashtagRepository } from './repositories/hashtag.js';
|
||||
import { PageRepository } from './repositories/page.js';
|
||||
import { PageLikeRepository } from './repositories/page-like.js';
|
||||
import { GalleryPostRepository } from './repositories/gallery-post.js';
|
||||
import { GalleryLikeRepository } from './repositories/gallery-like.js';
|
||||
import { ModerationLogRepository } from './repositories/moderation-logs.js';
|
||||
import { UsedUsername } from './entities/used-username.js';
|
||||
import { ClipRepository } from './repositories/clip.js';
|
||||
|
@ -108,8 +106,6 @@ export const Signins = (SigninRepository);
|
|||
export const MessagingMessages = (MessagingMessageRepository);
|
||||
export const Pages = (PageRepository);
|
||||
export const PageLikes = (PageLikeRepository);
|
||||
export const GalleryPosts = (GalleryPostRepository);
|
||||
export const GalleryLikes = (GalleryLikeRepository);
|
||||
export const ModerationLogs = (ModerationLogRepository);
|
||||
export const Clips = (ClipRepository);
|
||||
export const ClipNotes = db.getRepository(ClipNote);
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
import { db } from '@/db/postgre.js';
|
||||
import { GalleryLike } from '@/models/entities/gallery-like.js';
|
||||
import { GalleryPosts } from '../index.js';
|
||||
|
||||
export const GalleryLikeRepository = db.getRepository(GalleryLike).extend({
|
||||
async pack(
|
||||
src: GalleryLike['id'] | GalleryLike,
|
||||
me?: any,
|
||||
) {
|
||||
const like = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
|
||||
|
||||
return {
|
||||
id: like.id,
|
||||
post: await GalleryPosts.pack(like.post || like.postId, me),
|
||||
};
|
||||
},
|
||||
|
||||
packMany(
|
||||
likes: any[],
|
||||
me: any,
|
||||
) {
|
||||
return Promise.all(likes.map(x => this.pack(x, me)));
|
||||
},
|
||||
});
|
|
@ -1,39 +0,0 @@
|
|||
import { db } from '@/db/postgre.js';
|
||||
import { Packed } from '@/misc/schema.js';
|
||||
import { GalleryPost } from '@/models/entities/gallery-post.js';
|
||||
import { User } from '@/models/entities/user.js';
|
||||
import { awaitAll } from '@/prelude/await-all.js';
|
||||
import { Users, DriveFiles, GalleryLikes } from '../index.js';
|
||||
|
||||
export const GalleryPostRepository = db.getRepository(GalleryPost).extend({
|
||||
async pack(
|
||||
src: GalleryPost['id'] | GalleryPost,
|
||||
me?: { id: User['id'] } | null | undefined,
|
||||
): Promise<Packed<'GalleryPost'>> {
|
||||
const meId = me ? me.id : null;
|
||||
const post = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
|
||||
|
||||
return await awaitAll({
|
||||
id: post.id,
|
||||
createdAt: post.createdAt.toISOString(),
|
||||
updatedAt: post.updatedAt.toISOString(),
|
||||
userId: post.userId,
|
||||
user: Users.pack(post.user || post.userId, me),
|
||||
title: post.title,
|
||||
description: post.description,
|
||||
fileIds: post.fileIds,
|
||||
files: DriveFiles.packMany(post.fileIds),
|
||||
tags: post.tags.length > 0 ? post.tags : undefined,
|
||||
isSensitive: post.isSensitive,
|
||||
likedCount: post.likedCount,
|
||||
isLiked: meId ? await GalleryLikes.findOneBy({ postId: post.id, userId: meId }).then(x => x != null) : undefined,
|
||||
});
|
||||
},
|
||||
|
||||
packMany(
|
||||
posts: GalleryPost[],
|
||||
me?: { id: User['id'] } | null | undefined,
|
||||
) {
|
||||
return Promise.all(posts.map(x => this.pack(x, me)));
|
||||
},
|
||||
});
|
|
@ -1,69 +0,0 @@
|
|||
export const packedGalleryPostSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'date-time',
|
||||
},
|
||||
updatedAt: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'date-time',
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
},
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'UserLite',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
fileIds: {
|
||||
type: 'array',
|
||||
optional: true, nullable: false,
|
||||
items: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
},
|
||||
},
|
||||
files: {
|
||||
type: 'array',
|
||||
optional: true, nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'DriveFile',
|
||||
},
|
||||
},
|
||||
tags: {
|
||||
type: 'array',
|
||||
optional: true, nullable: false,
|
||||
items: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
isSensitive: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
} as const;
|
|
@ -138,15 +138,6 @@ import * as ep___following_requests_accept from './endpoints/following/requests/
|
|||
import * as ep___following_requests_cancel from './endpoints/following/requests/cancel.js';
|
||||
import * as ep___following_requests_list from './endpoints/following/requests/list.js';
|
||||
import * as ep___following_requests_reject from './endpoints/following/requests/reject.js';
|
||||
import * as ep___gallery_featured from './endpoints/gallery/featured.js';
|
||||
import * as ep___gallery_popular from './endpoints/gallery/popular.js';
|
||||
import * as ep___gallery_posts from './endpoints/gallery/posts.js';
|
||||
import * as ep___gallery_posts_create from './endpoints/gallery/posts/create.js';
|
||||
import * as ep___gallery_posts_delete from './endpoints/gallery/posts/delete.js';
|
||||
import * as ep___gallery_posts_like from './endpoints/gallery/posts/like.js';
|
||||
import * as ep___gallery_posts_show from './endpoints/gallery/posts/show.js';
|
||||
import * as ep___gallery_posts_unlike from './endpoints/gallery/posts/unlike.js';
|
||||
import * as ep___gallery_posts_update from './endpoints/gallery/posts/update.js';
|
||||
import * as ep___getOnlineUsersCount from './endpoints/get-online-users-count.js';
|
||||
import * as ep___hashtags_list from './endpoints/hashtags/list.js';
|
||||
import * as ep___hashtags_search from './endpoints/hashtags/search.js';
|
||||
|
@ -171,8 +162,6 @@ import * as ep___i_exportMute from './endpoints/i/export-mute.js';
|
|||
import * as ep___i_exportNotes from './endpoints/i/export-notes.js';
|
||||
import * as ep___i_exportUserLists from './endpoints/i/export-user-lists.js';
|
||||
import * as ep___i_favorites from './endpoints/i/favorites.js';
|
||||
import * as ep___i_gallery_likes from './endpoints/i/gallery/likes.js';
|
||||
import * as ep___i_gallery_posts from './endpoints/i/gallery/posts.js';
|
||||
import * as ep___i_getWordMutedNotesCount from './endpoints/i/get-word-muted-notes-count.js';
|
||||
import * as ep___i_importBlocking from './endpoints/i/import-blocking.js';
|
||||
import * as ep___i_importFollowing from './endpoints/i/import-following.js';
|
||||
|
@ -276,7 +265,6 @@ import * as ep___users from './endpoints/users.js';
|
|||
import * as ep___users_clips from './endpoints/users/clips.js';
|
||||
import * as ep___users_followers from './endpoints/users/followers.js';
|
||||
import * as ep___users_following from './endpoints/users/following.js';
|
||||
import * as ep___users_gallery_posts from './endpoints/users/gallery/posts.js';
|
||||
import * as ep___users_groups_create from './endpoints/users/groups/create.js';
|
||||
import * as ep___users_groups_delete from './endpoints/users/groups/delete.js';
|
||||
import * as ep___users_groups_invitations_accept from './endpoints/users/groups/invitations/accept.js';
|
||||
|
@ -446,15 +434,6 @@ const eps = [
|
|||
['following/requests/cancel', ep___following_requests_cancel],
|
||||
['following/requests/list', ep___following_requests_list],
|
||||
['following/requests/reject', ep___following_requests_reject],
|
||||
['gallery/featured', ep___gallery_featured],
|
||||
['gallery/popular', ep___gallery_popular],
|
||||
['gallery/posts', ep___gallery_posts],
|
||||
['gallery/posts/create', ep___gallery_posts_create],
|
||||
['gallery/posts/delete', ep___gallery_posts_delete],
|
||||
['gallery/posts/like', ep___gallery_posts_like],
|
||||
['gallery/posts/show', ep___gallery_posts_show],
|
||||
['gallery/posts/unlike', ep___gallery_posts_unlike],
|
||||
['gallery/posts/update', ep___gallery_posts_update],
|
||||
['get-online-users-count', ep___getOnlineUsersCount],
|
||||
['hashtags/list', ep___hashtags_list],
|
||||
['hashtags/search', ep___hashtags_search],
|
||||
|
@ -479,8 +458,6 @@ const eps = [
|
|||
['i/export-notes', ep___i_exportNotes],
|
||||
['i/export-user-lists', ep___i_exportUserLists],
|
||||
['i/favorites', ep___i_favorites],
|
||||
['i/gallery/likes', ep___i_gallery_likes],
|
||||
['i/gallery/posts', ep___i_gallery_posts],
|
||||
['i/get-word-muted-notes-count', ep___i_getWordMutedNotesCount],
|
||||
['i/import-blocking', ep___i_importBlocking],
|
||||
['i/import-following', ep___i_importFollowing],
|
||||
|
@ -584,7 +561,6 @@ const eps = [
|
|||
['users/clips', ep___users_clips],
|
||||
['users/followers', ep___users_followers],
|
||||
['users/following', ep___users_following],
|
||||
['users/gallery/posts', ep___users_gallery_posts],
|
||||
['users/groups/create', ep___users_groups_create],
|
||||
['users/groups/delete', ep___users_groups_delete],
|
||||
['users/groups/invitations/accept', ep___users_groups_invitations_accept],
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
import { DAY } from '@/const.js';
|
||||
import { GalleryPosts } from '@/models/index.js';
|
||||
import define from '../../define.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
|
||||
export default define(meta, paramDef, async (ps, me) => {
|
||||
const query = GalleryPosts.createQueryBuilder('post')
|
||||
.andWhere('post.createdAt > :date', { date: new Date(Date.now() - 3 * DAY) })
|
||||
.andWhere('post.likedCount > 0')
|
||||
.orderBy('post.likedCount', 'DESC');
|
||||
|
||||
const posts = await query.take(10).getMany();
|
||||
|
||||
return await GalleryPosts.packMany(posts, me);
|
||||
});
|
|
@ -1,35 +0,0 @@
|
|||
import { GalleryPosts } from '@/models/index.js';
|
||||
import define from '../../define.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
|
||||
export default define(meta, paramDef, async (ps, me) => {
|
||||
const query = GalleryPosts.createQueryBuilder('post')
|
||||
.andWhere('post.likedCount > 0')
|
||||
.orderBy('post.likedCount', 'DESC');
|
||||
|
||||
const posts = await query.take(10).getMany();
|
||||
|
||||
return await GalleryPosts.packMany(posts, me);
|
||||
});
|
|
@ -1,37 +0,0 @@
|
|||
import { GalleryPosts } from '@/models/index.js';
|
||||
import define from '../../define.js';
|
||||
import { makePaginationQuery } from '../../common/make-pagination-query.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
|
||||
export default define(meta, paramDef, async (ps, me) => {
|
||||
const query = makePaginationQuery(GalleryPosts.createQueryBuilder('post'), ps.sinceId, ps.untilId)
|
||||
.innerJoinAndSelect('post.user', 'user');
|
||||
|
||||
const posts = await query.take(ps.limit).getMany();
|
||||
|
||||
return await GalleryPosts.packMany(posts, me);
|
||||
});
|
|
@ -1,72 +0,0 @@
|
|||
import { DriveFiles, GalleryPosts } from '@/models/index.js';
|
||||
import { genId } from '@/misc/gen-id.js';
|
||||
import { GalleryPost } from '@/models/entities/gallery-post.js';
|
||||
import { DriveFile } from '@/models/entities/drive-file.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
import { ApiError } from '@/server/api/error.js';
|
||||
import define from '../../../define.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['gallery'],
|
||||
|
||||
requireCredential: true,
|
||||
|
||||
kind: 'write:gallery',
|
||||
|
||||
limit: {
|
||||
duration: HOUR,
|
||||
max: 300,
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'GalleryPost',
|
||||
},
|
||||
} 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
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const files = (await Promise.all(ps.fileIds.map(fileId =>
|
||||
DriveFiles.findOneBy({
|
||||
id: fileId,
|
||||
userId: user.id,
|
||||
}),
|
||||
))).filter((file): file is DriveFile => file != null);
|
||||
|
||||
if (files.length !== ps.fileIds.length) {
|
||||
throw new ApiError(
|
||||
'INVALID_PARAM',
|
||||
{
|
||||
param: '#/properties/fileIds/items',
|
||||
reason: 'contains invalid file IDs',
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const post = await GalleryPosts.insert(new GalleryPost({
|
||||
id: genId(),
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
title: ps.title,
|
||||
description: ps.description,
|
||||
userId: user.id,
|
||||
isSensitive: ps.isSensitive,
|
||||
fileIds: files.map(file => file.id),
|
||||
})).then(x => GalleryPosts.findOneByOrFail(x.identifiers[0]));
|
||||
|
||||
return await GalleryPosts.pack(post, user);
|
||||
});
|
|
@ -1,33 +0,0 @@
|
|||
import { GalleryPosts } from '@/models/index.js';
|
||||
import define from '../../../define.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['gallery'],
|
||||
|
||||
requireCredential: true,
|
||||
|
||||
kind: 'write:gallery',
|
||||
|
||||
errors: ['NO_SUCH_POST'],
|
||||
} 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
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const post = await GalleryPosts.findOneBy({
|
||||
id: ps.postId,
|
||||
userId: user.id,
|
||||
});
|
||||
|
||||
if (post == null) throw new ApiError('NO_SUCH_POST');
|
||||
|
||||
await GalleryPosts.delete(post.id);
|
||||
});
|
|
@ -1,46 +0,0 @@
|
|||
import { GalleryPosts, GalleryLikes } from '@/models/index.js';
|
||||
import { genId } from '@/misc/gen-id.js';
|
||||
import define from '../../../define.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['gallery'],
|
||||
|
||||
requireCredential: true,
|
||||
|
||||
kind: 'write:gallery-likes',
|
||||
|
||||
errors: ['NO_SUCH_POST', 'ALREADY_LIKED'],
|
||||
} 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
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const post = await GalleryPosts.findOneBy({ id: ps.postId });
|
||||
if (post == null) throw new ApiError('NO_SUCH_POST');
|
||||
|
||||
// if already liked
|
||||
const exist = await GalleryLikes.countBy({
|
||||
postId: post.id,
|
||||
userId: user.id,
|
||||
});
|
||||
|
||||
if (exist) throw new ApiError('ALREADY_LIKED');
|
||||
|
||||
// Create like
|
||||
await GalleryLikes.insert({
|
||||
id: genId(),
|
||||
createdAt: new Date(),
|
||||
postId: post.id,
|
||||
userId: user.id,
|
||||
});
|
||||
|
||||
GalleryPosts.increment({ id: post.id }, 'likedCount', 1);
|
||||
});
|
|
@ -1,36 +0,0 @@
|
|||
import { GalleryPosts } from '@/models/index.js';
|
||||
import define from '../../../define.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['gallery'],
|
||||
|
||||
requireCredential: false,
|
||||
|
||||
errors: ['NO_SUCH_POST'],
|
||||
|
||||
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
|
||||
export default define(meta, paramDef, async (ps, me) => {
|
||||
const post = await GalleryPosts.findOneBy({
|
||||
id: ps.postId,
|
||||
});
|
||||
|
||||
if (post == null) throw new ApiError('NO_SUCH_POST');
|
||||
|
||||
return await GalleryPosts.pack(post, me);
|
||||
});
|
|
@ -1,39 +0,0 @@
|
|||
import { GalleryPosts, GalleryLikes } from '@/models/index.js';
|
||||
import define from '../../../define.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['gallery'],
|
||||
|
||||
requireCredential: true,
|
||||
|
||||
kind: 'write:gallery-likes',
|
||||
|
||||
errors: ['NO_SUCH_POST', 'NOT_LIKED'],
|
||||
} 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
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const post = await GalleryPosts.findOneBy({ id: ps.postId });
|
||||
if (post == null) throw new ApiError('NO_SUCH_POST');
|
||||
|
||||
const exist = await GalleryLikes.findOneBy({
|
||||
postId: post.id,
|
||||
userId: user.id,
|
||||
});
|
||||
|
||||
if (exist == null) throw new ApiError('NOT_LIKED');
|
||||
|
||||
// Delete like
|
||||
await GalleryLikes.delete(exist.id);
|
||||
|
||||
GalleryPosts.decrement({ id: post.id }, 'likedCount', 1);
|
||||
});
|
|
@ -1,75 +0,0 @@
|
|||
import { DriveFiles, GalleryPosts } from '@/models/index.js';
|
||||
import { DriveFile } from '@/models/entities/drive-file.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
import { ApiError } from '@/server/api/error.js';
|
||||
import define from '../../../define.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['gallery'],
|
||||
|
||||
requireCredential: true,
|
||||
|
||||
kind: 'write:gallery',
|
||||
|
||||
limit: {
|
||||
duration: HOUR,
|
||||
max: 300,
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'GalleryPost',
|
||||
},
|
||||
|
||||
errors: ['INVALID_PARAM'],
|
||||
} 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
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const files = (await Promise.all(ps.fileIds.map(fileId =>
|
||||
DriveFiles.findOneBy({
|
||||
id: fileId,
|
||||
userId: user.id,
|
||||
}),
|
||||
))).filter((file): file is DriveFile => file != null);
|
||||
|
||||
if (files.length !== ps.fileIds.length) {
|
||||
throw new ApiError(
|
||||
'INVALID_PARAM',
|
||||
{
|
||||
param: '#/properties/fileIds/items',
|
||||
reason: 'contains invalid file IDs',
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
await GalleryPosts.update({
|
||||
id: ps.postId,
|
||||
userId: user.id,
|
||||
}, {
|
||||
updatedAt: new Date(),
|
||||
title: ps.title,
|
||||
description: ps.description,
|
||||
isSensitive: ps.isSensitive,
|
||||
fileIds: files.map(file => file.id),
|
||||
});
|
||||
|
||||
const post = await GalleryPosts.findOneByOrFail({ id: ps.postId });
|
||||
|
||||
return await GalleryPosts.pack(post, user);
|
||||
});
|
|
@ -1,55 +0,0 @@
|
|||
import { GalleryLikes } from '@/models/index.js';
|
||||
import define from '../../../define.js';
|
||||
import { makePaginationQuery } from '../../../common/make-pagination-query.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['account', 'gallery'],
|
||||
|
||||
requireCredential: true,
|
||||
|
||||
kind: 'read:gallery-likes',
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
},
|
||||
post: {
|
||||
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
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const query = makePaginationQuery(GalleryLikes.createQueryBuilder('like'), ps.sinceId, ps.untilId)
|
||||
.andWhere('like.userId = :meId', { meId: user.id })
|
||||
.leftJoinAndSelect('like.post', 'post');
|
||||
|
||||
const likes = await query
|
||||
.take(ps.limit)
|
||||
.getMany();
|
||||
|
||||
return await GalleryLikes.packMany(likes, user);
|
||||
});
|
|
@ -1,43 +0,0 @@
|
|||
import { GalleryPosts } from '@/models/index.js';
|
||||
import define from '../../../define.js';
|
||||
import { makePaginationQuery } from '../../../common/make-pagination-query.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['account', 'gallery'],
|
||||
|
||||
requireCredential: true,
|
||||
|
||||
kind: 'read: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
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const query = makePaginationQuery(GalleryPosts.createQueryBuilder('post'), ps.sinceId, ps.untilId)
|
||||
.andWhere('post.userId = :meId', { meId: user.id });
|
||||
|
||||
const posts = await query
|
||||
.take(ps.limit)
|
||||
.getMany();
|
||||
|
||||
return await GalleryPosts.packMany(posts, user);
|
||||
});
|
|
@ -1,42 +0,0 @@
|
|||
import { GalleryPosts } from '@/models/index.js';
|
||||
import define from '../../../define.js';
|
||||
import { makePaginationQuery } from '../../../common/make-pagination-query.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['users', 'gallery'],
|
||||
|
||||
description: 'Show all gallery posts by the given user.',
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'GalleryPost',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
userId: { type: 'string', format: 'misskey:id' },
|
||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||
sinceId: { type: 'string', format: 'misskey:id' },
|
||||
untilId: { type: 'string', format: 'misskey:id' },
|
||||
},
|
||||
required: ['userId'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const query = makePaginationQuery(GalleryPosts.createQueryBuilder('post'), ps.sinceId, ps.untilId)
|
||||
.andWhere('post.userId = :userId', { userId: ps.userId });
|
||||
|
||||
const posts = await query
|
||||
.take(ps.limit)
|
||||
.getMany();
|
||||
|
||||
return await GalleryPosts.packMany(posts, user);
|
||||
});
|
|
@ -73,7 +73,7 @@ export const errors: Record<string, { message: string, httpStatusCode: number }>
|
|||
httpStatusCode: 409,
|
||||
},
|
||||
ALREADY_LIKED: {
|
||||
message: 'You already liked that page or gallery post.',
|
||||
message: 'You already liked that page.',
|
||||
httpStatusCode: 409,
|
||||
},
|
||||
ALREADY_MUTING: {
|
||||
|
@ -292,10 +292,6 @@ export const errors: Record<string, { message: string, httpStatusCode: number }>
|
|||
message: 'No such parent folder.',
|
||||
httpStatusCode: 404,
|
||||
},
|
||||
NO_SUCH_POST: {
|
||||
message: 'No such gallery post.',
|
||||
httpStatusCode: 404,
|
||||
},
|
||||
NO_SUCH_RESET_REQUEST: {
|
||||
message: 'No such password reset request.',
|
||||
httpStatusCode: 404,
|
||||
|
@ -337,7 +333,7 @@ export const errors: Record<string, { message: string, httpStatusCode: number }>
|
|||
httpStatusCode: 409,
|
||||
},
|
||||
NOT_LIKED: {
|
||||
message: 'You have not liked that page or gallery post.',
|
||||
message: 'You have not liked that page.',
|
||||
httpStatusCode: 409,
|
||||
},
|
||||
NOT_MUTING: {
|
||||
|
|
|
@ -18,7 +18,7 @@ import { KoaAdapter } from '@bull-board/koa';
|
|||
import { In, IsNull } from 'typeorm';
|
||||
import { fetchMeta } from '@/misc/fetch-meta.js';
|
||||
import config from '@/config/index.js';
|
||||
import { Users, Notes, UserProfiles, Pages, Channels, Clips, GalleryPosts } from '@/models/index.js';
|
||||
import { Users, Notes, UserProfiles, Pages, Channels, Clips } from '@/models/index.js';
|
||||
import * as Acct from '@/misc/acct.js';
|
||||
import { getNoteSummary } from '@/misc/get-note-summary.js';
|
||||
import { queues } from '@/queue/queues.js';
|
||||
|
@ -421,31 +421,6 @@ router.get('/clips/:clip', async (ctx, next) => {
|
|||
await next();
|
||||
});
|
||||
|
||||
// Gallery post
|
||||
router.get('/gallery/:post', async (ctx, next) => {
|
||||
const post = await GalleryPosts.findOneBy({ id: ctx.params.post });
|
||||
|
||||
if (post) {
|
||||
const _post = await GalleryPosts.pack(post);
|
||||
const profile = await UserProfiles.findOneByOrFail({ userId: post.userId });
|
||||
const meta = await fetchMeta();
|
||||
await ctx.render('gallery-post', {
|
||||
post: _post,
|
||||
profile,
|
||||
avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: post.userId })),
|
||||
instanceName: meta.name || 'FoundKey',
|
||||
icon: meta.iconUrl,
|
||||
themeColor: meta.themeColor,
|
||||
});
|
||||
|
||||
ctx.set('Cache-Control', 'public, max-age=15');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await next();
|
||||
});
|
||||
|
||||
// Channel
|
||||
router.get('/channels/:channel', async (ctx, next) => {
|
||||
const channel = await Channels.findOneBy({
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
extends ./base
|
||||
|
||||
block vars
|
||||
- const user = post.user;
|
||||
- const title = post.title;
|
||||
- const url = `${config.url}/gallery/${post.id}`;
|
||||
|
||||
block title
|
||||
= `${title} | ${instanceName}`
|
||||
|
||||
block desc
|
||||
meta(name='description' content= post.description)
|
||||
|
||||
block og
|
||||
meta(property='og:type' content='article')
|
||||
meta(property='og:title' content= title)
|
||||
meta(property='og:description' content= post.description)
|
||||
meta(property='og:url' content= url)
|
||||
meta(property='og:image' content= post.files[0].thumbnailUrl)
|
||||
|
||||
block meta
|
||||
if user.host || profile.noCrawle
|
||||
meta(name='robots' content='noindex')
|
||||
|
||||
meta(name='misskey:user-username' content=user.username)
|
||||
meta(name='misskey:user-id' content=user.id)
|
||||
|
||||
// todo
|
||||
if user.twitter
|
||||
meta(name='twitter:creator' content=`@${user.twitter.screenName}`)
|
||||
|
||||
if !user.host
|
||||
link(rel='alternate' href=url type='application/activity+json')
|
Loading…
Reference in a new issue