Merge branch 'chore-api-R30906' into stream-types
This commit is contained in:
commit
e9b9afbd2a
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -7,6 +7,19 @@
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
## 12.x.x (unreleased)
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
- リモートユーザーのDeleteアクティビティに対応
|
||||||
|
|
||||||
|
### Bugfixes
|
||||||
|
|
||||||
|
## 12.90.1 (2021/09/05)
|
||||||
|
|
||||||
|
### Bugfixes
|
||||||
|
- Dockerfileを修正
|
||||||
|
- ノート翻訳時に公開範囲が考慮されていない問題を修正
|
||||||
|
|
||||||
## 12.90.0 (2021/09/04)
|
## 12.90.0 (2021/09/04)
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
|
|
@ -1150,6 +1150,10 @@ _permissions:
|
||||||
"write:user-groups": "ユーザーグループを操作する"
|
"write:user-groups": "ユーザーグループを操作する"
|
||||||
"read:channels": "チャンネルを見る"
|
"read:channels": "チャンネルを見る"
|
||||||
"write:channels": "チャンネルを操作する"
|
"write:channels": "チャンネルを操作する"
|
||||||
|
"read:gallery": "ギャラリーを見る"
|
||||||
|
"write:gallery": "ギャラリーを操作する"
|
||||||
|
"read:gallery-likes": "ギャラリーのいいねを見る"
|
||||||
|
"write:gallery-likes": "ギャラリーのいいねを操作する"
|
||||||
|
|
||||||
_auth:
|
_auth:
|
||||||
shareAccess: "「{name}」がアカウントにアクセスすることを許可しますか?"
|
shareAccess: "「{name}」がアカウントにアクセスすることを許可しますか?"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <syuilotan@yahoo.co.jp>",
|
"author": "syuilo <syuilotan@yahoo.co.jp>",
|
||||||
"version": "12.90.0",
|
"version": "12.90.1",
|
||||||
"codename": "indigo",
|
"codename": "indigo",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -32,3 +32,4 @@ export const kinds = [
|
||||||
'read:gallery-likes',
|
'read:gallery-likes',
|
||||||
'write:gallery-likes',
|
'write:gallery-likes',
|
||||||
];
|
];
|
||||||
|
// IF YOU ADD KINDS(PERMISSIONS), YOU MUST ADD TRANSLATIONS (under _permissions).
|
||||||
|
|
|
@ -18,7 +18,57 @@ export class NoteRepository extends Repository<Note> {
|
||||||
return x.trim().length <= 100;
|
return x.trim().length <= 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async isVisibleForMe(note: Note, meId: User['id'] | null): Promise<boolean> {
|
||||||
|
// visibility が specified かつ自分が指定されていなかったら非表示
|
||||||
|
if (note.visibility === 'specified') {
|
||||||
|
if (meId == null) {
|
||||||
|
return false;
|
||||||
|
} else if (meId === note.userId) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// 指定されているかどうか
|
||||||
|
const specified = note.visibleUserIds.some((id: any) => meId === id);
|
||||||
|
|
||||||
|
if (specified) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// visibility が followers かつ自分が投稿者のフォロワーでなかったら非表示
|
||||||
|
if (note.visibility === 'followers') {
|
||||||
|
if (meId == null) {
|
||||||
|
return false;
|
||||||
|
} else if (meId === note.userId) {
|
||||||
|
return true;
|
||||||
|
} else if (note.reply && (meId === note.reply.userId)) {
|
||||||
|
// 自分の投稿に対するリプライ
|
||||||
|
return true;
|
||||||
|
} else if (note.mentions && note.mentions.some(id => meId === id)) {
|
||||||
|
// 自分へのメンション
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// フォロワーかどうか
|
||||||
|
const following = await Followings.findOne({
|
||||||
|
followeeId: note.userId,
|
||||||
|
followerId: meId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (following == null) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private async hideNote(packedNote: PackedNote, meId: User['id'] | null) {
|
private async hideNote(packedNote: PackedNote, meId: User['id'] | null) {
|
||||||
|
// TODO: isVisibleForMe を使うようにしても良さそう(型違うけど)
|
||||||
let hide = false;
|
let hide = false;
|
||||||
|
|
||||||
// visibility が specified かつ自分が指定されていなかったら非表示
|
// visibility が specified かつ自分が指定されていなかったら非表示
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { Note } from '@/models/entities/note';
|
||||||
import { NoteReaction } from '@/models/entities/note-reaction';
|
import { NoteReaction } from '@/models/entities/note-reaction';
|
||||||
import { User } from '@/models/entities/user';
|
import { User } from '@/models/entities/user';
|
||||||
import { aggregateNoteEmojis, prefetchEmojis } from '@/misc/populate-emojis';
|
import { aggregateNoteEmojis, prefetchEmojis } from '@/misc/populate-emojis';
|
||||||
|
import { notificationTypes } from '@/types';
|
||||||
|
|
||||||
export type PackedNotification = SchemaType<typeof packedNotificationSchema>;
|
export type PackedNotification = SchemaType<typeof packedNotificationSchema>;
|
||||||
|
|
||||||
|
@ -124,20 +125,41 @@ export const packedNotificationSchema = {
|
||||||
optional: false as const, nullable: false as const,
|
optional: false as const, nullable: false as const,
|
||||||
format: 'date-time',
|
format: 'date-time',
|
||||||
},
|
},
|
||||||
|
isRead: {
|
||||||
|
type: 'boolean' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
},
|
||||||
type: {
|
type: {
|
||||||
type: 'string' as const,
|
type: 'string' as const,
|
||||||
optional: false as const, nullable: false as const,
|
optional: false as const, nullable: false as const,
|
||||||
enum: ['follow', 'followRequestAccepted', 'receiveFollowRequest', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote'],
|
enum: [...notificationTypes],
|
||||||
},
|
|
||||||
userId: {
|
|
||||||
type: 'string' as const,
|
|
||||||
optional: true as const, nullable: true as const,
|
|
||||||
format: 'id',
|
|
||||||
},
|
},
|
||||||
user: {
|
user: {
|
||||||
type: 'object' as const,
|
type: 'object' as const,
|
||||||
ref: 'User',
|
ref: 'User',
|
||||||
optional: true as const, nullable: true as const,
|
optional: true as const, nullable: true as const,
|
||||||
},
|
},
|
||||||
|
userId: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: true as const, nullable: true as const,
|
||||||
|
format: 'id',
|
||||||
|
},
|
||||||
|
note: {
|
||||||
|
type: 'object' as const,
|
||||||
|
ref: 'Note',
|
||||||
|
optional: true as const, nullable: true as const,
|
||||||
|
},
|
||||||
|
reaction: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: true as const, nullable: true as const,
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: true as const, nullable: true as const,
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: true as const, nullable: true as const,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { apLogger } from '../../logger';
|
||||||
|
import { createDeleteAccountJob } from '@/queue';
|
||||||
|
import { IRemoteUser } from '@/models/entities/user';
|
||||||
|
import { Users } from '@/models/index';
|
||||||
|
|
||||||
|
const logger = apLogger;
|
||||||
|
|
||||||
|
export async function deleteActor(actor: IRemoteUser, uri: string): Promise<string> {
|
||||||
|
logger.info(`Deleting the Actor: ${uri}`);
|
||||||
|
|
||||||
|
if (actor.uri !== uri) {
|
||||||
|
return `skip: delete actor ${actor.uri} !== ${uri}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actor.isDeleted) {
|
||||||
|
logger.info(`skip: already deleted`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const job = await createDeleteAccountJob(actor);
|
||||||
|
|
||||||
|
await Users.update(actor.id, {
|
||||||
|
isDeleted: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return `ok: queued ${job.name} ${job.id}`;
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ import deleteNote from './note';
|
||||||
import { IRemoteUser } from '@/models/entities/user';
|
import { IRemoteUser } from '@/models/entities/user';
|
||||||
import { IDelete, getApId, isTombstone, IObject, validPost, validActor } from '../../type';
|
import { IDelete, getApId, isTombstone, IObject, validPost, validActor } from '../../type';
|
||||||
import { toSingle } from '@/prelude/array';
|
import { toSingle } from '@/prelude/array';
|
||||||
|
import { deleteActor } from './actor';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 削除アクティビティを捌きます
|
* 削除アクティビティを捌きます
|
||||||
|
@ -41,7 +42,7 @@ export default async (actor: IRemoteUser, activity: IDelete): Promise<string> =>
|
||||||
if (validPost.includes(formarType)) {
|
if (validPost.includes(formarType)) {
|
||||||
return await deleteNote(actor, uri);
|
return await deleteNote(actor, uri);
|
||||||
} else if (validActor.includes(formarType)) {
|
} else if (validActor.includes(formarType)) {
|
||||||
return `Delete Actor is not implanted`;
|
return await deleteActor(actor, uri);
|
||||||
} else {
|
} else {
|
||||||
return `Unknown type ${formarType}`;
|
return `Unknown type ${formarType}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import config from '@/config/index';
|
||||||
import { getAgentByUrl } from '@/misc/fetch';
|
import { getAgentByUrl } from '@/misc/fetch';
|
||||||
import { URLSearchParams } from 'url';
|
import { URLSearchParams } from 'url';
|
||||||
import { fetchMeta } from '@/misc/fetch-meta';
|
import { fetchMeta } from '@/misc/fetch-meta';
|
||||||
|
import { Notes } from '@/models';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['notes'],
|
tags: ['notes'],
|
||||||
|
@ -43,6 +44,10 @@ export default define(meta, async (ps, user) => {
|
||||||
throw e;
|
throw e;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!(await Notes.isVisibleForMe(note, user ? user.id : null))) {
|
||||||
|
return 204; // TODO: 良い感じのエラー返す
|
||||||
|
}
|
||||||
|
|
||||||
if (note.text == null) {
|
if (note.text == null) {
|
||||||
return 204;
|
return 204;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue