diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e0e18329..903ecbf89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.125.0] - Not released ### Added +- The site administrator can now define a list of "privacy control groups" in + the config (the _privacyControlGroups_ entry). These groups will be always + shown in the feed selector of new or existing posts. The pages of such groups + do not show posts by default, and such groups cannot be subscribed to. - Support for the new "Notify of new comments" feature: - User can now turn on/off notification for new comments on the specific post via the "More" menu item; diff --git a/config/default.js b/config/default.js index a37939e79..cd2536855 100644 --- a/config/default.js +++ b/config/default.js @@ -174,4 +174,13 @@ export default { boostyProject: null, }, }, + + privacyControlGroups: { + hidePosts: true, // Hide posts on these groups pages + disableSubscriptions: true, // Disable subscriptions on these groups + groups: { + // Define groups like this: + // 'public-groupname': { label: 'Makes post public', privacy: 'public' } + }, + }, }; diff --git a/src/components/feeds-selector/options.jsx b/src/components/feeds-selector/options.jsx index ab789329e..5fc0f6919 100644 --- a/src/components/feeds-selector/options.jsx +++ b/src/components/feeds-selector/options.jsx @@ -1,3 +1,4 @@ +/* global CONFIG */ import { faGlobeAmericas, faHome, @@ -8,10 +9,8 @@ import { faUserFriends, faUserSlash, faExternalLinkAlt, - // faUsers, - // faUsersSlash, } from '@fortawesome/free-solid-svg-icons'; -import { uniq } from 'lodash-es'; +import { uniq, uniqBy } from 'lodash-es'; import { useEffect, useMemo } from 'react'; import { shallowEqual, useDispatch, useSelector } from 'react-redux'; import cn from 'classnames'; @@ -121,10 +120,15 @@ export function useSelectedOptions(usernames, fixedFeedNames) { const groupOptions = useMemo( () => - mySubscriptions - .filter((u) => u?.type === 'group' && u.youCan.includes('post')) - .map((u) => toOption(u, me)) - .sort(compareOptions), + uniqBy( + [ + ...privacyControlOptions(), + ...mySubscriptions + .filter((u) => u?.type === 'group' && u.youCan.includes('post')) + .map((u) => toOption(u, me)), + ], + 'value', + ).sort(compareOptions), [me, mySubscriptions], ); @@ -218,3 +222,14 @@ export function toOption(user, me) { privacy: user.type === 'group' || isMe ? getPrivacy(user) : 'user', }; } + +function privacyControlOptions() { + return [...Object.entries(CONFIG.privacyControlGroups.groups)].map( + ([value, { label, privacy }]) => ({ + label, + value, + privacy, + type: ACC_GROUP, + }), + ); +} diff --git a/src/components/user-card.jsx b/src/components/user-card.jsx index 14311ead5..0e79e77a5 100644 --- a/src/components/user-card.jsx +++ b/src/components/user-card.jsx @@ -1,3 +1,4 @@ +/* global CONFIG */ import { Component, createRef, useCallback } from 'react'; import { Link } from 'react-router'; import { connect } from 'react-redux'; @@ -81,6 +82,10 @@ class UserCard extends Component { renderSubscribeBlock() { const { props } = this; + const allowToSubscribe = + !CONFIG.privacyControlGroups.disableSubscriptions || + !CONFIG.privacyControlGroups.groups[props.user.username]; + if (props.subscribed) { return ( @@ -98,11 +103,13 @@ class UserCard extends Component { ); } - return ( - - Subscribe - - ); + if (allowToSubscribe) { + return ( + + Subscribe + + ); + } } return null; diff --git a/src/components/user-profile-head-actions.jsx b/src/components/user-profile-head-actions.jsx index 7347dc620..1494d78fc 100644 --- a/src/components/user-profile-head-actions.jsx +++ b/src/components/user-profile-head-actions.jsx @@ -1,3 +1,4 @@ +/* global CONFIG */ import { Link } from 'react-router'; import cn from 'classnames'; import { faClock } from '@fortawesome/free-regular-svg-icons'; @@ -40,6 +41,10 @@ export function UserProfileHeadActions({ const showBanDialog = useShowBanDialog(user); const showDisableBansDialog = useShowDisableBansDialog(user, isCurrentUserAdmin); + const allowToSubscribe = + !CONFIG.privacyControlGroups.disableSubscriptions || + !CONFIG.privacyControlGroups.groups[user.username]; + return (
+ You are on the {props.viewUser.username} group page. This is a + technical group, it just helps to customize the visibility of posts in other feeds. +
+
+ The posts in this group itself are fairly random and not organized around any
+ particular topic. Still want to see them?{' '}
+