summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMeiMei <30769358+mei23@users.noreply.github.com>2018-11-16 05:47:29 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2018-11-16 05:47:29 +0900
commitbceb02d760f53877f0f677144bc468ffbc4e66f2 (patch)
treecc12d9836b81deecead9417c8fd6df635784fefd
parent[Client] Add missing icon (diff)
downloadsharkey-bceb02d760f53877f0f677144bc468ffbc4e66f2.tar.gz
sharkey-bceb02d760f53877f0f677144bc468ffbc4e66f2.tar.bz2
sharkey-bceb02d760f53877f0f677144bc468ffbc4e66f2.zip
local only visibility (#3254)
* local only visibility * fix UI
-rw-r--r--locales/ja-JP.yml7
-rw-r--r--src/client/app/common/views/components/note-header.vue6
-rw-r--r--src/client/app/common/views/components/visibility-chooser.vue18
-rw-r--r--src/client/app/desktop/views/components/note.vue24
-rw-r--r--src/client/app/desktop/views/components/post-form.vue16
-rw-r--r--src/client/app/mobile/views/components/note.vue24
-rw-r--r--src/client/app/mobile/views/components/post-form.vue11
-rw-r--r--src/docs/api/entities/note.yaml7
-rw-r--r--src/models/note.ts1
-rw-r--r--src/queue/index.ts2
-rw-r--r--src/remote/activitypub/models/note.ts1
-rw-r--r--src/server/activitypub.ts6
-rw-r--r--src/server/activitypub/outbox.ts3
-rw-r--r--src/server/api/endpoints/notes/create.ts9
-rw-r--r--src/services/note/create.ts15
15 files changed, 139 insertions, 11 deletions
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index b7ef578c52..390bfc9f31 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -96,6 +96,9 @@ common:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
+ local-public: "公開(ローカルのみ)"
+ local-home: "ホーム(ローカルのみ)"
+ local-followers: "フォロワー(ローカルのみ)"
note-placeholders:
a: "今どうしてる?"
@@ -471,6 +474,9 @@ common/views/components/visibility-chooser.vue:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
+ local-public: "公開(ローカルのみ)"
+ local-home: "ホーム(ローカルのみ)"
+ local-followers: "フォロワー(ローカルのみ)"
common/views/components/trends.vue:
count: "{}人が投稿"
@@ -761,6 +767,7 @@ desktop/views/components/post-form.vue:
create-poll: "アンケートを作成"
text-remain: "残り{}文字"
recent-tags: "最近"
+ local-only-message: "この投稿はローカルにのみ公開されます"
click-to-tagging: "クリックでタグ付け"
visibility: "公開範囲"
geolocation-alert: "お使いの端末は位置情報に対応していません"
diff --git a/src/client/app/common/views/components/note-header.vue b/src/client/app/common/views/components/note-header.vue
index 2c7ae0194c..012b678ab3 100644
--- a/src/client/app/common/views/components/note-header.vue
+++ b/src/client/app/common/views/components/note-header.vue
@@ -19,6 +19,9 @@
<template v-if="note.visibility == 'specified'"><fa icon="envelope"/></template>
<template v-if="note.visibility == 'private'"><fa icon="lock"/></template>
</span>
+ <span class="localOnly" v-if="note.localOnly == true">
+ <template><fa icon="heart"/></template>
+ </span>
</div>
</header>
</template>
@@ -115,4 +118,7 @@ export default Vue.extend({
> .visibility
margin-left 8px
+ > .localOnly
+ margin-left 4px
+
</style>
diff --git a/src/client/app/common/views/components/visibility-chooser.vue b/src/client/app/common/views/components/visibility-chooser.vue
index 896be039b3..0335fba0ee 100644
--- a/src/client/app/common/views/components/visibility-chooser.vue
+++ b/src/client/app/common/views/components/visibility-chooser.vue
@@ -35,6 +35,24 @@
<span>{{ $t('private') }}</span>
</div>
</div>
+ <div @click="choose('local-public')" :class="{ active: v == 'local-public' }">
+ <div><fa icon="globe"/></div>
+ <div>
+ <span>{{ $t('local-public') }}</span>
+ </div>
+ </div>
+ <div @click="choose('local-home')" :class="{ active: v == 'local-home' }">
+ <div><fa icon="home"/></div>
+ <div>
+ <span>{{ $t('local-home') }}</span>
+ </div>
+ </div>
+ <div @click="choose('local-followers')" :class="{ active: v == 'local-followers' }">
+ <div><fa icon="unlock"/></div>
+ <div>
+ <span>{{ $t('local-followers') }}</span>
+ </div>
+ </div>
</div>
</div>
</template>
diff --git a/src/client/app/desktop/views/components/note.vue b/src/client/app/desktop/views/components/note.vue
index e2b67c150f..6bd4674269 100644
--- a/src/client/app/desktop/views/components/note.vue
+++ b/src/client/app/desktop/views/components/note.vue
@@ -20,6 +20,15 @@
<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link>
<span>{{ this.$t('reposted-by').substr(this.$t('reposted-by').indexOf('}') + 1) }}</span>
<mk-time :time="note.createdAt"/>
+ <span class="visibility" v-if="note.visibility != 'public'">
+ <template v-if="note.visibility == 'home'"><fa icon="home"/></template>
+ <template v-if="note.visibility == 'followers'"><fa icon="unlock"/></template>
+ <template v-if="note.visibility == 'specified'"><fa icon="envelope"/></template>
+ <template v-if="note.visibility == 'private'"><fa icon="lock"/></template>
+ </span>
+ <span class="localOnly" v-if="note.localOnly == true">
+ <template><fa icon="heart"/></template>
+ </span>
</div>
<article>
<mk-avatar class="avatar" :user="appearNote.user"/>
@@ -199,9 +208,6 @@ export default Vue.extend({
> span
flex-shrink 0
- &:last-of-type
- margin-right 8px
-
.name
overflow hidden
flex-shrink 1
@@ -215,6 +221,18 @@ export default Vue.extend({
flex-shrink 0
font-size 0.9em
+ > .visibility
+ margin-left 8px
+
+ [data-icon]
+ margin-right 0
+
+ > .localOnly
+ margin-left 4px
+
+ [data-icon]
+ margin-right 0
+
& + article
padding-top 8px
diff --git a/src/client/app/desktop/views/components/post-form.vue b/src/client/app/desktop/views/components/post-form.vue
index e05fab168c..02478b4eb3 100644
--- a/src/client/app/desktop/views/components/post-form.vue
+++ b/src/client/app/desktop/views/components/post-form.vue
@@ -14,6 +14,7 @@
<b>{{ $t('recent-tags') }}:</b>
<a v-for="tag in recentHashtags.slice(0, 5)" @click="addTag(tag)" :title="$t('click-to-tagging')">#{{ tag }}</a>
</div>
+ <div class="local-only" v-if="this.localOnly == true">{{ $t('local-only-message') }}</div>
<input v-show="useCw" v-model="cw" :placeholder="$t('annotations')">
<div class="textarea">
<textarea :class="{ with: (files.length != 0 || poll) }"
@@ -112,6 +113,7 @@ export default Vue.extend({
geo: null,
visibility: this.$store.state.settings.rememberNoteVisibility ? (this.$store.state.device.visibility || this.$store.state.settings.defaultNoteVisibility) : this.$store.state.settings.defaultNoteVisibility,
visibleUsers: [],
+ localOnly: false,
autocomplete: null,
draghover: false,
recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]'),
@@ -363,7 +365,14 @@ export default Vue.extend({
source: this.$refs.visibilityButton
});
w.$once('chosen', v => {
- this.visibility = v;
+ const m = v.match(/^local-(.+)/);
+ if (m) {
+ this.localOnly = true;
+ this.visibility = m[1];
+ } else {
+ this.localOnly = false;
+ this.visibility = v;
+ }
});
},
@@ -407,6 +416,7 @@ export default Vue.extend({
cw: this.useCw ? this.cw || '' : undefined,
visibility: this.visibility,
visibleUserIds: this.visibility == 'specified' ? this.visibleUsers.map(u => u.id) : undefined,
+ localOnly: this.localOnly,
geo: this.geo ? {
coordinates: [this.geo.longitude, this.geo.latitude],
altitude: this.geo.altitude,
@@ -640,6 +650,10 @@ export default Vue.extend({
margin-right 8px
white-space nowrap
+ > .local-only
+ margin 0 0 8px 0
+ color var(--primary)
+
> .mk-uploader
margin 8px 0 0 0
padding 8px
diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue
index d42efbf344..38fab0e5a1 100644
--- a/src/client/app/mobile/views/components/note.vue
+++ b/src/client/app/mobile/views/components/note.vue
@@ -16,6 +16,15 @@
<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link>
<span>{{ this.$t('reposted-by').substr(this.$t('reposted-by').indexOf('}') + 1) }}</span>
<mk-time :time="note.createdAt"/>
+ <span class="visibility" v-if="note.visibility != 'public'">
+ <template v-if="note.visibility == 'home'"><fa icon="home"/></template>
+ <template v-if="note.visibility == 'followers'"><fa icon="unlock"/></template>
+ <template v-if="note.visibility == 'specified'"><fa icon="envelope"/></template>
+ <template v-if="note.visibility == 'private'"><fa icon="lock"/></template>
+ </span>
+ <span class="localOnly" v-if="note.localOnly == true">
+ <template><fa icon="heart"/></template>
+ </span>
</div>
<article>
<mk-avatar class="avatar" :user="appearNote.user" v-if="$store.state.device.postStyle != 'smart'"/>
@@ -163,9 +172,6 @@ export default Vue.extend({
> span
flex-shrink 0
- &:last-of-type
- margin-right 8px
-
.name
overflow hidden
flex-shrink 1
@@ -179,6 +185,18 @@ export default Vue.extend({
flex-shrink 0
font-size 0.9em
+ > .visibility
+ margin-left 8px
+
+ [data-icon]
+ margin-right 0
+
+ > .localOnly
+ margin-left 4px
+
+ [data-icon]
+ margin-right 0
+
& + article
padding-top 8px
diff --git a/src/client/app/mobile/views/components/post-form.vue b/src/client/app/mobile/views/components/post-form.vue
index df7a5c5a04..f941c59d9f 100644
--- a/src/client/app/mobile/views/components/post-form.vue
+++ b/src/client/app/mobile/views/components/post-form.vue
@@ -102,6 +102,7 @@ export default Vue.extend({
geo: null,
visibility: this.$store.state.settings.rememberNoteVisibility ? (this.$store.state.device.visibility || this.$store.state.settings.defaultNoteVisibility) : this.$store.state.settings.defaultNoteVisibility,
visibleUsers: [],
+ localOnly: false,
useCw: false,
cw: null,
recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]'),
@@ -274,7 +275,14 @@ export default Vue.extend({
compact: true
});
w.$once('chosen', v => {
- this.visibility = v;
+ const m = v.match(/^local-(.+)/);
+ if (m) {
+ this.localOnly = true;
+ this.visibility = m[1];
+ } else {
+ this.localOnly = false;
+ this.visibility = v;
+ }
});
},
@@ -320,6 +328,7 @@ export default Vue.extend({
} : null,
visibility: this.visibility,
visibleUserIds: this.visibility == 'specified' ? this.visibleUsers.map(u => u.id) : undefined,
+ localOnly: this.localOnly,
viaMobile: viaMobile
}).then(data => {
this.$emit('posted');
diff --git a/src/docs/api/entities/note.yaml b/src/docs/api/entities/note.yaml
index 6654be2b02..89846a56c7 100644
--- a/src/docs/api/entities/note.yaml
+++ b/src/docs/api/entities/note.yaml
@@ -26,6 +26,13 @@ props:
ja-JP: "モバイル端末から投稿したか否か(自己申告であることに留意)"
en-US: "Whether this note sent via a mobile device"
+ localOnly:
+ type: "boolean"
+ optional: true
+ desc:
+ ja-JP: "ローカルのみに公開する投稿か否か"
+ en-US: "Whether this note is no federation"
+
text:
type: "string"
optional: true
diff --git a/src/models/note.ts b/src/models/note.ts
index 516045225c..717960bb23 100644
--- a/src/models/note.ts
+++ b/src/models/note.ts
@@ -50,6 +50,7 @@ export type INote = {
userId: mongo.ObjectID;
appId: mongo.ObjectID;
viaMobile: boolean;
+ localOnly: boolean;
renoteCount: number;
repliesCount: number;
reactionCounts: any;
diff --git a/src/queue/index.ts b/src/queue/index.ts
index 5a48dbe648..8683bcd1df 100644
--- a/src/queue/index.ts
+++ b/src/queue/index.ts
@@ -6,6 +6,8 @@ export function createHttpJob(data: any) {
}
export function deliver(user: ILocalUser, content: any, to: any) {
+ if (content == null) return;
+
createHttpJob({
type: 'deliver',
user,
diff --git a/src/remote/activitypub/models/note.ts b/src/remote/activitypub/models/note.ts
index 7501bf1a89..48a02e79bd 100644
--- a/src/remote/activitypub/models/note.ts
+++ b/src/remote/activitypub/models/note.ts
@@ -116,6 +116,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
cw: note.summary,
text: text,
viaMobile: false,
+ localOnly: false,
geo: undefined,
visibility,
visibleUsers,
diff --git a/src/server/activitypub.ts b/src/server/activitypub.ts
index 8da933a0f6..888feb08ce 100644
--- a/src/server/activitypub.ts
+++ b/src/server/activitypub.ts
@@ -66,7 +66,8 @@ router.get('/notes/:note', async (ctx, next) => {
const note = await Note.findOne({
_id: new mongo.ObjectID(ctx.params.note),
- visibility: { $in: ['public', 'home'] }
+ visibility: { $in: ['public', 'home'] },
+ localOnly: { $ne: true }
});
if (note === null) {
@@ -83,7 +84,8 @@ router.get('/notes/:note', async (ctx, next) => {
router.get('/notes/:note/activity', async ctx => {
const note = await Note.findOne({
_id: new mongo.ObjectID(ctx.params.note),
- visibility: { $in: ['public', 'home'] }
+ visibility: { $in: ['public', 'home'] },
+ localOnly: { $ne: true }
});
if (note === null) {
diff --git a/src/server/activitypub/outbox.ts b/src/server/activitypub/outbox.ts
index 24d4e3730e..6b917ef843 100644
--- a/src/server/activitypub/outbox.ts
+++ b/src/server/activitypub/outbox.ts
@@ -55,7 +55,8 @@ export default async (ctx: Router.IRouterContext) => {
const query = {
userId: user._id,
- visibility: { $in: ['public', 'home'] }
+ visibility: { $in: ['public', 'home'] },
+ localOnly: { $ne: true }
} as any;
if (sinceId) {
diff --git a/src/server/api/endpoints/notes/create.ts b/src/server/api/endpoints/notes/create.ts
index a7050e2ec2..4f8d6a4f4f 100644
--- a/src/server/api/endpoints/notes/create.ts
+++ b/src/server/api/endpoints/notes/create.ts
@@ -74,6 +74,14 @@ export const meta = {
}
},
+ localOnly: {
+ validator: $.bool.optional,
+ default: false,
+ desc: {
+ 'ja-JP': 'ローカルのみに投稿か否か。'
+ }
+ },
+
geo: {
validator: $.obj({
coordinates: $.arr().length(2)
@@ -226,6 +234,7 @@ export default define(meta, (ps, user, app) => new Promise(async (res, rej) => {
cw: ps.cw,
app,
viaMobile: ps.viaMobile,
+ localOnly: ps.localOnly,
visibility: ps.visibility,
visibleUsers,
geo: ps.geo
diff --git a/src/services/note/create.ts b/src/services/note/create.ts
index 53d51036b3..0fd983d6c2 100644
--- a/src/services/note/create.ts
+++ b/src/services/note/create.ts
@@ -95,6 +95,7 @@ type Option = {
geo?: any;
poll?: any;
viaMobile?: boolean;
+ localOnly?: boolean;
cw?: string;
visibility?: string;
visibleUsers?: IUser[];
@@ -109,6 +110,7 @@ export default async (user: IUser, data: Option, silent = false) => new Promise<
if (data.createdAt == null) data.createdAt = new Date();
if (data.visibility == null) data.visibility = 'public';
if (data.viaMobile == null) data.viaMobile = false;
+ if (data.localOnly == null) data.localOnly = false;
if (data.visibleUsers) {
data.visibleUsers = erase(null, data.visibleUsers);
@@ -139,6 +141,16 @@ export default async (user: IUser, data: Option, silent = false) => new Promise<
return rej('Renote target is private of others');
}
+ // ローカルのみをRenoteしたらローカルのみにする
+ if (data.renote && data.renote.localOnly) {
+ data.localOnly = true;
+ }
+
+ // ローカルのみにリプライしたらローカルのみにする
+ if (data.reply && data.reply.localOnly) {
+ data.localOnly = true;
+ }
+
if (data.text) {
data.text = data.text.trim();
}
@@ -308,6 +320,8 @@ export default async (user: IUser, data: Option, silent = false) => new Promise<
});
async function renderActivity(data: Option, note: INote) {
+ if (data.localOnly) return null;
+
const content = data.renote && data.text == null && data.poll == null && (data.files == null || data.files.length == 0)
? renderAnnounce(data.renote.uri ? data.renote.uri : `${config.url}/notes/${data.renote._id}`, note)
: renderCreate(await renderNote(note, false), note);
@@ -389,6 +403,7 @@ async function insertNote(user: IUser, data: Option, tags: string[], emojis: str
emojis,
userId: user._id,
viaMobile: data.viaMobile,
+ localOnly: data.localOnly,
geo: data.geo || null,
appId: data.app ? data.app._id : null,
visibility: data.visibility,