fix: distinction
This commit is contained in:
parent
2ef9155ca3
commit
8b0f1b109a
|
@ -2,10 +2,11 @@ import './index.scss';
|
||||||
|
|
||||||
import {useSocket} from '@latus/socket/client';
|
import {useSocket} from '@latus/socket/client';
|
||||||
import {channelIsAnonymous, renderChannel} from '@reddichat/core/client';
|
import {channelIsAnonymous, renderChannel} from '@reddichat/core/client';
|
||||||
|
import {ADMIN, MOD, submitMessageDistinction} from '@reddichat/chat/client';
|
||||||
import {idSelector, isAdminSelector, isModOfSelector} from '@reddichat/user/client';
|
import {idSelector, isAdminSelector, isModOfSelector} from '@reddichat/user/client';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {useSelector} from 'react-redux';
|
import {useDispatch, useSelector} from 'react-redux';
|
||||||
|
|
||||||
import Actions from 'components/actions';
|
import Actions from 'components/actions';
|
||||||
|
|
||||||
|
@ -17,6 +18,7 @@ export default function Moderation(props) {
|
||||||
uuid,
|
uuid,
|
||||||
} = props;
|
} = props;
|
||||||
const channel = useChannel();
|
const channel = useChannel();
|
||||||
|
const dispatch = useDispatch();
|
||||||
const id = useSelector(idSelector);
|
const id = useSelector(idSelector);
|
||||||
const isAnonymous = channelIsAnonymous(channel);
|
const isAnonymous = channelIsAnonymous(channel);
|
||||||
const isAdmin = useSelector(isAdminSelector);
|
const isAdmin = useSelector(isAdminSelector);
|
||||||
|
@ -24,13 +26,13 @@ export default function Moderation(props) {
|
||||||
const socket = useSocket();
|
const socket = useSocket();
|
||||||
const actions = [];
|
const actions = [];
|
||||||
if (isAdmin && (id === owner || 0 === owner)) {
|
if (isAdmin && (id === owner || 0 === owner)) {
|
||||||
actions.push(['👑', 'Admin distinction', () => {
|
actions.push(['👑', 'Toggle admin distinction', () => {
|
||||||
socket.send(['MessageAdminDistinction', uuid]);
|
dispatch(submitMessageDistinction({uuid, distinction: ADMIN}));
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
if (isMod && id === owner) {
|
if (isMod && id === owner) {
|
||||||
actions.push(['🎩', 'Moderator distinction', () => {
|
actions.push(['🎩', 'Toggle moderator distinction', () => {
|
||||||
socket.send(['MessageModeratorDistinction', uuid]);
|
dispatch(submitMessageDistinction({uuid, distinction: MOD}));
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
if (isAdmin) {
|
if (isAdmin) {
|
||||||
|
|
6
packages/chat/src/client/effects.js
vendored
6
packages/chat/src/client/effects.js
vendored
|
@ -19,6 +19,8 @@ import {
|
||||||
submitJoin,
|
submitJoin,
|
||||||
submitLeave,
|
submitLeave,
|
||||||
submitMessage,
|
submitMessage,
|
||||||
|
submitMessageDistinction,
|
||||||
|
toggleMessageDistinction,
|
||||||
} from './state';
|
} from './state';
|
||||||
|
|
||||||
export default ({config: {'%socket': socket}}) => {
|
export default ({config: {'%socket': socket}}) => {
|
||||||
|
@ -101,5 +103,9 @@ export default ({config: {'%socket': socket}}) => {
|
||||||
reject(Math.round(Math.max(0, error.msBeforeNext) / 1000) || 1);
|
reject(Math.round(Math.max(0, error.msBeforeNext) / 1000) || 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
[submitMessageDistinction]: async ({dispatch}, {payload}) => {
|
||||||
|
dispatch(toggleMessageDistinction(payload));
|
||||||
|
await socket.send(['MessageDistinction', payload]);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,7 @@ import Join from '../packets/join';
|
||||||
import Leave from '../packets/leave';
|
import Leave from '../packets/leave';
|
||||||
import Message from '../packets/message';
|
import Message from '../packets/message';
|
||||||
import MessageSiteBan from '../packets/message-site-ban';
|
import MessageSiteBan from '../packets/message-site-ban';
|
||||||
|
import MessageDistinction from '../packets/message-distinction';
|
||||||
|
|
||||||
import chat from './state';
|
import chat from './state';
|
||||||
|
|
||||||
|
@ -17,6 +18,7 @@ export default {
|
||||||
Leave: Leave(latus),
|
Leave: Leave(latus),
|
||||||
Message: Message(latus),
|
Message: Message(latus),
|
||||||
MessageSiteBan: MessageSiteBan(latus),
|
MessageSiteBan: MessageSiteBan(latus),
|
||||||
|
MessageDistinction: MessageDistinction(latus),
|
||||||
}),
|
}),
|
||||||
// eslint-disable-next-line global-require
|
// eslint-disable-next-line global-require
|
||||||
'@reddichat/state/effects': (latus) => require('./effects').default(latus),
|
'@reddichat/state/effects': (latus) => require('./effects').default(latus),
|
||||||
|
|
|
@ -120,6 +120,15 @@ const slice = createSlice({
|
||||||
submitJoin: () => {},
|
submitJoin: () => {},
|
||||||
submitLeave: () => {},
|
submitLeave: () => {},
|
||||||
submitMessage: () => {},
|
submitMessage: () => {},
|
||||||
|
submitMessageDistinction: () => {},
|
||||||
|
toggleMessageDistinction: ({messages}, {payload: {distinction, uuid}}) => {
|
||||||
|
const message = messages[uuid];
|
||||||
|
/* eslint-disable no-bitwise */
|
||||||
|
message.distinction = message.distinction & distinction
|
||||||
|
? message.distinction & ~distinction
|
||||||
|
: message.distinction | distinction;
|
||||||
|
/* eslint-enable no-bitwise */
|
||||||
|
},
|
||||||
},
|
},
|
||||||
/* eslint-enable no-param-reassign */
|
/* eslint-enable no-param-reassign */
|
||||||
});
|
});
|
||||||
|
@ -138,6 +147,8 @@ export const {
|
||||||
submitJoin,
|
submitJoin,
|
||||||
submitLeave,
|
submitLeave,
|
||||||
submitMessage,
|
submitMessage,
|
||||||
|
submitMessageDistinction,
|
||||||
|
toggleMessageDistinction,
|
||||||
} = slice.actions;
|
} = slice.actions;
|
||||||
|
|
||||||
slice.reducer.subscription = slice.reducer;
|
slice.reducer.subscription = slice.reducer;
|
||||||
|
|
|
@ -13,6 +13,7 @@ import Activity from './packets/activity.server';
|
||||||
import Join from './packets/join.server';
|
import Join from './packets/join.server';
|
||||||
import Leave from './packets/leave.server';
|
import Leave from './packets/leave.server';
|
||||||
import Message from './packets/message.server';
|
import Message from './packets/message.server';
|
||||||
|
import MessageDistinction from './packets/message-distinction.server';
|
||||||
import MessageSiteBan from './packets/message-site-ban.server';
|
import MessageSiteBan from './packets/message-site-ban.server';
|
||||||
|
|
||||||
import ensureCanonical from './ensure-canonical';
|
import ensureCanonical from './ensure-canonical';
|
||||||
|
@ -66,6 +67,7 @@ export default {
|
||||||
Join: Join(latus),
|
Join: Join(latus),
|
||||||
Leave: Leave(latus),
|
Leave: Leave(latus),
|
||||||
Message: Message(latus),
|
Message: Message(latus),
|
||||||
|
MessageDistinction: MessageDistinction(latus),
|
||||||
MessageSiteBan: MessageSiteBan(latus),
|
MessageSiteBan: MessageSiteBan(latus),
|
||||||
}),
|
}),
|
||||||
'@latus/socket/connect': async (socket, latus) => {
|
'@latus/socket/connect': async (socket, latus) => {
|
||||||
|
|
9
packages/chat/src/message-channel.js
Normal file
9
packages/chat/src/message-channel.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import {createClient, keys} from '@latus/redis';
|
||||||
|
import {parseChannel} from '@reddichat/core';
|
||||||
|
|
||||||
|
const messageChannel = async (latus, uuid) => {
|
||||||
|
const key = (await keys(createClient(latus), `*:messages:${uuid}`)).pop();
|
||||||
|
return parseChannel(key.split(':')[0]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default messageChannel;
|
22
packages/chat/src/packets/message-distinction.js
Normal file
22
packages/chat/src/packets/message-distinction.js
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import {Packet, ValidationError} from '@latus/socket/packets';
|
||||||
|
import {validate} from 'uuid';
|
||||||
|
|
||||||
|
export default () => class MessageDistinction extends Packet {
|
||||||
|
|
||||||
|
static get data() {
|
||||||
|
return {
|
||||||
|
distinction: 'uint8',
|
||||||
|
uuid: 'string',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static async validate({data: {uuid}}, {req: {user}}) {
|
||||||
|
if (!validate(uuid)) {
|
||||||
|
throw new ValidationError({code: 400, reason: 'malformed'});
|
||||||
|
}
|
||||||
|
if (!user) {
|
||||||
|
throw new ValidationError({code: 403, reason: 'unauthorized'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
46
packages/chat/src/packets/message-distinction.server.js
Normal file
46
packages/chat/src/packets/message-distinction.server.js
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import {ValidationError} from '@latus/socket/packets';
|
||||||
|
import {renderChannel} from '@reddichat/core';
|
||||||
|
|
||||||
|
import {ADMIN, MOD} from '../distinction';
|
||||||
|
import messageChannel from '../message-channel';
|
||||||
|
import replaceMessage from '../replace-message';
|
||||||
|
import MessageDistinction from './message-distinction';
|
||||||
|
|
||||||
|
export default (latus) => class MessageDistinctionServer extends MessageDistinction() {
|
||||||
|
|
||||||
|
static async respond({data: {distinction, uuid}}, socket) {
|
||||||
|
const {req} = socket;
|
||||||
|
const message = await replaceMessage(
|
||||||
|
req,
|
||||||
|
uuid,
|
||||||
|
(msg) => ({
|
||||||
|
...msg,
|
||||||
|
/* eslint-disable no-bitwise */
|
||||||
|
distinction: msg.distinction & distinction
|
||||||
|
? msg.distinction & ~distinction
|
||||||
|
: msg.distinction | distinction,
|
||||||
|
/* eslint-enable no-bitwise */
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const channel = await messageChannel(latus, uuid);
|
||||||
|
socket
|
||||||
|
.to(renderChannel(channel))
|
||||||
|
.send(['MessageDistinction', {uuid, distinction: message.distinction}]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async validate(packet, socket) {
|
||||||
|
super.validate(packet, socket);
|
||||||
|
const {data: {distinction, uuid}} = packet;
|
||||||
|
const {req} = socket;
|
||||||
|
const {user} = req;
|
||||||
|
// eslint-disable-next-line no-bitwise
|
||||||
|
if ((distinction & ADMIN) && !user.isAdmin) {
|
||||||
|
throw new ValidationError({code: 400, reason: 'unauthorized'});
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line no-bitwise
|
||||||
|
if ((distinction & MOD) && !user.isModOf(await messageChannel(latus, uuid))) {
|
||||||
|
throw new ValidationError({code: 400, reason: 'unauthorized'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
16
packages/chat/src/replace-message.js
Normal file
16
packages/chat/src/replace-message.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import {promisify} from 'util';
|
||||||
|
|
||||||
|
import {keys} from '@latus/redis';
|
||||||
|
|
||||||
|
const replaceMessage = async (req, uuid, fn) => {
|
||||||
|
const {pubClient} = req.adapter;
|
||||||
|
const get = promisify(pubClient.get.bind(pubClient));
|
||||||
|
const key = (await keys(pubClient, `*:messages:${uuid}`)).pop();
|
||||||
|
const message = fn(JSON.parse(await get(key)));
|
||||||
|
return new Promise((resolve, reject) => pubClient
|
||||||
|
.multi()
|
||||||
|
.set(key, JSON.stringify(message))
|
||||||
|
.exec((error) => (error ? reject(error) : resolve(message))));
|
||||||
|
};
|
||||||
|
|
||||||
|
export default replaceMessage;
|
Loading…
Reference in New Issue
Block a user