feat: ability to make existing posts private
This commit is contained in:
parent
764e516a3c
commit
5e0b1f1114
7 changed files with 105 additions and 6 deletions
|
@ -21,6 +21,7 @@
|
|||
|
||||
- 「秘密」という公開範囲を追加
|
||||
- 宛先無しのダイレクト投稿を言い換えているだけです
|
||||
- 既存の投稿を削除せずに後から秘密にすることもできます
|
||||
- パフォーマンス向上のためアクティブユーザー以外のチャート生成を無効化
|
||||
- サードパーティー製クライアントが動かなくなるのを阻止するため API のエンドポイントは残していますが、叩いても `0` が並んだ配列しか返しません。
|
||||
- モデレーターでない一般ユーザーにもカスタム絵文字の管理権を与えられるように
|
||||
|
|
|
@ -2176,3 +2176,5 @@ hideMyIcon: "Hide my icon"
|
|||
hideMyName: "Hide my name and ID"
|
||||
searchEngine: "Search engine used in search bar MFM"
|
||||
postSearch: "Post search on this server"
|
||||
makePrivate: "Make private"
|
||||
makePrivateConfirm: "This operation will send a deletion request to remote servers and change the visibility to private. Proceed?"
|
||||
|
|
|
@ -2015,3 +2015,5 @@ openServerInfo: "投稿内のサーバー名をクリックでサーバー情報
|
|||
searchEngine: "検索の MFM で使用する検索エンジン"
|
||||
postSearch: "このサーバーの投稿検索"
|
||||
indexableDescription: MastodonやFirefishなどの検索機能に、あなたの投稿が表示されるのを許可します。
|
||||
makePrivate: "秘密にする"
|
||||
makePrivateConfirm: "リモートサーバーに削除リクエストを送信し、投稿の公開範囲を「秘密」にして他の人から見られないようにします。実行しますか?"
|
||||
|
|
|
@ -255,6 +255,7 @@ import * as ep___notes_globalTimeline from "./endpoints/notes/global-timeline.js
|
|||
import * as ep___notes_hybridTimeline from "./endpoints/notes/hybrid-timeline.js";
|
||||
import * as ep___notes_localTimeline from "./endpoints/notes/local-timeline.js";
|
||||
import * as ep___notes_recommendedTimeline from "./endpoints/notes/recommended-timeline.js";
|
||||
import * as ep___notes_makePrivate from "./endpoints/notes/make-private.js";
|
||||
import * as ep___notes_mentions from "./endpoints/notes/mentions.js";
|
||||
import * as ep___notes_polls_recommendation from "./endpoints/notes/polls/recommendation.js";
|
||||
import * as ep___notes_polls_vote from "./endpoints/notes/polls/vote.js";
|
||||
|
@ -609,6 +610,7 @@ const eps = [
|
|||
["notes/hybrid-timeline", ep___notes_hybridTimeline],
|
||||
["notes/local-timeline", ep___notes_localTimeline],
|
||||
["notes/recommended-timeline", ep___notes_recommendedTimeline],
|
||||
["notes/make-private", ep___notes_makePrivate],
|
||||
["notes/mentions", ep___notes_mentions],
|
||||
["notes/polls/recommendation", ep___notes_polls_recommendation],
|
||||
["notes/polls/vote", ep___notes_polls_vote],
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
import deleteNote from "@/services/note/delete.js";
|
||||
import { Notes } from "@/models/index.js";
|
||||
import define from "../../define.js";
|
||||
import { getNote } from "../../common/getters.js";
|
||||
import { ApiError } from "../../error.js";
|
||||
import { SECOND, HOUR } from "@/const.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["notes"],
|
||||
|
||||
requireCredential: true,
|
||||
|
||||
kind: "write:notes",
|
||||
|
||||
limit: {
|
||||
duration: HOUR,
|
||||
max: 300,
|
||||
minInterval: SECOND,
|
||||
},
|
||||
|
||||
errors: {
|
||||
noSuchNote: {
|
||||
message: "No such note.",
|
||||
code: "NO_SUCH_NOTE",
|
||||
id: "490be23f-8c1f-4796-819f-94cb4f9d1630",
|
||||
},
|
||||
|
||||
accessDenied: {
|
||||
message: "Access denied.",
|
||||
code: "ACCESS_DENIED",
|
||||
id: "fe8d7103-0ea8-4ec3-814d-f8b401dc69e9",
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: "object",
|
||||
properties: {
|
||||
noteId: { type: "string", format: "misskey:id" },
|
||||
},
|
||||
required: ["noteId"],
|
||||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const note = await getNote(ps.noteId, user).catch((err) => {
|
||||
if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24")
|
||||
throw new ApiError(meta.errors.noSuchNote);
|
||||
throw err;
|
||||
});
|
||||
|
||||
if (note.userId !== user.id) {
|
||||
throw new ApiError(meta.errors.accessDenied);
|
||||
}
|
||||
|
||||
await deleteNote(user, note, false, false);
|
||||
await Notes.update(note.id, {
|
||||
visibility: "specified",
|
||||
visibleUserIds: [],
|
||||
});
|
||||
});
|
|
@ -27,19 +27,21 @@ export default async function (
|
|||
user: { id: User["id"]; uri: User["uri"]; host: User["host"] },
|
||||
note: Note,
|
||||
quiet = false,
|
||||
deleteFromDb = true,
|
||||
) {
|
||||
const deletedAt = new Date();
|
||||
|
||||
// この投稿を除く指定したユーザーによる指定したノートのリノートが存在しないとき
|
||||
if (
|
||||
note.renoteId &&
|
||||
(await countSameRenotes(user.id, note.renoteId, note.id)) === 0
|
||||
(await countSameRenotes(user.id, note.renoteId, note.id)) === 0 &&
|
||||
deleteFromDb
|
||||
) {
|
||||
Notes.decrement({ id: note.renoteId }, "renoteCount", 1);
|
||||
Notes.decrement({ id: note.renoteId }, "score", 1);
|
||||
}
|
||||
|
||||
if (note.replyId) {
|
||||
if (note.replyId && deleteFromDb) {
|
||||
await Notes.decrement({ id: note.replyId }, "repliesCount", 1);
|
||||
}
|
||||
|
||||
|
@ -106,10 +108,12 @@ export default async function (
|
|||
}
|
||||
}
|
||||
|
||||
await Notes.delete({
|
||||
id: note.id,
|
||||
userId: user.id,
|
||||
});
|
||||
if (deleteFromDb) {
|
||||
await Notes.delete({
|
||||
id: note.id,
|
||||
userId: user.id,
|
||||
});
|
||||
}
|
||||
|
||||
if (meilisearch) {
|
||||
await meilisearch.deleteNotes(note.id);
|
||||
|
|
|
@ -10,6 +10,7 @@ import { url } from "@/config";
|
|||
import { noteActions } from "@/store";
|
||||
import { shareAvailable } from "@/scripts/share-available";
|
||||
import { getUserMenu } from "@/scripts/get-user-menu";
|
||||
import { unisonReload } from "@/scripts/unison-reload";
|
||||
|
||||
export function getNoteMenu(props: {
|
||||
note: firefish.entities.Note;
|
||||
|
@ -72,6 +73,21 @@ export function getNoteMenu(props: {
|
|||
});
|
||||
}
|
||||
|
||||
function makePrivate(): void {
|
||||
os.confirm({
|
||||
type: "warning",
|
||||
text: i18n.ts.makePrivateConfirm,
|
||||
}).then(async ({ canceled }) => {
|
||||
if (canceled) return;
|
||||
|
||||
await os.api("notes/make-private", {
|
||||
noteId: appearNote.id,
|
||||
});
|
||||
|
||||
unisonReload();
|
||||
});
|
||||
}
|
||||
|
||||
function toggleFavorite(favorite: boolean): void {
|
||||
os.apiWithDialog(
|
||||
favorite ? "notes/favorites/create" : "notes/favorites/delete",
|
||||
|
@ -437,6 +453,18 @@ export function getNoteMenu(props: {
|
|||
action: edit,
|
||||
}
|
||||
: undefined,
|
||||
isAppearAuthor &&
|
||||
!(
|
||||
appearNote.visibility === "specified" &&
|
||||
appearNote.visibleUserIds.length === 0
|
||||
)
|
||||
? {
|
||||
icon: "ph-eye-slash ph-bold ph-lg",
|
||||
text: i18n.ts.makePrivate,
|
||||
danger: true,
|
||||
action: makePrivate,
|
||||
}
|
||||
: undefined,
|
||||
isAppearAuthor
|
||||
? {
|
||||
icon: "ph-eraser ph-bold ph-lg",
|
||||
|
|
Loading…
Reference in a new issue