diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index f90f906509..560dca6654 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -938,6 +938,7 @@ desktop/views/components/settings.profile.vue: save: "保存" locked-account: "アカウントの保護" is-locked: "フォローを承認制にする" + careful-bot: "Botからのフォローだけ承認制にする" other: "その他" is-bot: "このアカウントはBotです" is-cat: "このアカウントはCatです" @@ -1420,6 +1421,7 @@ mobile/views/pages/settings/settings.profile.vue: banner: "バナー" is-cat: "このアカウントはCatです" is-locked: "フォローを承認制にする" + careful-bot: "Botからのフォローだけ承認制にする" advanced: "その他" privacy: "プライバシー" save: "保存" diff --git a/src/client/app/desktop/views/components/settings.profile.vue b/src/client/app/desktop/views/components/settings.profile.vue index 5f465a52bb..15569d3694 100644 --- a/src/client/app/desktop/views/components/settings.profile.vue +++ b/src/client/app/desktop/views/components/settings.profile.vue @@ -21,12 +21,13 @@ <ui-button primary @click="save">%i18n:@save%</ui-button> <section> <h2>%i18n:@locked-account%</h2> - <ui-switch v-model="$store.state.i.isLocked" @change="onChangeIsLocked">%i18n:@is-locked%</ui-switch> + <ui-switch v-model="isLocked" @change="save(false)">%i18n:@is-locked%</ui-switch> + <ui-switch v-model="carefulBot" @change="save(false)">%i18n:@careful-bot%</ui-switch> </section> <section> <h2>%i18n:@other%</h2> - <ui-switch v-model="$store.state.i.isBot" @change="onChangeIsBot">%i18n:@is-bot%</ui-switch> - <ui-switch v-model="$store.state.i.isCat" @change="onChangeIsCat">%i18n:@is-cat%</ui-switch> + <ui-switch v-model="isBot" @change="save(false)">%i18n:@is-bot%</ui-switch> + <ui-switch v-model="isCat" @change="save(false)">%i18n:@is-cat%</ui-switch> <ui-switch v-model="alwaysMarkNsfw">%i18n:common.always-mark-nsfw%</ui-switch> </section> </div> @@ -42,6 +43,10 @@ export default Vue.extend({ location: null, description: null, birthday: null, + isBot: false, + isCat: false, + isLocked: false, + carefulBot: false, }; }, computed: { @@ -55,34 +60,29 @@ export default Vue.extend({ this.location = this.$store.state.i.profile.location; this.description = this.$store.state.i.description; this.birthday = this.$store.state.i.profile.birthday; + this.isCat = this.$store.state.i.isCat; + this.isBot = this.$store.state.i.isBot; + this.isLocked = this.$store.state.i.isLocked; + this.carefulBot = this.$store.state.i.carefulBot; }, methods: { updateAvatar() { (this as any).apis.updateAvatar(); }, - save() { + save(notify) { (this as any).api('i/update', { name: this.name || null, location: this.location || null, description: this.description || null, - birthday: this.birthday || null + birthday: this.birthday || null, + isCat: this.isCat, + isBot: this.isBot, + isLocked: this.isLocked, + carefulBot: this.carefulBot }).then(() => { - (this as any).apis.notify('%i18n:@profile-updated%'); - }); - }, - onChangeIsLocked() { - (this as any).api('i/update', { - isLocked: this.$store.state.i.isLocked - }); - }, - onChangeIsBot() { - (this as any).api('i/update', { - isBot: this.$store.state.i.isBot - }); - }, - onChangeIsCat() { - (this as any).api('i/update', { - isCat: this.$store.state.i.isCat + if (notify) { + (this as any).apis.notify('%i18n:@profile-updated%'); + } }); } } diff --git a/src/client/app/desktop/views/components/ui.header.account.vue b/src/client/app/desktop/views/components/ui.header.account.vue index a541dea121..80fc1648de 100644 --- a/src/client/app/desktop/views/components/ui.header.account.vue +++ b/src/client/app/desktop/views/components/ui.header.account.vue @@ -19,7 +19,7 @@ <li @click="list"> <p>%fa:list%<span>%i18n:@lists%</span>%fa:angle-right%</p> </li> - <li @click="followRequests" v-if="$store.state.i.isLocked"> + <li @click="followRequests" v-if="($store.state.i.isLocked || $store.state.i.carefulBot)"> <p>%fa:envelope R%<span>%i18n:@follow-requests%<i v-if="$store.state.i.pendingReceivedFollowRequestsCount">{{ $store.state.i.pendingReceivedFollowRequestsCount }}</i></span>%fa:angle-right%</p> </li> </ul> diff --git a/src/client/app/mobile/views/components/ui.nav.vue b/src/client/app/mobile/views/components/ui.nav.vue index c9c0c082b2..068ad74815 100644 --- a/src/client/app/mobile/views/components/ui.nav.vue +++ b/src/client/app/mobile/views/components/ui.nav.vue @@ -18,7 +18,7 @@ <li><router-link to="/" :data-active="$route.name == 'index'">%fa:home%%i18n:@timeline%%fa:angle-right%</router-link></li> <li><router-link to="/i/notifications" :data-active="$route.name == 'notifications'">%fa:R bell%%i18n:@notifications%<template v-if="hasUnreadNotification">%fa:circle%</template>%fa:angle-right%</router-link></li> <li><router-link to="/i/messaging" :data-active="$route.name == 'messaging'">%fa:R comments%%i18n:@messaging%<template v-if="hasUnreadMessagingMessage">%fa:circle%</template>%fa:angle-right%</router-link></li> - <li v-if="$store.getters.isSignedIn && $store.state.i.isLocked"><router-link to="/i/received-follow-requests" :data-active="$route.name == 'received-follow-requests'">%fa:R envelope%%i18n:@follow-requests%<template v-if="$store.getters.isSignedIn && $store.state.i.pendingReceivedFollowRequestsCount">%fa:circle%</template>%fa:angle-right%</router-link></li> + <li v-if="$store.getters.isSignedIn && ($store.state.i.isLocked || $store.state.i.carefulBot)"><router-link to="/i/received-follow-requests" :data-active="$route.name == 'received-follow-requests'">%fa:R envelope%%i18n:@follow-requests%<template v-if="$store.getters.isSignedIn && $store.state.i.pendingReceivedFollowRequestsCount">%fa:circle%</template>%fa:angle-right%</router-link></li> <li><router-link to="/reversi" :data-active="$route.name == 'reversi'">%fa:gamepad%%i18n:@game%<template v-if="hasGameInvitation">%fa:circle%</template>%fa:angle-right%</router-link></li> </ul> <ul> diff --git a/src/client/app/mobile/views/pages/settings/settings.profile.vue b/src/client/app/mobile/views/pages/settings/settings.profile.vue index 77c59faf37..160a05a3e0 100644 --- a/src/client/app/mobile/views/pages/settings/settings.profile.vue +++ b/src/client/app/mobile/views/pages/settings/settings.profile.vue @@ -58,6 +58,7 @@ <div> <ui-switch v-model="isLocked" @change="save(false)">%i18n:@is-locked%</ui-switch> + <ui-switch v-model="carefulBot" @change="save(false)">%i18n:@careful-bot%</ui-switch> </div> </section> </ui-card> @@ -80,6 +81,7 @@ export default Vue.extend({ bannerId: null, isCat: false, isLocked: false, + carefulBot: false, saving: false, avatarUploading: false, bannerUploading: false @@ -103,6 +105,7 @@ export default Vue.extend({ this.bannerId = this.$store.state.i.bannerId; this.isCat = this.$store.state.i.isCat; this.isLocked = this.$store.state.i.isLocked; + this.carefulBot = this.$store.state.i.carefulBot; }, methods: { @@ -161,7 +164,8 @@ export default Vue.extend({ avatarId: this.avatarId, bannerId: this.bannerId, isCat: this.isCat, - isLocked: this.isLocked + isLocked: this.isLocked, + carefulBot: this.carefulBot }).then(i => { this.saving = false; this.$store.state.i.avatarId = i.avatarId; diff --git a/src/models/user.ts b/src/models/user.ts index e0ce561421..6ca09ca168 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -65,6 +65,16 @@ type IUserBase = { */ isLocked: boolean; + /** + * Botか否か + */ + isBot: boolean; + + /** + * Botからのフォローを承認制にするか + */ + carefulBot: boolean; + /** * このアカウントに届いているフォローリクエストの数 */ @@ -94,7 +104,6 @@ export interface ILocalUser extends IUserBase { tags: string[]; }; lastUsedAt: Date; - isBot: boolean; isCat: boolean; isAdmin?: boolean; isVerified?: boolean; diff --git a/src/server/api/endpoints/i/update.ts b/src/server/api/endpoints/i/update.ts index 548ce5cadb..77825a4aaa 100644 --- a/src/server/api/endpoints/i/update.ts +++ b/src/server/api/endpoints/i/update.ts @@ -67,6 +67,12 @@ export const meta = { } }), + carefulBot: $.bool.optional.note({ + desc: { + 'ja-JP': 'Botからのフォローを承認制にするか' + } + }), + isBot: $.bool.optional.note({ desc: { 'ja-JP': 'Botか否か' @@ -110,6 +116,7 @@ export default async (params: any, user: ILocalUser, app: IApp) => new Promise(a if (ps.wallpaperId !== undefined) updates.wallpaperId = ps.wallpaperId; if (typeof ps.isLocked == 'boolean') updates.isLocked = ps.isLocked; if (typeof ps.isBot == 'boolean') updates.isBot = ps.isBot; + if (typeof ps.carefulBot == 'boolean') updates.carefulBot = ps.carefulBot; if (typeof ps.isCat == 'boolean') updates.isCat = ps.isCat; if (typeof ps.autoWatch == 'boolean') updates['settings.autoWatch'] = ps.autoWatch; if (typeof ps.alwaysMarkNsfw == 'boolean') updates['settings.alwaysMarkNsfw'] = ps.alwaysMarkNsfw; diff --git a/src/services/following/create.ts b/src/services/following/create.ts index 637e3e8093..01b6b4aed9 100644 --- a/src/services/following/create.ts +++ b/src/services/following/create.ts @@ -11,70 +11,75 @@ import { deliver } from '../../queue'; import createFollowRequest from './requests/create'; export default async function(follower: IUser, followee: IUser) { - if (followee.isLocked || isLocalUser(follower) && isRemoteUser(followee)) { + // フォロー対象が鍵アカウントである or + // フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or + // フォロワーがローカルユーザーであり、フォロー対象がリモートユーザーである + // 上記のいずれかに当てはまる場合はすぐフォローせずにフォローリクエストを発行しておく + if (followee.isLocked || (followee.carefulBot && follower.isBot) || (isLocalUser(follower) && isRemoteUser(followee))) { await createFollowRequest(follower, followee); - } else { - const following = await Following.insert({ - createdAt: new Date(), - followerId: follower._id, - followeeId: followee._id, + return; + } - // 非正規化 - _follower: { - host: follower.host, - inbox: isRemoteUser(follower) ? follower.inbox : undefined, - sharedInbox: isRemoteUser(follower) ? follower.sharedInbox : undefined - }, - _followee: { - host: followee.host, - inbox: isRemoteUser(followee) ? followee.inbox : undefined, - sharedInbox: isRemoteUser(followee) ? followee.sharedInbox : undefined - } - }); + const following = await Following.insert({ + createdAt: new Date(), + followerId: follower._id, + followeeId: followee._id, - //#region Increment following count - User.update({ _id: follower._id }, { - $inc: { - followingCount: 1 - } - }); - - FollowingLog.insert({ - createdAt: following.createdAt, - userId: follower._id, - count: follower.followingCount + 1 - }); - //#endregion - - //#region Increment followers count - User.update({ _id: followee._id }, { - $inc: { - followersCount: 1 - } - }); - FollowedLog.insert({ - createdAt: following.createdAt, - userId: followee._id, - count: followee.followersCount + 1 - }); - //#endregion - - // Publish follow event - if (isLocalUser(follower)) { - packUser(followee, follower).then(packed => publishMainStream(follower._id, 'follow', packed)); + // 非正規化 + _follower: { + host: follower.host, + inbox: isRemoteUser(follower) ? follower.inbox : undefined, + sharedInbox: isRemoteUser(follower) ? follower.sharedInbox : undefined + }, + _followee: { + host: followee.host, + inbox: isRemoteUser(followee) ? followee.inbox : undefined, + sharedInbox: isRemoteUser(followee) ? followee.sharedInbox : undefined } + }); - // Publish followed event - if (isLocalUser(followee)) { - packUser(follower, followee).then(packed => publishMainStream(followee._id, 'followed', packed)), - - // 通知を作成 - notify(followee._id, follower._id, 'follow'); + //#region Increment following count + User.update({ _id: follower._id }, { + $inc: { + followingCount: 1 } + }); - if (isRemoteUser(follower) && isLocalUser(followee)) { - const content = pack(renderAccept(renderFollow(follower, followee))); - deliver(followee, content, follower.inbox); + FollowingLog.insert({ + createdAt: following.createdAt, + userId: follower._id, + count: follower.followingCount + 1 + }); + //#endregion + + //#region Increment followers count + User.update({ _id: followee._id }, { + $inc: { + followersCount: 1 } + }); + FollowedLog.insert({ + createdAt: following.createdAt, + userId: followee._id, + count: followee.followersCount + 1 + }); + //#endregion + + // Publish follow event + if (isLocalUser(follower)) { + packUser(followee, follower).then(packed => publishMainStream(follower._id, 'follow', packed)); + } + + // Publish followed event + if (isLocalUser(followee)) { + packUser(follower, followee).then(packed => publishMainStream(followee._id, 'followed', packed)), + + // 通知を作成 + notify(followee._id, follower._id, 'follow'); + } + + if (isRemoteUser(follower) && isLocalUser(followee)) { + const content = pack(renderAccept(renderFollow(follower, followee))); + deliver(followee, content, follower.inbox); } }