forked from FoundKeyGang/FoundKey
Compare commits
8 commits
main
...
feature/ap
Author | SHA1 | Date | |
---|---|---|---|
Johann150 | af80492c16 | ||
Johann150 | 94182876c6 | ||
Johann150 | 0d15b74193 | ||
Andy | 7fd6ea563f | ||
Andy | 91b97e4980 | ||
Andy | b5b5dd51af | ||
Andy | 5c0cf99b59 | ||
Andy | 096f2129ab |
|
@ -1,4 +1,5 @@
|
|||
.autogen
|
||||
.vscode
|
||||
.config
|
||||
.woodpecker
|
||||
Dockerfile
|
||||
|
|
|
@ -2,10 +2,9 @@ root = true
|
|||
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
|
||||
[*.yml]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,6 +1,6 @@
|
|||
# Visual Studio Code
|
||||
/.vscode
|
||||
/.vsls.json
|
||||
!/.vscode/extensions.json
|
||||
|
||||
# Intelij-IDEA
|
||||
/.idea
|
||||
|
|
8
.vscode/extensions.json
vendored
Normal file
8
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"editorconfig.editorconfig",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"Vue.volar",
|
||||
"Vue.vscode-typescript-vue-plugin"
|
||||
]
|
||||
}
|
4
.vsls.json
Normal file
4
.vsls.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "http://json.schemastore.org/vsls",
|
||||
"gitignore": "exclude"
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
clone:
|
||||
git:
|
||||
image: woodpeckerci/plugin-git
|
||||
settings:
|
||||
depth: 1 # CI does not need commit history
|
||||
recursive: true
|
||||
|
||||
pipeline:
|
||||
install:
|
||||
when:
|
||||
event:
|
||||
- pull_request
|
||||
image: node:18.6.0
|
||||
commands:
|
||||
- yarn install
|
||||
lint:
|
||||
when:
|
||||
event:
|
||||
- pull_request
|
||||
image: node:18.6.0
|
||||
commands:
|
||||
- yarn workspace sw run lint
|
|
@ -36,7 +36,7 @@ gulp.task('copy:client:locales', cb => {
|
|||
});
|
||||
|
||||
gulp.task('build:backend:script', () => {
|
||||
return gulp.src(['./packages/backend/src/server/web/boot.js'])
|
||||
return gulp.src(['./packages/backend/src/server/web/boot.js', './packages/backend/src/server/web/bios.js', './packages/backend/src/server/web/cli.js'])
|
||||
.pipe(replace('LANGS', JSON.stringify(Object.keys(locales))))
|
||||
.pipe(terser({
|
||||
toplevel: true
|
||||
|
@ -45,7 +45,7 @@ gulp.task('build:backend:script', () => {
|
|||
});
|
||||
|
||||
gulp.task('build:backend:style', () => {
|
||||
return gulp.src(['./packages/backend/src/server/web/style.css'])
|
||||
return gulp.src(['./packages/backend/src/server/web/style.css', './packages/backend/src/server/web/bios.css', './packages/backend/src/server/web/cli.css'])
|
||||
.pipe(cssnano({
|
||||
zindex: false
|
||||
}))
|
||||
|
|
|
@ -96,8 +96,6 @@ unfollow: "Unfollow"
|
|||
followRequestPending: "Follow request pending"
|
||||
renote: "Renote"
|
||||
unrenote: "Take back renote"
|
||||
unrenoteAll: "Take back all renotes"
|
||||
unrenoteAllConfirm: "Are you sure that you want to take back all renotes of this note?"
|
||||
quote: "Quote"
|
||||
pinnedNote: "Pinned note"
|
||||
you: "You"
|
||||
|
|
|
@ -46,11 +46,11 @@
|
|||
"devDependencies": {
|
||||
"@types/gulp": "4.0.9",
|
||||
"@types/gulp-rename": "2.0.1",
|
||||
"@typescript-eslint/parser": "^5.46.1",
|
||||
"@typescript-eslint/parser": "^5.44.0",
|
||||
"cross-env": "7.0.3",
|
||||
"cypress": "10.3.0",
|
||||
"start-server-and-test": "1.14.0",
|
||||
"typescript": "^4.9.4"
|
||||
"typescript": "^4.9.3"
|
||||
},
|
||||
"packageManager": "yarn@3.3.0"
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json || echo done. && tsc-alias -p tsconfig.json",
|
||||
"watch": "node watch.mjs",
|
||||
"lint": "tsc --noEmit && eslint src --ext .ts",
|
||||
"lint": "eslint src --ext .ts",
|
||||
"mocha": "cross-env NODE_ENV=test TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha",
|
||||
"migrate": "npx typeorm migration:run -d ormconfig.js",
|
||||
"start": "node --experimental-json-modules ./built/index.js",
|
||||
|
@ -166,14 +166,14 @@
|
|||
"@types/web-push": "3.3.2",
|
||||
"@types/websocket": "1.0.5",
|
||||
"@types/ws": "8.5.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.46.1",
|
||||
"@typescript-eslint/parser": "^5.46.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.44.0",
|
||||
"@typescript-eslint/parser": "^5.44.0",
|
||||
"cross-env": "7.0.3",
|
||||
"eslint": "^8.29.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"execa": "6.1.0",
|
||||
"form-data": "^4.0.0",
|
||||
"sinon": "^14.0.2",
|
||||
"typescript": "^4.9.4"
|
||||
"typescript": "^4.9.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ export default function load(): Config {
|
|||
|
||||
config.images = Object.assign({
|
||||
info: '/twemoji/1f440.svg',
|
||||
notFound: '/twemoji/2049.svg',
|
||||
notFound: '/twemoji/2040.svg',
|
||||
error: '/twemoji/1f480.svg',
|
||||
}, config.images ?? {});
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// https://github.com/typeorm/typeorm/issues/2400
|
||||
import pg from 'pg';
|
||||
import { SECOND } from '@/const.js';
|
||||
|
||||
pg.types.setTypeParser(20, Number);
|
||||
|
||||
|
@ -7,7 +8,6 @@ import { Logger, DataSource } from 'typeorm';
|
|||
import * as highlight from 'cli-highlight';
|
||||
import config from '@/config/index.js';
|
||||
|
||||
import { SECOND } from '@/const.js';
|
||||
import { User } from '@/models/entities/user.js';
|
||||
import { DriveFile } from '@/models/entities/drive-file.js';
|
||||
import { DriveFolder } from '@/models/entities/drive-folder.js';
|
||||
|
@ -78,33 +78,33 @@ import { redisClient } from './redis.js';
|
|||
const sqlLogger = dbLogger.createSubLogger('sql', 'gray', false);
|
||||
|
||||
class MyCustomLogger implements Logger {
|
||||
private highlight(sql: string): string {
|
||||
private highlight(sql: string) {
|
||||
return highlight.highlight(sql, {
|
||||
language: 'sql', ignoreIllegals: true,
|
||||
});
|
||||
}
|
||||
|
||||
public logQuery(query: string): void {
|
||||
public logQuery(query: string, parameters?: any[]) {
|
||||
sqlLogger.info(this.highlight(query).substring(0, 100));
|
||||
}
|
||||
|
||||
public logQueryError(error: string, query: string): void {
|
||||
public logQueryError(error: string, query: string, parameters?: any[]) {
|
||||
sqlLogger.error(this.highlight(query));
|
||||
}
|
||||
|
||||
public logQuerySlow(time: number, query: string): void {
|
||||
public logQuerySlow(time: number, query: string, parameters?: any[]) {
|
||||
sqlLogger.warn(this.highlight(query));
|
||||
}
|
||||
|
||||
public logSchemaBuild(message: string): void {
|
||||
public logSchemaBuild(message: string) {
|
||||
sqlLogger.info(message);
|
||||
}
|
||||
|
||||
public log(message: string): void {
|
||||
public log(message: string) {
|
||||
sqlLogger.info(message);
|
||||
}
|
||||
|
||||
public logMigration(message: string): void {
|
||||
public logMigration(message: string) {
|
||||
sqlLogger.info(message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as crypto from 'node:crypto';
|
||||
|
||||
const L_CHARS = '0123456789abcdefghijklmnopqrstuvwxyz';
|
||||
const LU_CHARS = L_CHARS + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
const LU_CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
|
||||
export function secureRndstrCustom(length = 32, chars: string): string {
|
||||
const chars_len = chars.length;
|
||||
|
|
|
@ -17,7 +17,7 @@ export class AbuseUserReport {
|
|||
@Column(id())
|
||||
public targetUserId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -27,7 +27,7 @@ export class AbuseUserReport {
|
|||
@Column(id())
|
||||
public reporterId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -39,7 +39,7 @@ export class AbuseUserReport {
|
|||
})
|
||||
public assigneeId: User['id'] | null;
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'SET NULL',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -41,7 +41,7 @@ export class AccessToken {
|
|||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -53,7 +53,7 @@ export class AccessToken {
|
|||
})
|
||||
public appId: App['id'] | null;
|
||||
|
||||
@ManyToOne(() => App, {
|
||||
@ManyToOne(type => App, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -18,7 +18,7 @@ export class AnnouncementRead {
|
|||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -28,7 +28,7 @@ export class AnnouncementRead {
|
|||
@Column(id())
|
||||
public announcementId: Announcement['id'];
|
||||
|
||||
@ManyToOne(() => Announcement, {
|
||||
@ManyToOne(type => Announcement, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -16,7 +16,7 @@ export class AntennaNote {
|
|||
})
|
||||
public noteId: Note['id'];
|
||||
|
||||
@ManyToOne(() => Note, {
|
||||
@ManyToOne(type => Note, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -29,7 +29,7 @@ export class AntennaNote {
|
|||
})
|
||||
public antennaId: Antenna['id'];
|
||||
|
||||
@ManyToOne(() => Antenna, {
|
||||
@ManyToOne(type => Antenna, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -21,7 +21,7 @@ export class Antenna {
|
|||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -42,7 +42,7 @@ export class Antenna {
|
|||
})
|
||||
public userListId: UserList['id'] | null;
|
||||
|
||||
@ManyToOne(() => UserList, {
|
||||
@ManyToOne(type => UserList, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -54,7 +54,7 @@ export class Antenna {
|
|||
})
|
||||
public userGroupJoiningId: UserGroupJoining['id'] | null;
|
||||
|
||||
@ManyToOne(() => UserGroupJoining, {
|
||||
@ManyToOne(type => UserGroupJoining, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -21,7 +21,7 @@ export class App {
|
|||
})
|
||||
public userId: User['id'] | null;
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'SET NULL',
|
||||
nullable: true,
|
||||
})
|
||||
|
|
|
@ -11,7 +11,7 @@ export class AttestationChallenge {
|
|||
@PrimaryColumn(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Entity, PrimaryColumn, Index, Column, ManyToOne, JoinColumn } from 'typeorm';
|
||||
import { Entity, PrimaryColumn, Index, Column, ManyToOne, OneToOne, JoinColumn } from 'typeorm';
|
||||
import { id } from '../id.js';
|
||||
import { AccessToken } from './access-token.js';
|
||||
import { App } from './app.js';
|
||||
|
|
|
@ -21,7 +21,7 @@ export class Blocking {
|
|||
})
|
||||
public blockeeId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -34,7 +34,7 @@ export class Blocking {
|
|||
})
|
||||
public blockerId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -22,7 +22,7 @@ export class ChannelFollowing {
|
|||
})
|
||||
public followeeId: Channel['id'];
|
||||
|
||||
@ManyToOne(() => Channel, {
|
||||
@ManyToOne(type => Channel, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -35,7 +35,7 @@ export class ChannelFollowing {
|
|||
})
|
||||
public followerId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -18,7 +18,7 @@ export class ChannelNotePining {
|
|||
@Column(id())
|
||||
public channelId: Channel['id'];
|
||||
|
||||
@ManyToOne(() => Channel, {
|
||||
@ManyToOne(type => Channel, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -27,7 +27,7 @@ export class ChannelNotePining {
|
|||
@Column(id())
|
||||
public noteId: Note['id'];
|
||||
|
||||
@ManyToOne(() => Note, {
|
||||
@ManyToOne(type => Note, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -28,7 +28,7 @@ export class Channel {
|
|||
})
|
||||
public userId: User['id'] | null;
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'SET NULL',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -53,7 +53,7 @@ export class Channel {
|
|||
})
|
||||
public bannerId: DriveFile['id'] | null;
|
||||
|
||||
@ManyToOne(() => DriveFile, {
|
||||
@ManyToOne(type => DriveFile, {
|
||||
onDelete: 'SET NULL',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -16,7 +16,7 @@ export class ClipNote {
|
|||
})
|
||||
public noteId: Note['id'];
|
||||
|
||||
@ManyToOne(() => Note, {
|
||||
@ManyToOne(type => Note, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -29,7 +29,7 @@ export class ClipNote {
|
|||
})
|
||||
public clipId: Clip['id'];
|
||||
|
||||
@ManyToOne(() => Clip, {
|
||||
@ManyToOne(type => Clip, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -19,7 +19,7 @@ export class Clip {
|
|||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -23,7 +23,7 @@ export class DriveFile {
|
|||
})
|
||||
public userId: User['id'] | null;
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'RESTRICT',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -144,7 +144,7 @@ export class DriveFile {
|
|||
})
|
||||
public folderId: DriveFolder['id'] | null;
|
||||
|
||||
@ManyToOne(() => DriveFolder, {
|
||||
@ManyToOne(type => DriveFolder, {
|
||||
onDelete: 'SET NULL',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -27,7 +27,7 @@ export class DriveFolder {
|
|||
})
|
||||
public userId: User['id'] | null;
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -41,7 +41,7 @@ export class DriveFolder {
|
|||
})
|
||||
public parentId: DriveFolder['id'] | null;
|
||||
|
||||
@ManyToOne(() => DriveFolder, {
|
||||
@ManyToOne(type => DriveFolder, {
|
||||
onDelete: 'SET NULL',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -20,7 +20,7 @@ export class FollowRequest {
|
|||
})
|
||||
public followeeId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -33,7 +33,7 @@ export class FollowRequest {
|
|||
})
|
||||
public followerId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -21,7 +21,7 @@ export class Following {
|
|||
})
|
||||
public followeeId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -34,7 +34,7 @@ export class Following {
|
|||
})
|
||||
public followerId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -16,7 +16,7 @@ export class GalleryLike {
|
|||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -25,7 +25,7 @@ export class GalleryLike {
|
|||
@Column(id())
|
||||
public postId: GalleryPost['id'];
|
||||
|
||||
@ManyToOne(() => GalleryPost, {
|
||||
@ManyToOne(type => GalleryPost, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -37,7 +37,7 @@ export class GalleryPost {
|
|||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -22,7 +22,7 @@ export class MessagingMessage {
|
|||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -35,7 +35,7 @@ export class MessagingMessage {
|
|||
})
|
||||
public recipientId: User['id'] | null;
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -48,7 +48,7 @@ export class MessagingMessage {
|
|||
})
|
||||
public groupId: UserGroup['id'] | null;
|
||||
|
||||
@ManyToOne(() => UserGroup, {
|
||||
@ManyToOne(type => UserGroup, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -81,7 +81,7 @@ export class MessagingMessage {
|
|||
})
|
||||
public fileId: DriveFile['id'] | null;
|
||||
|
||||
@ManyToOne(() => DriveFile, {
|
||||
@ManyToOne(type => DriveFile, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -134,7 +134,7 @@ export class Meta {
|
|||
})
|
||||
public proxyAccountId: User['id'] | null;
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'SET NULL',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -16,7 +16,7 @@ export class ModerationLog {
|
|||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -17,7 +17,7 @@ export class MutedNote {
|
|||
})
|
||||
public noteId: Note['id'];
|
||||
|
||||
@ManyToOne(() => Note, {
|
||||
@ManyToOne(type => Note, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -30,7 +30,7 @@ export class MutedNote {
|
|||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -27,7 +27,7 @@ export class Muting {
|
|||
})
|
||||
public muteeId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -40,7 +40,7 @@ export class Muting {
|
|||
})
|
||||
public muterId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -18,7 +18,7 @@ export class NoteFavorite {
|
|||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -27,7 +27,7 @@ export class NoteFavorite {
|
|||
@Column(id())
|
||||
public noteId: Note['id'];
|
||||
|
||||
@ManyToOne(() => Note, {
|
||||
@ManyToOne(type => Note, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -19,7 +19,7 @@ export class NoteReaction {
|
|||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -29,7 +29,7 @@ export class NoteReaction {
|
|||
@Column(id())
|
||||
public noteId: Note['id'];
|
||||
|
||||
@ManyToOne(() => Note, {
|
||||
@ManyToOne(type => Note, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -20,7 +20,7 @@ export class NoteThreadMuting {
|
|||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -14,7 +14,7 @@ export class NoteUnread {
|
|||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -24,7 +24,7 @@ export class NoteUnread {
|
|||
@Column(id())
|
||||
public noteId: Note['id'];
|
||||
|
||||
@ManyToOne(() => Note, {
|
||||
@ManyToOne(type => Note, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -22,7 +22,7 @@ export class NoteWatching {
|
|||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -35,7 +35,7 @@ export class NoteWatching {
|
|||
})
|
||||
public noteId: Note['id'];
|
||||
|
||||
@ManyToOne(() => Note, {
|
||||
@ManyToOne(type => Note, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -27,7 +27,7 @@ export class Note {
|
|||
})
|
||||
public replyId: Note['id'] | null;
|
||||
|
||||
@ManyToOne(() => Note, {
|
||||
@ManyToOne(type => Note, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -41,7 +41,7 @@ export class Note {
|
|||
})
|
||||
public renoteId: Note['id'] | null;
|
||||
|
||||
@ManyToOne(() => Note, {
|
||||
@ManyToOne(type => Note, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -75,7 +75,7 @@ export class Note {
|
|||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -179,7 +179,7 @@ export class Note {
|
|||
})
|
||||
public channelId: Channel['id'] | null;
|
||||
|
||||
@ManyToOne(() => Channel, {
|
||||
@ManyToOne(type => Channel, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -28,7 +28,7 @@ export class Notification {
|
|||
})
|
||||
public notifieeId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -45,7 +45,7 @@ export class Notification {
|
|||
})
|
||||
public notifierId: User['id'] | null;
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -89,7 +89,7 @@ export class Notification {
|
|||
})
|
||||
public noteId: Note['id'] | null;
|
||||
|
||||
@ManyToOne(() => Note, {
|
||||
@ManyToOne(type => Note, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -101,7 +101,7 @@ export class Notification {
|
|||
})
|
||||
public followRequestId: FollowRequest['id'] | null;
|
||||
|
||||
@ManyToOne(() => FollowRequest, {
|
||||
@ManyToOne(type => FollowRequest, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -113,7 +113,7 @@ export class Notification {
|
|||
})
|
||||
public userGroupInvitationId: UserGroupInvitation['id'] | null;
|
||||
|
||||
@ManyToOne(() => UserGroupInvitation, {
|
||||
@ManyToOne(type => UserGroupInvitation, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -165,7 +165,7 @@ export class Notification {
|
|||
})
|
||||
public appAccessTokenId: AccessToken['id'] | null;
|
||||
|
||||
@ManyToOne(() => AccessToken, {
|
||||
@ManyToOne(type => AccessToken, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -16,7 +16,7 @@ export class PageLike {
|
|||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -25,7 +25,7 @@ export class PageLike {
|
|||
@Column(id())
|
||||
public pageId: Page['id'];
|
||||
|
||||
@ManyToOne(() => Page, {
|
||||
@ManyToOne(type => Page, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -57,7 +57,7 @@ export class Page {
|
|||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -69,7 +69,7 @@ export class Page {
|
|||
})
|
||||
public eyeCatchingImageId: DriveFile['id'] | null;
|
||||
|
||||
@ManyToOne(() => DriveFile, {
|
||||
@ManyToOne(type => DriveFile, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -22,7 +22,7 @@ export class PasswordResetRequest {
|
|||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -19,7 +19,7 @@ export class PollVote {
|
|||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -29,7 +29,7 @@ export class PollVote {
|
|||
@Column(id())
|
||||
public noteId: Note['id'];
|
||||
|
||||
@ManyToOne(() => Note, {
|
||||
@ManyToOne(type => Note, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -9,7 +9,7 @@ export class Poll {
|
|||
@PrimaryColumn(id())
|
||||
public noteId: Note['id'];
|
||||
|
||||
@OneToOne(() => Note, {
|
||||
@OneToOne(type => Note, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -25,7 +25,7 @@ export class RegistryItem {
|
|||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -21,7 +21,7 @@ export class RenoteMuting {
|
|||
})
|
||||
public muteeId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -34,7 +34,7 @@ export class RenoteMuting {
|
|||
})
|
||||
public muterId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -16,7 +16,7 @@ export class Signin {
|
|||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -14,7 +14,7 @@ export class SwSubscription {
|
|||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -21,7 +21,7 @@ export class UserGroupInvitation {
|
|||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -34,7 +34,7 @@ export class UserGroupInvitation {
|
|||
})
|
||||
public userGroupId: UserGroup['id'];
|
||||
|
||||
@ManyToOne(() => UserGroup, {
|
||||
@ManyToOne(type => UserGroup, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -21,7 +21,7 @@ export class UserGroupJoining {
|
|||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -34,7 +34,7 @@ export class UserGroupJoining {
|
|||
})
|
||||
public userGroupId: UserGroup['id'];
|
||||
|
||||
@ManyToOne(() => UserGroup, {
|
||||
@ManyToOne(type => UserGroup, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -25,7 +25,7 @@ export class UserGroup {
|
|||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -7,7 +7,7 @@ export class UserKeypair {
|
|||
@PrimaryColumn(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@OneToOne(() => User, {
|
||||
@OneToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -21,7 +21,7 @@ export class UserListJoining {
|
|||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -34,7 +34,7 @@ export class UserListJoining {
|
|||
})
|
||||
public userListId: UserList['id'];
|
||||
|
||||
@ManyToOne(() => UserList, {
|
||||
@ManyToOne(type => UserList, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -19,7 +19,7 @@ export class UserList {
|
|||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -18,7 +18,7 @@ export class UserNotePining {
|
|||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -27,7 +27,7 @@ export class UserNotePining {
|
|||
@Column(id())
|
||||
public noteId: Note['id'];
|
||||
|
||||
@ManyToOne(() => Note, {
|
||||
@ManyToOne(type => Note, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -11,7 +11,7 @@ export class UserProfile {
|
|||
@PrimaryColumn(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@OneToOne(() => User, {
|
||||
@OneToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -161,7 +161,7 @@ export class UserProfile {
|
|||
})
|
||||
public pinnedPageId: Page['id'] | null;
|
||||
|
||||
@OneToOne(() => Page, {
|
||||
@OneToOne(type => Page, {
|
||||
onDelete: 'SET NULL',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -7,7 +7,7 @@ export class UserPublickey {
|
|||
@PrimaryColumn(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@OneToOne(() => User, {
|
||||
@OneToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -13,7 +13,7 @@ export class UserSecurityKey {
|
|||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -81,7 +81,7 @@ export class User {
|
|||
})
|
||||
public avatarId: DriveFile['id'] | null;
|
||||
|
||||
@OneToOne(() => DriveFile, {
|
||||
@OneToOne(type => DriveFile, {
|
||||
onDelete: 'SET NULL',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
@ -94,7 +94,7 @@ export class User {
|
|||
})
|
||||
public bannerId: DriveFile['id'] | null;
|
||||
|
||||
@OneToOne(() => DriveFile, {
|
||||
@OneToOne(type => DriveFile, {
|
||||
onDelete: 'SET NULL',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -21,7 +21,7 @@ export class Webhook {
|
|||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(() => User, {
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
|
|
|
@ -27,7 +27,9 @@ export const DriveFileRepository = db.getRepository(DriveFile).extend({
|
|||
|
||||
getPublicProperties(file: DriveFile): DriveFile['properties'] {
|
||||
if (file.properties.orientation != null) {
|
||||
const properties = structuredClone(file.properties);
|
||||
// TODO
|
||||
//const properties = structuredClone(file.properties);
|
||||
const properties = JSON.parse(JSON.stringify(file.properties));
|
||||
if (file.properties.orientation >= 5) {
|
||||
[properties.width, properties.height] = [properties.height, properties.width];
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ export function initialize<T>(name: string, limitPerSec = -1): Bull.Queue<T> {
|
|||
}
|
||||
|
||||
// ref. https://github.com/misskey-dev/misskey/pull/7635#issue-971097019
|
||||
function apBackoff(attemptsMade: number /*, err: Error */): number {
|
||||
function apBackoff(attemptsMade: number, err: Error) {
|
||||
const baseDelay = MINUTE;
|
||||
const maxBackoff = 8 * HOUR;
|
||||
let backoff = (Math.pow(2, attemptsMade) - 1) * baseDelay;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import escapeRegexp from 'escape-regexp';
|
||||
import config from '@/config/index.js';
|
||||
import { Note } from '@/models/entities/note.js';
|
||||
import { CacheableUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser, CacheableUser } from '@/models/entities/user.js';
|
||||
import { MessagingMessage } from '@/models/entities/messaging-message.js';
|
||||
import { Notes, MessagingMessages } from '@/models/index.js';
|
||||
import { uriPersonCache, userByIdCache } from '@/services/user-cache.js';
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { IsNull, Not } from 'typeorm';
|
||||
import { ILocalUser, IRemoteUser, User } from '@/models/entities/user.js';
|
||||
import { Users, Followings } from '@/models/index.js';
|
||||
import { deliver } from '@/queue/index.js';
|
||||
|
|
|
@ -9,7 +9,7 @@ import { getApId, IObject, ICreate } from '@/remote/activitypub/type.js';
|
|||
/**
|
||||
* 投稿作成アクティビティを捌きます
|
||||
*/
|
||||
export default async function(resolver: Resolver, actor: CacheableRemoteUser, note: IObject, silent = false): Promise<string> {
|
||||
export default async function(resolver: Resolver, actor: CacheableRemoteUser, note: IObject, silent = false, activity?: ICreate): Promise<string> {
|
||||
const uri = getApId(note);
|
||||
|
||||
if (typeof note === 'object') {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { getApId, getApType, IUpdate, isActor } from '@/remote/activitypub/type.js';
|
||||
import { getApType, IUpdate, isActor } from '@/remote/activitypub/type.js';
|
||||
import { apLogger } from '@/remote/activitypub/logger.js';
|
||||
import { updateQuestion } from '@/remote/activitypub/models/question.js';
|
||||
import { Resolver } from '@/remote/activitypub/resolver.js';
|
||||
|
@ -21,11 +21,7 @@ export default async (actor: CacheableRemoteUser, activity: IUpdate, resolver: R
|
|||
});
|
||||
|
||||
if (isActor(object)) {
|
||||
if (actor.uri !== getApId(object)) {
|
||||
return 'skip: actor id !== updated actor id';
|
||||
}
|
||||
|
||||
await updatePerson(object, resolver);
|
||||
await updatePerson(actor.uri!, resolver, object);
|
||||
return 'ok: Person updated';
|
||||
} else if (getApType(object) === 'Question') {
|
||||
await updateQuestion(object, resolver).catch(e => console.log(e));
|
||||
|
|
|
@ -5,7 +5,7 @@ import { Resolver } from '@/remote/activitypub/resolver.js';
|
|||
import { IObject, isMention, IApMention } from '../type.js';
|
||||
import { resolvePerson } from './person.js';
|
||||
|
||||
export async function extractApMentions(tags: IObject | IObject[] | null | undefined, resolver: Resolver): Promise<CacheableUser[]> {
|
||||
export async function extractApMentions(tags: IObject | IObject[] | null | undefined, resolver: Resolver) {
|
||||
const hrefs = unique(extractApMentionObjects(tags).map(x => x.href as string));
|
||||
|
||||
const limit = promiseLimit<CacheableUser | null>(2);
|
||||
|
|
|
@ -28,7 +28,9 @@ import { extractApHashtags } from './tag.js';
|
|||
import { extractPollFromQuestion } from './question.js';
|
||||
import { extractApMentions } from './mention.js';
|
||||
|
||||
export function validateNote(object: IObject): Error | null {
|
||||
export function validateNote(object: any, uri: string): Error | null {
|
||||
const expectHost = extractDbHost(uri);
|
||||
|
||||
if (object == null) {
|
||||
return new Error('invalid Note: object is null');
|
||||
}
|
||||
|
@ -37,20 +39,12 @@ export function validateNote(object: IObject): Error | null {
|
|||
return new Error(`invalid Note: invalid object type ${getApType(object)}`);
|
||||
}
|
||||
|
||||
const id = getApId(object);
|
||||
if (id == null) {
|
||||
// Only transient objects or anonymous objects may not have an id or an id that is explicitly null.
|
||||
// We consider all Notes as not transient and not anonymous so require ids for them.
|
||||
return new Error(`invalid Note: id required but not present`);
|
||||
if (object.id && extractDbHost(object.id) !== expectHost) {
|
||||
return new Error(`invalid Note: id has different host. expected: ${expectHost}, actual: ${extractDbHost(object.id)}`);
|
||||
}
|
||||
|
||||
// Check that the server is authorized to act on behalf of this author.
|
||||
const expectHost = extractDbHost(id);
|
||||
const attributedToHost = object.attributedTo
|
||||
? extractDbHost(getOneApId(object.attributedTo))
|
||||
: null;
|
||||
if (attributedToHost !== expectHost) {
|
||||
return new Error(`invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${attributedToHost}`);
|
||||
if (object.attributedTo && extractDbHost(getOneApId(object.attributedTo)) !== expectHost) {
|
||||
return new Error(`invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${extractDbHost(object.attributedTo)}`);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -70,9 +64,10 @@ export async function fetchNote(object: string | IObject): Promise<Note | null>
|
|||
* Noteを作成します。
|
||||
*/
|
||||
export async function createNote(value: string | IObject, resolver: Resolver, silent = false): Promise<Note | null> {
|
||||
const object: IObject = await resolver.resolve(value);
|
||||
const object: any = await resolver.resolve(value);
|
||||
|
||||
const err = validateNote(object);
|
||||
const entryUri = getApId(value);
|
||||
const err = validateNote(object, entryUri);
|
||||
if (err) {
|
||||
apLogger.error(`${err.message}`, {
|
||||
resolver: {
|
||||
|
|
|
@ -13,7 +13,7 @@ import { genId } from '@/misc/gen-id.js';
|
|||
import { instanceChart, usersChart } from '@/services/chart/index.js';
|
||||
import { UserPublickey } from '@/models/entities/user-publickey.js';
|
||||
import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js';
|
||||
import { extractDbHost } from '@/misc/convert-host.js';
|
||||
import { toPuny } from '@/misc/convert-host.js';
|
||||
import { UserProfile } from '@/models/entities/user-profile.js';
|
||||
import { toArray } from '@/prelude/array.js';
|
||||
import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata.js';
|
||||
|
@ -39,7 +39,8 @@ const summaryLength = 2048;
|
|||
* @param x Fetched object
|
||||
* @param uri Fetch target URI
|
||||
*/
|
||||
function validateActor(x: IObject): IActor {
|
||||
function validateActor(x: IObject, uri: string): IActor {
|
||||
const expectHost = toPuny(new URL(uri).hostname);
|
||||
|
||||
if (x == null) {
|
||||
throw new Error('invalid Actor: object is null');
|
||||
|
@ -49,10 +50,7 @@ function validateActor(x: IObject): IActor {
|
|||
throw new Error(`invalid Actor type '${x.type}'`);
|
||||
}
|
||||
|
||||
const uri = getApId(x);
|
||||
if (uri == null) {
|
||||
// Only transient objects or anonymous objects may not have an id or an id that is explicitly null.
|
||||
// We consider all actors as not transient and not anonymous so require ids for them.
|
||||
if (!(typeof x.id === 'string' && x.id.length > 0)) {
|
||||
throw new Error('invalid Actor: wrong id');
|
||||
}
|
||||
|
||||
|
@ -80,13 +78,17 @@ function validateActor(x: IObject): IActor {
|
|||
x.summary = truncate(x.summary, summaryLength);
|
||||
}
|
||||
|
||||
const idHost = toPuny(new URL(x.id!).hostname);
|
||||
if (idHost !== expectHost) {
|
||||
throw new Error('invalid Actor: id has different host');
|
||||
}
|
||||
|
||||
if (x.publicKey) {
|
||||
if (typeof x.publicKey.id !== 'string') {
|
||||
throw new Error('invalid Actor: publicKey.id is not a string');
|
||||
}
|
||||
|
||||
const expectHost = extractDbHost(uri);
|
||||
const publicKeyIdHost = extractDbHost(x.publicKey.id);
|
||||
const publicKeyIdHost = toPuny(new URL(x.publicKey.id).hostname);
|
||||
if (publicKeyIdHost !== expectHost) {
|
||||
throw new Error('invalid Actor: publicKey.id has different host');
|
||||
}
|
||||
|
@ -129,18 +131,20 @@ export async function fetchPerson(uri: string, resolver: Resolver): Promise<Cach
|
|||
/**
|
||||
* Personを作成します。
|
||||
*/
|
||||
export async function createPerson(value: string | IObject, resolver: Resolver): Promise<User> {
|
||||
if (getApId(value).startsWith(config.url)) {
|
||||
export async function createPerson(uri: string, resolver: Resolver): Promise<User> {
|
||||
if (typeof uri !== 'string') throw new Error('uri is not string');
|
||||
|
||||
if (uri.startsWith(config.url)) {
|
||||
throw new StatusError('cannot resolve local user', 400, 'cannot resolve local user');
|
||||
}
|
||||
|
||||
const object = await resolver.resolve(value) as any;
|
||||
const object = await resolver.resolve(uri) as any;
|
||||
|
||||
const person = validateActor(object);
|
||||
const person = validateActor(object, uri);
|
||||
|
||||
apLogger.info(`Creating the Person: ${person.id}`);
|
||||
|
||||
const host = extractDbHost(object.id);
|
||||
const host = toPuny(new URL(object.id).hostname);
|
||||
|
||||
const { fields } = analyzeAttachments(person.attachment || []);
|
||||
|
||||
|
@ -270,32 +274,33 @@ export async function createPerson(value: string | IObject, resolver: Resolver):
|
|||
/**
|
||||
* Update Person information.
|
||||
* If the target Person is not registered in FoundKey, it is ignored.
|
||||
* @param value URI of Person or Person itself
|
||||
* @param uri URI of Person
|
||||
* @param resolver Resolver
|
||||
* @param hint Hint of Person object (If this value is a valid Person, it is used for updating without Remote resolve.)
|
||||
*/
|
||||
export async function updatePerson(value: IObject | string, resolver: Resolver): Promise<void> {
|
||||
const uri = getApId(value);
|
||||
export async function updatePerson(uri: string, resolver: Resolver, hint?: IObject): Promise<void> {
|
||||
if (typeof uri !== 'string') throw new Error('uri is not string');
|
||||
|
||||
// skip local URIs
|
||||
if (uri.startsWith(config.url)) {
|
||||
// URIがこのサーバーを指しているならスキップ
|
||||
if (uri.startsWith(config.url + '/')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// do we already know this user?
|
||||
//#region このサーバーに既に登録されているか
|
||||
const exist = await Users.findOneBy({ uri }) as IRemoteUser;
|
||||
|
||||
if (exist == null) {
|
||||
return;
|
||||
}
|
||||
//#endregion
|
||||
|
||||
const object = await resolver.resolve(value);
|
||||
const object = hint || await resolver.resolve(uri);
|
||||
|
||||
const person = validateActor(object);
|
||||
const person = validateActor(object, uri);
|
||||
|
||||
apLogger.info(`Updating the Person: ${person.id}`);
|
||||
|
||||
// Fetch avatar and banner image
|
||||
// アバターとヘッダー画像をフェッチ
|
||||
const [avatar, banner] = await Promise.all([
|
||||
person.icon,
|
||||
person.image,
|
||||
|
@ -305,7 +310,7 @@ export async function updatePerson(value: IObject | string, resolver: Resolver):
|
|||
: resolveImage(exist, img, resolver).catch(() => null),
|
||||
));
|
||||
|
||||
// Get custom emoji
|
||||
// カスタム絵文字取得
|
||||
const emojis = await extractEmojis(person.tag || [], exist.host).catch(e => {
|
||||
apLogger.info(`extractEmojis: ${e}`);
|
||||
return [] as Emoji[];
|
||||
|
@ -313,7 +318,7 @@ export async function updatePerson(value: IObject | string, resolver: Resolver):
|
|||
|
||||
const emojiNames = emojis.map(emoji => emoji.name);
|
||||
|
||||
const { fields } = analyzeAttachments(person.attachment ?? []);
|
||||
const { fields } = analyzeAttachments(person.attachment || []);
|
||||
|
||||
const tags = extractApHashtags(person.tag).map(tag => normalizeForSearch(tag)).splice(0, 32);
|
||||
|
||||
|
@ -322,7 +327,7 @@ export async function updatePerson(value: IObject | string, resolver: Resolver):
|
|||
const updates = {
|
||||
lastFetchedAt: new Date(),
|
||||
inbox: person.inbox,
|
||||
sharedInbox: person.sharedInbox ?? (person.endpoints ? person.endpoints.sharedInbox : undefined),
|
||||
sharedInbox: person.sharedInbox || (person.endpoints ? person.endpoints.sharedInbox : undefined),
|
||||
followersUri: person.followers ? getApId(person.followers) : undefined,
|
||||
featured: person.featured,
|
||||
emojis: emojiNames,
|
||||
|
@ -362,13 +367,14 @@ export async function updatePerson(value: IObject | string, resolver: Resolver):
|
|||
|
||||
publishInternalEvent('remoteUserUpdated', { id: exist.id });
|
||||
|
||||
// ハッシュタグ更新
|
||||
updateUsertags(exist, tags);
|
||||
|
||||
// If the user in question is already a follower, followers will also be updated.
|
||||
// 該当ユーザーが既にフォロワーになっていた場合はFollowingもアップデートする
|
||||
await Followings.update({
|
||||
followerId: exist.id,
|
||||
}, {
|
||||
followerSharedInbox: person.sharedInbox ?? (person.endpoints ? person.endpoints.sharedInbox : undefined),
|
||||
followerSharedInbox: person.sharedInbox || (person.endpoints ? person.endpoints.sharedInbox : undefined),
|
||||
});
|
||||
|
||||
await updateFeatured(exist.id, resolver).catch(err => apLogger.error(err));
|
||||
|
|
|
@ -2,20 +2,13 @@ import config from '@/config/index.js';
|
|||
import { Relay } from '@/models/entities/relay.js';
|
||||
import { ILocalUser } from '@/models/entities/user.js';
|
||||
|
||||
export type FollowRelay = {
|
||||
id: string;
|
||||
type: 'Follow';
|
||||
actor: string;
|
||||
object: 'https://www.w3.org/ns/activitystreams#Public';
|
||||
};
|
||||
|
||||
export function renderFollowRelay(relay: Relay, relayActor: ILocalUser): FollowRelay {
|
||||
export function renderFollowRelay(relay: Relay, relayActor: ILocalUser) {
|
||||
const follow = {
|
||||
id: `${config.url}/activities/follow-relay/${relay.id}`,
|
||||
type: 'Follow',
|
||||
actor: `${config.url}/users/${relayActor.id}`,
|
||||
object: 'https://www.w3.org/ns/activitystreams#Public',
|
||||
} as const;
|
||||
};
|
||||
|
||||
return follow;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import config from '@/config/index.js';
|
||||
import { getJson } from '@/misc/fetch.js';
|
||||
import { ILocalUser } from '@/models/entities/user.js';
|
||||
import { getInstanceActor } from '@/services/instance-actor.js';
|
||||
import { extractDbHost, isSelfHost } from '@/misc/convert-host.js';
|
||||
|
@ -11,7 +13,7 @@ import { renderActivity } from '@/remote/activitypub/renderer/index.js';
|
|||
import renderFollow from '@/remote/activitypub/renderer/follow.js';
|
||||
import { shouldBlockInstance } from '@/misc/should-block-instance.js';
|
||||
import { signedGet } from './request.js';
|
||||
import { getApId, IObject, isCollectionOrOrderedCollection, ICollection, IOrderedCollection } from './type.js';
|
||||
import { IObject, isCollectionOrOrderedCollection, ICollection, IOrderedCollection } from './type.js';
|
||||
import { parseUri } from './db-resolver.js';
|
||||
|
||||
/**
|
||||
|
@ -84,18 +86,11 @@ export class Resolver {
|
|||
|
||||
const object = await signedGet(value, this.user);
|
||||
|
||||
if (
|
||||
object == null
|
||||
|| // check that this is an activitypub object by looking at the @context
|
||||
(
|
||||
Array.isArray(object['@context']) ?
|
||||
!(object['@context'] as unknown[]).includes('https://www.w3.org/ns/activitystreams') :
|
||||
object['@context'] !== 'https://www.w3.org/ns/activitystreams'
|
||||
)
|
||||
// Did we actually get the object that corresponds to the canonical URL?
|
||||
// Does the host we requested stuff from actually correspond to the host that owns the activity?
|
||||
|| !(getApId(object) == null || getApId(object) === value)
|
||||
) {
|
||||
if (object == null || (
|
||||
Array.isArray(object['@context']) ?
|
||||
!(object['@context'] as unknown[]).includes('https://www.w3.org/ns/activitystreams') :
|
||||
object['@context'] !== 'https://www.w3.org/ns/activitystreams'
|
||||
)) {
|
||||
throw new Error('invalid response');
|
||||
}
|
||||
|
||||
|
|
|
@ -2,13 +2,14 @@ import { URL } from 'node:url';
|
|||
import chalk from 'chalk';
|
||||
import { IsNull } from 'typeorm';
|
||||
import { DAY } from '@/const.js';
|
||||
import config from '@/config/index.js';
|
||||
import { isSelfHost, toPuny } from '@/misc/convert-host.js';
|
||||
import { User, IRemoteUser } from '@/models/entities/user.js';
|
||||
import { Users } from '@/models/index.js';
|
||||
import { Resolver } from '@/remote/activitypub/resolver.js';
|
||||
import webFinger from './webfinger.js';
|
||||
import { createPerson, updatePerson } from './activitypub/models/person.js';
|
||||
import { remoteLogger } from './logger.js';
|
||||
import { Resolver } from '@/remote/activitypub/resolver.js';
|
||||
|
||||
const logger = remoteLogger.createSubLogger('resolve-user');
|
||||
|
||||
|
|
|
@ -5,12 +5,23 @@ import authenticate, { AuthenticationError } from './authenticate.js';
|
|||
import call from './call.js';
|
||||
import { ApiError } from './error.js';
|
||||
|
||||
function getRequestArguments(ctx: Koa.Context): Record<string, any> {
|
||||
const args = {
|
||||
...(ctx.params || {}),
|
||||
...ctx.query,
|
||||
...(ctx.request.body || {}),
|
||||
};
|
||||
|
||||
// For security reasons, we drop the i parameter if it's a GET request
|
||||
if (ctx.method === 'GET') {
|
||||
delete args['i'];
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export async function handler(endpoint: IEndpoint, ctx: Koa.Context): Promise<void> {
|
||||
const body = ctx.is('multipart/form-data')
|
||||
? (ctx.request as any).body
|
||||
: ctx.method === 'GET'
|
||||
? ctx.query
|
||||
: ctx.request.body;
|
||||
const body = getRequestArguments(ctx);
|
||||
|
||||
const error = (e: ApiError): void => {
|
||||
ctx.status = e.httpStatusCode;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import * as crypto from 'node:crypto';
|
||||
import Koa from 'koa';
|
||||
import { IsNull, Not } from 'typeorm';
|
||||
import { Apps, AuthSessions } from '@/models/index.js';
|
||||
import { Apps, AuthSessions, AccessTokens } from '@/models/index.js';
|
||||
import config from '@/config/index.js';
|
||||
import { compareUrl } from './compare-url.js';
|
||||
|
||||
export async function oauth(ctx: Koa.Context): void {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as fs from 'node:fs';
|
||||
import Ajv from 'ajv';
|
||||
import { CacheableLocalUser } from '@/models/entities/user.js';
|
||||
import { CacheableLocalUser, ILocalUser } from '@/models/entities/user.js';
|
||||
import { Schema, SchemaType } from '@/misc/schema.js';
|
||||
import { AccessToken } from '@/models/entities/access-token.js';
|
||||
import { IEndpointMeta } from './endpoints.js';
|
||||
|
|
|
@ -702,6 +702,24 @@ export interface IEndpointMeta {
|
|||
* 正常応答をキャッシュ (Cache-Control: public) する秒数
|
||||
*/
|
||||
readonly cacheSec?: number;
|
||||
|
||||
/**
|
||||
* API v2 options
|
||||
*/
|
||||
readonly v2?: {
|
||||
|
||||
/**
|
||||
* HTTP verb this endpoint supports
|
||||
*/
|
||||
readonly method: 'get' | 'put' | 'post' | 'patch' | 'delete';
|
||||
|
||||
/**
|
||||
* Path alias for v2 endpoint
|
||||
*
|
||||
* @example (v0) /api/notes/create -> /api/v2/notes
|
||||
*/
|
||||
readonly alias?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IEndpoint {
|
||||
|
|
|
@ -114,8 +114,8 @@ async function fetchAny(uri: string, me: CacheableLocalUser | null | undefined):
|
|||
|
||||
return await mergePack(
|
||||
me,
|
||||
isActor(object) ? await createPerson(object, resolver) : null,
|
||||
isPost(object) ? await createNote(object, resolver, true) : null,
|
||||
isActor(object) ? await createPerson(getApId(object), resolver) : null,
|
||||
isPost(object) ? await createNote(getApId(object), resolver, true) : null,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Apps } from '@/models/index.js';
|
||||
import { genId } from '@/misc/gen-id.js';
|
||||
import { unique } from '@/prelude/array.js';
|
||||
import { secureRndstr } from '@/misc/secure-rndstr.js';
|
||||
import { kinds } from '@/misc/api-permissions.js';
|
||||
import define from '../../define.js';
|
||||
|
|
|
@ -32,7 +32,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
token: ps.token,
|
||||
});
|
||||
|
||||
if (result.affected === 0) {
|
||||
if (result.affected == 0) {
|
||||
throw new ApiError(meta.errors.noSuchSession);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Apps, AuthSessions, Users } from '@/models/index.js';
|
||||
import { Apps, AuthSessions, AccessTokens, Users } from '@/models/index.js';
|
||||
import define from '../../../define.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
|
|
|
@ -233,6 +233,10 @@ export const meta = {
|
|||
},
|
||||
},
|
||||
},
|
||||
|
||||
v2: {
|
||||
method: 'get'
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
|
|
@ -21,6 +21,11 @@ export const meta = {
|
|||
ref: 'Note',
|
||||
},
|
||||
},
|
||||
|
||||
v2: {
|
||||
method: 'get',
|
||||
alias: 'notes/:noteId/children',
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
|
|
@ -19,6 +19,11 @@ export const meta = {
|
|||
},
|
||||
},
|
||||
|
||||
v2: {
|
||||
method: 'get',
|
||||
alias: 'notes/:noteId/clips',
|
||||
},
|
||||
|
||||
errors: ['NO_SUCH_NOTE'],
|
||||
} as const;
|
||||
|
||||
|
|
|
@ -19,6 +19,11 @@ export const meta = {
|
|||
},
|
||||
},
|
||||
|
||||
v2: {
|
||||
method: 'get',
|
||||
alias: 'notes/:noteId/conversation',
|
||||
},
|
||||
|
||||
errors: ['NO_SUCH_NOTE'],
|
||||
} as const;
|
||||
|
||||
|
|
|
@ -37,6 +37,11 @@ export const meta = {
|
|||
},
|
||||
},
|
||||
|
||||
v2: {
|
||||
method: 'post',
|
||||
alias: 'notes',
|
||||
},
|
||||
|
||||
errors: ['NO_SUCH_NOTE', 'PURE_RENOTE', 'EXPIRED_POLL', 'NO_SUCH_CHANNEL', 'BLOCKED', 'LESS_RESTRICTIVE_VISIBILITY'],
|
||||
} as const;
|
||||
|
||||
|
|
|
@ -18,6 +18,11 @@ export const meta = {
|
|||
minInterval: SECOND,
|
||||
},
|
||||
|
||||
v2: {
|
||||
method: 'delete',
|
||||
alias: 'notes/:noteId',
|
||||
},
|
||||
|
||||
errors: ['ACCESS_DENIED', 'NO_SUCH_NOTE'],
|
||||
} as const;
|
||||
|
||||
|
|
|
@ -18,6 +18,10 @@ export const meta = {
|
|||
ref: 'Note',
|
||||
},
|
||||
},
|
||||
|
||||
v2: {
|
||||
method: 'get',
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
|
|
@ -23,6 +23,11 @@ export const meta = {
|
|||
},
|
||||
},
|
||||
|
||||
v2: {
|
||||
method: 'get',
|
||||
alias: 'notes/:noteId/reactions/:type?',
|
||||
},
|
||||
|
||||
errors: ['NO_SUCH_NOTE'],
|
||||
} as const;
|
||||
|
||||
|
|
|
@ -22,6 +22,11 @@ export const meta = {
|
|||
},
|
||||
},
|
||||
|
||||
v2: {
|
||||
method: 'get',
|
||||
alias: 'notes/:noteId/renotes',
|
||||
},
|
||||
|
||||
errors: ['NO_SUCH_NOTE'],
|
||||
} as const;
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import { Notes } from '@/models/index.js';
|
||||
import { ApiError } from '@/server/api/error.js';
|
||||
import define from '../../define.js';
|
||||
import { makePaginationQuery } from '../../common/make-pagination-query.js';
|
||||
import { generateVisibilityQuery } from '../../common/generate-visibility-query.js';
|
||||
import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js';
|
||||
import { generateBlockedUserQuery } from '../../common/generate-block-query.js';
|
||||
import { getNote } from '../../common/getters.js';
|
||||
import { ApiError } from '@/server/api/error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['notes'],
|
||||
|
@ -22,6 +21,11 @@ export const meta = {
|
|||
},
|
||||
},
|
||||
|
||||
v2: {
|
||||
method: 'get',
|
||||
alias: 'notes/:noteId/replies',
|
||||
},
|
||||
|
||||
errors: ['NO_SUCH_NOTE'],
|
||||
} as const;
|
||||
|
||||
|
@ -38,7 +42,7 @@ export const paramDef = {
|
|||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
await getNote(ps.noteId, user).catch(err => {
|
||||
const note = await getNote(ps.noteId, user).catch(err => {
|
||||
if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError('NO_SUCH_NOTE');
|
||||
throw err;
|
||||
});
|
||||
|
|
|
@ -14,6 +14,11 @@ export const meta = {
|
|||
ref: 'Note',
|
||||
},
|
||||
|
||||
v2: {
|
||||
method: 'get',
|
||||
alias: 'notes/:noteId',
|
||||
},
|
||||
|
||||
errors: ['NO_SUCH_NOTE'],
|
||||
} as const;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { NoteFavorites, NoteThreadMutings, NoteWatchings } from '@/models/index.js';
|
||||
import { ApiError } from '@/server/api/error.js';
|
||||
import { NoteFavorites, Notes, NoteThreadMutings, NoteWatchings } from '@/models/index.js';
|
||||
import { getNote } from '../../common/getters.js';
|
||||
import define from '../../define.js';
|
||||
import { ApiError } from '@/server/api/error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['notes'],
|
||||
|
@ -27,6 +27,11 @@ export const meta = {
|
|||
},
|
||||
},
|
||||
|
||||
v2: {
|
||||
method: 'get',
|
||||
alias: 'notes/:noteId/status',
|
||||
},
|
||||
|
||||
errors: ['NO_SUCH_NOTE'],
|
||||
} as const;
|
||||
|
||||
|
|
|
@ -56,6 +56,11 @@ export const meta = {
|
|||
},
|
||||
},
|
||||
|
||||
v2: {
|
||||
method: 'get',
|
||||
alias: 'notes/:noteId/translate/:targetLang/:sourceLang?',
|
||||
},
|
||||
|
||||
errors: ['NO_SUCH_NOTE'],
|
||||
} as const;
|
||||
|
||||
|
|
|
@ -18,6 +18,11 @@ export const meta = {
|
|||
minInterval: SECOND,
|
||||
},
|
||||
|
||||
v2: {
|
||||
method: 'delete',
|
||||
alias: 'notes/:noteId/renotes',
|
||||
},
|
||||
|
||||
errors: ['NO_SUCH_NOTE'],
|
||||
} as const;
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue