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 {channelIsAnonymous, renderChannel} from '@reddichat/core/client';
|
||||
import {ADMIN, MOD, submitMessageDistinction} from '@reddichat/chat/client';
|
||||
import {idSelector, isAdminSelector, isModOfSelector} from '@reddichat/user/client';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import {useSelector} from 'react-redux';
|
||||
import {useDispatch, useSelector} from 'react-redux';
|
||||
|
||||
import Actions from 'components/actions';
|
||||
|
||||
|
@ -17,6 +18,7 @@ export default function Moderation(props) {
|
|||
uuid,
|
||||
} = props;
|
||||
const channel = useChannel();
|
||||
const dispatch = useDispatch();
|
||||
const id = useSelector(idSelector);
|
||||
const isAnonymous = channelIsAnonymous(channel);
|
||||
const isAdmin = useSelector(isAdminSelector);
|
||||
|
@ -24,13 +26,13 @@ export default function Moderation(props) {
|
|||
const socket = useSocket();
|
||||
const actions = [];
|
||||
if (isAdmin && (id === owner || 0 === owner)) {
|
||||
actions.push(['👑', 'Admin distinction', () => {
|
||||
socket.send(['MessageAdminDistinction', uuid]);
|
||||
actions.push(['👑', 'Toggle admin distinction', () => {
|
||||
dispatch(submitMessageDistinction({uuid, distinction: ADMIN}));
|
||||
}]);
|
||||
}
|
||||
if (isMod && id === owner) {
|
||||
actions.push(['🎩', 'Moderator distinction', () => {
|
||||
socket.send(['MessageModeratorDistinction', uuid]);
|
||||
actions.push(['🎩', 'Toggle moderator distinction', () => {
|
||||
dispatch(submitMessageDistinction({uuid, distinction: MOD}));
|
||||
}]);
|
||||
}
|
||||
if (isAdmin) {
|
||||
|
|
6
packages/chat/src/client/effects.js
vendored
6
packages/chat/src/client/effects.js
vendored
|
@ -19,6 +19,8 @@ import {
|
|||
submitJoin,
|
||||
submitLeave,
|
||||
submitMessage,
|
||||
submitMessageDistinction,
|
||||
toggleMessageDistinction,
|
||||
} from './state';
|
||||
|
||||
export default ({config: {'%socket': socket}}) => {
|
||||
|
@ -101,5 +103,9 @@ export default ({config: {'%socket': socket}}) => {
|
|||
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 Message from '../packets/message';
|
||||
import MessageSiteBan from '../packets/message-site-ban';
|
||||
import MessageDistinction from '../packets/message-distinction';
|
||||
|
||||
import chat from './state';
|
||||
|
||||
|
@ -17,6 +18,7 @@ export default {
|
|||
Leave: Leave(latus),
|
||||
Message: Message(latus),
|
||||
MessageSiteBan: MessageSiteBan(latus),
|
||||
MessageDistinction: MessageDistinction(latus),
|
||||
}),
|
||||
// eslint-disable-next-line global-require
|
||||
'@reddichat/state/effects': (latus) => require('./effects').default(latus),
|
||||
|
|
|
@ -120,6 +120,15 @@ const slice = createSlice({
|
|||
submitJoin: () => {},
|
||||
submitLeave: () => {},
|
||||
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 */
|
||||
});
|
||||
|
@ -138,6 +147,8 @@ export const {
|
|||
submitJoin,
|
||||
submitLeave,
|
||||
submitMessage,
|
||||
submitMessageDistinction,
|
||||
toggleMessageDistinction,
|
||||
} = slice.actions;
|
||||
|
||||
slice.reducer.subscription = slice.reducer;
|
||||
|
|
|
@ -13,6 +13,7 @@ import Activity from './packets/activity.server';
|
|||
import Join from './packets/join.server';
|
||||
import Leave from './packets/leave.server';
|
||||
import Message from './packets/message.server';
|
||||
import MessageDistinction from './packets/message-distinction.server';
|
||||
import MessageSiteBan from './packets/message-site-ban.server';
|
||||
|
||||
import ensureCanonical from './ensure-canonical';
|
||||
|
@ -66,6 +67,7 @@ export default {
|
|||
Join: Join(latus),
|
||||
Leave: Leave(latus),
|
||||
Message: Message(latus),
|
||||
MessageDistinction: MessageDistinction(latus),
|
||||
MessageSiteBan: MessageSiteBan(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