module IHP.IDE.SchemaDesigner.Controller.Policies where

import IHP.ControllerPrelude
import IHP.IDE.ToolServer.Types

import IHP.IDE.SchemaDesigner.View.Policies.New
import IHP.IDE.SchemaDesigner.View.Policies.Edit

import IHP.IDE.SchemaDesigner.Types
import IHP.IDE.SchemaDesigner.View.Layout (schemaDesignerLayout, findStatementByName)
import IHP.IDE.SchemaDesigner.Controller.Helper


import qualified IHP.IDE.SchemaDesigner.SchemaOperations as SchemaOperations

instance Controller PoliciesController where
    beforeAction :: (?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::PoliciesController) =>
IO ()
beforeAction = (?context::ControllerContext) =>
((?context::ControllerContext) => Layout) -> IO ()
((?context::ControllerContext) => Layout) -> IO ()
setLayout (?context::ControllerContext) => Layout
Layout
Html -> Html
schemaDesignerLayout

    action :: (?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::PoliciesController) =>
PoliciesController -> IO ()
action NewPolicyAction { Text
tableName :: Text
$sel:tableName:NewPolicyAction :: PoliciesController -> Text
tableName } = do
        [Statement]
statements <- IO [Statement]
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
IO [Statement]
readSchema
        let (Just Statement
table) = Text -> [Statement] -> Maybe Statement
forall {t :: * -> *}.
Foldable t =>
Text -> t Statement -> Maybe Statement
findStatementByName Text
tableName [Statement]
statements
        let policy :: Statement
policy = [Statement] -> Statement -> Statement
SchemaOperations.suggestPolicy [Statement]
statements Statement
table
        let columns :: [Column]
columns = (Statement -> CreateTable
unsafeGetCreateTable Statement
table).columns
        NewPolicyView -> IO ()
forall view.
(View view, ?context::ControllerContext) =>
view -> IO ()
render NewPolicyView { [Column]
[Statement]
Text
Statement
tableName :: Text
statements :: [Statement]
policy :: Statement
columns :: [Column]
$sel:statements:NewPolicyView :: [Statement]
$sel:tableName:NewPolicyView :: Text
$sel:columns:NewPolicyView :: [Column]
$sel:policy:NewPolicyView :: Statement
.. }

    action EditPolicyAction { Text
$sel:tableName:NewPolicyAction :: PoliciesController -> Text
tableName :: Text
tableName, Text
policyName :: Text
$sel:policyName:NewPolicyAction :: PoliciesController -> Text
policyName } = do
        [Statement]
statements <- IO [Statement]
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
IO [Statement]
readSchema
        let (Just Statement
policy) = [Statement]
statements
                [Statement] -> ([Statement] -> Maybe Statement) -> Maybe Statement
forall {t1} {t2}. t1 -> (t1 -> t2) -> t2
|> (Statement -> Bool) -> [Statement] -> Maybe Statement
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find \case
                    CreatePolicy { $sel:name:StatementCreateTable :: Statement -> Text
name = Text
policyName', $sel:tableName:StatementCreateTable :: Statement -> Text
tableName = Text
tableName' } -> Text
policyName' Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
policyName Bool -> Bool -> Bool
&& Text
tableName' Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
tableName
                    Statement
otherwise                                                   -> Bool
False
        let table :: Maybe Statement
table = Text -> [Statement] -> Maybe Statement
forall {t :: * -> *}.
Foldable t =>
Text -> t Statement -> Maybe Statement
findStatementByName Text
tableName [Statement]
statements
        let columns :: [Column]
columns = [Column] -> (Statement -> [Column]) -> Maybe Statement -> [Column]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] ((.columns) (CreateTable -> [Column])
-> (Statement -> CreateTable) -> Statement -> [Column]
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Statement -> CreateTable
unsafeGetCreateTable) Maybe Statement
table

        EditPolicyView -> IO ()
forall view.
(View view, ?context::ControllerContext) =>
view -> IO ()
render EditPolicyView { [Column]
[Statement]
Text
Statement
tableName :: Text
statements :: [Statement]
policy :: Statement
columns :: [Column]
$sel:statements:EditPolicyView :: [Statement]
$sel:tableName:EditPolicyView :: Text
$sel:columns:EditPolicyView :: [Column]
$sel:policy:EditPolicyView :: Statement
.. }

    action PoliciesController
UpdatePolicyAction = do
        [Statement]
statements <- IO [Statement]
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
IO [Statement]
readSchema
        let tableName :: Text
tableName = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"tableName"
        let name :: Text
name = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"name"

        
        ([Statement] -> [Statement]) -> IO ()
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
([Statement] -> [Statement]) -> IO ()
updateSchema (([Statement] -> [Statement]) -> IO ())
-> ([Statement] -> [Statement]) -> IO ()
forall a b. (a -> b) -> a -> b
$ UpdatePolicyOptions -> [Statement] -> [Statement]
SchemaOperations.updatePolicy SchemaOperations.UpdatePolicyOptions
                { $sel:currentName:UpdatePolicyOptions :: Text
currentName = Text
name
                , $sel:tableName:UpdatePolicyOptions :: Text
tableName = Text
tableName
                , $sel:name:UpdatePolicyOptions :: Text
name = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"policyName"
                , $sel:using:UpdatePolicyOptions :: Maybe Expression
using = ByteString -> Maybe Expression
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"using"
                , $sel:check:UpdatePolicyOptions :: Maybe Expression
check = ByteString -> Maybe Expression
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"check"
                }

        TablesController -> IO ()
forall action.
(?context::ControllerContext, HasPath action) =>
action -> IO ()
redirectTo ShowTableAction { Text
tableName :: Text
$sel:tableName:TablesAction :: Text
.. }
    
    action PoliciesController
CreatePolicyAction = do
        [Statement]
statements <- IO [Statement]
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
IO [Statement]
readSchema
        let tableName :: Text
tableName = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"tableName"
        
        let addPolicy :: [Statement] -> [Statement]
addPolicy = AddPolicyOptions -> [Statement] -> [Statement]
SchemaOperations.addPolicy SchemaOperations.AddPolicyOptions
                { $sel:tableName:AddPolicyOptions :: Text
tableName = Text
tableName
                , $sel:name:AddPolicyOptions :: Text
name = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"policyName"
                , $sel:using:AddPolicyOptions :: Maybe Expression
using = ByteString -> Maybe Expression
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"using"
                , $sel:check:AddPolicyOptions :: Maybe Expression
check = ByteString -> Maybe Expression
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"check"
                }
        let enableRLS :: [Statement] -> [Statement]
enableRLS = Text -> [Statement] -> [Statement]
SchemaOperations.enableRowLevelSecurity Text
tableName

        ([Statement] -> [Statement]) -> IO ()
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
([Statement] -> [Statement]) -> IO ()
updateSchema ([Statement] -> [Statement]
enableRLS ([Statement] -> [Statement])
-> ([Statement] -> [Statement]) -> [Statement] -> [Statement]
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [Statement] -> [Statement]
addPolicy)

        TablesController -> IO ()
forall action.
(?context::ControllerContext, HasPath action) =>
action -> IO ()
redirectTo ShowTableAction { Text
$sel:tableName:TablesAction :: Text
tableName :: Text
.. }

    action DeletePolicyAction { Text
$sel:tableName:NewPolicyAction :: PoliciesController -> Text
tableName :: Text
tableName, Text
$sel:policyName:NewPolicyAction :: PoliciesController -> Text
policyName :: Text
policyName } = do
        let deletePolicy :: [Statement] -> [Statement]
deletePolicy = DeletePolicyOptions -> [Statement] -> [Statement]
SchemaOperations.deletePolicy SchemaOperations.DeletePolicyOptions { Text
tableName :: Text
$sel:tableName:DeletePolicyOptions :: Text
tableName, Text
policyName :: Text
$sel:policyName:DeletePolicyOptions :: Text
policyName }
        let disableRLSIfNoPolicies :: [Statement] -> [Statement]
disableRLSIfNoPolicies = Text -> [Statement] -> [Statement]
SchemaOperations.disableRowLevelSecurityIfNoPolicies Text
tableName
        ([Statement] -> [Statement]) -> IO ()
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
([Statement] -> [Statement]) -> IO ()
updateSchema ([Statement] -> [Statement]
disableRLSIfNoPolicies ([Statement] -> [Statement])
-> ([Statement] -> [Statement]) -> [Statement] -> [Statement]
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [Statement] -> [Statement]
deletePolicy)

        TablesController -> IO ()
forall action.
(?context::ControllerContext, HasPath action) =>
action -> IO ()
redirectTo ShowTableAction { Text
$sel:tableName:TablesAction :: Text
tableName :: Text
.. }