From b441c76c471a3ee684b3d180f22e0ab011e07d6a Mon Sep 17 00:00:00 2001 From: HF Date: Mon, 26 Sep 2022 23:19:14 +0200 Subject: [PATCH] add option to set profile private --- src/components/SocialSettings.jsx | 32 ++++++++++++++++++++----- src/core/Ranks.js | 9 ++++--- src/core/chartSettings.js | 3 +-- src/data/User.js | 2 ++ src/data/redis/ranks.js | 16 ++++--------- src/data/sql/RegUser.js | 21 ++++++++++++---- src/routes/api/index.js | 3 +++ src/routes/api/privatize.js | 40 +++++++++++++++++++++++++++++++ src/store/actions/fetch.js | 19 +++++++++++++++ src/store/actions/index.js | 7 ++++++ src/store/actions/thunks.js | 25 ++++++++++++++++--- src/store/reducers/user.js | 13 ++++++++++ 12 files changed, 160 insertions(+), 30 deletions(-) create mode 100644 src/routes/api/privatize.js diff --git a/src/components/SocialSettings.jsx b/src/components/SocialSettings.jsx index a5978ce..81aca0c 100644 --- a/src/components/SocialSettings.jsx +++ b/src/components/SocialSettings.jsx @@ -3,32 +3,52 @@ */ import React from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useDispatch, useSelector, shallowEqual } from 'react-redux'; import { t } from 'ttag'; import { setBlockingDm, + setPrivatize, setUserBlock, } from '../store/actions/thunks'; import SettingsItem from './SettingsItem'; +const selectBlocks = (state) => [ + state.chat.blocked, + state.user.blockDm, + state.user.priv, + state.fetching.fetchingApi, +]; + const SocialSettings = ({ done }) => { - const blocked = useSelector((state) => state.chat.blocked); - const blockDm = useSelector((state) => state.user.blockDm); - const fetching = useSelector((state) => state.fetching.fetchingApi); + const [ + blocked, + blockDm, + priv, + fetching, + ] = useSelector(selectBlocks, shallowEqual); const dispatch = useDispatch(); return (
{ if (!fetching) { dispatch(setBlockingDm(!blockDm)); } }} - /> + >{t`Block all Private Messages`} + { + if (!fetching) { + dispatch(setPrivatize(!priv)); + } + }} + >{t`Don't show me in global stats`}

day.filter( + (r) => histStats.users.some((u) => u.id === r.id), + )); const ret = { prevTop, pDailyStats, + histStats, }; if (socketEvents.amIImportant()) { // only main shard sends to others diff --git a/src/core/chartSettings.js b/src/core/chartSettings.js index f1ebd2f..da4a8b6 100644 --- a/src/core/chartSettings.js +++ b/src/core/chartSettings.js @@ -246,8 +246,7 @@ export function getHistChartData(histStats) { const labels = []; let ts = Date.now(); let c = stats.length; - // skipping todays dataset - while (c > 1) { + while (c) { const dAmount = stats.length - c; c -= 1; // x label diff --git a/src/data/User.js b/src/data/User.js index e985bd2..0acc086 100644 --- a/src/data/User.js +++ b/src/data/User.js @@ -241,6 +241,7 @@ class User { name: null, mailVerified: false, blockDm: false, + priv: false, mailreg: false, }; } @@ -256,6 +257,7 @@ class User { name: regUser.name, mailVerified: regUser.mailVerified, blockDm: regUser.blockDm, + priv: regUser.priv, totalPixels, dailyTotalPixels, ranking, diff --git a/src/data/redis/ranks.js b/src/data/redis/ranks.js index 03e55dd..b245a7a 100644 --- a/src/data/redis/ranks.js +++ b/src/data/redis/ranks.js @@ -194,17 +194,11 @@ export async function getDailyPixelStats() { export async function getTopDailyHistory() { const stats = []; const users = []; - let ts; - let key; - for (let c = 0; c < 14; c += 1) { - if (!ts) { - ts = Date.now(); - key = DAILY_RANKED_KEY; - } else { - ts -= 1000 * 3600 * 24; - const dateKey = getDateKeyOfTs(ts); - key = `${DAY_STATS_RANKS_KEY}:${dateKey}`; - } + let ts = Date.now(); + for (let c = 0; c < 13; c += 1) { + ts -= 1000 * 3600 * 24; + const dateKey = getDateKeyOfTs(ts); + const key = `${DAY_STATS_RANKS_KEY}:${dateKey}`; // eslint-disable-next-line no-await-in-loop let dData = await client.zRangeWithScores(key, 0, 9, { REV: true, diff --git a/src/data/sql/RegUser.js b/src/data/sql/RegUser.js index 388dbcf..1f125c4 100644 --- a/src/data/sql/RegUser.js +++ b/src/data/sql/RegUser.js @@ -28,11 +28,14 @@ const RegUser = sequelize.define('User', { allowNull: false, }, - // currently just moderator - roles: { - type: DataTypes.TINYINT, + /* + * if account is private, + * exclude it from statistics etc. + */ + priv: { + type: DataTypes.BOOLEAN, allowNull: false, - defaultValue: 0, + defaultValue: false, }, // null if external oauth authentification @@ -41,6 +44,13 @@ const RegUser = sequelize.define('User', { allowNull: true, }, + // currently just moderator + roles: { + type: DataTypes.TINYINT, + allowNull: false, + defaultValue: 0, + }, + // mail and Minecraft verified verified: { type: DataTypes.TINYINT, @@ -205,6 +215,7 @@ export async function populateRanking(rawRanks) { ], where: { id: uids, + priv: false, }, raw: true, }); @@ -216,7 +227,7 @@ export async function populateRanking(rawRanks) { dat.age = age; } } - return rawRanks; + return rawRanks.filter((r) => r.name); } export default RegUser; diff --git a/src/routes/api/index.js b/src/routes/api/index.js index f0b633f..26765cf 100644 --- a/src/routes/api/index.js +++ b/src/routes/api/index.js @@ -14,6 +14,7 @@ import startDm from './startdm'; import leaveChan from './leavechan'; import block from './block'; import blockdm from './blockdm'; +import privatize from './privatize'; import modtools from './modtools'; import baninfo from './baninfo'; import getiid from './getiid'; @@ -94,6 +95,8 @@ router.post('/block', block); router.post('/blockdm', blockdm); +router.post('/privatize', privatize); + router.get('/chathistory', chatHistory); router.get('/me', me); diff --git a/src/routes/api/privatize.js b/src/routes/api/privatize.js new file mode 100644 index 0000000..70f567f --- /dev/null +++ b/src/routes/api/privatize.js @@ -0,0 +1,40 @@ +/* + * + * block all private messages + * + */ +import logger from '../../core/logger'; + +async function privatize(req, res) { + const { priv } = req.body; + const { user } = req; + + const errors = []; + if (typeof priv !== 'boolean') { + errors.push('Not defined if setting or unsetting private'); + } + if (!user || !user.regUser) { + errors.push('You are not logged in'); + } + if (errors.length) { + res.status(400); + res.json({ + errors, + }); + return; + } + + logger.info( + `User ${user.getName()} set private status to ${priv}`, + ); + + await user.regUser.update({ + priv, + }); + + res.json({ + status: 'ok', + }); +} + +export default privatize; diff --git a/src/store/actions/fetch.js b/src/store/actions/fetch.js index ac1166f..fff4df3 100644 --- a/src/store/actions/fetch.js +++ b/src/store/actions/fetch.js @@ -151,6 +151,25 @@ export async function requestBlock(userId, block) { return t`Unknown Error`; } +/* + * set / unset provile as private + * @param priv + * @return error string or null if successful + */ +export async function requestPrivatize(priv) { + const res = await makeAPIPOSTRequest( + '/api/privatize', + { priv }, + ); + if (res.errors) { + return res.errors[0]; + } + if (res.status === 'ok') { + return null; + } + return t`Unknown Error`; +} + /* * start new DM channel with user * @param query Object with either userId or userName: string diff --git a/src/store/actions/index.js b/src/store/actions/index.js index 9339fba..969df1e 100644 --- a/src/store/actions/index.js +++ b/src/store/actions/index.js @@ -475,6 +475,13 @@ export function blockingDm(blockDm) { }; } +export function privatize(priv) { + return { + type: 's/SET_PRIVATE', + priv, + }; +} + export function removeChatChannel(cid) { return { type: 's/REMOVE_CHAT_CHANNEL', diff --git a/src/store/actions/thunks.js b/src/store/actions/thunks.js index cb93a02..dd8a903 100644 --- a/src/store/actions/thunks.js +++ b/src/store/actions/thunks.js @@ -5,6 +5,7 @@ import { requestStartDm, requestBlock, requestBlockDm, + requestPrivatize, requestLeaveChan, requestRankings, requestChatMessages, @@ -19,6 +20,7 @@ import { blockUser, unblockUser, blockingDm, + privatize, removeChatChannel, } from './index'; @@ -127,9 +129,7 @@ export function setUserBlock( }; } -export function setBlockingDm( - block, -) { +export function setBlockingDm(block) { return async (dispatch) => { dispatch(setApiFetching(true)); const res = await requestBlockDm(block); @@ -147,6 +147,25 @@ export function setBlockingDm( }; } +export function setPrivatize(priv) { + return async (dispatch) => { + dispatch(setApiFetching(true)); + const res = await requestPrivatize(priv); + if (res) { + dispatch(pAlert( + 'Setting User Private Error', + res, + 'error', + 'OK', + )); + } else { + dispatch(privatize(priv)); + } + dispatch(setApiFetching(false)); + }; +} + + export function setLeaveChannel( cid, ) { diff --git a/src/store/reducers/user.js b/src/store/reducers/user.js index 8328c7c..a81f20d 100644 --- a/src/store/reducers/user.js +++ b/src/store/reducers/user.js @@ -10,6 +10,8 @@ const initialState = { mailreg: false, // blocking all Dms blockDm: false, + // privile is private + priv: false, // if user is using touchscreen isOnMobile: false, // small notifications for received cooldown @@ -92,6 +94,7 @@ export default function user( name, mailreg, blockDm, + priv, userlvl, } = action; const messages = (action.messages) ? action.messages : []; @@ -102,6 +105,7 @@ export default function user( messages, mailreg, blockDm, + priv, userlvl, }; } @@ -114,6 +118,7 @@ export default function user( messages: [], mailreg: false, blockDm: false, + priv: false, userlvl: 0, }; } @@ -134,6 +139,14 @@ export default function user( }; } + case 's/SET_PRIVATE': { + const { priv } = action; + return { + ...state, + priv, + }; + } + case 'SET_NOTIFICATION': { return { ...state,