content: {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE ScopedTypeVariables #-}
  {-# OPTIONS_GHC -fno-warn-orphans #-}
  
  -- This file is part of the Wire Server implementation.
  --
  -- Copyright (C) 2022 Wire Swiss GmbH <opensource@wire.com>
  --
  -- This program is free software: you can redistribute it and/or modify it under
  -- the terms of the GNU Affero General Public License as published by the Free
  -- Software Foundation, either version 3 of the License, or (at your option) any
  -- later version.
  --
  -- This program is distributed in the hope that it will be useful, but WITHOUT
  -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  -- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  -- details.
  --
  -- You should have received a copy of the GNU Affero General Public License along
  -- with this program. If not, see <https://www.gnu.org/licenses/>.
  
  module Work
    ( runCommand,
    )
  where
  
  import Cassandra
  import Data.Id
  import Data.List.Extra (nubOrd)
  import Imports
  import System.Logger (Logger)
  import System.Logger qualified as Log
  import UnliftIO.Async (pooledMapConcurrentlyN_)
  
  runCommand :: Logger -> ClientState -> IO ()
  runCommand l brig = runClient brig $ do
    services <- getServices
    existing <- filterM doesServiceExist (nubOrd services)
    pooledMapConcurrentlyN_ 20 (whitelistService l) existing
  
  ----------------------------------------------------------------------------
  -- Queries
  
  -- | Get all services in team conversations
  getServices :: Client [(ProviderId, ServiceId, TeamId)]
  getServices = retry x5 $ query cql (params LocalQuorum ())
    where
      cql :: PrepQuery R () (ProviderId, ServiceId, TeamId)
      cql = "SELECT provider, service, team FROM service_team"
  
  -- | Check if a service exists
  doesServiceExist :: (ProviderId, ServiceId, a) -> Client Bool
  doesServiceExist (pid, sid, _) =
    retry x5 $ isJust <$> query1 cql (params LocalQuorum (pid, sid))
    where
      cql :: PrepQuery R (ProviderId, ServiceId) (Identity ServiceId)
      cql =
        "SELECT id FROM service \
        \WHERE provider = ? AND id = ?"
  
  -- | Add the service to the whitelist
  whitelistService :: Logger -> (ProviderId, ServiceId, TeamId) -> Client ()
  whitelistService l (pid, sid, tid) = do
    Log.info l $
      Log.msg (Log.val "Whitelisting")
        . Log.field "provider" (show pid)
        . Log.field "service" (show sid)
        . Log.field "team" (show tid)
    retry x5 . batch $ do
      setConsistency LocalQuorum
      setType BatchLogged
      addPrepQuery insert1 (tid, pid, sid)
      addPrepQuery insert1Rev (tid, pid, sid)
    where
      insert1 :: PrepQuery W (TeamId, ProviderId, ServiceId) ()
      insert1 =
        "INSERT INTO service_whitelist \
        \(team, provider, service) \
        \VALUES (?, ?, ?)"
      insert1Rev :: PrepQuery W (TeamId, ProviderId, ServiceId) ()
      insert1Rev =
        "INSERT INTO service_whitelist_rev \
        \(team, provider, service) \
        \VALUES (?, ?, ?)"
  