Removed all references to user pages
ci/woodpecker/tag/ociImageTag Pipeline was successful Details

This commit is contained in:
Natty 2024-01-10 23:42:54 +01:00
parent da04190d47
commit 8654fe13a6
Signed by: natty
GPG Key ID: BF6CB659ADEE60EC
26 changed files with 5 additions and 1139 deletions

View File

@ -41,8 +41,6 @@ import {UserPublickey} from "@/models/entities/user-publickey.js";
import {UserProfile} from "@/models/entities/user-profile.js";
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";
@ -136,8 +134,6 @@ export const entities = [
NoteWatching,
NoteThreadMuting,
NoteUnread,
Page,
PageLike,
GalleryPost,
GalleryLike,
DriveFile,

View File

@ -17,10 +17,6 @@ export const kinds = [
"read:reactions",
"write:reactions",
"write:votes",
"read:pages",
"write:pages",
"write:page-likes",
"read:page-likes",
"read:gallery",
"write:gallery",
"read:gallery-likes",

View File

@ -143,7 +143,7 @@ export class Meta {
@Column("varchar", {
length: 512,
array: true,
default: "{/featured,/explore,/pages,/about-calckey}",
default: "{/featured,/explore,/about-calckey}",
})
public pinnedPages: string[];

View File

@ -1,40 +0,0 @@
import {
PrimaryColumn,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
} from "typeorm";
import { User } from "./user.js";
import { id } from "../id.js";
import { Page } from "./page.js";
@Entity()
@Index(["userId", "pageId"], { unique: true })
export class PageLike {
@PrimaryColumn(id())
public id: string;
@Column("timestamp with time zone")
public createdAt: Date;
@Index()
@Column(id())
public userId: User["id"];
@ManyToOne((type) => User, {
onDelete: "CASCADE",
})
@JoinColumn()
public user: User | null;
@Column(id())
public pageId: Page["id"];
@ManyToOne((type) => Page, {
onDelete: "CASCADE",
})
@JoinColumn()
public page: Page | null;
}

View File

@ -1,133 +0,0 @@
import {
Entity,
Index,
JoinColumn,
Column,
PrimaryColumn,
ManyToOne,
} from "typeorm";
import { User } from "./user.js";
import { id } from "../id.js";
import { DriveFile } from "./drive-file.js";
@Entity()
@Index(["userId", "name"], { unique: true })
export class Page {
@PrimaryColumn(id())
public id: string;
@Index()
@Column("timestamp with time zone", {
comment: "The created date of the Page.",
})
public createdAt: Date;
@Index()
@Column("timestamp with time zone", {
comment: "The updated date of the Page.",
})
public updatedAt: Date;
@Column("varchar", {
length: 256,
})
public title: string;
@Index()
@Column("varchar", {
length: 256,
})
public name: string;
@Column("varchar", {
length: 256,
nullable: true,
})
public summary: string | null;
@Column("boolean")
public alignCenter: boolean;
@Column("boolean")
public isPublic: boolean;
@Column("boolean", {
default: false,
})
public hideTitleWhenPinned: boolean;
@Column("varchar", {
length: 32,
})
public font: string;
@Index()
@Column({
...id(),
comment: "The ID of author.",
})
public userId: User["id"];
@ManyToOne((type) => User, {
onDelete: "CASCADE",
})
@JoinColumn()
public user: User | null;
@Column({
...id(),
nullable: true,
})
public eyeCatchingImageId: DriveFile["id"] | null;
@ManyToOne((type) => DriveFile, {
onDelete: "CASCADE",
})
@JoinColumn()
public eyeCatchingImage: DriveFile | null;
@Column("jsonb", {
default: [],
})
public content: Record<string, any>[];
@Column("jsonb", {
default: [],
})
public variables: Record<string, any>[];
@Column("varchar", {
length: 16384,
default: "",
})
public script: string;
/**
* public ...
* followers ...
* specified ... visibleUserIds
*/
@Column("enum", { enum: ["public", "followers", "specified"] })
public visibility: "public" | "followers" | "specified";
@Index()
@Column({
...id(),
array: true,
default: "{}",
})
public visibleUserIds: User["id"][];
@Column("integer", {
default: 0,
})
public likedCount: number;
constructor(data: Partial<Page>) {
if (data == null) return;
for (const [k, v] of Object.entries(data)) {
(this as any)[k] = v;
}
}
}

View File

@ -2,7 +2,6 @@ import {Column, Entity, Index, JoinColumn, OneToOne, PrimaryColumn,} from "typeo
import {ffVisibility, notificationTypes} from "@/types.js";
import {id} from "../id.js";
import {User} from "./user.js";
import {Page} from "./page.js";
// TODO: このテーブルで管理している情報すべてレジストリで管理するようにしても良いかも
// ただ、「emailVerified が true なユーザーを find する」のようなクエリは書けなくなるからウーン
@ -184,18 +183,6 @@ export class UserProfile {
})
public receiveAnnouncementEmail: boolean;
@Column({
...id(),
nullable: true,
})
public pinnedPageId: Page["id"] | null;
@OneToOne((type) => Page, {
onDelete: "SET NULL",
})
@JoinColumn()
public pinnedPage: Page | null;
@Index()
@Column("boolean", {
default: false,

View File

@ -4,7 +4,6 @@ import {Announcement} from "./entities/announcement.js";
import {AnnouncementRead} from "./entities/announcement-read.js";
import {Poll} from "./entities/poll.js";
import {PollVote} from "./entities/poll-vote.js";
import {Meta} from "./entities/meta.js";
import {SwSubscription} from "./entities/sw-subscription.js";
import {NoteWatching} from "./entities/note-watching.js";
import {NoteThreadMuting} from "./entities/note-thread-muting.js";
@ -36,8 +35,6 @@ import {UserProfile} from "./entities/user-profile.js";
import {AttestationChallenge} from "./entities/attestation-challenge.js";
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";
@ -91,7 +88,6 @@ export const Emojis = EmojiRepository;
export const DriveFiles = DriveFileRepository;
export const DriveFolders = DriveFolderRepository;
export const Notifications = NotificationRepository;
export const Metas = db.getRepository(Meta);
export const Mutings = MutingRepository;
export const RenoteMutings = RenoteMutingRepository;
export const Blockings = BlockingRepository;
@ -102,8 +98,6 @@ export const RegistrationTickets = db.getRepository(RegistrationTicket);
export const AuthSessions = AuthSessionRepository;
export const AccessTokens = db.getRepository(AccessToken);
export const Signins = SigninRepository;
export const Pages = PageRepository;
export const PageLikes = PageLikeRepository;
export const GalleryPosts = GalleryPostRepository;
export const GalleryLikes = GalleryLikeRepository;
export const ModerationLogs = ModerationLogRepository;

View File

@ -1,23 +0,0 @@
import { db } from "@/db/postgre.js";
import { PageLike } from "@/models/entities/page-like.js";
import type { User } from "@/models/entities/user.js";
import { Pages } from "../index.js";
export const PageLikeRepository = db.getRepository(PageLike).extend({
async pack(
src: PageLike["id"] | PageLike,
me?: { id: User["id"] } | null | undefined,
) {
const like =
typeof src === "object" ? src : await this.findOneByOrFail({ id: src });
return {
id: like.id,
page: await Pages.pack(like.page || like.pageId, me),
};
},
packMany(likes: PageLike[], me: { id: User["id"] }) {
return Promise.all(likes.map((x) => this.pack(x, me)));
},
});

View File

@ -1,99 +0,0 @@
import { db } from "@/db/postgre.js";
import { Page } from "@/models/entities/page.js";
import type { Packed } from "@/misc/schema.js";
import { awaitAll } from "@/prelude/await-all.js";
import type { DriveFile } from "@/models/entities/drive-file.js";
import type { User } from "@/models/entities/user.js";
import { Users, DriveFiles, PageLikes } from "../index.js";
export const PageRepository = db.getRepository(Page).extend({
async pack(
src: Page["id"] | Page,
me?: { id: User["id"] } | null | undefined,
): Promise<Packed<"Page">> {
const meId = me ? me.id : null;
const page =
typeof src === "object" ? src : await this.findOneByOrFail({ id: src });
const attachedFiles: Promise<DriveFile | null>[] = [];
const collectFile = (xs: any[]) => {
for (const x of xs) {
if (x.type === "image") {
attachedFiles.push(
DriveFiles.findOneBy({
id: x.fileId,
userId: page.userId,
}),
);
}
if (x.children) {
collectFile(x.children);
}
}
};
collectFile(page.content);
// 後方互換性のため
let migrated = false;
const migrate = (xs: any[]) => {
for (const x of xs) {
if (x.type === "input") {
if (x.inputType === "text") {
x.type = "textInput";
}
if (x.inputType === "number") {
x.type = "numberInput";
if (x.default) x.default = parseInt(x.default, 10);
}
migrated = true;
}
if (x.children) {
migrate(x.children);
}
}
};
migrate(page.content);
if (migrated) {
this.update(page.id, {
content: page.content,
});
}
return await awaitAll({
id: page.id,
createdAt: page.createdAt.toISOString(),
updatedAt: page.updatedAt.toISOString(),
userId: page.userId,
user: Users.pack(page.user || page.userId, me), // { detail: true } すると無限ループするので注意
content: page.content,
variables: page.variables,
title: page.title,
isPublic: page.isPublic,
name: page.name,
summary: page.summary,
hideTitleWhenPinned: page.hideTitleWhenPinned,
alignCenter: page.alignCenter,
font: page.font,
script: page.script,
eyeCatchingImageId: page.eyeCatchingImageId,
eyeCatchingImage: page.eyeCatchingImageId
? await DriveFiles.pack(page.eyeCatchingImageId)
: null,
attachedFiles: DriveFiles.packMany(
(
await Promise.all(attachedFiles)
).filter((x): x is DriveFile => x != null),
),
likedCount: page.likedCount,
isLiked: meId
? await PageLikes.findOneBy({ pageId: page.id, userId: meId }).then(
(x) => x != null,
)
: undefined,
});
},
packMany(pages: Page[], me?: { id: User["id"] } | null | undefined) {
return Promise.all(pages.map((x) => this.pack(x, me)));
},
});

View File

@ -27,7 +27,6 @@ import {
Mutings,
NoteUnreads,
Notifications,
Pages,
RenoteMutings,
UserNotePinings,
UserProfiles,
@ -420,10 +419,6 @@ export const UserRepository = db.getRepository(User).extend({
followingCount: followingCount || 0,
notesCount: user.notesCount,
pinnedNoteIds: pins.map((pin) => pin.noteId),
pinnedPageId: profile!.pinnedPageId,
pinnedPage: profile!.pinnedPageId
? Pages.pack(profile!.pinnedPageId, me)
: null,
publicReactions: profile!.publicReactions,
ffVisibility: profile!.ffVisibility,
twoFactorEnabled: profile!.twoFactorEnabled,

View File

@ -220,17 +220,6 @@ export const packedUserDetailedNotMeOnlySchema = {
format: "id",
},
},
pinnedPageId: {
type: "string",
nullable: true,
optional: false,
},
pinnedPage: {
type: "object",
nullable: true,
optional: false,
ref: "Page",
},
publicReactions: {
type: "boolean",
nullable: false,

View File

@ -183,8 +183,6 @@ import * as ep___i_importFollowing from "./endpoints/i/import-following.js";
import * as ep___i_importMuting from "./endpoints/i/import-muting.js";
import * as ep___i_importUserLists from "./endpoints/i/import-user-lists.js";
import * as ep___i_notifications from "./endpoints/i/notifications.js";
import * as ep___i_pageLikes from "./endpoints/i/page-likes.js";
import * as ep___i_pages from "./endpoints/i/pages.js";
import * as ep___i_pin from "./endpoints/i/pin.js";
import * as ep___i_readAllUnreadNotes from "./endpoints/i/read-all-unread-notes.js";
import * as ep___i_readAnnouncement from "./endpoints/i/read-announcement.js";
@ -251,14 +249,6 @@ import * as ep___notes_watching_delete from "./endpoints/notes/watching/delete.j
import * as ep___notifications_create from "./endpoints/notifications/create.js";
import * as ep___notifications_markAllAsRead from "./endpoints/notifications/mark-all-as-read.js";
import * as ep___notifications_read from "./endpoints/notifications/read.js";
import * as ep___pagePush from "./endpoints/page-push.js";
import * as ep___pages_create from "./endpoints/pages/create.js";
import * as ep___pages_delete from "./endpoints/pages/delete.js";
import * as ep___pages_featured from "./endpoints/pages/featured.js";
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___ping from "./endpoints/ping.js";
import * as ep___recommendedInstances from "./endpoints/recommended-instances.js";
import * as ep___pinnedUsers from "./endpoints/pinned-users.js";
@ -292,7 +282,6 @@ import * as ep___users_lists_push from "./endpoints/users/lists/push.js";
import * as ep___users_lists_show from "./endpoints/users/lists/show.js";
import * as ep___users_lists_update from "./endpoints/users/lists/update.js";
import * as ep___users_notes from "./endpoints/users/notes.js";
import * as ep___users_pages from "./endpoints/users/pages.js";
import * as ep___users_reactions from "./endpoints/users/reactions.js";
import * as ep___users_recommendation from "./endpoints/users/recommendation.js";
import * as ep___users_relation from "./endpoints/users/relation.js";
@ -499,8 +488,6 @@ const eps = [
["i/import-muting", ep___i_importMuting],
["i/import-user-lists", ep___i_importUserLists],
["i/notifications", ep___i_notifications],
["i/page-likes", ep___i_pageLikes],
["i/pages", ep___i_pages],
["i/pin", ep___i_pin],
["i/read-all-unread-notes", ep___i_readAllUnreadNotes],
["i/read-announcement", ep___i_readAnnouncement],
@ -564,14 +551,6 @@ const eps = [
["notifications/create", ep___notifications_create],
["notifications/mark-all-as-read", ep___notifications_markAllAsRead],
["notifications/read", ep___notifications_read],
["page-push", ep___pagePush],
["pages/create", ep___pages_create],
["pages/delete", ep___pages_delete],
["pages/featured", ep___pages_featured],
["pages/like", ep___pages_like],
["pages/show", ep___pages_show],
["pages/unlike", ep___pages_unlike],
["pages/update", ep___pages_update],
["ping", ep___ping],
["pinned-users", ep___pinnedUsers],
["recommended-instances", ep___recommendedInstances],
@ -608,7 +587,6 @@ const eps = [
["users/lists/show", ep___users_lists_show],
["users/lists/update", ep___users_lists_update],
["users/notes", ep___users_notes],
["users/pages", ep___users_pages],
["users/reactions", ep___users_reactions],
["users/recommendation", ep___users_recommendation],
["users/relation", ep___users_relation],

View File

@ -1,58 +0,0 @@
import { PageLikes } from "@/models/index.js";
import define from "../../define.js";
import { makePaginationQuery } from "../../common/make-pagination-query.js";
export const meta = {
tags: ["account", "pages"],
requireCredential: true,
kind: "read:page-likes",
res: {
type: "array",
optional: false,
nullable: false,
items: {
type: "object",
properties: {
id: {
type: "string",
optional: false,
nullable: false,
format: "id",
},
page: {
type: "object",
optional: false,
nullable: false,
ref: "Page",
},
},
},
},
} 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;
export default define(meta, paramDef, async (ps, user) => {
const query = makePaginationQuery(
PageLikes.createQueryBuilder("like"),
ps.sinceId,
ps.untilId,
)
.andWhere("like.userId = :meId", { meId: user.id })
.leftJoinAndSelect("like.page", "page");
const likes = await query.take(ps.limit).getMany();
return PageLikes.packMany(likes, user);
});

View File

@ -1,45 +0,0 @@
import { Pages } from "@/models/index.js";
import define from "../../define.js";
import { makePaginationQuery } from "../../common/make-pagination-query.js";
export const meta = {
tags: ["account", "pages"],
requireCredential: true,
kind: "read:pages",
res: {
type: "array",
optional: false,
nullable: false,
items: {
type: "object",
optional: false,
nullable: false,
ref: "Page",
},
},
} 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;
export default define(meta, paramDef, async (ps, user) => {
const query = makePaginationQuery(
Pages.createQueryBuilder("page"),
ps.sinceId,
ps.untilId,
).andWhere("page.userId = :meId", { meId: user.id });
const pages = await query.take(ps.limit).getMany();
return await Pages.packMany(pages);
});

View File

@ -6,7 +6,7 @@ import {publishToFollowers} from "@/services/i/update.js";
import {extractCustomEmojisFromMfm} from "@/misc/extract-custom-emojis-from-mfm.js";
import {extractHashtags} from "@/misc/extract-hashtags.js";
import {updateUsertags} from "@/services/update-hashtag.js";
import {DriveFiles, Pages, UserProfiles, Users} from "@/models/index.js";
import {DriveFiles, UserProfiles, Users} from "@/models/index.js";
import type {User} from "@/models/entities/user.js";
import type {UserProfile} from "@/models/entities/user-profile.js";
import {notificationTypes} from "@/types.js";
@ -219,17 +219,6 @@ export default define(meta, paramDef, async (ps, _user, token) => {
throw new ApiError(meta.errors.bannerNotAnImage);
}
if (ps.pinnedPageId) {
const page = await Pages.findOneBy({ id: ps.pinnedPageId });
if (page == null || page.userId !== user.id)
throw new ApiError(meta.errors.noSuchPage);
profileUpdates.pinnedPageId = page.id;
} else if (ps.pinnedPageId === null) {
profileUpdates.pinnedPageId = null;
}
if (ps.fields) {
profileUpdates.fields = ps.fields
.filter(

View File

@ -1,48 +0,0 @@
import { publishMainStream } from "@/services/stream.js";
import { Users, Pages } from "@/models/index.js";
import define from "../define.js";
import { ApiError } from "../error.js";
export const meta = {
requireCredential: true,
secure: true,
errors: {
noSuchPage: {
message: "No such page.",
code: "NO_SUCH_PAGE",
id: "4a13ad31-6729-46b4-b9af-e86b265c2e74",
},
},
} as const;
export const paramDef = {
type: "object",
properties: {
pageId: { type: "string", format: "misskey:id" },
event: { type: "string" },
var: {},
},
required: ["pageId", "event"],
} as const;
export default define(meta, paramDef, async (ps, user) => {
const page = await Pages.findOneBy({ id: ps.pageId });
if (page == null) {
throw new ApiError(meta.errors.noSuchPage);
}
publishMainStream(page.userId, "pageEvent", {
pageId: ps.pageId,
event: ps.event,
var: ps.var,
userId: user.id,
user: await Users.pack(
user.id,
{ id: page.userId },
{
detail: true,
},
),
});
});

View File

@ -1,123 +0,0 @@
import { Pages, DriveFiles } from "@/models/index.js";
import { genId } from "@/misc/gen-id.js";
import { Page } from "@/models/entities/page.js";
import define from "../../define.js";
import { ApiError } from "../../error.js";
import { HOUR } from "@/const.js";
export const meta = {
tags: ["pages"],
requireCredential: true,
kind: "write:pages",
limit: {
duration: HOUR,
max: 300,
},
res: {
type: "object",
optional: false,
nullable: false,
ref: "Page",
},
errors: {
noSuchFile: {
message: "No such file.",
code: "NO_SUCH_FILE",
id: "b7b97489-0f66-4b12-a5ff-b21bd63f6e1c",
},
nameAlreadyExists: {
message: "Specified name already exists.",
code: "NAME_ALREADY_EXISTS",
id: "4650348e-301c-499a-83c9-6aa988c66bc1",
},
},
} as const;
export const paramDef = {
type: "object",
properties: {
title: { type: "string" },
name: { type: "string", minLength: 1 },
summary: { type: "string", nullable: true },
content: {
type: "array",
items: {
type: "object",
additionalProperties: true,
},
},
variables: {
type: "array",
items: {
type: "object",
additionalProperties: true,
},
},
script: { type: "string" },
eyeCatchingImageId: {
type: "string",
format: "misskey:id",
nullable: true,
},
font: {
type: "string",
enum: ["serif", "sans-serif"],
default: "sans-serif",
},
alignCenter: { type: "boolean", default: false },
isPublic: { type: "boolean", default: true },
hideTitleWhenPinned: { type: "boolean", default: false },
},
required: ["title", "name", "content", "variables", "script"],
} as const;
export default define(meta, paramDef, async (ps, user) => {
let eyeCatchingImage = null;
if (ps.eyeCatchingImageId != null) {
eyeCatchingImage = await DriveFiles.findOneBy({
id: ps.eyeCatchingImageId,
userId: user.id,
});
if (eyeCatchingImage == null) {
throw new ApiError(meta.errors.noSuchFile);
}
}
await Pages.findBy({
userId: user.id,
name: ps.name,
}).then((result) => {
if (result.length > 0) {
throw new ApiError(meta.errors.nameAlreadyExists);
}
});
const page = await Pages.insert(
new Page({
id: genId(),
createdAt: new Date(),
updatedAt: new Date(),
title: ps.title,
name: ps.name,
summary: ps.summary,
content: ps.content,
variables: ps.variables,
script: ps.script,
eyeCatchingImageId: eyeCatchingImage ? eyeCatchingImage.id : null,
userId: user.id,
visibility: "public",
alignCenter: ps.alignCenter,
hideTitleWhenPinned: ps.hideTitleWhenPinned,
font: ps.font,
isPublic: ps.isPublic,
}),
).then((x) => Pages.findOneByOrFail(x.identifiers[0]));
return await Pages.pack(page);
});

View File

@ -1,45 +0,0 @@
import { Pages } from "@/models/index.js";
import define from "../../define.js";
import { ApiError } from "../../error.js";
export const meta = {
tags: ["pages"],
requireCredential: true,
kind: "write:pages",
errors: {
noSuchPage: {
message: "No such page.",
code: "NO_SUCH_PAGE",
id: "eb0c6e1d-d519-4764-9486-52a7e1c6392a",
},
accessDenied: {
message: "Access denied.",
code: "ACCESS_DENIED",
id: "8b741b3e-2c22-44b3-a15f-29949aa1601e",
},
},
} as const;
export const paramDef = {
type: "object",
properties: {
pageId: { type: "string", format: "misskey:id" },
},
required: ["pageId"],
} as const;
export default define(meta, paramDef, async (ps, user) => {
const page = await Pages.findOneBy({ id: ps.pageId });
if (page == null) {
throw new ApiError(meta.errors.noSuchPage);
}
if (page.userId !== user.id) {
throw new ApiError(meta.errors.accessDenied);
}
await Pages.delete(page.id);
});

View File

@ -1,38 +0,0 @@
import { Pages } from "@/models/index.js";
import define from "../../define.js";
export const meta = {
tags: ["pages"],
requireCredential: false,
requireCredentialPrivateMode: true,
res: {
type: "array",
optional: false,
nullable: false,
items: {
type: "object",
optional: false,
nullable: false,
ref: "Page",
},
},
} as const;
export const paramDef = {
type: "object",
properties: {},
required: [],
} as const;
export default define(meta, paramDef, async (ps, me) => {
const query = Pages.createQueryBuilder("page")
.where("page.visibility = 'public'")
.andWhere("page.likedCount > 0")
.orderBy("page.likedCount", "DESC");
const pages = await query.take(10).getMany();
return await Pages.packMany(pages, me);
});

View File

@ -1,61 +0,0 @@
import { Pages, PageLikes } 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: ["pages"],
requireCredential: true,
kind: "write:page-likes",
errors: {
noSuchPage: {
message: "No such page.",
code: "NO_SUCH_PAGE",
id: "cc98a8a2-0dc3-4123-b198-62c71df18ed3",
},
alreadyLiked: {
message: "The page has already been liked.",
code: "ALREADY_LIKED",
id: "cc98a8a2-0dc3-4123-b198-62c71df18ed3",
},
},
} as const;
export const paramDef = {
type: "object",
properties: {
pageId: { type: "string", format: "misskey:id" },
},
required: ["pageId"],
} as const;
export default define(meta, paramDef, async (ps, user) => {
const page = await Pages.findOneBy({ id: ps.pageId });
if (page == null) {
throw new ApiError(meta.errors.noSuchPage);
}
// if already liked
const exist = await PageLikes.findOneBy({
pageId: page.id,
userId: user.id,
});
if (exist != null) {
throw new ApiError(meta.errors.alreadyLiked);
}
// Create like
await PageLikes.insert({
id: genId(),
createdAt: new Date(),
pageId: page.id,
userId: user.id,
});
Pages.increment({ id: page.id }, "likedCount", 1);
});

View File

@ -1,75 +0,0 @@
import { IsNull } from "typeorm";
import { Pages, Users } from "@/models/index.js";
import type { Page } from "@/models/entities/page.js";
import define from "../../define.js";
import { ApiError } from "../../error.js";
export const meta = {
tags: ["pages"],
requireCredential: false,
requireCredentialPrivateMode: true,
res: {
type: "object",
optional: false,
nullable: false,
ref: "Page",
},
errors: {
noSuchPage: {
message: "No such page.",
code: "NO_SUCH_PAGE",
id: "222120c0-3ead-4528-811b-b96f233388d7",
},
},
} as const;
export const paramDef = {
type: "object",
anyOf: [
{
properties: {
pageId: { type: "string", format: "misskey:id" },
},
required: ["pageId"],
},
{
properties: {
name: { type: "string" },
username: { type: "string" },
},
required: ["name", "username"],
},
],
} as const;
export default define(meta, paramDef, async (ps, user) => {
let page: Page | null = null;
if (ps.pageId) {
page = await Pages.findOneBy({ id: ps.pageId });
} else if (ps.name && ps.username) {
const author = await Users.findOneBy({
host: IsNull(),
usernameLower: ps.username.toLowerCase(),
});
if (author) {
page = await Pages.findOneBy({
name: ps.name,
userId: author.id,
});
}
}
if (page == null) {
throw new ApiError(meta.errors.noSuchPage);
}
if (!page.isPublic && (user == null || page.userId !== user.id)) {
throw new ApiError(meta.errors.noSuchPage);
}
return await Pages.pack(page, user);
});

View File

@ -1,54 +0,0 @@
import { Pages, PageLikes } from "@/models/index.js";
import define from "../../define.js";
import { ApiError } from "../../error.js";
export const meta = {
tags: ["pages"],
requireCredential: true,
kind: "write:page-likes",
errors: {
noSuchPage: {
message: "No such page.",
code: "NO_SUCH_PAGE",
id: "a0d41e20-1993-40bd-890e-f6e560ae648e",
},
notLiked: {
message: "You have not liked that page.",
code: "NOT_LIKED",
id: "f5e586b0-ce93-4050-b0e3-7f31af5259ee",
},
},
} as const;
export const paramDef = {
type: "object",
properties: {
pageId: { type: "string", format: "misskey:id" },
},
required: ["pageId"],
} as const;
export default define(meta, paramDef, async (ps, user) => {
const page = await Pages.findOneBy({ id: ps.pageId });
if (page == null) {
throw new ApiError(meta.errors.noSuchPage);
}
const exist = await PageLikes.findOneBy({
pageId: page.id,
userId: user.id,
});
if (exist == null) {
throw new ApiError(meta.errors.notLiked);
}
// Delete like
await PageLikes.delete(exist.id);
Pages.decrement({ id: page.id }, "likedCount", 1);
});

View File

@ -1,134 +0,0 @@
import { Not } from "typeorm";
import { Pages, DriveFiles } from "@/models/index.js";
import define from "../../define.js";
import { ApiError } from "../../error.js";
import { HOUR } from "@/const.js";
export const meta = {
tags: ["pages"],
requireCredential: true,
kind: "write:pages",
limit: {
duration: HOUR,
max: 300,
},
errors: {
noSuchPage: {
message: "No such page.",
code: "NO_SUCH_PAGE",
id: "21149b9e-3616-4778-9592-c4ce89f5a864",
},
accessDenied: {
message: "Access denied.",
code: "ACCESS_DENIED",
id: "3c15cd52-3b4b-4274-967d-6456fc4f792b",
},
noSuchFile: {
message: "No such file.",
code: "NO_SUCH_FILE",
id: "cfc23c7c-3887-490e-af30-0ed576703c82",
},
nameAlreadyExists: {
message: "Specified name already exists.",
code: "NAME_ALREADY_EXISTS",
id: "2298a392-d4a1-44c5-9ebb-ac1aeaa5a9ab",
},
},
} as const;
export const paramDef = {
type: "object",
properties: {
pageId: { type: "string", format: "misskey:id" },
title: { type: "string" },
name: { type: "string", minLength: 1 },
summary: { type: "string", nullable: true },
content: {
type: "array",
items: {
type: "object",
additionalProperties: true,
},
},
variables: {
type: "array",
items: {
type: "object",
additionalProperties: true,
},
},
script: { type: "string" },
eyeCatchingImageId: {
type: "string",
format: "misskey:id",
nullable: true,
},
font: { type: "string", enum: ["serif", "sans-serif"] },
alignCenter: { type: "boolean" },
hideTitleWhenPinned: { type: "boolean" },
isPublic: { type: "boolean" },
},
required: ["pageId", "title", "name", "content", "variables", "script"],
} as const;
export default define(meta, paramDef, async (ps, user) => {
const page = await Pages.findOneBy({ id: ps.pageId });
if (page == null) {
throw new ApiError(meta.errors.noSuchPage);
}
if (page.userId !== user.id) {
throw new ApiError(meta.errors.accessDenied);
}
let eyeCatchingImage = null;
if (ps.eyeCatchingImageId != null) {
eyeCatchingImage = await DriveFiles.findOneBy({
id: ps.eyeCatchingImageId,
userId: user.id,
});
if (eyeCatchingImage == null) {
throw new ApiError(meta.errors.noSuchFile);
}
}
await Pages.findBy({
id: Not(ps.pageId),
userId: user.id,
name: ps.name,
}).then((result) => {
if (result.length > 0) {
throw new ApiError(meta.errors.nameAlreadyExists);
}
});
await Pages.update(page.id, {
updatedAt: new Date(),
title: ps.title,
name: ps.name === undefined ? page.name : ps.name,
summary: ps.name === undefined ? page.summary : ps.summary,
content: ps.content,
variables: ps.variables,
script: ps.script,
isPublic: ps.isPublic,
alignCenter:
ps.alignCenter === undefined ? page.alignCenter : ps.alignCenter,
hideTitleWhenPinned:
ps.hideTitleWhenPinned === undefined
? page.hideTitleWhenPinned
: ps.hideTitleWhenPinned,
font: ps.font === undefined ? page.font : ps.font,
eyeCatchingImageId:
ps.eyeCatchingImageId === null
? null
: ps.eyeCatchingImageId === undefined
? page.eyeCatchingImageId
: eyeCatchingImage!.id,
});
});

View File

@ -1,48 +0,0 @@
import { Pages } from "@/models/index.js";
import define from "../../define.js";
import { makePaginationQuery } from "../../common/make-pagination-query.js";
export const meta = {
tags: ["users", "pages"],
requireCredentialPrivateMode: true,
description: "Show all pages this user created.",
res: {
type: "array",
optional: false,
nullable: false,
items: {
type: "object",
optional: false,
nullable: false,
ref: "Page",
},
},
} 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;
export default define(meta, paramDef, async (ps, user) => {
const query = makePaginationQuery(
Pages.createQueryBuilder("page"),
ps.sinceId,
ps.untilId,
)
.andWhere("page.userId = :userId", { userId: ps.userId })
.andWhere("page.visibility = 'public'")
.andWhere("page.isPublic = true");
const pages = await query.take(ps.limit).getMany();
return await Pages.packMany(pages);
});

View File

@ -1,16 +1,7 @@
import {
DriveFiles,
Followings,
NoteFavorites,
NoteReactions,
Notes,
PageLikes,
PollVotes,
Users,
} from "@/models/index.js";
import { awaitAll } from "@/prelude/await-all.js";
import {DriveFiles, Followings, NoteFavorites, NoteReactions, Notes, PollVotes, Users,} from "@/models/index.js";
import {awaitAll} from "@/prelude/await-all.js";
import define from "../../define.js";
import { ApiError } from "../../error.js";
import {ApiError} from "../../error.js";
export const meta = {
tags: ["users"],
@ -113,16 +104,6 @@ export const meta = {
optional: false,
nullable: false,
},
pageLikesCount: {
type: "integer",
optional: false,
nullable: false,
},
pageLikedCount: {
type: "integer",
optional: false,
nullable: false,
},
driveFilesCount: {
type: "integer",
optional: false,
@ -203,13 +184,6 @@ export default define(meta, paramDef, async (ps, me) => {
noteFavoritesCount: NoteFavorites.createQueryBuilder("favorite")
.where("favorite.userId = :userId", { userId: user.id })
.getCount(),
pageLikesCount: PageLikes.createQueryBuilder("like")
.where("like.userId = :userId", { userId: user.id })
.getCount(),
pageLikedCount: PageLikes.createQueryBuilder("like")
.innerJoin("like.page", "page")
.where("page.userId = :userId", { userId: user.id })
.getCount(),
driveFilesCount: DriveFiles.createQueryBuilder("file")
.where("file.userId = :userId", { userId: user.id })
.getCount(),

View File

@ -9,7 +9,6 @@ import type {DriveFolder} from "@/models/entities/drive-folder.js";
import type {UserList} from "@/models/entities/user-list.js";
import type {AbuseUserReport} from "@/models/entities/abuse-user-report.js";
import type {Signin} from "@/models/entities/signin.js";
import type {Page} from "@/models/entities/page.js";
import type {Packed} from "@/misc/schema.js";
import type {Webhook} from "@/models/entities/webhook";
@ -71,13 +70,6 @@ export interface MainStreamTypes {
followed: Packed<"User">;
unfollow: Packed<"User">;
meUpdated: Packed<"User">;
pageEvent: {
pageId: Page["id"];
event: string;
var: any;
userId: User["id"];
user: Packed<"User">;
};
urlUploadFinished: {
marker?: string | null;
file: Packed<"DriveFile">;