mirror of
https://git.joinsharkey.org/Sharkey/Sharkey.git
synced 2024-12-25 19:23:07 +02:00
User blocking (Following part) (#3035)
* block wip * UndoBlock * UnBlock * wip * follow * UI * fix
This commit is contained in:
parent
bcb0588409
commit
d64dc45899
17 changed files with 537 additions and 4 deletions
|
@ -1203,6 +1203,9 @@ desktop/views/pages/user/user.profile.vue:
|
||||||
mute: "ミュートする"
|
mute: "ミュートする"
|
||||||
muted: "ミュートしています"
|
muted: "ミュートしています"
|
||||||
unmute: "ミュート解除"
|
unmute: "ミュート解除"
|
||||||
|
block: "ブロックする"
|
||||||
|
unblock: "ブロック解除"
|
||||||
|
block-confirm: "このユーザーをブロックしますか?"
|
||||||
push-to-a-list: "リストに追加"
|
push-to-a-list: "リストに追加"
|
||||||
list-pushed: "{user}を{list}に追加しました。"
|
list-pushed: "{user}を{list}に追加しました。"
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,10 @@
|
||||||
<span v-if="user.isMuted">%fa:eye% %i18n:@unmute%</span>
|
<span v-if="user.isMuted">%fa:eye% %i18n:@unmute%</span>
|
||||||
<span v-if="!user.isMuted">%fa:eye-slash% %i18n:@mute%</span>
|
<span v-if="!user.isMuted">%fa:eye-slash% %i18n:@mute%</span>
|
||||||
</ui-button>
|
</ui-button>
|
||||||
|
<ui-button @click="user.isBlocking ? unblock() : block()" v-if="$store.state.i.id != user.id">
|
||||||
|
<span v-if="user.isBlocking">%fa:user% %i18n:@unblock%</span>
|
||||||
|
<span v-if="!user.isBlocking">%fa:user-slash% %i18n:@block%</span>
|
||||||
|
</ui-button>
|
||||||
<ui-button @click="list">%fa:list% %i18n:@push-to-a-list%</ui-button>
|
<ui-button @click="list">%fa:list% %i18n:@push-to-a-list%</ui-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -66,6 +70,27 @@ export default Vue.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
block() {
|
||||||
|
if (!window.confirm('%i18n:@block-confirm%')) return;
|
||||||
|
(this as any).api('blocking/create', {
|
||||||
|
userId: this.user.id
|
||||||
|
}).then(() => {
|
||||||
|
this.user.isBlocking = true;
|
||||||
|
}, () => {
|
||||||
|
alert('error');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
unblock() {
|
||||||
|
(this as any).api('blocking/delete', {
|
||||||
|
userId: this.user.id
|
||||||
|
}).then(() => {
|
||||||
|
this.user.isBlocking = false;
|
||||||
|
}, () => {
|
||||||
|
alert('error');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
list() {
|
list() {
|
||||||
const w = (this as any).os.new(MkUserListsWindow);
|
const w = (this as any).os.new(MkUserListsWindow);
|
||||||
w.$once('choosen', async list => {
|
w.$once('choosen', async list => {
|
||||||
|
|
41
src/models/blocking.ts
Normal file
41
src/models/blocking.ts
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import * as mongo from 'mongodb';
|
||||||
|
import db from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
|
|
||||||
|
const Blocking = db.get<IBlocking>('blocking');
|
||||||
|
Blocking.createIndex(['blockerId', 'blockeeId'], { unique: true });
|
||||||
|
export default Blocking;
|
||||||
|
|
||||||
|
export type IBlocking = {
|
||||||
|
_id: mongo.ObjectID;
|
||||||
|
createdAt: Date;
|
||||||
|
blockeeId: mongo.ObjectID;
|
||||||
|
blockerId: mongo.ObjectID;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blockingを物理削除します
|
||||||
|
*/
|
||||||
|
export async function deleteBlocking(blocking: string | mongo.ObjectID | IBlocking) {
|
||||||
|
let f: IBlocking;
|
||||||
|
|
||||||
|
// Populate
|
||||||
|
if (isObjectId(blocking)) {
|
||||||
|
f = await Blocking.findOne({
|
||||||
|
_id: blocking
|
||||||
|
});
|
||||||
|
} else if (typeof blocking === 'string') {
|
||||||
|
f = await Blocking.findOne({
|
||||||
|
_id: new mongo.ObjectID(blocking)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
f = blocking as IBlocking;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f == null) return;
|
||||||
|
|
||||||
|
// このBlockingを削除
|
||||||
|
await Blocking.remove({
|
||||||
|
_id: f._id
|
||||||
|
});
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import db from '../db/mongodb';
|
||||||
import isObjectId from '../misc/is-objectid';
|
import isObjectId from '../misc/is-objectid';
|
||||||
import Note, { packMany as packNoteMany, deleteNote } from './note';
|
import Note, { packMany as packNoteMany, deleteNote } from './note';
|
||||||
import Following, { deleteFollowing } from './following';
|
import Following, { deleteFollowing } from './following';
|
||||||
|
import Blocking, { deleteBlocking } from './blocking';
|
||||||
import Mute, { deleteMute } from './mute';
|
import Mute, { deleteMute } from './mute';
|
||||||
import { getFriendIds } from '../server/api/common/get-friends';
|
import { getFriendIds } from '../server/api/common/get-friends';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
|
@ -275,6 +276,16 @@ export async function deleteUser(user: string | mongo.ObjectID | IUser) {
|
||||||
await FollowRequest.find({ followeeId: u._id })
|
await FollowRequest.find({ followeeId: u._id })
|
||||||
).map(x => deleteFollowRequest(x)));
|
).map(x => deleteFollowRequest(x)));
|
||||||
|
|
||||||
|
// このユーザーのBlockingをすべて削除
|
||||||
|
await Promise.all((
|
||||||
|
await Blocking.find({ blockerId: u._id })
|
||||||
|
).map(x => deleteBlocking(x)));
|
||||||
|
|
||||||
|
// このユーザーへのBlockingをすべて削除
|
||||||
|
await Promise.all((
|
||||||
|
await Blocking.find({ blockeeId: u._id })
|
||||||
|
).map(x => deleteBlocking(x)));
|
||||||
|
|
||||||
// このユーザーのSwSubscriptionをすべて削除
|
// このユーザーのSwSubscriptionをすべて削除
|
||||||
await Promise.all((
|
await Promise.all((
|
||||||
await SwSubscription.find({ userId: u._id })
|
await SwSubscription.find({ userId: u._id })
|
||||||
|
@ -427,7 +438,7 @@ export const pack = (
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meId && !meId.equals(_user.id)) {
|
if (meId && !meId.equals(_user.id)) {
|
||||||
const [following1, following2, followReq1, followReq2, mute] = await Promise.all([
|
const [following1, following2, followReq1, followReq2, toBlocking, fromBlocked, mute] = await Promise.all([
|
||||||
Following.findOne({
|
Following.findOne({
|
||||||
followerId: meId,
|
followerId: meId,
|
||||||
followeeId: _user.id
|
followeeId: _user.id
|
||||||
|
@ -444,6 +455,14 @@ export const pack = (
|
||||||
followerId: _user.id,
|
followerId: _user.id,
|
||||||
followeeId: meId
|
followeeId: meId
|
||||||
}),
|
}),
|
||||||
|
Blocking.findOne({
|
||||||
|
blockerId: meId,
|
||||||
|
blockeeId: _user.id
|
||||||
|
}),
|
||||||
|
Blocking.findOne({
|
||||||
|
blockerId: _user.id,
|
||||||
|
blockeeId: meId
|
||||||
|
}),
|
||||||
Mute.findOne({
|
Mute.findOne({
|
||||||
muterId: meId,
|
muterId: meId,
|
||||||
muteeId: _user.id
|
muteeId: _user.id
|
||||||
|
@ -460,6 +479,12 @@ export const pack = (
|
||||||
// Whether the user is followed
|
// Whether the user is followed
|
||||||
_user.isFollowed = following2 !== null;
|
_user.isFollowed = following2 !== null;
|
||||||
|
|
||||||
|
// Whether the user is blocking
|
||||||
|
_user.isBlocking = toBlocking !== null;
|
||||||
|
|
||||||
|
// Whether the user is blocked
|
||||||
|
_user.isBlocked = fromBlocked !== null;
|
||||||
|
|
||||||
// Whether the user is muted
|
// Whether the user is muted
|
||||||
_user.isMuted = mute !== null;
|
_user.isMuted = mute !== null;
|
||||||
}
|
}
|
||||||
|
|
34
src/remote/activitypub/kernel/block/index.ts
Normal file
34
src/remote/activitypub/kernel/block/index.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import * as mongo from 'mongodb';
|
||||||
|
import User, { IRemoteUser } from '../../../../models/user';
|
||||||
|
import config from '../../../../config';
|
||||||
|
import * as debug from 'debug';
|
||||||
|
import { IBlock } from '../../type';
|
||||||
|
import block from '../../../../services/blocking/create';
|
||||||
|
|
||||||
|
const log = debug('misskey:activitypub');
|
||||||
|
|
||||||
|
export default async (actor: IRemoteUser, activity: IBlock): Promise<void> => {
|
||||||
|
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
|
||||||
|
|
||||||
|
const uri = activity.id || activity;
|
||||||
|
|
||||||
|
log(`Block: ${uri}`);
|
||||||
|
|
||||||
|
if (!id.startsWith(config.url + '/')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const blockee = await User.findOne({
|
||||||
|
_id: new mongo.ObjectID(id.split('/').pop())
|
||||||
|
});
|
||||||
|
|
||||||
|
if (blockee === null) {
|
||||||
|
throw new Error('blockee not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blockee.host != null) {
|
||||||
|
throw new Error('ブロックしようとしているユーザーはローカルユーザーではありません');
|
||||||
|
}
|
||||||
|
|
||||||
|
block(actor, blockee);
|
||||||
|
};
|
|
@ -10,6 +10,7 @@ import accept from './accept';
|
||||||
import reject from './reject';
|
import reject from './reject';
|
||||||
import add from './add';
|
import add from './add';
|
||||||
import remove from './remove';
|
import remove from './remove';
|
||||||
|
import block from './block';
|
||||||
|
|
||||||
const self = async (actor: IRemoteUser, activity: Object): Promise<void> => {
|
const self = async (actor: IRemoteUser, activity: Object): Promise<void> => {
|
||||||
switch (activity.type) {
|
switch (activity.type) {
|
||||||
|
@ -53,6 +54,10 @@ const self = async (actor: IRemoteUser, activity: Object): Promise<void> => {
|
||||||
await undo(actor, activity);
|
await undo(actor, activity);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'Block':
|
||||||
|
await block(actor, activity);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'Collection':
|
case 'Collection':
|
||||||
case 'OrderedCollection':
|
case 'OrderedCollection':
|
||||||
// TODO
|
// TODO
|
||||||
|
|
34
src/remote/activitypub/kernel/undo/block.ts
Normal file
34
src/remote/activitypub/kernel/undo/block.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import * as mongo from 'mongodb';
|
||||||
|
import User, { IRemoteUser } from '../../../../models/user';
|
||||||
|
import config from '../../../../config';
|
||||||
|
import * as debug from 'debug';
|
||||||
|
import { IBlock } from '../../type';
|
||||||
|
import unblock from '../../../../services/blocking/delete';
|
||||||
|
|
||||||
|
const log = debug('misskey:activitypub');
|
||||||
|
|
||||||
|
export default async (actor: IRemoteUser, activity: IBlock): Promise<void> => {
|
||||||
|
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
|
||||||
|
|
||||||
|
const uri = activity.id || activity;
|
||||||
|
|
||||||
|
log(`UnBlock: ${uri}`);
|
||||||
|
|
||||||
|
if (!id.startsWith(config.url + '/')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const blockee = await User.findOne({
|
||||||
|
_id: new mongo.ObjectID(id.split('/').pop())
|
||||||
|
});
|
||||||
|
|
||||||
|
if (blockee === null) {
|
||||||
|
throw new Error('blockee not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blockee.host != null) {
|
||||||
|
throw new Error('ブロック解除しようとしているユーザーはローカルユーザーではありません');
|
||||||
|
}
|
||||||
|
|
||||||
|
unblock(actor, blockee);
|
||||||
|
};
|
|
@ -1,8 +1,9 @@
|
||||||
import * as debug from 'debug';
|
import * as debug from 'debug';
|
||||||
|
|
||||||
import { IRemoteUser } from '../../../../models/user';
|
import { IRemoteUser } from '../../../../models/user';
|
||||||
import { IUndo, IFollow } from '../../type';
|
import { IUndo, IFollow, IBlock } from '../../type';
|
||||||
import unfollow from './follow';
|
import unfollow from './follow';
|
||||||
|
import unblock from './block';
|
||||||
import Resolver from '../../resolver';
|
import Resolver from '../../resolver';
|
||||||
|
|
||||||
const log = debug('misskey:activitypub');
|
const log = debug('misskey:activitypub');
|
||||||
|
@ -31,6 +32,9 @@ export default async (actor: IRemoteUser, activity: IUndo): Promise<void> => {
|
||||||
case 'Follow':
|
case 'Follow':
|
||||||
unfollow(actor, object as IFollow);
|
unfollow(actor, object as IFollow);
|
||||||
break;
|
break;
|
||||||
|
case 'Block':
|
||||||
|
unblock(actor, object as IBlock);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
8
src/remote/activitypub/renderer/block.ts
Normal file
8
src/remote/activitypub/renderer/block.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import config from '../../../config';
|
||||||
|
import { ILocalUser, IRemoteUser } from "../../../models/user";
|
||||||
|
|
||||||
|
export default (blocker?: ILocalUser, blockee?: IRemoteUser) => ({
|
||||||
|
type: 'Block',
|
||||||
|
actor: `${config.url}/users/${blocker._id}`,
|
||||||
|
object: blockee.uri
|
||||||
|
});
|
|
@ -108,6 +108,10 @@ export interface IAnnounce extends IActivity {
|
||||||
type: 'Announce';
|
type: 'Announce';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IBlock extends IActivity {
|
||||||
|
type: 'Block';
|
||||||
|
}
|
||||||
|
|
||||||
export type Object =
|
export type Object =
|
||||||
ICollection |
|
ICollection |
|
||||||
IOrderedCollection |
|
IOrderedCollection |
|
||||||
|
@ -120,4 +124,5 @@ export type Object =
|
||||||
IAdd |
|
IAdd |
|
||||||
IRemove |
|
IRemove |
|
||||||
ILike |
|
ILike |
|
||||||
IAnnounce;
|
IAnnounce |
|
||||||
|
IBlock;
|
||||||
|
|
75
src/server/api/endpoints/blocking/create.ts
Normal file
75
src/server/api/endpoints/blocking/create.ts
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
import $ from 'cafy'; import ID from '../../../../misc/cafy-id';
|
||||||
|
const ms = require('ms');
|
||||||
|
import User, { pack, ILocalUser } from '../../../../models/user';
|
||||||
|
import Blocking from '../../../../models/blocking';
|
||||||
|
import create from '../../../../services/blocking/create';
|
||||||
|
import getParams from '../../get-params';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
stability: 'stable',
|
||||||
|
|
||||||
|
desc: {
|
||||||
|
'ja-JP': '指定したユーザーをブロックします。',
|
||||||
|
'en-US': 'Block a user.'
|
||||||
|
},
|
||||||
|
|
||||||
|
limit: {
|
||||||
|
duration: ms('1hour'),
|
||||||
|
max: 100
|
||||||
|
},
|
||||||
|
|
||||||
|
requireCredential: true,
|
||||||
|
|
||||||
|
kind: 'following-write',
|
||||||
|
|
||||||
|
params: {
|
||||||
|
userId: $.type(ID).note({
|
||||||
|
desc: {
|
||||||
|
'ja-JP': '対象のユーザーのID',
|
||||||
|
'en-US': 'Target user ID'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default (params: any, user: ILocalUser) => new Promise(async (res, rej) => {
|
||||||
|
const [ps, psErr] = getParams(meta, params);
|
||||||
|
if (psErr) return rej(psErr);
|
||||||
|
|
||||||
|
const blocker = user;
|
||||||
|
|
||||||
|
// 自分自身
|
||||||
|
if (user._id.equals(ps.userId)) {
|
||||||
|
return rej('blockee is yourself');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get blockee
|
||||||
|
const blockee = await User.findOne({
|
||||||
|
_id: ps.userId
|
||||||
|
}, {
|
||||||
|
fields: {
|
||||||
|
data: false,
|
||||||
|
profile: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (blockee === null) {
|
||||||
|
return rej('user not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if already blocking
|
||||||
|
const exist = await Blocking.findOne({
|
||||||
|
blockerId: blocker._id,
|
||||||
|
blockeeId: blockee._id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (exist !== null) {
|
||||||
|
return rej('already blocking');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create blocking
|
||||||
|
await create(blocker, blockee);
|
||||||
|
|
||||||
|
// Send response
|
||||||
|
res(await pack(blockee._id, user));
|
||||||
|
});
|
75
src/server/api/endpoints/blocking/delete.ts
Normal file
75
src/server/api/endpoints/blocking/delete.ts
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
import $ from 'cafy'; import ID from '../../../../misc/cafy-id';
|
||||||
|
const ms = require('ms');
|
||||||
|
import User, { pack, ILocalUser } from '../../../../models/user';
|
||||||
|
import Blocking from '../../../../models/blocking';
|
||||||
|
import deleteBlocking from '../../../../services/blocking/delete';
|
||||||
|
import getParams from '../../get-params';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
stability: 'stable',
|
||||||
|
|
||||||
|
desc: {
|
||||||
|
'ja-JP': '指定したユーザーのブロックを解除します。',
|
||||||
|
'en-US': 'Unblock a user.'
|
||||||
|
},
|
||||||
|
|
||||||
|
limit: {
|
||||||
|
duration: ms('1hour'),
|
||||||
|
max: 100
|
||||||
|
},
|
||||||
|
|
||||||
|
requireCredential: true,
|
||||||
|
|
||||||
|
kind: 'following-write',
|
||||||
|
|
||||||
|
params: {
|
||||||
|
userId: $.type(ID).note({
|
||||||
|
desc: {
|
||||||
|
'ja-JP': '対象のユーザーのID',
|
||||||
|
'en-US': 'Target user ID'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default (params: any, user: ILocalUser) => new Promise(async (res, rej) => {
|
||||||
|
const [ps, psErr] = getParams(meta, params);
|
||||||
|
if (psErr) return rej(psErr);
|
||||||
|
|
||||||
|
const blocker = user;
|
||||||
|
|
||||||
|
// Check if the blockee is yourself
|
||||||
|
if (user._id.equals(ps.userId)) {
|
||||||
|
return rej('blockee is yourself');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get blockee
|
||||||
|
const blockee = await User.findOne({
|
||||||
|
_id: ps.userId
|
||||||
|
}, {
|
||||||
|
fields: {
|
||||||
|
data: false,
|
||||||
|
'profile': false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (blockee === null) {
|
||||||
|
return rej('user not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check not blocking
|
||||||
|
const exist = await Blocking.findOne({
|
||||||
|
blockerId: blocker._id,
|
||||||
|
blockeeId: blockee._id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (exist === null) {
|
||||||
|
return rej('already not blocking');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete blocking
|
||||||
|
await deleteBlocking(blocker, blockee);
|
||||||
|
|
||||||
|
// Send response
|
||||||
|
res(await pack(blockee._id, user));
|
||||||
|
});
|
|
@ -68,7 +68,11 @@ export default (params: any, user: ILocalUser) => new Promise(async (res, rej) =
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create following
|
// Create following
|
||||||
|
try {
|
||||||
await create(follower, followee);
|
await create(follower, followee);
|
||||||
|
} catch (e) {
|
||||||
|
return rej(e && e.message ? e.message : e);
|
||||||
|
}
|
||||||
|
|
||||||
// Send response
|
// Send response
|
||||||
res(await pack(followee._id, user));
|
res(await pack(followee._id, user));
|
||||||
|
|
121
src/services/blocking/create.ts
Normal file
121
src/services/blocking/create.ts
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
import User, { isLocalUser, isRemoteUser, pack as packUser, IUser } from '../../models/user';
|
||||||
|
import Following from '../../models/following';
|
||||||
|
import FollowRequest from '../../models/follow-request';
|
||||||
|
import { publishMainStream } from '../../stream';
|
||||||
|
import pack from '../../remote/activitypub/renderer';
|
||||||
|
import renderFollow from '../../remote/activitypub/renderer/follow';
|
||||||
|
import renderUndo from '../../remote/activitypub/renderer/undo';
|
||||||
|
import renderBlock from '../../remote/activitypub/renderer/block';
|
||||||
|
import { deliver } from '../../queue';
|
||||||
|
import renderReject from '../../remote/activitypub/renderer/reject';
|
||||||
|
import perUserFollowingChart from '../../chart/per-user-following';
|
||||||
|
import Blocking from '../../models/blocking';
|
||||||
|
|
||||||
|
export default async function(blocker: IUser, blockee: IUser) {
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
cancelRequest(blocker, blockee),
|
||||||
|
cancelRequest(blockee, blocker),
|
||||||
|
unFollow(blocker, blockee),
|
||||||
|
unFollow(blockee, blocker)
|
||||||
|
]);
|
||||||
|
|
||||||
|
await Blocking.insert({
|
||||||
|
createdAt: new Date(),
|
||||||
|
blockerId: blocker._id,
|
||||||
|
blockeeId: blockee._id,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isLocalUser(blocker) && isRemoteUser(blockee)) {
|
||||||
|
const content = pack(renderBlock(blocker, blockee));
|
||||||
|
deliver(blocker, content, blockee.inbox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function cancelRequest(follower: IUser, followee: IUser) {
|
||||||
|
const request = await FollowRequest.findOne({
|
||||||
|
followeeId: followee._id,
|
||||||
|
followerId: follower._id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (request == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await FollowRequest.remove({
|
||||||
|
followeeId: followee._id,
|
||||||
|
followerId: follower._id
|
||||||
|
});
|
||||||
|
|
||||||
|
await User.update({ _id: followee._id }, {
|
||||||
|
$inc: {
|
||||||
|
pendingReceivedFollowRequestsCount: -1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isLocalUser(followee)) {
|
||||||
|
packUser(followee, followee, {
|
||||||
|
detail: true
|
||||||
|
}).then(packed => publishMainStream(followee._id, 'meUpdated', packed));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLocalUser(follower)) {
|
||||||
|
packUser(followee, follower).then(packed => publishMainStream(follower._id, 'unfollow', packed));
|
||||||
|
}
|
||||||
|
|
||||||
|
// リモートにフォローリクエストをしていたらUndoFollow送信
|
||||||
|
if (isLocalUser(follower) && isRemoteUser(followee)) {
|
||||||
|
const content = pack(renderUndo(renderFollow(follower, followee), follower));
|
||||||
|
deliver(follower, content, followee.inbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
// リモートからフォローリクエストを受けていたらReject送信
|
||||||
|
if (isRemoteUser(follower) && isLocalUser(followee)) {
|
||||||
|
const content = pack(renderReject(renderFollow(follower, followee, request.requestId), followee));
|
||||||
|
deliver(followee, content, follower.inbox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function unFollow(follower: IUser, followee: IUser) {
|
||||||
|
const following = await Following.findOne({
|
||||||
|
followerId: follower._id,
|
||||||
|
followeeId: followee._id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (following == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Following.remove({
|
||||||
|
_id: following._id
|
||||||
|
});
|
||||||
|
|
||||||
|
//#region Decrement following count
|
||||||
|
User.update({ _id: follower._id }, {
|
||||||
|
$inc: {
|
||||||
|
followingCount: -1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region Decrement followers count
|
||||||
|
User.update({ _id: followee._id }, {
|
||||||
|
$inc: {
|
||||||
|
followersCount: -1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
perUserFollowingChart.update(follower, followee, false);
|
||||||
|
|
||||||
|
// Publish unfollow event
|
||||||
|
if (isLocalUser(follower)) {
|
||||||
|
packUser(followee, follower).then(packed => publishMainStream(follower._id, 'unfollow', packed));
|
||||||
|
}
|
||||||
|
|
||||||
|
// リモートにフォローをしていたらUndoFollow送信
|
||||||
|
if (isLocalUser(follower) && isRemoteUser(followee)) {
|
||||||
|
const content = pack(renderUndo(renderFollow(follower, followee), follower));
|
||||||
|
deliver(follower, content, followee.inbox);
|
||||||
|
}
|
||||||
|
}
|
28
src/services/blocking/delete.ts
Normal file
28
src/services/blocking/delete.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { isLocalUser, isRemoteUser, IUser } from '../../models/user';
|
||||||
|
import Blocking from '../../models/blocking';
|
||||||
|
import pack from '../../remote/activitypub/renderer';
|
||||||
|
import renderBlock from '../../remote/activitypub/renderer/block';
|
||||||
|
import renderUndo from '../../remote/activitypub/renderer/undo';
|
||||||
|
import { deliver } from '../../queue';
|
||||||
|
|
||||||
|
export default async function(blocker: IUser, blockee: IUser) {
|
||||||
|
const blocking = await Blocking.findOne({
|
||||||
|
blockerId: blocker._id,
|
||||||
|
blockeeId: blockee._id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (blocking == null) {
|
||||||
|
console.warn('ブロック解除がリクエストされましたがブロックしていませんでした');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Blocking.remove({
|
||||||
|
_id: blocking._id
|
||||||
|
});
|
||||||
|
|
||||||
|
// deliver if remote bloking
|
||||||
|
if (isLocalUser(blocker) && isRemoteUser(blockee)) {
|
||||||
|
const content = pack(renderUndo(renderBlock(blocker, blockee), blocker));
|
||||||
|
deliver(blocker, content, blockee.inbox);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,45 @@
|
||||||
import User, { isLocalUser, isRemoteUser, pack as packUser, IUser } from '../../models/user';
|
import User, { isLocalUser, isRemoteUser, pack as packUser, IUser } from '../../models/user';
|
||||||
import Following from '../../models/following';
|
import Following from '../../models/following';
|
||||||
|
import Blocking from '../../models/blocking';
|
||||||
import { publishMainStream } from '../../stream';
|
import { publishMainStream } from '../../stream';
|
||||||
import notify from '../../notify';
|
import notify from '../../notify';
|
||||||
import pack from '../../remote/activitypub/renderer';
|
import pack from '../../remote/activitypub/renderer';
|
||||||
import renderFollow from '../../remote/activitypub/renderer/follow';
|
import renderFollow from '../../remote/activitypub/renderer/follow';
|
||||||
import renderAccept from '../../remote/activitypub/renderer/accept';
|
import renderAccept from '../../remote/activitypub/renderer/accept';
|
||||||
|
import renderReject from '../../remote/activitypub/renderer/reject';
|
||||||
import { deliver } from '../../queue';
|
import { deliver } from '../../queue';
|
||||||
import createFollowRequest from './requests/create';
|
import createFollowRequest from './requests/create';
|
||||||
import perUserFollowingChart from '../../chart/per-user-following';
|
import perUserFollowingChart from '../../chart/per-user-following';
|
||||||
|
|
||||||
export default async function(follower: IUser, followee: IUser, requestId?: string) {
|
export default async function(follower: IUser, followee: IUser, requestId?: string) {
|
||||||
|
// check blocking
|
||||||
|
const [ blocking, blocked ] = await Promise.all([
|
||||||
|
Blocking.findOne({
|
||||||
|
blockerId: follower._id,
|
||||||
|
blockeeId: followee._id,
|
||||||
|
}),
|
||||||
|
Blocking.findOne({
|
||||||
|
blockerId: followee._id,
|
||||||
|
blockeeId: follower._id,
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (isRemoteUser(follower) && isLocalUser(followee) && blocked) {
|
||||||
|
// リモートフォローを受けてブロックしていた場合は、エラーにするのではなくRejectを送り返しておしまい。
|
||||||
|
const content = pack(renderReject(renderFollow(follower, followee, requestId), followee));
|
||||||
|
deliver(followee , content, follower.inbox);
|
||||||
|
return;
|
||||||
|
} else if (isRemoteUser(follower) && isLocalUser(followee) && blocking) {
|
||||||
|
// リモートフォローを受けてブロックされているはずの場合だったら、ブロック解除しておく。
|
||||||
|
await Blocking.remove({
|
||||||
|
_id: blocking._id
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// それ以外は単純に例外
|
||||||
|
if (blocking != null) throw new Error('blocking');
|
||||||
|
if (blocked != null) throw new Error('blocked');
|
||||||
|
}
|
||||||
|
|
||||||
// フォロー対象が鍵アカウントである or
|
// フォロー対象が鍵アカウントである or
|
||||||
// フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or
|
// フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or
|
||||||
// フォロワーがローカルユーザーであり、フォロー対象がリモートユーザーである
|
// フォロワーがローカルユーザーであり、フォロー対象がリモートユーザーである
|
||||||
|
|
|
@ -5,8 +5,24 @@ import pack from '../../../remote/activitypub/renderer';
|
||||||
import renderFollow from '../../../remote/activitypub/renderer/follow';
|
import renderFollow from '../../../remote/activitypub/renderer/follow';
|
||||||
import { deliver } from '../../../queue';
|
import { deliver } from '../../../queue';
|
||||||
import FollowRequest from '../../../models/follow-request';
|
import FollowRequest from '../../../models/follow-request';
|
||||||
|
import Blocking from '../../../models/blocking';
|
||||||
|
|
||||||
export default async function(follower: IUser, followee: IUser, requestId?: string) {
|
export default async function(follower: IUser, followee: IUser, requestId?: string) {
|
||||||
|
// check blocking
|
||||||
|
const [ blocking, blocked ] = await Promise.all([
|
||||||
|
Blocking.findOne({
|
||||||
|
blockerId: follower._id,
|
||||||
|
blockeeId: followee._id,
|
||||||
|
}),
|
||||||
|
Blocking.findOne({
|
||||||
|
blockerId: followee._id,
|
||||||
|
blockeeId: follower._id,
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (blocking != null) throw new Error('blocking');
|
||||||
|
if (blocked != null) throw new Error('blocked');
|
||||||
|
|
||||||
await FollowRequest.insert({
|
await FollowRequest.insert({
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
followerId: follower._id,
|
followerId: follower._id,
|
||||||
|
|
Loading…
Reference in a new issue