summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/app/common/views/components/note-menu.vue27
-rw-r--r--src/server/api/endpoints/i/pin.ts49
-rw-r--r--src/server/api/endpoints/i/unpin.ts57
-rw-r--r--src/server/api/endpoints/notes/favorites/create.ts18
-rw-r--r--src/services/i/pin.ts22
5 files changed, 127 insertions, 46 deletions
diff --git a/src/client/app/common/views/components/note-menu.vue b/src/client/app/common/views/components/note-menu.vue
index 08fae46dd6..a3e80e33de 100644
--- a/src/client/app/common/views/components/note-menu.vue
+++ b/src/client/app/common/views/components/note-menu.vue
@@ -28,11 +28,19 @@ export default Vue.extend({
}];
if (this.note.userId == this.$store.state.i.id) {
- items.push({
- icon: '%fa:thumbtack%',
- text: '%i18n:@pin%',
- action: this.pin
- });
+ if (this.$store.state.i.pinnedNoteIds.includes(this.note.id)) {
+ items.push({
+ icon: '%fa:thumbtack%',
+ text: '%i18n:@unpin%',
+ action: this.unpin
+ });
+ } else {
+ items.push({
+ icon: '%fa:thumbtack%',
+ text: '%i18n:@pin%',
+ action: this.pin
+ });
+ }
}
if (this.note.userId == this.$store.state.i.id || this.$store.state.i.isAdmin) {
@@ -56,6 +64,7 @@ export default Vue.extend({
return items;
}
},
+
methods: {
detail() {
this.$router.push(`/notes/${ this.note.id }`);
@@ -73,6 +82,14 @@ export default Vue.extend({
});
},
+ unpin() {
+ (this as any).api('i/unpin', {
+ noteId: this.note.id
+ }).then(() => {
+ this.destroyDom();
+ });
+ },
+
del() {
if (!window.confirm('%i18n:@delete-confirm%')) return;
(this as any).api('notes/delete', {
diff --git a/src/server/api/endpoints/i/pin.ts b/src/server/api/endpoints/i/pin.ts
index d075976b74..f9ae032b11 100644
--- a/src/server/api/endpoints/i/pin.ts
+++ b/src/server/api/endpoints/i/pin.ts
@@ -1,21 +1,35 @@
-import * as mongo from 'mongodb';
import $ from 'cafy'; import ID from '../../../../misc/cafy-id';
import User, { ILocalUser } from '../../../../models/user';
import Note from '../../../../models/note';
import { pack } from '../../../../models/user';
import { deliverPinnedChange } from '../../../../services/i/pin';
+import getParams from '../../get-params';
+
+export const meta = {
+ desc: {
+ 'ja-JP': '指定した投稿をピン留めします。'
+ },
+
+ requireCredential: true,
+
+ kind: 'account-write',
+
+ params: {
+ noteId: $.type(ID).note({
+ desc: {
+ 'ja-JP': '対象の投稿のID'
+ }
+ })
+ }
+};
-/**
- * Pin note
- */
export default async (params: any, user: ILocalUser) => new Promise(async (res, rej) => {
- // Get 'noteId' parameter
- const [noteId, noteIdErr] = $.type(ID).get(params.noteId);
- if (noteIdErr) return rej('invalid noteId param');
+ const [ps, psErr] = getParams(meta, params);
+ if (psErr) return rej(psErr);
// Fetch pinee
const note = await Note.findOne({
- _id: noteId,
+ _id: ps.noteId,
userId: user._id
});
@@ -23,21 +37,17 @@ export default async (params: any, user: ILocalUser) => new Promise(async (res,
return rej('note not found');
}
- let addedId: mongo.ObjectID;
- let removedId: mongo.ObjectID;
-
const pinnedNoteIds = user.pinnedNoteIds || [];
+ if (pinnedNoteIds.length > 5) {
+ return rej('cannot pin more notes');
+ }
+
if (pinnedNoteIds.some(id => id.equals(note._id))) {
return rej('already exists');
}
pinnedNoteIds.unshift(note._id);
- addedId = note._id;
-
- if (pinnedNoteIds.length > 5) {
- removedId = pinnedNoteIds.pop();
- }
await User.update(user._id, {
$set: {
@@ -45,14 +55,13 @@ export default async (params: any, user: ILocalUser) => new Promise(async (res,
}
});
- // Serialize
const iObj = await pack(user, user, {
detail: true
});
- // Send Add/Remove to followers
- deliverPinnedChange(user._id, removedId, addedId);
-
// Send response
res(iObj);
+
+ // Send Add to followers
+ deliverPinnedChange(user._id, note._id, true);
});
diff --git a/src/server/api/endpoints/i/unpin.ts b/src/server/api/endpoints/i/unpin.ts
new file mode 100644
index 0000000000..82625ae5fb
--- /dev/null
+++ b/src/server/api/endpoints/i/unpin.ts
@@ -0,0 +1,57 @@
+import $ from 'cafy'; import ID from '../../../../misc/cafy-id';
+import User, { ILocalUser } from '../../../../models/user';
+import Note from '../../../../models/note';
+import { pack } from '../../../../models/user';
+import { deliverPinnedChange } from '../../../../services/i/pin';
+import getParams from '../../get-params';
+
+export const meta = {
+ desc: {
+ 'ja-JP': '指定した投稿のピン留めを解除します。'
+ },
+
+ requireCredential: true,
+
+ kind: 'account-write',
+
+ params: {
+ noteId: $.type(ID).note({
+ desc: {
+ 'ja-JP': '対象の投稿のID'
+ }
+ })
+ }
+};
+
+export default async (params: any, user: ILocalUser) => new Promise(async (res, rej) => {
+ const [ps, psErr] = getParams(meta, params);
+ if (psErr) return rej(psErr);
+
+ // Fetch unpinee
+ const note = await Note.findOne({
+ _id: ps.noteId,
+ userId: user._id
+ });
+
+ if (note === null) {
+ return rej('note not found');
+ }
+
+ const pinnedNoteIds = (user.pinnedNoteIds || []).filter(id => !id.equals(note._id));
+
+ await User.update(user._id, {
+ $set: {
+ pinnedNoteIds: pinnedNoteIds
+ }
+ });
+
+ const iObj = await pack(user, user, {
+ detail: true
+ });
+
+ // Send response
+ res(iObj);
+
+ // Send Remove to followers
+ deliverPinnedChange(user._id, note._id, false);
+});
diff --git a/src/server/api/endpoints/notes/favorites/create.ts b/src/server/api/endpoints/notes/favorites/create.ts
index daf7780abc..9aefb701ae 100644
--- a/src/server/api/endpoints/notes/favorites/create.ts
+++ b/src/server/api/endpoints/notes/favorites/create.ts
@@ -2,6 +2,7 @@ import $ from 'cafy'; import ID from '../../../../../misc/cafy-id';
import Favorite from '../../../../../models/favorite';
import Note from '../../../../../models/note';
import { ILocalUser } from '../../../../../models/user';
+import getParams from '../../../get-params';
export const meta = {
desc: {
@@ -11,17 +12,24 @@ export const meta = {
requireCredential: true,
- kind: 'favorite-write'
+ kind: 'favorite-write',
+
+ params: {
+ noteId: $.type(ID).note({
+ desc: {
+ 'ja-JP': '対象の投稿のID'
+ }
+ })
+ }
};
export default (params: any, user: ILocalUser) => new Promise(async (res, rej) => {
- // Get 'noteId' parameter
- const [noteId, noteIdErr] = $.type(ID).get(params.noteId);
- if (noteIdErr) return rej('invalid noteId param');
+ const [ps, psErr] = getParams(meta, params);
+ if (psErr) return rej(psErr);
// Get favoritee
const note = await Note.findOne({
- _id: noteId
+ _id: ps.noteId
});
if (note === null) {
diff --git a/src/services/i/pin.ts b/src/services/i/pin.ts
index 5bf8d166bb..8b7287e68d 100644
--- a/src/services/i/pin.ts
+++ b/src/services/i/pin.ts
@@ -7,7 +7,7 @@ import renderRemove from '../../remote/activitypub/renderer/remove';
import packAp from '../../remote/activitypub/renderer';
import { deliver } from '../../queue';
-export async function deliverPinnedChange(userId: mongo.ObjectID, oldId?: mongo.ObjectID, newId?: mongo.ObjectID) {
+export async function deliverPinnedChange(userId: mongo.ObjectID, noteId: mongo.ObjectID, isAddition: boolean) {
const user = await User.findOne({
_id: userId
});
@@ -20,21 +20,11 @@ export async function deliverPinnedChange(userId: mongo.ObjectID, oldId?: mongo.
const target = `${config.url}/users/${user._id}/collections/featured`;
- if (oldId) {
- const oldItem = `${config.url}/notes/${oldId}`;
- const content = packAp(renderRemove(user, target, oldItem));
- queue.forEach(inbox => {
- deliver(user, content, inbox);
- });
- }
-
- if (newId) {
- const newItem = `${config.url}/notes/${newId}`;
- const content = packAp(renderAdd(user, target, newItem));
- queue.forEach(inbox => {
- deliver(user, content, inbox);
- });
- }
+ const item = `${config.url}/notes/${noteId}`;
+ const content = packAp(isAddition ? renderAdd(user, target, item) : renderRemove(user, target, item));
+ queue.forEach(inbox => {
+ deliver(user, content, inbox);
+ });
}
/**