|
|
|
@@ -21,7 +21,6 @@ module Directory.Service
|
|
|
|
|
where
|
|
|
|
|
|
|
|
|
|
import Control.Concurrent (forkIO)
|
|
|
|
|
import Control.Concurrent.Async
|
|
|
|
|
import Control.Concurrent.STM
|
|
|
|
|
import Control.Logger.Simple
|
|
|
|
|
import Control.Monad
|
|
|
|
@@ -54,7 +53,6 @@ import Simplex.Chat.Markdown (Format (..), FormattedText (..), parseMaybeMarkdow
|
|
|
|
|
import Simplex.Chat.Messages
|
|
|
|
|
import Simplex.Chat.Options
|
|
|
|
|
import Simplex.Chat.Protocol (MsgContent (..))
|
|
|
|
|
import Simplex.Chat.Store (GroupLink (..))
|
|
|
|
|
import Simplex.Chat.Store.Direct (getContact)
|
|
|
|
|
import Simplex.Chat.Store.Groups (getGroupInfo, getGroupLink, getGroupSummary, getUserGroupsWithSummary, setGroupCustomData)
|
|
|
|
|
import Simplex.Chat.Store.Profiles (GroupLinkInfo (..), getGroupLinkInfo)
|
|
|
|
@@ -69,7 +67,7 @@ import Simplex.Messaging.Agent.Protocol (AConnectionLink (..), ConnectionLink (.
|
|
|
|
|
import Simplex.Messaging.Encoding.String
|
|
|
|
|
import Simplex.Messaging.TMap (TMap)
|
|
|
|
|
import qualified Simplex.Messaging.TMap as TM
|
|
|
|
|
import Simplex.Messaging.Util (safeDecodeUtf8, tshow, unlessM, whenM, ($>>=), (<$$>))
|
|
|
|
|
import Simplex.Messaging.Util (raceAny_, safeDecodeUtf8, tshow, unlessM, whenM, ($>>=), (<$$>))
|
|
|
|
|
import System.Directory (getAppUserDataDirectory)
|
|
|
|
|
import System.Exit (exitFailure)
|
|
|
|
|
import System.Process (readProcess)
|
|
|
|
@@ -96,7 +94,8 @@ data GroupRolesStatus
|
|
|
|
|
data ServiceState = ServiceState
|
|
|
|
|
{ searchRequests :: TMap ContactId SearchRequest,
|
|
|
|
|
blockedWordsCfg :: BlockedWordsConfig,
|
|
|
|
|
pendingCaptchas :: TMap GroupMemberId PendingCaptcha
|
|
|
|
|
pendingCaptchas :: TMap GroupMemberId PendingCaptcha,
|
|
|
|
|
updateListingsJob :: TMVar ChatController
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data PendingCaptcha = PendingCaptcha
|
|
|
|
@@ -119,7 +118,8 @@ newServiceState opts = do
|
|
|
|
|
searchRequests <- TM.emptyIO
|
|
|
|
|
blockedWordsCfg <- readBlockedWordsConfig opts
|
|
|
|
|
pendingCaptchas <- TM.emptyIO
|
|
|
|
|
pure ServiceState {searchRequests, blockedWordsCfg, pendingCaptchas}
|
|
|
|
|
updateListingsJob <- newEmptyTMVarIO
|
|
|
|
|
pure ServiceState {searchRequests, blockedWordsCfg, pendingCaptchas, updateListingsJob}
|
|
|
|
|
|
|
|
|
|
welcomeGetOpts :: IO DirectoryOpts
|
|
|
|
|
welcomeGetOpts = do
|
|
|
|
@@ -146,22 +146,41 @@ directoryServiceCLI st opts = do
|
|
|
|
|
env <- newServiceState opts
|
|
|
|
|
eventQ <- newTQueueIO
|
|
|
|
|
let eventHook cc resp = atomically $ resp <$ writeTQueue eventQ (cc, resp)
|
|
|
|
|
chatHooks = defaultChatHooks {postStartHook = Just $ directoryStartHook st opts, eventHook = Just eventHook, acceptMember = Just $ acceptMemberHook opts env}
|
|
|
|
|
race_
|
|
|
|
|
(simplexChatCLI' terminalChatConfig {chatHooks} (mkChatOpts opts) Nothing)
|
|
|
|
|
(processEvents eventQ env)
|
|
|
|
|
chatHooks = defaultChatHooks {postStartHook = Just $ directoryStartHook opts env, eventHook = Just eventHook, acceptMember = Just $ acceptMemberHook opts env}
|
|
|
|
|
raceAny_ $
|
|
|
|
|
[ simplexChatCLI' terminalChatConfig {chatHooks} (mkChatOpts opts) Nothing,
|
|
|
|
|
processEvents eventQ env
|
|
|
|
|
]
|
|
|
|
|
<> updateListingsThread_ st opts env
|
|
|
|
|
where
|
|
|
|
|
processEvents eventQ env = forever $ do
|
|
|
|
|
(cc, resp) <- atomically $ readTQueue eventQ
|
|
|
|
|
u_ <- readTVarIO (currentUser cc)
|
|
|
|
|
forM_ u_ $ \user -> directoryServiceEvent st opts env user cc resp
|
|
|
|
|
|
|
|
|
|
directoryStartHook :: DirectoryStore -> DirectoryOpts -> ChatController -> IO ()
|
|
|
|
|
directoryStartHook st opts cc =
|
|
|
|
|
updateListingDelay :: Int
|
|
|
|
|
updateListingDelay = 15 * 60 * 1000000 -- update every 15 minutes
|
|
|
|
|
|
|
|
|
|
updateListingsThread_ :: DirectoryStore -> DirectoryOpts -> ServiceState -> [IO ()]
|
|
|
|
|
updateListingsThread_ st opts env = maybe [] (\f -> [updateListingsThread f]) $ webFolder opts
|
|
|
|
|
where
|
|
|
|
|
updateListingsThread f = do
|
|
|
|
|
cc <- atomically $ takeTMVar $ updateListingsJob env
|
|
|
|
|
forever $ do
|
|
|
|
|
u <- readTVarIO $ currentUser cc
|
|
|
|
|
forM_ u $ \user -> updateGroupListingFiles cc st user f
|
|
|
|
|
delay <- registerDelay updateListingDelay
|
|
|
|
|
atomically $ void (takeTMVar $ updateListingsJob env) `orElse` unlessM (readTVar delay) retry
|
|
|
|
|
|
|
|
|
|
listingsUpdated :: ServiceState -> ChatController -> IO ()
|
|
|
|
|
listingsUpdated env = void . atomically . tryPutTMVar (updateListingsJob env)
|
|
|
|
|
|
|
|
|
|
directoryStartHook :: DirectoryOpts -> ServiceState -> ChatController -> IO ()
|
|
|
|
|
directoryStartHook opts env cc =
|
|
|
|
|
readTVarIO (currentUser cc) >>= \case
|
|
|
|
|
Nothing -> putStrLn "No current user" >> exitFailure
|
|
|
|
|
Just user@User {userId, profile = p@LocalProfile {preferences}} -> do
|
|
|
|
|
forM_ (webFolder opts) $ updateGroupListingFiles cc st user
|
|
|
|
|
Just User {userId, profile = p@LocalProfile {preferences}} -> do
|
|
|
|
|
listingsUpdated env cc
|
|
|
|
|
let cmds = fromMaybe [] $ preferences >>= commands_
|
|
|
|
|
unless (cmds == directoryCommands) $ do
|
|
|
|
|
let prefs = (fromMaybe emptyChatPrefs preferences) {files = Just FilesPreference {allow = FANo}, commands = Just directoryCommands} :: Preferences
|
|
|
|
@@ -188,12 +207,23 @@ directoryCommands =
|
|
|
|
|
where
|
|
|
|
|
idParam = Just "<ID>"
|
|
|
|
|
|
|
|
|
|
directoryService :: DirectoryStore -> DirectoryOpts -> ServiceState -> User -> ChatController -> IO ()
|
|
|
|
|
directoryService st opts@DirectoryOpts {testing} env user cc = do
|
|
|
|
|
initializeBotAddress' (not testing) cc
|
|
|
|
|
race_ (forever $ void getLine) . forever $ do
|
|
|
|
|
(_, resp) <- atomically . readTBQueue $ outputQ cc
|
|
|
|
|
directoryServiceEvent st opts env user cc resp
|
|
|
|
|
directoryService :: DirectoryStore -> DirectoryOpts -> ChatConfig -> IO ()
|
|
|
|
|
directoryService st opts@DirectoryOpts {testing} cfg = do
|
|
|
|
|
env <- newServiceState opts
|
|
|
|
|
let chatHooks =
|
|
|
|
|
defaultChatHooks
|
|
|
|
|
{ postStartHook = Just $ directoryStartHook opts env,
|
|
|
|
|
acceptMember = Just $ acceptMemberHook opts env
|
|
|
|
|
}
|
|
|
|
|
simplexChatCore cfg {chatHooks} (mkChatOpts opts) $ \user cc -> do
|
|
|
|
|
initializeBotAddress' (not testing) cc
|
|
|
|
|
raceAny_ $
|
|
|
|
|
[ forever $ void getLine,
|
|
|
|
|
forever $ do
|
|
|
|
|
(_, resp) <- atomically . readTBQueue $ outputQ cc
|
|
|
|
|
directoryServiceEvent st opts env user cc resp
|
|
|
|
|
]
|
|
|
|
|
<> updateListingsThread_ st opts env
|
|
|
|
|
|
|
|
|
|
acceptMemberHook :: DirectoryOpts -> ServiceState -> GroupInfo -> GroupLinkInfo -> Profile -> IO (Either GroupRejectionReason (GroupAcceptance, GroupMemberRole))
|
|
|
|
|
acceptMemberHook
|
|
|
|
@@ -301,7 +331,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
getDuplicateGroup GroupInfo {groupId, groupProfile = GroupProfile {displayName, fullName}} =
|
|
|
|
|
getGroups fullName >>= mapM duplicateGroup
|
|
|
|
|
where
|
|
|
|
|
sameGroupNotRemoved (GIS g@GroupInfo {groupId = gId, groupProfile = GroupProfile {displayName = n, fullName = fn}} _) =
|
|
|
|
|
sameGroupNotRemoved (GIS g@GroupInfo {groupId = gId, groupProfile = GroupProfile {displayName = n, fullName = fn}} _ _) =
|
|
|
|
|
gId /= groupId && n == displayName && fn == fullName && not (memberRemoved $ membership g)
|
|
|
|
|
duplicateGroup [] = pure DGUnique
|
|
|
|
|
duplicateGroup groups = do
|
|
|
|
@@ -310,13 +340,13 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
then pure DGUnique
|
|
|
|
|
else do
|
|
|
|
|
(lgs, rgs) <- atomically $ (,) <$> readTVar (listedGroups st) <*> readTVar (reservedGroups st)
|
|
|
|
|
let reserved = any (\(GIS GroupInfo {groupId = gId} _) -> gId `S.member` lgs || gId `S.member` rgs) gs
|
|
|
|
|
let reserved = any (\(GIS GroupInfo {groupId = gId} _ _) -> gId `S.member` lgs || gId `S.member` rgs) gs
|
|
|
|
|
if reserved
|
|
|
|
|
then pure DGReserved
|
|
|
|
|
else do
|
|
|
|
|
removed <- foldM (\r -> fmap (r &&) . isGroupRemoved) True gs
|
|
|
|
|
pure $ if removed then DGUnique else DGRegistered
|
|
|
|
|
isGroupRemoved (GIS GroupInfo {groupId = gId} _) =
|
|
|
|
|
isGroupRemoved (GIS GroupInfo {groupId = gId} _ _) =
|
|
|
|
|
getGroupReg st gId >>= \case
|
|
|
|
|
Just GroupReg {groupRegStatus} -> groupRemoved <$> readTVarIO groupRegStatus
|
|
|
|
|
Nothing -> pure True
|
|
|
|
@@ -395,7 +425,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
notifyOwner gr $ "Joined the group " <> displayName <> ", creating the link…"
|
|
|
|
|
sendChatCmd cc (APICreateGroupLink groupId GRMember) >>= \case
|
|
|
|
|
Right CRGroupLinkCreated {groupLink = GroupLink {connLinkContact = gLink}} -> do
|
|
|
|
|
setGroupStatus st opts cc user gr GRSPendingUpdate
|
|
|
|
|
setGroupStatus st env cc gr GRSPendingUpdate
|
|
|
|
|
notifyOwner
|
|
|
|
|
gr
|
|
|
|
|
"Created the public link to join the group via this directory service that is always online.\n\n\
|
|
|
|
@@ -456,7 +486,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
Just DGReserved -> notifyOwner gr $ groupAlreadyListed toGroup
|
|
|
|
|
_ -> do
|
|
|
|
|
let gaId = 1
|
|
|
|
|
setGroupStatus st opts cc user gr $ GRSPendingApproval gaId
|
|
|
|
|
setGroupStatus st env cc gr $ GRSPendingApproval gaId
|
|
|
|
|
notifyOwner gr $
|
|
|
|
|
("Thank you! The group link for " <> userGroupReference gr toGroup <> " is added to the welcome message" <> byMember)
|
|
|
|
|
<> ".\nYou will be notified once the group is added to the directory - it may take up to 48 hours."
|
|
|
|
@@ -466,18 +496,18 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
groupRef = groupReference toGroup
|
|
|
|
|
groupProfileUpdate >>= \case
|
|
|
|
|
GPNoServiceLink -> do
|
|
|
|
|
setGroupStatus st opts cc user gr GRSPendingUpdate
|
|
|
|
|
setGroupStatus st env cc gr GRSPendingUpdate
|
|
|
|
|
notifyOwner gr $
|
|
|
|
|
("The group profile is updated for " <> userGroupRef <> byMember <> ", but no link is added to the welcome message.\n\n")
|
|
|
|
|
<> "The group will remain hidden from the directory until the group link is added and the group is re-approved."
|
|
|
|
|
GPServiceLinkRemoved -> do
|
|
|
|
|
setGroupStatus st opts cc user gr GRSPendingUpdate
|
|
|
|
|
setGroupStatus st env cc gr GRSPendingUpdate
|
|
|
|
|
notifyOwner gr $
|
|
|
|
|
("The group link for " <> userGroupRef <> " is removed from the welcome message" <> byMember)
|
|
|
|
|
<> ".\n\nThe group is hidden from the directory until the group link is added and the group is re-approved."
|
|
|
|
|
notifyAdminUsers $ "The group link is removed from " <> groupRef <> ", de-listed."
|
|
|
|
|
GPServiceLinkAdded _ -> do
|
|
|
|
|
setGroupStatus st opts cc user gr $ GRSPendingApproval n'
|
|
|
|
|
setGroupStatus st env cc gr $ GRSPendingApproval n'
|
|
|
|
|
notifyOwner gr $
|
|
|
|
|
("The group link is added to " <> userGroupRef <> byMember)
|
|
|
|
|
<> "!\nIt is hidden from the directory until approved."
|
|
|
|
@@ -490,7 +520,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
<> "!\nThe group is listed in directory."
|
|
|
|
|
notifyAdminUsers $ "The group " <> groupRef <> " is updated" <> byMember <> " - only link or whitespace changes.\nThe group remained listed in directory."
|
|
|
|
|
| otherwise -> do
|
|
|
|
|
setGroupStatus st opts cc user gr $ GRSPendingApproval n'
|
|
|
|
|
setGroupStatus st env cc gr $ GRSPendingApproval n'
|
|
|
|
|
notifyOwner gr $
|
|
|
|
|
("The group " <> userGroupRef <> " is updated" <> byMember)
|
|
|
|
|
<> "!\nIt is hidden from the directory until approved."
|
|
|
|
@@ -628,14 +658,14 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
when (ctId `isOwner` gr) $ do
|
|
|
|
|
readTVarIO (groupRegStatus gr) >>= \case
|
|
|
|
|
GRSSuspendedBadRoles -> when (rStatus == GRSOk) $ do
|
|
|
|
|
setGroupStatus st opts cc user gr GRSActive
|
|
|
|
|
setGroupStatus st env cc gr GRSActive
|
|
|
|
|
notifyOwner gr $ uCtRole <> ".\n\nThe group is listed in the directory again."
|
|
|
|
|
notifyAdminUsers $ "The group " <> groupRef <> " is listed " <> suCtRole
|
|
|
|
|
GRSPendingApproval gaId -> when (rStatus == GRSOk) $ do
|
|
|
|
|
sendToApprove g gr gaId
|
|
|
|
|
notifyOwner gr $ uCtRole <> ".\n\nThe group is submitted for approval."
|
|
|
|
|
GRSActive -> when (rStatus /= GRSOk) $ do
|
|
|
|
|
setGroupStatus st opts cc user gr GRSSuspendedBadRoles
|
|
|
|
|
setGroupStatus st env cc gr GRSSuspendedBadRoles
|
|
|
|
|
notifyOwner gr $ uCtRole <> ".\n\nThe group is no longer listed in the directory."
|
|
|
|
|
notifyAdminUsers $ "The group " <> groupRef <> " is de-listed " <> suCtRole
|
|
|
|
|
_ -> pure ()
|
|
|
|
@@ -654,7 +684,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
readTVarIO (groupRegStatus gr) >>= \case
|
|
|
|
|
GRSSuspendedBadRoles -> when (serviceRole == GRAdmin) $
|
|
|
|
|
whenContactIsOwner gr $ do
|
|
|
|
|
setGroupStatus st opts cc user gr GRSActive
|
|
|
|
|
setGroupStatus st env cc gr GRSActive
|
|
|
|
|
notifyOwner gr $ uSrvRole <> ".\n\nThe group is listed in the directory again."
|
|
|
|
|
notifyAdminUsers $ "The group " <> groupRef <> " is listed " <> suSrvRole
|
|
|
|
|
GRSPendingApproval gaId -> when (serviceRole == GRAdmin) $
|
|
|
|
@@ -662,7 +692,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
sendToApprove g gr gaId
|
|
|
|
|
notifyOwner gr $ uSrvRole <> ".\n\nThe group is submitted for approval."
|
|
|
|
|
GRSActive -> when (serviceRole /= GRAdmin) $ do
|
|
|
|
|
setGroupStatus st opts cc user gr GRSSuspendedBadRoles
|
|
|
|
|
setGroupStatus st env cc gr GRSSuspendedBadRoles
|
|
|
|
|
notifyOwner gr $ uSrvRole <> ".\n\nThe group is no longer listed in the directory."
|
|
|
|
|
notifyAdminUsers $ "The group " <> groupRef <> " is de-listed " <> suSrvRole
|
|
|
|
|
_ -> pure ()
|
|
|
|
@@ -679,7 +709,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
logInfo $ "contact ID " <> tshow ctId <> " removed from group " <> viewGroupName g
|
|
|
|
|
withGroupReg g "contact removed" $ \gr -> do
|
|
|
|
|
when (ctId `isOwner` gr) $ do
|
|
|
|
|
setGroupStatus st opts cc user gr GRSRemoved
|
|
|
|
|
setGroupStatus st env cc gr GRSRemoved
|
|
|
|
|
notifyOwner gr $ "You are removed from the group " <> userGroupReference gr g <> ".\n\nThe group is no longer listed in the directory."
|
|
|
|
|
notifyAdminUsers $ "The group " <> groupReference g <> " is de-listed (group owner is removed)."
|
|
|
|
|
|
|
|
|
@@ -688,7 +718,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
logInfo $ "contact ID " <> tshow ctId <> " left group " <> viewGroupName g
|
|
|
|
|
withGroupReg g "contact left" $ \gr -> do
|
|
|
|
|
when (ctId `isOwner` gr) $ do
|
|
|
|
|
setGroupStatus st opts cc user gr GRSRemoved
|
|
|
|
|
setGroupStatus st env cc gr GRSRemoved
|
|
|
|
|
notifyOwner gr $ "You left the group " <> userGroupReference gr g <> ".\n\nThe group is no longer listed in the directory."
|
|
|
|
|
notifyAdminUsers $ "The group " <> groupReference g <> " is de-listed (group owner left)."
|
|
|
|
|
|
|
|
|
@@ -696,7 +726,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
deServiceRemovedFromGroup g = do
|
|
|
|
|
logInfo $ "service removed from group " <> viewGroupName g
|
|
|
|
|
withGroupReg g "service removed" $ \gr -> do
|
|
|
|
|
setGroupStatus st opts cc user gr GRSRemoved
|
|
|
|
|
setGroupStatus st env cc gr GRSRemoved
|
|
|
|
|
notifyOwner gr $ serviceName <> " is removed from the group " <> userGroupReference gr g <> ".\n\nThe group is no longer listed in the directory."
|
|
|
|
|
notifyAdminUsers $ "The group " <> groupReference g <> " is de-listed (directory service is removed)."
|
|
|
|
|
|
|
|
|
@@ -704,7 +734,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
deGroupDeleted g = do
|
|
|
|
|
logInfo $ "group removed " <> viewGroupName g
|
|
|
|
|
withGroupReg g "group removed" $ \gr -> do
|
|
|
|
|
setGroupStatus st opts cc user gr GRSRemoved
|
|
|
|
|
setGroupStatus st env cc gr GRSRemoved
|
|
|
|
|
notifyOwner gr $ "The group " <> userGroupReference gr g <> " is deleted.\n\nThe group is no longer listed in the directory."
|
|
|
|
|
notifyAdminUsers $ "The group " <> groupReference g <> " is de-listed (group is deleted)."
|
|
|
|
|
|
|
|
|
@@ -925,7 +955,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
where
|
|
|
|
|
msgs = replyMsg :| map foundGroup gs <> [moreMsg | moreGroups > 0]
|
|
|
|
|
replyMsg = (Just ciId, MCText reply)
|
|
|
|
|
foundGroup (GIS GroupInfo {groupId, groupProfile = p@GroupProfile {image = image_}} GroupSummary {currentMembers}) =
|
|
|
|
|
foundGroup (GIS GroupInfo {groupId, groupProfile = p@GroupProfile {image = image_}} GroupSummary {currentMembers} _) =
|
|
|
|
|
let membersStr = "_" <> tshow currentMembers <> " members_"
|
|
|
|
|
showId = if isAdmin then tshow groupId <> ". " else ""
|
|
|
|
|
text = showId <> groupInfoText p <> "\n" <> membersStr
|
|
|
|
@@ -946,16 +976,16 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
_ -> do
|
|
|
|
|
getGroupRolesStatus g gr >>= \case
|
|
|
|
|
Just GRSOk -> do
|
|
|
|
|
setGroupStatus st opts cc user gr GRSActive
|
|
|
|
|
setGroupStatus st env cc gr GRSActive
|
|
|
|
|
forM_ promote $ \promo ->
|
|
|
|
|
if promo -- admins can unpromote, only super-user can promote when approving
|
|
|
|
|
then
|
|
|
|
|
unlessM (readTVarIO promoted) $
|
|
|
|
|
if knownCt `elem` superUsers
|
|
|
|
|
then setGroupPromoted st opts cc user gr True
|
|
|
|
|
then setGroupPromoted st env cc gr True
|
|
|
|
|
else sendReply "You cannot promote groups"
|
|
|
|
|
else do
|
|
|
|
|
whenM (readTVarIO promoted) $ setGroupPromoted st opts cc user gr False
|
|
|
|
|
whenM (readTVarIO promoted) $ setGroupPromoted st env cc gr False
|
|
|
|
|
notifyOtherSuperUsers $ "Group promotion is disabled for " <> groupRef
|
|
|
|
|
let approved = "The group " <> userGroupReference' gr n <> " is approved"
|
|
|
|
|
notifyOwner gr $
|
|
|
|
@@ -991,7 +1021,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
withGroupAndReg sendReply groupId gName $ \_ gr ->
|
|
|
|
|
readTVarIO (groupRegStatus gr) >>= \case
|
|
|
|
|
GRSActive -> do
|
|
|
|
|
setGroupStatus st opts cc user gr GRSSuspended
|
|
|
|
|
setGroupStatus st env cc gr GRSSuspended
|
|
|
|
|
let suspended = "The group " <> userGroupReference' gr gName <> " is suspended"
|
|
|
|
|
notifyOwner gr $ suspended <> " and hidden from directory. Please contact the administrators."
|
|
|
|
|
sendReply "Group suspended!"
|
|
|
|
@@ -1002,7 +1032,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
withGroupAndReg sendReply groupId gName $ \_ gr ->
|
|
|
|
|
readTVarIO (groupRegStatus gr) >>= \case
|
|
|
|
|
GRSSuspended -> do
|
|
|
|
|
setGroupStatus st opts cc user gr GRSActive
|
|
|
|
|
setGroupStatus st env cc gr GRSActive
|
|
|
|
|
let groupStr = "The group " <> userGroupReference' gr gName
|
|
|
|
|
notifyOwner gr $ groupStr <> " is listed in the directory again!"
|
|
|
|
|
sendReply "Group listing resumed!"
|
|
|
|
@@ -1078,7 +1108,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
withGroupAndReg sendReply groupId gName $ \_ gr@GroupReg {groupRegStatus, promoted} -> do
|
|
|
|
|
status <- readTVarIO groupRegStatus
|
|
|
|
|
promote <- readTVarIO promoted
|
|
|
|
|
when (promote' /= promote) $ setGroupPromoted st opts cc user gr promote'
|
|
|
|
|
when (promote' /= promote) $ setGroupPromoted st env cc gr promote'
|
|
|
|
|
let msg =
|
|
|
|
|
"Group promotion "
|
|
|
|
|
<> (if promote' then "enabled" <> (if status == GRSActive then "." else ", but the group is not listed.") else "disabled.")
|
|
|
|
@@ -1132,18 +1162,16 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|
|
|
|
let text = T.unlines $ [tshow useGroupId <> ". Error: getGroup. Please notify the developers."] <> maybeToList ownerStr_ <> [statusStr]
|
|
|
|
|
sendComposedMessage cc ct Nothing $ MCText text
|
|
|
|
|
|
|
|
|
|
setGroupStatus :: DirectoryStore -> DirectoryOpts -> ChatController -> User -> GroupReg -> GroupRegStatus -> IO ()
|
|
|
|
|
setGroupStatus st opts cc u gr grStatus' = do
|
|
|
|
|
setGroupStatus :: DirectoryStore -> ServiceState -> ChatController -> GroupReg -> GroupRegStatus -> IO ()
|
|
|
|
|
setGroupStatus st env cc gr grStatus' = do
|
|
|
|
|
let status' = grDirectoryStatus grStatus'
|
|
|
|
|
status <- setGroupStatusStore st gr grStatus'
|
|
|
|
|
forM_ (webFolder opts) $ \dir ->
|
|
|
|
|
when ((status == DSListed || status' == DSListed) && status /= status') $ updateGroupListingFiles cc st u dir
|
|
|
|
|
when ((status == DSListed || status' == DSListed) && status /= status') $ listingsUpdated env cc
|
|
|
|
|
|
|
|
|
|
setGroupPromoted :: DirectoryStore -> DirectoryOpts -> ChatController -> User -> GroupReg -> Bool -> IO ()
|
|
|
|
|
setGroupPromoted st opts cc u gr grPromoted' = do
|
|
|
|
|
setGroupPromoted :: DirectoryStore -> ServiceState -> ChatController -> GroupReg -> Bool -> IO ()
|
|
|
|
|
setGroupPromoted st env cc gr grPromoted' = do
|
|
|
|
|
(status, grPromoted) <- setGroupPromotedStore st gr grPromoted'
|
|
|
|
|
forM_ (webFolder opts) $ \dir ->
|
|
|
|
|
when (status == DSListed && grPromoted' /= grPromoted) $ updateGroupListingFiles cc st u dir
|
|
|
|
|
when (status == DSListed && grPromoted' /= grPromoted) $ listingsUpdated env cc
|
|
|
|
|
|
|
|
|
|
updateGroupListingFiles :: ChatController -> DirectoryStore -> User -> FilePath -> IO ()
|
|
|
|
|
updateGroupListingFiles cc st u dir =
|
|
|
|
|