From 233e1eeeb220cdc37fcc6192f19550b353c464fb Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 18 Apr 2018 14:09:55 +0900 Subject: Fix bug --- src/remote/activitypub/kernel/follow.ts | 5 ++++- src/remote/activitypub/kernel/like.ts | 3 ++- src/remote/activitypub/kernel/undo/follow.ts | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) (limited to 'src/remote/activitypub/kernel') diff --git a/src/remote/activitypub/kernel/follow.ts b/src/remote/activitypub/kernel/follow.ts index 6a8b5a1bec..7e31eb32ea 100644 --- a/src/remote/activitypub/kernel/follow.ts +++ b/src/remote/activitypub/kernel/follow.ts @@ -1,3 +1,4 @@ +import * as mongo from 'mongodb'; import User, { IRemoteUser } from '../../../models/user'; import config from '../../../config'; import follow from '../../../services/following/create'; @@ -10,7 +11,9 @@ export default async (actor: IRemoteUser, activity: IFollow): Promise => { return null; } - const followee = await User.findOne({ _id: id.split('/').pop() }); + const followee = await User.findOne({ + _id: new mongo.ObjectID(id.split('/').pop()) + }); if (followee === null) { throw new Error('followee not found'); diff --git a/src/remote/activitypub/kernel/like.ts b/src/remote/activitypub/kernel/like.ts index 4941608588..fc5d0a2f61 100644 --- a/src/remote/activitypub/kernel/like.ts +++ b/src/remote/activitypub/kernel/like.ts @@ -1,3 +1,4 @@ +import * as mongo from 'mongodb'; import Note from '../../../models/note'; import { IRemoteUser } from '../../../models/user'; import { ILike } from '../type'; @@ -9,7 +10,7 @@ export default async (actor: IRemoteUser, activity: ILike) => { // Transform: // https://misskey.ex/notes/xxxx to // xxxx - const noteId = id.split('/').pop(); + const noteId = new mongo.ObjectID(id.split('/').pop()); const note = await Note.findOne({ _id: noteId }); if (note === null) { diff --git a/src/remote/activitypub/kernel/undo/follow.ts b/src/remote/activitypub/kernel/undo/follow.ts index a85cb0305d..c0b10c1898 100644 --- a/src/remote/activitypub/kernel/undo/follow.ts +++ b/src/remote/activitypub/kernel/undo/follow.ts @@ -1,3 +1,4 @@ +import * as mongo from 'mongodb'; import User, { IRemoteUser } from '../../../../models/user'; import config from '../../../../config'; import unfollow from '../../../../services/following/delete'; @@ -10,7 +11,9 @@ export default async (actor: IRemoteUser, activity: IFollow): Promise => { return null; } - const followee = await User.findOne({ _id: id.split('/').pop() }); + const followee = await User.findOne({ + _id: new mongo.ObjectID(id.split('/').pop()) + }); if (followee === null) { throw new Error('followee not found'); -- cgit v1.2.3-freya From 20e77196f28178c869402985761bd4c2fa74bf0a Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 22 Apr 2018 10:44:17 +0900 Subject: AP: 投票をレンダリング MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/client/app/desktop/views/components/notes.note.vue | 2 +- src/client/docs/api/entities/note.yaml | 6 ------ src/client/docs/api/entities/post.yaml | 6 ------ src/models/messaging-message.ts | 1 - src/models/note.ts | 1 - src/remote/activitypub/kernel/delete/note.ts | 1 - src/remote/activitypub/misc/get-note-html.ts | 18 ++++++++++++++++++ src/remote/activitypub/renderer/note.ts | 3 ++- src/server/api/endpoints/messaging/messages/create.ts | 3 --- src/services/note/create.ts | 2 -- 10 files changed, 21 insertions(+), 22 deletions(-) create mode 100644 src/remote/activitypub/misc/get-note-html.ts (limited to 'src/remote/activitypub/kernel') diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue index 1352fc4ee7..ae2793db92 100644 --- a/src/client/app/desktop/views/components/notes.note.vue +++ b/src/client/app/desktop/views/components/notes.note.vue @@ -36,7 +36,7 @@

diff --git a/src/client/docs/api/entities/note.yaml b/src/client/docs/api/entities/note.yaml index 718d331d13..6fd26543bb 100644 --- a/src/client/docs/api/entities/note.yaml +++ b/src/client/docs/api/entities/note.yaml @@ -29,12 +29,6 @@ props: desc: ja: "投稿の本文 (ローカルの場合Markdown風のフォーマット)" en: "The text of this note (in Markdown like format if local)" - - name: "textHtml" - type: "string" - optional: true - desc: - ja: "投稿の本文 (HTML) (投稿時は無視)" - en: "The text of this note (in HTML. Ignored when posting.)" - name: "mediaIds" type: "id(DriveFile)[]" optional: true diff --git a/src/client/docs/api/entities/post.yaml b/src/client/docs/api/entities/post.yaml index 718d331d13..6fd26543bb 100644 --- a/src/client/docs/api/entities/post.yaml +++ b/src/client/docs/api/entities/post.yaml @@ -29,12 +29,6 @@ props: desc: ja: "投稿の本文 (ローカルの場合Markdown風のフォーマット)" en: "The text of this note (in Markdown like format if local)" - - name: "textHtml" - type: "string" - optional: true - desc: - ja: "投稿の本文 (HTML) (投稿時は無視)" - en: "The text of this note (in HTML. Ignored when posting.)" - name: "mediaIds" type: "id(DriveFile)[]" optional: true diff --git a/src/models/messaging-message.ts b/src/models/messaging-message.ts index 9d62fab4fa..a6a50fc8cf 100644 --- a/src/models/messaging-message.ts +++ b/src/models/messaging-message.ts @@ -12,7 +12,6 @@ export interface IMessagingMessage { _id: mongo.ObjectID; createdAt: Date; text: string; - textHtml: string; userId: mongo.ObjectID; recipientId: mongo.ObjectID; isRead: boolean; diff --git a/src/models/note.ts b/src/models/note.ts index d4b16afa4c..02801b62de 100644 --- a/src/models/note.ts +++ b/src/models/note.ts @@ -38,7 +38,6 @@ export type INote = { poll: any; // todo text: string; tags: string[]; - textHtml: string; cw: string; userId: mongo.ObjectID; appId: mongo.ObjectID; diff --git a/src/remote/activitypub/kernel/delete/note.ts b/src/remote/activitypub/kernel/delete/note.ts index 64c342d39b..b2868f69a3 100644 --- a/src/remote/activitypub/kernel/delete/note.ts +++ b/src/remote/activitypub/kernel/delete/note.ts @@ -22,7 +22,6 @@ export default async function(actor: IRemoteUser, uri: string): Promise { $set: { deletedAt: new Date(), text: null, - textHtml: null, mediaIds: [], poll: null } diff --git a/src/remote/activitypub/misc/get-note-html.ts b/src/remote/activitypub/misc/get-note-html.ts new file mode 100644 index 0000000000..a63059a38d --- /dev/null +++ b/src/remote/activitypub/misc/get-note-html.ts @@ -0,0 +1,18 @@ +import { INote } from "../../../models/note"; +import toHtml from '../../../text/html'; +import parse from '../../../text/parse'; +import config from '../../../config'; + +export default function(note: INote) { + if (note.text == null) return null; + + let html = toHtml(parse(note.text)); + + if (note.poll != null) { + const url = `${config.url}/notes/${note._id}`; + // TODO: i18n + html += `

【投票】
${url}

`; + } + + return html; +} diff --git a/src/remote/activitypub/renderer/note.ts b/src/remote/activitypub/renderer/note.ts index c364b13249..a05c12b388 100644 --- a/src/remote/activitypub/renderer/note.ts +++ b/src/remote/activitypub/renderer/note.ts @@ -4,6 +4,7 @@ import config from '../../../config'; import DriveFile from '../../../models/drive-file'; import Note, { INote } from '../../../models/note'; import User from '../../../models/user'; +import toHtml from '../misc/get-note-html'; export default async function renderNote(note: INote, dive = true) { const promisedFiles = note.mediaIds @@ -48,7 +49,7 @@ export default async function renderNote(note: INote, dive = true) { id: `${config.url}/notes/${note._id}`, type: 'Note', attributedTo, - content: note.textHtml, + content: toHtml(note), published: note.createdAt.toISOString(), to: 'https://www.w3.org/ns/activitystreams#Public', cc: `${attributedTo}/followers`, diff --git a/src/server/api/endpoints/messaging/messages/create.ts b/src/server/api/endpoints/messaging/messages/create.ts index 085e75e6cf..0483b602b2 100644 --- a/src/server/api/endpoints/messaging/messages/create.ts +++ b/src/server/api/endpoints/messaging/messages/create.ts @@ -12,8 +12,6 @@ import { pack } from '../../../../../models/messaging-message'; import publishUserStream from '../../../../../publishers/stream'; import { publishMessagingStream, publishMessagingIndexStream } from '../../../../../publishers/stream'; import pushSw from '../../../../../publishers/push-sw'; -import html from '../../../../../text/html'; -import parse from '../../../../../text/parse'; import config from '../../../../../config'; /** @@ -77,7 +75,6 @@ module.exports = (params, user) => new Promise(async (res, rej) => { fileId: file ? file._id : undefined, recipientId: recipient._id, text: text ? text : undefined, - textHtml: text ? html(parse(text)) : undefined, userId: user._id, isRead: false }); diff --git a/src/services/note/create.ts b/src/services/note/create.ts index ca01b557d6..2380e64ce3 100644 --- a/src/services/note/create.ts +++ b/src/services/note/create.ts @@ -15,7 +15,6 @@ import Mute from '../../models/mute'; import pushSw from '../../publishers/push-sw'; import event from '../../publishers/stream'; import parse from '../../text/parse'; -import html from '../../text/html'; import { IApp } from '../../models/app'; export default async (user: IUser, data: { @@ -63,7 +62,6 @@ export default async (user: IUser, data: { replyId: data.reply ? data.reply._id : null, renoteId: data.renote ? data.renote._id : null, text: data.text, - textHtml: tokens === null ? null : html(tokens), poll: data.poll, cw: data.cw, tags, -- cgit v1.2.3-freya From 02bb99ac029e8fc12aec384717341f603052d7c0 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 23 Apr 2018 15:27:01 +0900 Subject: 他のMisskeyインスタンスにリアクション情報を伝えるように MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/models/note-reaction.ts | 13 +++++++++++++ src/remote/activitypub/kernel/like.ts | 12 +++++++++++- src/remote/activitypub/renderer/like.ts | 5 +++-- src/remote/activitypub/type.ts | 1 + src/server/api/endpoints/notes/reactions/create.ts | 13 ++----------- src/services/note/reaction/create.ts | 2 +- 6 files changed, 31 insertions(+), 15 deletions(-) (limited to 'src/remote/activitypub/kernel') diff --git a/src/models/note-reaction.ts b/src/models/note-reaction.ts index 9bf467f222..7891ebdf17 100644 --- a/src/models/note-reaction.ts +++ b/src/models/note-reaction.ts @@ -1,4 +1,5 @@ import * as mongo from 'mongodb'; +import $ from 'cafy'; import deepcopy = require('deepcopy'); import db from '../db/mongodb'; import Reaction from './note-reaction'; @@ -16,6 +17,18 @@ export interface INoteReaction { reaction: string; } +export const validateReaction = $().string().or([ + 'like', + 'love', + 'laugh', + 'hmm', + 'surprise', + 'congrats', + 'angry', + 'confused', + 'pudding' +]); + /** * NoteReactionを物理削除します */ diff --git a/src/remote/activitypub/kernel/like.ts b/src/remote/activitypub/kernel/like.ts index fc5d0a2f61..17ec73f12b 100644 --- a/src/remote/activitypub/kernel/like.ts +++ b/src/remote/activitypub/kernel/like.ts @@ -3,6 +3,7 @@ import Note from '../../../models/note'; import { IRemoteUser } from '../../../models/user'; import { ILike } from '../type'; import create from '../../../services/note/reaction/create'; +import { validateReaction } from '../../../models/note-reaction'; export default async (actor: IRemoteUser, activity: ILike) => { const id = typeof activity.object == 'string' ? activity.object : activity.object.id; @@ -17,5 +18,14 @@ export default async (actor: IRemoteUser, activity: ILike) => { throw new Error(); } - await create(actor, note, 'pudding'); + let reaction = 'pudding'; + + // 他のMisskeyインスタンスからのリアクション + if (activity._misskey_reaction) { + if (validateReaction.ok(activity._misskey_reaction)) { + reaction = activity._misskey_reaction; + } + } + + await create(actor, note, reaction); }; diff --git a/src/remote/activitypub/renderer/like.ts b/src/remote/activitypub/renderer/like.ts index 061a10ba84..33e1341a20 100644 --- a/src/remote/activitypub/renderer/like.ts +++ b/src/remote/activitypub/renderer/like.ts @@ -1,8 +1,9 @@ import config from '../../../config'; import { ILocalUser } from '../../../models/user'; -export default (user: ILocalUser, note) => ({ +export default (user: ILocalUser, note, reaction: string) => ({ type: 'Like', actor: `${config.url}/users/${user._id}`, - object: note.uri ? note.uri : `${config.url}/notes/${note._id}` + object: note.uri ? note.uri : `${config.url}/notes/${note._id}`, + _misskey_reaction: reaction }); diff --git a/src/remote/activitypub/type.ts b/src/remote/activitypub/type.ts index 08e5493dd4..6018ac29c4 100644 --- a/src/remote/activitypub/type.ts +++ b/src/remote/activitypub/type.ts @@ -82,6 +82,7 @@ export interface IAccept extends IActivity { export interface ILike extends IActivity { type: 'Like'; + _misskey_reaction: string; } export interface IAnnounce extends IActivity { diff --git a/src/server/api/endpoints/notes/reactions/create.ts b/src/server/api/endpoints/notes/reactions/create.ts index c80c5416b1..9e217cc3e0 100644 --- a/src/server/api/endpoints/notes/reactions/create.ts +++ b/src/server/api/endpoints/notes/reactions/create.ts @@ -4,6 +4,7 @@ import $ from 'cafy'; import Note from '../../../../../models/note'; import create from '../../../../../services/note/reaction/create'; +import { validateReaction } from '../../../../../models/note-reaction'; /** * React to a note @@ -14,17 +15,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { if (noteIdErr) return rej('invalid noteId param'); // Get 'reaction' parameter - const [reaction, reactionErr] = $(params.reaction).string().or([ - 'like', - 'love', - 'laugh', - 'hmm', - 'surprise', - 'congrats', - 'angry', - 'confused', - 'pudding' - ]).$; + const [reaction, reactionErr] = $(params.reaction).string().pipe(validateReaction.ok).$; if (reactionErr) return rej('invalid reaction param'); // Fetch reactee diff --git a/src/services/note/reaction/create.ts b/src/services/note/reaction/create.ts index 06fd6c0576..123c091c85 100644 --- a/src/services/note/reaction/create.ts +++ b/src/services/note/reaction/create.ts @@ -87,7 +87,7 @@ export default async (user: IUser, note: INote, reaction: string) => new Promise //#region 配信 // リアクターがローカルユーザーかつリアクション対象がリモートユーザーの投稿なら配送 if (isLocalUser(user) && isRemoteUser(note._user)) { - const content = pack(renderLike(user, note)); + const content = pack(renderLike(user, note, reaction)); deliver(user, content, note._user.inbox); } //#endregion -- cgit v1.2.3-freya From 47ce59d555eab91b0642b4e4b62c8ecc4ff2288a Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 28 Apr 2018 17:25:56 +0900 Subject: wip --- .../common/views/components/visibility-chooser.vue | 213 +++++++++++++++++++++ .../app/desktop/views/components/post-form.vue | 32 ++-- src/models/note.ts | 11 +- src/remote/activitypub/kernel/announce/note.ts | 4 +- src/remote/activitypub/models/note.ts | 4 +- 5 files changed, 244 insertions(+), 20 deletions(-) create mode 100644 src/client/app/common/views/components/visibility-chooser.vue (limited to 'src/remote/activitypub/kernel') diff --git a/src/client/app/common/views/components/visibility-chooser.vue b/src/client/app/common/views/components/visibility-chooser.vue new file mode 100644 index 0000000000..71e92a85f2 --- /dev/null +++ b/src/client/app/common/views/components/visibility-chooser.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/src/client/app/desktop/views/components/post-form.vue b/src/client/app/desktop/views/components/post-form.vue index 80d9d66753..d1d7076a30 100644 --- a/src/client/app/desktop/views/components/post-form.vue +++ b/src/client/app/desktop/views/components/post-form.vue @@ -30,7 +30,7 @@ -

{{ '%i18n:!@text-remain%'.replace('{}', 1000 - text.length) }}

+ @@ -43,10 +43,12 @@ import Vue from 'vue'; import * as XDraggable from 'vuedraggable'; import getKao from '../../../common/scripts/get-kao'; +import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue'; export default Vue.extend({ components: { - XDraggable + XDraggable, + MkVisibilityChooser }, props: ['reply', 'renote'], @@ -61,6 +63,7 @@ export default Vue.extend({ useCw: false, cw: null, geo: null, + visibility: 'public', autocomplete: null, draghover: false }; @@ -246,6 +249,16 @@ export default Vue.extend({ this.$emit('geo-dettached'); }, + setVisibility() { + const w = (this as any).os.new(MkVisibilityChooser, { + source: this.$refs.visibilityButton, + v: this.visibility + }); + w.$once('chosen', v => { + this.visibility = v; + }); + }, + post() { this.posting = true; @@ -256,6 +269,7 @@ export default Vue.extend({ renoteId: this.renote ? this.renote.id : undefined, poll: this.poll ? (this.$refs.poll as any).get() : undefined, cw: this.useCw ? this.cw || '' : undefined, + visibility: this.visibility, geo: this.geo ? { coordinates: [this.geo.longitude, this.geo.latitude], altitude: this.geo.altitude, @@ -450,19 +464,6 @@ root(isDark) input[type='file'] display none - .text-count - pointer-events none - display block - position absolute - bottom 16px - right 138px - margin 0 - line-height 40px - color rgba($theme-color, 0.5) - - &.over - color #ec3828 - .submit display block position absolute @@ -532,6 +533,7 @@ root(isDark) > .kao > .poll > .geo + > .visibility display inline-block cursor pointer padding 0 diff --git a/src/models/note.ts b/src/models/note.ts index 3c835ed190..2f95cbfd65 100644 --- a/src/models/note.ts +++ b/src/models/note.ts @@ -46,7 +46,16 @@ export type INote = { repliesCount: number; reactionCounts: any; mentions: mongo.ObjectID[]; - visibility: 'public' | 'unlisted' | 'private' | 'direct'; + + /** + * public ... 公開 + * home ... ホームタイムライン(ユーザーページのタイムライン含む)のみに流す + * followers ... フォロワーのみ + * mentioned ... 言及したユーザーのみ + * private ... 自分のみ + */ + visibility: 'public' | 'home' | 'followers' | 'mentioned' | 'private'; + geo: { coordinates: number[]; altitude: number; diff --git a/src/remote/activitypub/kernel/announce/note.ts b/src/remote/activitypub/kernel/announce/note.ts index a288dd499a..e2f3806d75 100644 --- a/src/remote/activitypub/kernel/announce/note.ts +++ b/src/remote/activitypub/kernel/announce/note.ts @@ -30,8 +30,8 @@ export default async function(resolver: Resolver, actor: IRemoteUser, activity: //#region Visibility let visibility = 'public'; - if (!activity.to.includes('https://www.w3.org/ns/activitystreams#Public')) visibility = 'unlisted'; - if (activity.cc.length == 0) visibility = 'private'; + if (!activity.to.includes('https://www.w3.org/ns/activitystreams#Public')) visibility = 'home'; + if (activity.cc.length == 0) visibility = 'followers'; // TODO if (visibility != 'public') throw new Error('unspported visibility'); //#endergion diff --git a/src/remote/activitypub/models/note.ts b/src/remote/activitypub/models/note.ts index f830370a23..c0f67cb2f9 100644 --- a/src/remote/activitypub/models/note.ts +++ b/src/remote/activitypub/models/note.ts @@ -65,8 +65,8 @@ export async function createNote(value: any, resolver?: Resolver, silent = false //#region Visibility let visibility = 'public'; - if (!note.to.includes('https://www.w3.org/ns/activitystreams#Public')) visibility = 'unlisted'; - if (note.cc.length == 0) visibility = 'private'; + if (!note.to.includes('https://www.w3.org/ns/activitystreams#Public')) visibility = 'home'; + if (note.cc.length == 0) visibility = 'followers'; // TODO if (visibility != 'public') return null; //#endergion -- cgit v1.2.3-freya From 671c5e7c12feb187c17633baa239bddd2d92a6c1 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 29 Apr 2018 04:44:58 +0900 Subject: wip --- src/remote/activitypub/kernel/announce/note.ts | 15 +++++++++++---- src/remote/activitypub/models/note.ts | 13 ++++++++++--- 2 files changed, 21 insertions(+), 7 deletions(-) (limited to 'src/remote/activitypub/kernel') diff --git a/src/remote/activitypub/kernel/announce/note.ts b/src/remote/activitypub/kernel/announce/note.ts index e2f3806d75..fe645b07b5 100644 --- a/src/remote/activitypub/kernel/announce/note.ts +++ b/src/remote/activitypub/kernel/announce/note.ts @@ -5,6 +5,7 @@ import post from '../../../../services/note/create'; import { IRemoteUser } from '../../../../models/user'; import { IAnnounce, INote } from '../../type'; import { fetchNote, resolveNote } from '../../models/note'; +import { resolvePerson } from '../../models/person'; const log = debug('misskey:activitypub'); @@ -30,16 +31,22 @@ export default async function(resolver: Resolver, actor: IRemoteUser, activity: //#region Visibility let visibility = 'public'; - if (!activity.to.includes('https://www.w3.org/ns/activitystreams#Public')) visibility = 'home'; - if (activity.cc.length == 0) visibility = 'followers'; - // TODO - if (visibility != 'public') throw new Error('unspported visibility'); + let visibleUsers = []; + if (!note.to.includes('https://www.w3.org/ns/activitystreams#Public')) { + if (note.cc.includes('https://www.w3.org/ns/activitystreams#Public')) { + visibility = 'home'; + } else { + visibility = 'specified'; + visibleUsers = await Promise.all(note.to.map(uri => resolvePerson(uri))); + } + } if (activity.cc.length == 0) visibility = 'followers'; //#endergion await post(actor, { createdAt: new Date(activity.published), renote, visibility, + visibleUsers, uri }); } diff --git a/src/remote/activitypub/models/note.ts b/src/remote/activitypub/models/note.ts index c0f67cb2f9..9a0cc4e0c9 100644 --- a/src/remote/activitypub/models/note.ts +++ b/src/remote/activitypub/models/note.ts @@ -65,10 +65,16 @@ export async function createNote(value: any, resolver?: Resolver, silent = false //#region Visibility let visibility = 'public'; - if (!note.to.includes('https://www.w3.org/ns/activitystreams#Public')) visibility = 'home'; + let visibleUsers = []; + if (!note.to.includes('https://www.w3.org/ns/activitystreams#Public')) { + if (note.cc.includes('https://www.w3.org/ns/activitystreams#Public')) { + visibility = 'home'; + } else { + visibility = 'specified'; + visibleUsers = await Promise.all(note.to.map(uri => resolvePerson(uri))); + } + } if (note.cc.length == 0) visibility = 'followers'; - // TODO - if (visibility != 'public') return null; //#endergion // 添付メディア @@ -99,6 +105,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false viaMobile: false, geo: undefined, visibility, + visibleUsers, uri: note.id }, silent); } -- cgit v1.2.3-freya