mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 09:22:43 +03:00
Move RoleName into SchemaContext.
### Description I am not 100% sure about this PR; while I think the code is better this way, I'm willing to be convinced otherwise. In short, this PR moves the `RoleName` field into the `SchemaContext`, instead of being a nebulous `Has RoleName` constraint on the reader monad. The major upside of this is that it makes it an explicit named field, rather than something that must be given as part of a tuple of arguments when calling `runReader`. However, the downside is that it breaks the helper permissions functions of `Schema.Table`, which relied on `Has RoleName r`. This PR makes the choice of passing the role name explicitly to all of those functions, which in turn means first explicitly fetching the role name in a lot of places. It makes it more explicit when a schema building block relies on the role name, but is a bit verbose... ### Alternatives Some alternatives worth considering: - attempting something like `Has context r, Has RoleName context`, which would allow them to be independent from the context but still fetch the role name from the reader, but might require type annotations to not be ambiguous - keeping the permission functions the same, with `Has RoleName r`, and introducing a bunch of newtypes instead of using tuples to explicitly implement all the required `Has` instances - changing the permission functions to `Has SchemaContext r`, since they are functions used only to build the schema, and therefore may be allowed to be tied to the context. What do y'all think? PR-URL: https://github.com/hasura/graphql-engine-mono/pull/5073 GitOrigin-RevId: 8fd09fafb54905a4d115ef30842d35da0c3db5d2
This commit is contained in:
parent
178e452b6b
commit
0a69db81c9
@ -420,12 +420,13 @@ bqComputedField ::
|
||||
m (Maybe (FieldParser n (AnnotatedField 'BigQuery)))
|
||||
bqComputedField sourceName ComputedFieldInfo {..} tableName tableInfo = runMaybeT do
|
||||
stringifyNumbers <- retrieve Options.soStringifyNumbers
|
||||
roleName <- retrieve scRole
|
||||
fieldName <- lift $ textToName $ computedFieldNameToText _cfiName
|
||||
functionArgsParser <- lift $ computedFieldFunctionArgs _cfiFunction
|
||||
case _cfiReturnType of
|
||||
BigQuery.ReturnExistingTable returnTable -> do
|
||||
returnTableInfo <- lift $ askTableInfo sourceName returnTable
|
||||
returnTablePermissions <- MaybeT $ tableSelectPermissions returnTableInfo
|
||||
returnTablePermissions <- hoistMaybe $ tableSelectPermissions roleName returnTableInfo
|
||||
selectionSetParser <- MaybeT (fmap (P.multiple . P.nonNullableParser) <$> tableSelectionSet sourceName returnTableInfo)
|
||||
selectArgsParser <- lift $ tableArguments sourceName returnTableInfo
|
||||
let fieldArgsParser = liftA2 (,) functionArgsParser selectArgsParser
|
||||
@ -444,7 +445,7 @@ bqComputedField sourceName ComputedFieldInfo {..} tableName tableInfo = runMaybe
|
||||
}
|
||||
BigQuery.ReturnTableSchema returnFields -> do
|
||||
-- Check if the computed field is available in the select permission
|
||||
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
|
||||
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
|
||||
guard $ Map.member _cfiName $ spiComputedFields selectPermissions
|
||||
objectTypeName <-
|
||||
mkTypename =<< do
|
||||
|
@ -36,7 +36,6 @@ import Hasura.GraphQL.Schema.Parser
|
||||
)
|
||||
import Hasura.GraphQL.Schema.Parser qualified as P
|
||||
import Hasura.GraphQL.Schema.Select
|
||||
import Hasura.GraphQL.Schema.Table
|
||||
import Hasura.GraphQL.Schema.Typename (MkTypename)
|
||||
import Hasura.GraphQL.Schema.Update qualified as SU
|
||||
import Hasura.Name qualified as Name
|
||||
@ -131,8 +130,9 @@ msBuildTableUpdateMutationFields ::
|
||||
C.GQLNameIdentifier ->
|
||||
m [FieldParser n (AnnotatedUpdateG 'MSSQL (RemoteRelationshipField UnpreparedValue) (UnpreparedValue 'MSSQL))]
|
||||
msBuildTableUpdateMutationFields scenario sourceName tableName tableInfo gqlName = do
|
||||
roleName <- retrieve scRole
|
||||
fieldParsers <- runMaybeT do
|
||||
updatePerms <- MaybeT $ _permUpd <$> tablePermissions tableInfo
|
||||
updatePerms <- hoistMaybe $ _permUpd $ getRolePermInfo roleName tableInfo
|
||||
let mkBackendUpdate backendUpdateTableInfo =
|
||||
(fmap . fmap) BackendUpdate $
|
||||
SU.buildUpdateOperators
|
||||
|
@ -72,7 +72,8 @@ ifMatchedObjectParser ::
|
||||
m (Maybe (Parser 'Input n (IfMatched (UnpreparedValue 'MSSQL))))
|
||||
ifMatchedObjectParser sourceInfo tableInfo = runMaybeT do
|
||||
-- Short-circuit if we don't have sufficient permissions.
|
||||
updatePerms <- MaybeT $ _permUpd <$> tablePermissions tableInfo
|
||||
roleName <- retrieve scRole
|
||||
updatePerms <- hoistMaybe $ _permUpd $ getRolePermInfo roleName tableInfo
|
||||
matchColumnsEnum <- MaybeT $ tableInsertMatchColumnsEnum sourceInfo tableInfo
|
||||
lift do
|
||||
updateColumnsEnum <- updateColumnsPlaceholderParser tableInfo
|
||||
|
@ -59,7 +59,7 @@ import Hasura.GraphQL.Schema.Parser
|
||||
)
|
||||
import Hasura.GraphQL.Schema.Parser qualified as P
|
||||
import Hasura.GraphQL.Schema.Select
|
||||
import Hasura.GraphQL.Schema.Table
|
||||
import Hasura.GraphQL.Schema.Table (getTableGQLName, tableColumns)
|
||||
import Hasura.GraphQL.Schema.Typename
|
||||
import Hasura.GraphQL.Schema.Update qualified as SU
|
||||
import Hasura.Name qualified as Name
|
||||
@ -78,7 +78,7 @@ import Hasura.RQL.Types.Column
|
||||
import Hasura.RQL.Types.Function (FunctionInfo)
|
||||
import Hasura.RQL.Types.Source
|
||||
import Hasura.RQL.Types.SourceCustomization
|
||||
import Hasura.RQL.Types.Table (CustomRootField (..), RolePermInfo (..), TableConfig (..), TableCoreInfoG (..), TableCustomRootFields (..), TableInfo (..), UpdPermInfo (..), ViewInfo (..), isMutable, tableInfoName)
|
||||
import Hasura.RQL.Types.Table (CustomRootField (..), RolePermInfo (..), TableConfig (..), TableCoreInfoG (..), TableCustomRootFields (..), TableInfo (..), UpdPermInfo (..), ViewInfo (..), getRolePermInfo, isMutable, tableInfoName)
|
||||
import Hasura.SQL.Backend (BackendType (Postgres), PostgresKind (Citus, Vanilla))
|
||||
import Hasura.SQL.Tag (HasTag)
|
||||
import Hasura.SQL.Types
|
||||
@ -225,9 +225,10 @@ pgkBuildTableUpdateMutationFields ::
|
||||
-- | field display name
|
||||
C.GQLNameIdentifier ->
|
||||
m [FieldParser n (IR.AnnotatedUpdateG ('Postgres pgKind) (RemoteRelationshipField IR.UnpreparedValue) (IR.UnpreparedValue ('Postgres pgKind)))]
|
||||
pgkBuildTableUpdateMutationFields scenario sourceInfo tableName tableInfo gqlName =
|
||||
pgkBuildTableUpdateMutationFields scenario sourceInfo tableName tableInfo gqlName = do
|
||||
roleName <- retrieve scRole
|
||||
concat . maybeToList <$> runMaybeT do
|
||||
updatePerms <- MaybeT $ _permUpd <$> tablePermissions tableInfo
|
||||
updatePerms <- hoistMaybe $ _permUpd $ getRolePermInfo roleName tableInfo
|
||||
lift $ do
|
||||
-- update_table and update_table_by_pk
|
||||
singleUpdates <-
|
||||
@ -279,10 +280,11 @@ updateTableMany ::
|
||||
m (Maybe (P.FieldParser n (IR.AnnotatedUpdateG ('Postgres pgKind) (RemoteRelationshipField IR.UnpreparedValue) (IR.UnpreparedValue ('Postgres pgKind)))))
|
||||
updateTableMany scenario sourceInfo tableInfo gqlName = runMaybeT do
|
||||
tCase <- asks getter
|
||||
roleName <- retrieve scRole
|
||||
let columns = tableColumns tableInfo
|
||||
viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
|
||||
guard $ isMutable viIsUpdatable viewInfo
|
||||
updatePerms <- MaybeT $ _permUpd <$> tablePermissions tableInfo
|
||||
updatePerms <- hoistMaybe $ _permUpd $ getRolePermInfo roleName tableInfo
|
||||
guard $ not $ scenario == Frontend && upiBackendOnly updatePerms
|
||||
updates <- lift (mkMultiRowUpdateParser sourceInfo tableInfo updatePerms)
|
||||
selection <- lift $ P.multiple <$> GSB.mutationSelectionSet sourceInfo tableInfo
|
||||
|
@ -62,8 +62,9 @@ onConflictFieldParser ::
|
||||
m (InputFieldsParser n (Maybe (IR.OnConflictClause ('Postgres pgKind) (IR.UnpreparedValue ('Postgres pgKind)))))
|
||||
onConflictFieldParser sourceInfo tableInfo = do
|
||||
tCase <- asks getter
|
||||
permissions <- tablePermissions tableInfo
|
||||
let maybeConstraints = tciUniqueOrPrimaryKeyConstraints . _tiCoreInfo $ tableInfo
|
||||
roleName <- retrieve scRole
|
||||
let permissions = getRolePermInfo roleName tableInfo
|
||||
maybeConstraints = tciUniqueOrPrimaryKeyConstraints . _tiCoreInfo $ tableInfo
|
||||
maybeConflictObject = conflictObjectParser sourceInfo tableInfo (_permUpd permissions) <$> maybeConstraints
|
||||
case maybeConflictObject of
|
||||
Just conflictObject -> conflictObject <&> P.fieldOptional (applyFieldNameCaseCust tCase Name._on_conflict) (Just "upsert condition")
|
||||
|
@ -62,8 +62,9 @@ selectFunction ::
|
||||
m (Maybe (FieldParser n (SelectExp ('Postgres pgKind))))
|
||||
selectFunction sourceInfo fi@FunctionInfo {..} description = runMaybeT do
|
||||
tCase <- asks getter
|
||||
roleName <- retrieve scRole
|
||||
tableInfo <- lift $ askTableInfo sourceInfo _fiReturnType
|
||||
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
|
||||
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
|
||||
selectionSetParser <- MaybeT $ returnFunctionParser sourceInfo tableInfo
|
||||
lift do
|
||||
stringifyNumbers <- retrieve Options.soStringifyNumbers
|
||||
@ -101,8 +102,9 @@ selectFunctionAggregate ::
|
||||
m (Maybe (FieldParser n (AggSelectExp ('Postgres pgKind))))
|
||||
selectFunctionAggregate sourceInfo fi@FunctionInfo {..} description = runMaybeT do
|
||||
tCase <- asks getter
|
||||
roleName <- retrieve scRole
|
||||
targetTableInfo <- askTableInfo sourceInfo _fiReturnType
|
||||
selectPermissions <- MaybeT $ tableSelectPermissions targetTableInfo
|
||||
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName targetTableInfo
|
||||
guard $ spiAllowAgg selectPermissions
|
||||
xNodesAgg <- hoistMaybe $ nodesAggExtension @('Postgres pgKind)
|
||||
tableInfo <- askTableInfo sourceInfo _fiReturnType
|
||||
@ -153,8 +155,9 @@ selectFunctionConnection ::
|
||||
m (Maybe (FieldParser n (ConnectionSelectExp ('Postgres pgKind))))
|
||||
selectFunctionConnection sourceInfo fi@FunctionInfo {..} description pkeyColumns = runMaybeT do
|
||||
tCase <- asks getter
|
||||
roleName <- retrieve scRole
|
||||
returnTableInfo <- lift $ askTableInfo sourceInfo _fiReturnType
|
||||
selectPermissions <- MaybeT $ tableSelectPermissions returnTableInfo
|
||||
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName returnTableInfo
|
||||
xRelayInfo <- hoistMaybe $ relayExtension @('Postgres pgKind)
|
||||
tableInfo <- lift $ askTableInfo sourceInfo _fiReturnType
|
||||
selectionSetParser <- MaybeT $ tableConnectionSelectionSet sourceInfo tableInfo
|
||||
@ -195,8 +198,9 @@ computedFieldPG ::
|
||||
m (Maybe (FieldParser n (AnnotatedField ('Postgres pgKind))))
|
||||
computedFieldPG sourceInfo ComputedFieldInfo {..} parentTable tableInfo = runMaybeT do
|
||||
tCase <- asks getter
|
||||
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
|
||||
roleName <- retrieve scRole
|
||||
stringifyNumbers <- retrieve Options.soStringifyNumbers
|
||||
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
|
||||
fieldName <- lift $ textToName $ computedFieldNameToText _cfiName
|
||||
functionArgsParser <- lift $ computedFieldFunctionArgs _cfiFunction
|
||||
case _cfiReturnType of
|
||||
@ -226,7 +230,7 @@ computedFieldPG sourceInfo ComputedFieldInfo {..} parentTable tableInfo = runMay
|
||||
pure $ P.selection fieldName fieldDescription fieldArgsParser dummyParser
|
||||
PG.CFRSetofTable tableName -> do
|
||||
otherTableInfo <- lift $ askTableInfo sourceInfo tableName
|
||||
remotePerms <- MaybeT $ tableSelectPermissions otherTableInfo
|
||||
remotePerms <- hoistMaybe $ tableSelectPermissions roleName otherTableInfo
|
||||
selectionSetParser <- MaybeT (fmap (P.multiple . P.nonNullableParser) <$> tableSelectionSet sourceInfo otherTableInfo)
|
||||
selectArgsParser <- lift $ tableArguments sourceInfo otherTableInfo
|
||||
let fieldArgsParser = liftA2 (,) functionArgsParser selectArgsParser
|
||||
|
@ -116,8 +116,7 @@ fetchRemoteSchema env manager _rscName rsDef@ValidatedRemoteSchemaDef {..} = do
|
||||
-- Minimum valid information required to run schema generation for
|
||||
-- the remote schema.
|
||||
minimumValidContext =
|
||||
( adminRoleName :: RoleName,
|
||||
mempty :: CustomizeRemoteFieldName,
|
||||
( mempty :: CustomizeRemoteFieldName,
|
||||
mempty :: MkTypename,
|
||||
mempty :: MkRootFieldName,
|
||||
HasuraCase,
|
||||
@ -137,6 +136,7 @@ fetchRemoteSchema env manager _rscName rsDef@ValidatedRemoteSchemaDef {..} = do
|
||||
SchemaContext
|
||||
HasuraSchema
|
||||
ignoreRemoteRelationship
|
||||
adminRoleName
|
||||
)
|
||||
|
||||
-- | Sends a GraphQL query to the given server.
|
||||
|
@ -197,7 +197,8 @@ buildRoleContext options sources remotes allActionInfos customTypes role remoteS
|
||||
SchemaContext
|
||||
HasuraSchema
|
||||
(remoteRelationshipField sources (fst <$> remotes) remoteSchemaPermsCtx)
|
||||
runMonadSchema schemaOptions schemaContext role $ do
|
||||
role
|
||||
runMonadSchema schemaOptions schemaContext $ do
|
||||
-- build all sources (`apolloFedTableParsers` contains all the parsers and
|
||||
-- type names, which are eligible for the `_Entity` Union)
|
||||
(sourcesQueryFields, sourcesMutationFrontendFields, sourcesMutationBackendFields, subscriptionFields, apolloFedTableParsers) <-
|
||||
@ -338,7 +339,8 @@ buildRelayRoleContext options sources allActionInfos customTypes role expFeature
|
||||
SchemaContext
|
||||
(RelaySchema $ nodeInterface sources)
|
||||
(remoteRelationshipField sources mempty Options.DisableRemoteSchemaPermissions)
|
||||
runMonadSchema schemaOptions schemaContext role do
|
||||
role
|
||||
runMonadSchema schemaOptions schemaContext do
|
||||
node <- fmap NotNamespaced <$> nodeField sources
|
||||
fieldsList <- traverse (buildBackendSource buildSource) $ toList sources
|
||||
let (queryFields, mutationFrontendFields, mutationBackendFields, subscriptionFields) = mconcat fieldsList
|
||||
@ -460,6 +462,7 @@ unauthenticatedContext allRemotes remoteSchemaPermsCtx = do
|
||||
SchemaContext
|
||||
HasuraSchema
|
||||
ignoreRemoteRelationship
|
||||
fakeRole
|
||||
-- chosen arbitrarily to be as improbable as possible
|
||||
fakeRole = mkRoleNameSafe [NT.nonEmptyTextQQ|MyNameIsOzymandiasKingOfKingsLookOnMyWorksYeMightyAndDespair|]
|
||||
-- we delete all references to remote joins
|
||||
@ -467,7 +470,7 @@ unauthenticatedContext allRemotes remoteSchemaPermsCtx = do
|
||||
allRemotes <&> first \context ->
|
||||
context {_rscRemoteRelationships = mempty}
|
||||
|
||||
runMonadSchema fakeSchemaOptions fakeSchemaContext fakeRole do
|
||||
runMonadSchema fakeSchemaOptions fakeSchemaContext do
|
||||
(queryFields, mutationFields, subscriptionFields, remoteErrors) <- case remoteSchemaPermsCtx of
|
||||
Options.EnableRemoteSchemaPermissions ->
|
||||
-- Permissions are enabled, unauthenticated users have access to nothing.
|
||||
@ -583,7 +586,7 @@ buildQueryAndSubscriptionFields ::
|
||||
StreamingSubscriptionsCtx ->
|
||||
m ([P.FieldParser n (QueryRootField UnpreparedValue)], [P.FieldParser n (SubscriptionRootField UnpreparedValue)], [(G.Name, Parser 'Output n (ApolloFederationParserFunction n))])
|
||||
buildQueryAndSubscriptionFields sourceInfo tables (takeExposedAs FEAQuery -> functions) streamingSubsCtx = do
|
||||
roleName <- asks getter
|
||||
roleName <- retrieve scRole
|
||||
functionPermsCtx <- retrieve Options.soInferFunctionPermissions
|
||||
functionSelectExpParsers <-
|
||||
concat . catMaybes
|
||||
@ -624,11 +627,12 @@ buildRelayQueryAndSubscriptionFields ::
|
||||
FunctionCache b ->
|
||||
m ([P.FieldParser n (QueryRootField UnpreparedValue)], [P.FieldParser n (SubscriptionRootField UnpreparedValue)])
|
||||
buildRelayQueryAndSubscriptionFields sourceInfo tables (takeExposedAs FEAQuery -> functions) = do
|
||||
roleName <- retrieve scRole
|
||||
(tableConnectionQueryFields, tableConnectionSubscriptionFields) <-
|
||||
unzip . catMaybes
|
||||
<$> for (Map.toList tables) \(tableName, tableInfo) -> runMaybeT do
|
||||
tableIdentifierName <- getTableIdentifierName @b tableInfo
|
||||
SelPermInfo {..} <- MaybeT $ tableSelectPermissions tableInfo
|
||||
SelPermInfo {..} <- hoistMaybe $ tableSelectPermissions roleName tableInfo
|
||||
pkeyColumns <- hoistMaybe $ tableInfo ^? tiCoreInfo . tciPrimaryKey . _Just . pkColumns
|
||||
relayRootFields <- lift $ mkRFs $ buildTableRelayQueryFields sourceInfo tableName tableInfo tableIdentifierName pkeyColumns
|
||||
let includeRelayWhen True = Just relayRootFields
|
||||
@ -663,7 +667,7 @@ buildMutationFields ::
|
||||
FunctionCache b ->
|
||||
m [P.FieldParser n (MutationRootField UnpreparedValue)]
|
||||
buildMutationFields scenario sourceInfo tables (takeExposedAs FEAMutation -> functions) = do
|
||||
roleName <- asks getter
|
||||
roleName <- retrieve scRole
|
||||
tableMutations <- for (Map.toList tables) \(tableName, tableInfo) -> do
|
||||
tableIdentifierName <- getTableIdentifierName @b tableInfo
|
||||
inserts <-
|
||||
@ -905,7 +909,6 @@ type ConcreteSchemaT m a =
|
||||
( ReaderT
|
||||
( SchemaOptions,
|
||||
SchemaContext,
|
||||
RoleName,
|
||||
MkTypename,
|
||||
MkRootFieldName,
|
||||
CustomizeRemoteFieldName,
|
||||
@ -920,11 +923,10 @@ runMonadSchema ::
|
||||
Monad m =>
|
||||
SchemaOptions ->
|
||||
SchemaContext ->
|
||||
RoleName ->
|
||||
ConcreteSchemaT m a ->
|
||||
m a
|
||||
runMonadSchema options context roleName m =
|
||||
flip runReaderT (options, context, roleName, mempty, mempty, mempty, HasuraCase) $
|
||||
runMonadSchema options context m =
|
||||
flip runReaderT (options, context, mempty, mempty, mempty, HasuraCase) $
|
||||
P.runSchemaT m
|
||||
|
||||
buildBackendSource ::
|
||||
|
@ -10,7 +10,6 @@ where
|
||||
import Data.Aeson qualified as J
|
||||
import Data.Aeson.Key qualified as K
|
||||
import Data.Aeson.KeyMap qualified as KM
|
||||
import Data.Has
|
||||
import Data.HashMap.Strict qualified as Map
|
||||
import Data.Text.Extended
|
||||
import Data.Text.NonEmpty
|
||||
@ -65,7 +64,7 @@ actionExecute ::
|
||||
ActionInfo ->
|
||||
m (Maybe (FieldParser n (IR.AnnActionExecution (IR.RemoteRelationshipField IR.UnpreparedValue))))
|
||||
actionExecute customTypes actionInfo = runMaybeT do
|
||||
roleName <- asks getter
|
||||
roleName <- retrieve scRole
|
||||
guard (roleName == adminRoleName || roleName `Map.member` permissions)
|
||||
let fieldName = unActionName actionName
|
||||
description = G.Description <$> comment
|
||||
@ -109,7 +108,7 @@ actionAsyncMutation ::
|
||||
ActionInfo ->
|
||||
m (Maybe (FieldParser n IR.AnnActionMutationAsync))
|
||||
actionAsyncMutation nonObjectTypeMap actionInfo = runMaybeT do
|
||||
roleName <- asks getter
|
||||
roleName <- retrieve scRole
|
||||
guard $ roleName == adminRoleName || roleName `Map.member` permissions
|
||||
inputArguments <- lift $ actionInputArguments nonObjectTypeMap $ _adArguments definition
|
||||
let fieldName = unActionName actionName
|
||||
@ -140,7 +139,7 @@ actionAsyncQuery ::
|
||||
ActionInfo ->
|
||||
m (Maybe (FieldParser n (IR.AnnActionAsyncQuery ('Postgres 'Vanilla) (IR.RemoteRelationshipField IR.UnpreparedValue))))
|
||||
actionAsyncQuery objectTypes actionInfo = runMaybeT do
|
||||
roleName <- asks getter
|
||||
roleName <- retrieve scRole
|
||||
guard $ roleName == adminRoleName || roleName `Map.member` permissions
|
||||
createdAtFieldParser <-
|
||||
lift $ columnParser @('Postgres 'Vanilla) (ColumnScalar PGTimeStampTZ) (G.Nullability False)
|
||||
|
@ -14,7 +14,7 @@ import Data.Text.Casing qualified as C
|
||||
import Data.Text.Extended
|
||||
import Hasura.GraphQL.Parser.Class
|
||||
import Hasura.GraphQL.Schema.Backend
|
||||
import Hasura.GraphQL.Schema.Common (askTableInfo, partialSQLExpToUnpreparedValue)
|
||||
import Hasura.GraphQL.Schema.Common (SchemaContext (..), askTableInfo, partialSQLExpToUnpreparedValue, retrieve)
|
||||
import Hasura.GraphQL.Schema.NamingCase
|
||||
import Hasura.GraphQL.Schema.Options qualified as Options
|
||||
import Hasura.GraphQL.Schema.Parser
|
||||
@ -85,6 +85,7 @@ boolExp sourceInfo tableInfo = memoizeOn 'boolExp (_siName sourceInfo, tableName
|
||||
FieldInfo b ->
|
||||
m (Maybe (InputFieldsParser n (Maybe (AnnBoolExpFld b (UnpreparedValue b)))))
|
||||
mkField fieldInfo = runMaybeT do
|
||||
roleName <- retrieve scRole
|
||||
fieldName <- hoistMaybe $ fieldInfoGraphQLName fieldInfo
|
||||
P.fieldOptional fieldName Nothing <$> case fieldInfo of
|
||||
-- field_name: field_type_comparison_exp
|
||||
@ -93,10 +94,10 @@ boolExp sourceInfo tableInfo = memoizeOn 'boolExp (_siName sourceInfo, tableName
|
||||
-- field_name: field_type_bool_exp
|
||||
FIRelationship relationshipInfo -> do
|
||||
remoteTableInfo <- askTableInfo sourceInfo $ riRTable relationshipInfo
|
||||
remotePermissions <- lift $ tableSelectPermissions remoteTableInfo
|
||||
let remoteTableFilter =
|
||||
fmap partialSQLExpToUnpreparedValue
|
||||
<$> maybe annBoolExpTrue spiFilter remotePermissions
|
||||
(fmap . fmap) partialSQLExpToUnpreparedValue $
|
||||
maybe annBoolExpTrue spiFilter $
|
||||
tableSelectPermissions roleName remoteTableInfo
|
||||
remoteBoolExp <- lift $ boolExp sourceInfo remoteTableInfo
|
||||
pure $ fmap (AVRelationship relationshipInfo . andAnnBoolExps remoteTableFilter) remoteBoolExp
|
||||
FIComputedField ComputedFieldInfo {..} -> do
|
||||
|
@ -118,6 +118,7 @@ buildTableQueryAndSubscriptionFields ::
|
||||
)
|
||||
buildTableQueryAndSubscriptionFields sourceInfo tableName tableInfo streamSubCtx gqlName = do
|
||||
tCase <- asks getter
|
||||
roleName <- retrieve scRole
|
||||
-- select table
|
||||
selectName <- mkRootFieldName $ setFieldNameCase tCase tableInfo _tcrfSelect mkSelectField gqlName
|
||||
-- select table by pk
|
||||
@ -125,13 +126,11 @@ buildTableQueryAndSubscriptionFields sourceInfo tableName tableInfo streamSubCtx
|
||||
-- select table aggregate
|
||||
selectAggName <- mkRootFieldName $ setFieldNameCase tCase tableInfo _tcrfSelectAggregate mkSelectAggregateField gqlName
|
||||
|
||||
selectPermission <- tableSelectPermissions tableInfo
|
||||
|
||||
selectTableParser <- optionalFieldParser QDBMultipleRows $ selectTable sourceInfo tableInfo selectName selectDesc
|
||||
selectTableByPkParser <- optionalFieldParser QDBSingleRow $ selectTableByPk sourceInfo tableInfo selectPKName selectPKDesc
|
||||
selectTableAggregateParser <- optionalFieldParser QDBAggregation $ selectTableAggregate sourceInfo tableInfo selectAggName selectAggDesc
|
||||
|
||||
case selectPermission of
|
||||
case tableSelectPermissions roleName tableInfo of
|
||||
-- No select permission found for the current role, so
|
||||
-- no root fields will be accessible to the role
|
||||
Nothing -> pure (mempty, mempty, Nothing)
|
||||
@ -169,7 +168,7 @@ buildTableQueryAndSubscriptionFields sourceInfo tableName tableInfo streamSubCtx
|
||||
apolloFedTableParser <- runMaybeT do
|
||||
guard $ isApolloFedV1enabled (_tciApolloFederationConfig (_tiCoreInfo tableInfo))
|
||||
tableSelSet <- MaybeT $ tableSelectionSet sourceInfo tableInfo
|
||||
selectPerm <- MaybeT $ tableSelectPermissions tableInfo
|
||||
selectPerm <- hoistMaybe $ tableSelectPermissions roleName tableInfo
|
||||
stringifyNumbers <- retrieve Options.soStringifyNumbers
|
||||
primaryKeys <- hoistMaybe $ fmap _pkColumns . _tciPrimaryKey . _tiCoreInfo $ tableInfo
|
||||
let tableSelPerm = tablePermissionsInfo selectPerm
|
||||
|
@ -82,7 +82,9 @@ data SchemaContext = SchemaContext
|
||||
{ -- | the kind of schema being built
|
||||
scSchemaKind :: SchemaKind,
|
||||
-- | how to process remote relationships
|
||||
scRemoteRelationshipParserBuilder :: RemoteRelationshipParserBuilder
|
||||
scRemoteRelationshipParserBuilder :: RemoteRelationshipParserBuilder,
|
||||
-- | the role for which the schema is being built
|
||||
scRole :: RoleName
|
||||
}
|
||||
|
||||
-- | The kind of schema we're building, and its associated options.
|
||||
@ -103,7 +105,6 @@ type MonadBuildSchemaBase r m n =
|
||||
Has SchemaOptions r,
|
||||
Has SchemaContext r,
|
||||
-- TODO: make all `Has x r` explicit fields of 'SchemaContext'
|
||||
Has RoleName r,
|
||||
Has MkTypename r,
|
||||
Has MkRootFieldName r,
|
||||
Has CustomizeRemoteFieldName r,
|
||||
|
@ -73,13 +73,15 @@ insertIntoTable ::
|
||||
insertIntoTable backendInsertAction scenario sourceInfo tableInfo fieldName description = runMaybeT $ do
|
||||
let viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
|
||||
guard $ isMutable viIsInsertable viewInfo
|
||||
insertPerms <- MaybeT $ _permIns <$> tablePermissions tableInfo
|
||||
roleName <- retrieve scRole
|
||||
let permissions = getRolePermInfo roleName tableInfo
|
||||
insertPerms <- hoistMaybe $ _permIns permissions
|
||||
-- If we're in a frontend scenario, we should not include backend_only inserts
|
||||
-- For more info see Note [Backend only permissions]
|
||||
guard $ not $ scenario == Frontend && ipiBackendOnly insertPerms
|
||||
tCase <- asks getter
|
||||
lift do
|
||||
updatePerms <- _permUpd <$> tablePermissions tableInfo
|
||||
let updatePerms = _permUpd permissions
|
||||
-- objects [{ ... }]
|
||||
objectParser <- tableFieldsInput sourceInfo tableInfo
|
||||
backendInsertParser <- backendInsertAction sourceInfo tableInfo
|
||||
@ -122,14 +124,16 @@ insertOneIntoTable ::
|
||||
insertOneIntoTable backendInsertAction scenario sourceInfo tableInfo fieldName description = runMaybeT do
|
||||
let viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
|
||||
guard $ isMutable viIsInsertable viewInfo
|
||||
insertPerms <- MaybeT $ _permIns <$> tablePermissions tableInfo
|
||||
roleName <- retrieve scRole
|
||||
let permissions = getRolePermInfo roleName tableInfo
|
||||
insertPerms <- hoistMaybe $ _permIns permissions
|
||||
-- If we're in a frontend scenario, we should not include backend_only inserts
|
||||
-- For more info see Note [Backend only permissions]
|
||||
guard $ not $ scenario == Frontend && ipiBackendOnly insertPerms
|
||||
selectionParser <- MaybeT $ tableSelectionSet sourceInfo tableInfo
|
||||
tCase <- asks getter
|
||||
lift do
|
||||
updatePerms <- _permUpd <$> tablePermissions tableInfo
|
||||
let updatePerms = _permUpd permissions
|
||||
objectParser <- tableFieldsInput sourceInfo tableInfo
|
||||
backendInsertParser <- backendInsertAction sourceInfo tableInfo
|
||||
let argsParser = do
|
||||
@ -206,7 +210,8 @@ tableFieldsInput sourceInfo tableInfo =
|
||||
ColumnInfo b ->
|
||||
m (Maybe (InputFieldsParser n (Maybe (IR.AnnotatedInsertField b (IR.UnpreparedValue b)))))
|
||||
mkColumnParser columnInfo = runMaybeT $ do
|
||||
insertPerms <- MaybeT $ _permIns <$> tablePermissions tableInfo
|
||||
roleName <- retrieve scRole
|
||||
insertPerms <- hoistMaybe $ _permIns $ getRolePermInfo roleName tableInfo
|
||||
let columnName = ciName columnInfo
|
||||
columnDesc = ciDescription columnInfo
|
||||
isAllowed = Set.member (ciColumn columnInfo) (ipiCols insertPerms)
|
||||
@ -259,10 +264,11 @@ objectRelationshipInput ::
|
||||
TableInfo b ->
|
||||
m (Maybe (Parser 'Input n (IR.SingleObjectInsert b (IR.UnpreparedValue b))))
|
||||
objectRelationshipInput backendInsertAction sourceInfo tableInfo = runMaybeT $ do
|
||||
insertPerms <- MaybeT $ _permIns <$> tablePermissions tableInfo
|
||||
roleName <- retrieve scRole
|
||||
let permissions = getRolePermInfo roleName tableInfo
|
||||
updatePerms = _permUpd permissions
|
||||
insertPerms <- hoistMaybe $ _permIns permissions
|
||||
lift $ memoizeOn 'objectRelationshipInput (_siName sourceInfo, tableName) do
|
||||
updatePerms <- _permUpd <$> tablePermissions tableInfo
|
||||
_selectPerms <- _permSel <$> tablePermissions tableInfo
|
||||
tableGQLName <- getTableGQLName tableInfo
|
||||
objectParser <- tableFieldsInput sourceInfo tableInfo
|
||||
backendInsertParser <- backendInsertAction sourceInfo tableInfo
|
||||
@ -292,10 +298,11 @@ arrayRelationshipInput ::
|
||||
TableInfo b ->
|
||||
m (Maybe (Parser 'Input n (IR.MultiObjectInsert b (IR.UnpreparedValue b))))
|
||||
arrayRelationshipInput backendInsertAction sourceInfo tableInfo = runMaybeT $ do
|
||||
insertPerms <- MaybeT $ _permIns <$> tablePermissions tableInfo
|
||||
roleName <- retrieve scRole
|
||||
let permissions = getRolePermInfo roleName tableInfo
|
||||
updatePerms = _permUpd permissions
|
||||
insertPerms <- hoistMaybe $ _permIns permissions
|
||||
lift $ memoizeOn 'arrayRelationshipInput (_siName sourceInfo, tableName) do
|
||||
updatePerms <- _permUpd <$> tablePermissions tableInfo
|
||||
_selectPerms <- _permSel <$> tablePermissions tableInfo
|
||||
tableGQLName <- getTableGQLName tableInfo
|
||||
objectParser <- tableFieldsInput sourceInfo tableInfo
|
||||
backendInsertParser <- backendInsertAction sourceInfo tableInfo
|
||||
@ -358,7 +365,8 @@ deleteFromTable ::
|
||||
deleteFromTable scenario sourceInfo tableInfo fieldName description = runMaybeT $ do
|
||||
let viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
|
||||
guard $ isMutable viIsInsertable viewInfo
|
||||
deletePerms <- MaybeT $ _permDel <$> tablePermissions tableInfo
|
||||
roleName <- retrieve scRole
|
||||
deletePerms <- hoistMaybe $ _permDel $ getRolePermInfo roleName tableInfo
|
||||
-- If we're in a frontend scenario, we should not include backend_only deletes
|
||||
-- For more info see Note [Backend only permissions]
|
||||
guard $ not $ scenario == Frontend && dpiBackendOnly deletePerms
|
||||
@ -394,7 +402,8 @@ deleteFromTableByPk scenario sourceInfo tableInfo fieldName description = runMay
|
||||
let viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
|
||||
guard $ isMutable viIsInsertable viewInfo
|
||||
pkArgs <- MaybeT $ primaryKeysArguments tableInfo
|
||||
deletePerms <- MaybeT $ _permDel <$> tablePermissions tableInfo
|
||||
roleName <- retrieve scRole
|
||||
deletePerms <- hoistMaybe $ _permDel $ getRolePermInfo roleName tableInfo
|
||||
-- If we're in a frontend scenario, we should not include backend_only deletes
|
||||
-- For more info see Note [Backend only permissions]
|
||||
guard $ not $ scenario == Frontend && dpiBackendOnly deletePerms
|
||||
@ -437,9 +446,10 @@ mutationSelectionSet ::
|
||||
m (Parser 'Output n (IR.MutFldsG b (IR.RemoteRelationshipField IR.UnpreparedValue) (IR.UnpreparedValue b)))
|
||||
mutationSelectionSet sourceInfo tableInfo =
|
||||
memoizeOn 'mutationSelectionSet (_siName sourceInfo, tableName) do
|
||||
roleName <- retrieve scRole
|
||||
tableGQLName <- getTableGQLName tableInfo
|
||||
returning <- runMaybeT do
|
||||
_permissions <- MaybeT $ tableSelectPermissions tableInfo
|
||||
_permissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
|
||||
tableSet <- MaybeT $ tableSelectionList sourceInfo tableInfo
|
||||
let returningName = Name._returning
|
||||
returningDesc = "data from the rows affected by the mutation"
|
||||
@ -473,7 +483,8 @@ primaryKeysArguments ::
|
||||
TableInfo b ->
|
||||
m (Maybe (InputFieldsParser n (AnnBoolExp b (IR.UnpreparedValue b))))
|
||||
primaryKeysArguments tableInfo = runMaybeT $ do
|
||||
selectPerms <- MaybeT $ tableSelectPermissions tableInfo
|
||||
roleName <- retrieve scRole
|
||||
selectPerms <- hoistMaybe $ tableSelectPermissions roleName tableInfo
|
||||
primaryKeys <- hoistMaybe $ _tciPrimaryKey . _tiCoreInfo $ tableInfo
|
||||
let columns = _pkColumns primaryKeys
|
||||
guard $ all (\c -> ciColumn c `Map.member` spiCols selectPerms) columns
|
||||
|
@ -80,7 +80,8 @@ orderByExp sourceInfo tableInfo = memoizeOn 'orderByExp (_siName sourceInfo, tab
|
||||
NamingCase ->
|
||||
FieldInfo b ->
|
||||
m (Maybe (InputFieldsParser n (Maybe [IR.AnnotatedOrderByItemG b (IR.UnpreparedValue b)])))
|
||||
mkField tCase fieldInfo = runMaybeT $
|
||||
mkField tCase fieldInfo = runMaybeT $ do
|
||||
roleName <- retrieve scRole
|
||||
case fieldInfo of
|
||||
FIColumn columnInfo -> do
|
||||
let fieldName = ciName columnInfo
|
||||
@ -92,8 +93,8 @@ orderByExp sourceInfo tableInfo = memoizeOn 'orderByExp (_siName sourceInfo, tab
|
||||
<&> fmap (pure . mkOrderByItemG @b (IR.AOCColumn columnInfo)) . join
|
||||
FIRelationship relationshipInfo -> do
|
||||
remoteTableInfo <- askTableInfo sourceInfo $ riRTable relationshipInfo
|
||||
perms <- hoistMaybe $ tableSelectPermissions roleName remoteTableInfo
|
||||
fieldName <- hoistMaybe $ G.mkName $ relNameToTxt $ riName relationshipInfo
|
||||
perms <- MaybeT $ tableSelectPermissions remoteTableInfo
|
||||
let newPerms = fmap partialSQLExpToUnpreparedValue <$> spiFilter perms
|
||||
case riType relationshipInfo of
|
||||
ObjRel -> do
|
||||
@ -128,7 +129,7 @@ orderByExp sourceInfo tableInfo = memoizeOn 'orderByExp (_siName sourceInfo, tab
|
||||
ReturnsTable table -> do
|
||||
let aggregateFieldName = applyFieldNameCaseIdentifier tCase $ C.fromTuple (fieldName, [G.convertNameToSuffix Name._aggregate])
|
||||
tableInfo' <- askTableInfo sourceInfo table
|
||||
perms <- MaybeT $ tableSelectPermissions tableInfo'
|
||||
perms <- hoistMaybe $ tableSelectPermissions roleName tableInfo'
|
||||
let newPerms = fmap partialSQLExpToUnpreparedValue <$> spiFilter perms
|
||||
aggregationParser <- lift $ orderByAggregation sourceInfo tableInfo'
|
||||
pure $ do
|
||||
|
@ -58,6 +58,7 @@ nodeInterface sourceCache = NodeInterfaceParserBuilder $ memoizeOn 'nodeInterfac
|
||||
idField = P.selection_ Name._id (Just idDescription) P.identifier
|
||||
nodeInterfaceDescription = G.Description "An object with globally unique ID"
|
||||
tCase <- asks getter
|
||||
roleName <- retrieve scRole
|
||||
tables :: [Parser 'Output n (SourceName, AB.AnyBackend TableMap)] <-
|
||||
catMaybes . concat <$> for (Map.toList sourceCache) \(sourceName, anySourceInfo) ->
|
||||
AB.dispatchAnyBackendWithTwoConstraints @BackendSchema @BackendTableSelectSchema
|
||||
@ -65,7 +66,7 @@ nodeInterface sourceCache = NodeInterfaceParserBuilder $ memoizeOn 'nodeInterfac
|
||||
\(sourceInfo :: SourceInfo b) ->
|
||||
for (Map.toList $ takeValidTables $ _siTables sourceInfo) \(tableName, tableInfo) -> runMaybeT do
|
||||
tablePkeyColumns <- hoistMaybe $ tableInfo ^? tiCoreInfo . tciPrimaryKey . _Just . pkColumns
|
||||
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
|
||||
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
|
||||
annotatedFieldsParser <-
|
||||
MaybeT $
|
||||
withTypenameCustomization
|
||||
|
@ -71,7 +71,7 @@ remoteRelationshipToSchemaField ::
|
||||
RemoteSchemaFieldInfo ->
|
||||
m (Maybe (FieldParser n (IR.RemoteSchemaSelect (IR.RemoteRelationshipField IR.UnpreparedValue))))
|
||||
remoteRelationshipToSchemaField remoteSchemaCache remoteSchemaPermissions lhsFields RemoteSchemaFieldInfo {..} = runMaybeT do
|
||||
roleName <- asks getter
|
||||
roleName <- retrieve scRole
|
||||
remoteSchemaContext <-
|
||||
Map.lookup _rrfiRemoteSchemaName remoteSchemaCache
|
||||
`onNothing` throw500 ("invalid remote schema name: " <>> _rrfiRemoteSchemaName)
|
||||
@ -188,13 +188,13 @@ remoteRelationshipToSourceField ::
|
||||
remoteRelationshipToSourceField sourceCache RemoteSourceFieldInfo {..} =
|
||||
withTypenameCustomization (mkCustomizedTypename (Just _rsfiSourceCustomization) HasuraCase) do
|
||||
tCase <- asks getter
|
||||
roleName <- retrieve scRole
|
||||
sourceInfo <-
|
||||
onNothing (unsafeSourceInfo @tgt =<< Map.lookup _rsfiSource sourceCache) $
|
||||
throw500 $ "source not found " <> dquote _rsfiSource
|
||||
tableInfo <- askTableInfo sourceInfo _rsfiTable
|
||||
fieldName <- textToName $ relNameToTxt _rsfiName
|
||||
maybePerms <- tableSelectPermissions @tgt tableInfo
|
||||
case maybePerms of
|
||||
case tableSelectPermissions @tgt roleName tableInfo of
|
||||
Nothing -> pure []
|
||||
Just tablePerms -> do
|
||||
parsers <- case _rsfiType of
|
||||
|
@ -104,7 +104,8 @@ defaultSelectTable ::
|
||||
m (Maybe (FieldParser n (SelectExp b)))
|
||||
defaultSelectTable sourceInfo tableInfo fieldName description = runMaybeT do
|
||||
tCase <- asks getter
|
||||
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
|
||||
roleName <- retrieve scRole
|
||||
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
|
||||
selectionSetParser <- MaybeT $ tableSelectionList sourceInfo tableInfo
|
||||
lift $ memoizeOn 'defaultSelectTable (_siName sourceInfo, tableName, fieldName) do
|
||||
stringifyNumbers <- retrieve Options.soStringifyNumbers
|
||||
@ -160,8 +161,9 @@ selectTableConnection ::
|
||||
m (Maybe (FieldParser n (ConnectionSelectExp b)))
|
||||
selectTableConnection sourceInfo tableInfo fieldName description pkeyColumns = runMaybeT do
|
||||
tCase <- asks getter
|
||||
roleName <- retrieve scRole
|
||||
xRelayInfo <- hoistMaybe $ relayExtension @b
|
||||
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
|
||||
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
|
||||
selectionSetParser <- fmap P.nonNullableParser <$> MaybeT $ tableConnectionSelectionSet sourceInfo tableInfo
|
||||
lift $ memoizeOn 'selectTableConnection (_siName sourceInfo, tableName, fieldName) do
|
||||
stringifyNumbers <- retrieve Options.soStringifyNumbers
|
||||
@ -210,7 +212,8 @@ selectTableByPk ::
|
||||
m (Maybe (FieldParser n (SelectExp b)))
|
||||
selectTableByPk sourceInfo tableInfo fieldName description = runMaybeT do
|
||||
tCase <- asks getter
|
||||
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
|
||||
roleName <- retrieve scRole
|
||||
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
|
||||
primaryKeys <- hoistMaybe $ fmap _pkColumns . _tciPrimaryKey . _tiCoreInfo $ tableInfo
|
||||
selectionSetParser <- MaybeT $ tableSelectionSet sourceInfo tableInfo
|
||||
guard $ all (\c -> ciColumn c `Map.member` spiCols selectPermissions) primaryKeys
|
||||
@ -264,7 +267,8 @@ defaultSelectTableAggregate ::
|
||||
m (Maybe (FieldParser n (AggSelectExp b)))
|
||||
defaultSelectTableAggregate sourceInfo tableInfo fieldName description = runMaybeT $ do
|
||||
tCase <- asks getter
|
||||
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
|
||||
roleName <- retrieve scRole
|
||||
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
|
||||
guard $ spiAllowAgg selectPermissions
|
||||
xNodesAgg <- hoistMaybe $ nodesAggExtension @b
|
||||
nodesParser <- MaybeT $ tableSelectionList sourceInfo tableInfo
|
||||
@ -371,7 +375,8 @@ defaultTableSelectionSet ::
|
||||
TableInfo b ->
|
||||
m (Maybe (Parser 'Output n (AnnotatedFields b)))
|
||||
defaultTableSelectionSet sourceInfo tableInfo = runMaybeT do
|
||||
_selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
|
||||
roleName <- retrieve scRole
|
||||
_selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
|
||||
schemaKind <- lift $ retrieve scSchemaKind
|
||||
-- If this check fails, it means we're attempting to build a Relay schema, but
|
||||
-- the current backend b does't support Relay; rather than returning an
|
||||
@ -475,8 +480,9 @@ tableConnectionSelectionSet ::
|
||||
TableInfo b ->
|
||||
m (Maybe (Parser 'Output n (ConnectionFields b)))
|
||||
tableConnectionSelectionSet sourceInfo tableInfo = runMaybeT do
|
||||
roleName <- retrieve scRole
|
||||
tableGQLName <- lift $ getTableGQLName tableInfo
|
||||
_selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
|
||||
void $ hoistMaybe $ tableSelectPermissions roleName tableInfo
|
||||
edgesParser <- MaybeT $ tableEdgesSelectionSet tableGQLName
|
||||
lift $ memoizeOn 'tableConnectionSelectionSet (_siName sourceInfo, tableName) do
|
||||
connectionTypeName <- mkTypename $ tableGQLName <> Name._Connection
|
||||
@ -973,6 +979,7 @@ fieldSelection ::
|
||||
fieldSelection sourceInfo table tableInfo = \case
|
||||
FIColumn columnInfo ->
|
||||
maybeToList <$> runMaybeT do
|
||||
roleName <- retrieve scRole
|
||||
schemaKind <- retrieve scSchemaKind
|
||||
let fieldName = ciName columnInfo
|
||||
-- If the field name is 'id' and we're building a schema for the Relay
|
||||
@ -980,7 +987,7 @@ fieldSelection sourceInfo table tableInfo = \case
|
||||
-- ignore the original.
|
||||
guard $ isHasuraSchema schemaKind || fieldName /= Name._id
|
||||
let columnName = ciColumn columnInfo
|
||||
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
|
||||
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
|
||||
guard $ columnName `Map.member` spiCols selectPermissions
|
||||
let caseBoolExp = join $ Map.lookup columnName (spiCols selectPermissions)
|
||||
caseBoolExpUnpreparedValue =
|
||||
@ -1124,15 +1131,16 @@ relationshipField ::
|
||||
m (Maybe [FieldParser n (AnnotatedField b)])
|
||||
relationshipField sourceInfo table ri = runMaybeT do
|
||||
tCase <- asks getter
|
||||
roleName <- retrieve scRole
|
||||
optimizePermissionFilters <- retrieve Options.soOptimizePermissionFilters
|
||||
tableInfo <- lift $ askTableInfo sourceInfo table
|
||||
otherTableInfo <- lift $ askTableInfo sourceInfo $ riRTable ri
|
||||
remotePerms <- MaybeT $ tableSelectPermissions otherTableInfo
|
||||
tablePerms <- hoistMaybe $ tableSelectPermissions roleName tableInfo
|
||||
remotePerms <- hoistMaybe $ tableSelectPermissions roleName otherTableInfo
|
||||
relFieldName <- lift $ textToName $ relNameToTxt $ riName ri
|
||||
-- START black magic to deduplicate permission checks
|
||||
thisTablePerm <-
|
||||
IR._tpFilter . tablePermissionsInfo
|
||||
<$> MaybeT (tableSelectPermissions =<< askTableInfo sourceInfo table)
|
||||
let deduplicatePermissions :: AnnBoolExp b (IR.UnpreparedValue b) -> AnnBoolExp b (IR.UnpreparedValue b)
|
||||
let thisTablePerm = IR._tpFilter $ tablePermissionsInfo tablePerms
|
||||
deduplicatePermissions :: AnnBoolExp b (IR.UnpreparedValue b) -> AnnBoolExp b (IR.UnpreparedValue b)
|
||||
deduplicatePermissions x =
|
||||
case (optimizePermissionFilters, x) of
|
||||
(OptimizePermissionFilters, BoolAnd [BoolField (AVRelationship remoteRI remoteTablePerm)]) ->
|
||||
@ -1192,7 +1200,6 @@ relationshipField sourceInfo table ri = runMaybeT do
|
||||
nullable <- case (riIsManual ri, riInsertOrder ri) of
|
||||
-- Automatically generated forward relationship
|
||||
(False, BeforeParent) -> do
|
||||
tableInfo <- askTableInfo sourceInfo table
|
||||
let columns = Map.keys $ riMapping ri
|
||||
fieldInfoMap = _tciFieldInfoMap $ _tiCoreInfo tableInfo
|
||||
findColumn col = Map.lookup (fromCol @b col) fieldInfoMap ^? _Just . _FIColumn
|
||||
|
@ -250,7 +250,8 @@ selectStreamTable ::
|
||||
Maybe G.Description ->
|
||||
m (Maybe (P.FieldParser n (StreamSelectExp b)))
|
||||
selectStreamTable sourceInfo tableInfo fieldName description = runMaybeT $ do
|
||||
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
|
||||
roleName <- retrieve scRole
|
||||
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
|
||||
xStreamSubscription <- hoistMaybe $ streamSubscriptionExtension @b
|
||||
stringifyNumbers <- retrieve Options.soStringifyNumbers
|
||||
tableStreamArgsParser <- lift $ tableStreamArguments sourceInfo tableInfo
|
||||
|
@ -4,7 +4,6 @@ module Hasura.GraphQL.Schema.Table
|
||||
tableSelectColumnsEnum,
|
||||
tableUpdateColumnsEnum,
|
||||
updateColumnsPlaceholderParser,
|
||||
tablePermissions,
|
||||
tableSelectPermissions,
|
||||
tableSelectFields,
|
||||
tableColumns,
|
||||
@ -119,13 +118,13 @@ tableUpdateColumnsEnum ::
|
||||
TableInfo b ->
|
||||
m (Maybe (Parser 'Both n (Column b)))
|
||||
tableUpdateColumnsEnum tableInfo = do
|
||||
roleName <- retrieve scRole
|
||||
tableGQLName <- getTableGQLName tableInfo
|
||||
columns <- tableUpdateColumns tableInfo
|
||||
enumName <- mkTypename $ tableGQLName <> Name.__update_column
|
||||
let tableName = tableInfoName tableInfo
|
||||
enumDesc = Just $ G.Description $ "update columns of table " <>> tableName
|
||||
enumValues = do
|
||||
column <- columns
|
||||
column <- tableUpdateColumns roleName tableInfo
|
||||
pure (define $ ciName column, ciColumn column)
|
||||
pure $ P.enum enumName enumDesc <$> nonEmpty enumValues
|
||||
where
|
||||
@ -152,52 +151,40 @@ updateColumnsPlaceholderParser tableInfo = do
|
||||
Nothing
|
||||
)
|
||||
|
||||
tablePermissions ::
|
||||
forall b r m.
|
||||
(MonadReader r m, Has RoleName r) =>
|
||||
TableInfo b ->
|
||||
m (RolePermInfo b)
|
||||
tablePermissions tableInfo = do
|
||||
roleName <- asks getter
|
||||
pure $ getRolePermInfo roleName tableInfo
|
||||
|
||||
tableSelectPermissions ::
|
||||
forall b r m.
|
||||
(MonadReader r m, Has RoleName r) =>
|
||||
TableInfo b ->
|
||||
m (Maybe (SelPermInfo b))
|
||||
tableSelectPermissions tableInfo = _permSel <$> tablePermissions tableInfo
|
||||
tableSelectPermissions :: RoleName -> TableInfo b -> Maybe (SelPermInfo b)
|
||||
tableSelectPermissions role tableInfo = _permSel $ getRolePermInfo role tableInfo
|
||||
|
||||
tableSelectFields ::
|
||||
forall b r m.
|
||||
( Backend b,
|
||||
MonadError QErr m,
|
||||
MonadReader r m,
|
||||
Has RoleName r
|
||||
Has SchemaContext r
|
||||
) =>
|
||||
SourceInfo b ->
|
||||
TableInfo b ->
|
||||
m [FieldInfo b]
|
||||
tableSelectFields sourceInfo tableInfo = do
|
||||
roleName <- retrieve scRole
|
||||
let tableFields = _tciFieldInfoMap . _tiCoreInfo $ tableInfo
|
||||
permissions <- tableSelectPermissions tableInfo
|
||||
filterM (canBeSelected permissions) $ Map.elems tableFields
|
||||
permissions = tableSelectPermissions roleName tableInfo
|
||||
filterM (canBeSelected roleName permissions) $ Map.elems tableFields
|
||||
where
|
||||
canBeSelected Nothing _ = pure False
|
||||
canBeSelected (Just permissions) (FIColumn columnInfo) =
|
||||
canBeSelected _ Nothing _ = pure False
|
||||
canBeSelected _ (Just permissions) (FIColumn columnInfo) =
|
||||
pure $ Map.member (ciColumn columnInfo) (spiCols permissions)
|
||||
canBeSelected _ (FIRelationship relationshipInfo) = do
|
||||
canBeSelected role _ (FIRelationship relationshipInfo) = do
|
||||
tableInfo' <- askTableInfo sourceInfo $ riRTable relationshipInfo
|
||||
isJust <$> tableSelectPermissions @b tableInfo'
|
||||
canBeSelected (Just permissions) (FIComputedField computedFieldInfo) =
|
||||
pure $ isJust $ tableSelectPermissions @b role tableInfo'
|
||||
canBeSelected role (Just permissions) (FIComputedField computedFieldInfo) =
|
||||
case computedFieldReturnType @b (_cfiReturnType computedFieldInfo) of
|
||||
ReturnsScalar _ ->
|
||||
pure $ Map.member (_cfiName computedFieldInfo) $ spiComputedFields permissions
|
||||
ReturnsTable tableName -> do
|
||||
tableInfo' <- askTableInfo sourceInfo tableName
|
||||
isJust <$> tableSelectPermissions @b tableInfo'
|
||||
pure $ isJust $ tableSelectPermissions @b role tableInfo'
|
||||
ReturnsOthers -> pure False
|
||||
canBeSelected _ (FIRemoteRelationship _) = pure True
|
||||
canBeSelected _ _ (FIRemoteRelationship _) = pure True
|
||||
|
||||
tableColumns ::
|
||||
forall b. TableInfo b -> [ColumnInfo b]
|
||||
@ -214,7 +201,7 @@ tableSelectColumns ::
|
||||
( Backend b,
|
||||
MonadError QErr m,
|
||||
MonadReader r m,
|
||||
Has RoleName r
|
||||
Has SchemaContext r
|
||||
) =>
|
||||
SourceInfo b ->
|
||||
TableInfo b ->
|
||||
@ -228,17 +215,14 @@ tableSelectColumns sourceInfo tableInfo =
|
||||
-- | Get the columns of a table that my be updated under the given update
|
||||
-- permissions.
|
||||
tableUpdateColumns ::
|
||||
forall b r m.
|
||||
( Backend b,
|
||||
MonadError QErr m,
|
||||
MonadReader r m,
|
||||
Has RoleName r
|
||||
) =>
|
||||
forall b.
|
||||
Backend b =>
|
||||
RoleName ->
|
||||
TableInfo b ->
|
||||
m [ColumnInfo b]
|
||||
tableUpdateColumns tableInfo = do
|
||||
permissions <- _permUpd <$> tablePermissions tableInfo
|
||||
pure $ filter (isUpdatable permissions) $ tableColumns tableInfo
|
||||
[ColumnInfo b]
|
||||
tableUpdateColumns role tableInfo =
|
||||
let permissions = _permUpd $ getRolePermInfo role tableInfo
|
||||
in filter (isUpdatable permissions) $ tableColumns tableInfo
|
||||
where
|
||||
isUpdatable :: Maybe (UpdPermInfo b) -> ColumnInfo b -> Bool
|
||||
isUpdatable (Just permissions) columnInfo = columnIsUpdatable && columnIsPermitted && columnHasNoPreset
|
||||
|
@ -25,11 +25,11 @@ import Hasura.Base.Error (QErr)
|
||||
import Hasura.Base.ToErrorValue
|
||||
import Hasura.GraphQL.Schema.Backend (BackendSchema (..), BackendTableSelectSchema (..), MonadBuildSchema, columnParser)
|
||||
import Hasura.GraphQL.Schema.BoolExp (boolExp)
|
||||
import Hasura.GraphQL.Schema.Common (Scenario (..), mapField, partialSQLExpToUnpreparedValue)
|
||||
import Hasura.GraphQL.Schema.Common (Scenario (..), SchemaContext (..), mapField, partialSQLExpToUnpreparedValue, retrieve)
|
||||
import Hasura.GraphQL.Schema.Mutation (mutationSelectionSet, primaryKeysArguments)
|
||||
import Hasura.GraphQL.Schema.NamingCase
|
||||
import Hasura.GraphQL.Schema.Parser qualified as P
|
||||
import Hasura.GraphQL.Schema.Table (getTableGQLName, tableColumns, tablePermissions, tableUpdateColumns)
|
||||
import Hasura.GraphQL.Schema.Table (getTableGQLName, tableColumns, tableUpdateColumns)
|
||||
import Hasura.GraphQL.Schema.Typename
|
||||
import Hasura.Prelude
|
||||
import Hasura.RQL.IR.BoolExp (AnnBoolExp, annBoolExpTrue)
|
||||
@ -115,7 +115,8 @@ runUpdateOperator ::
|
||||
runUpdateOperator tableInfo UpdateOperator {..} = do
|
||||
let tableName = tableInfoName tableInfo
|
||||
tableGQLName <- getTableGQLName tableInfo
|
||||
columns <- tableUpdateColumns tableInfo
|
||||
roleName <- retrieve scRole
|
||||
let columns = tableUpdateColumns roleName tableInfo
|
||||
|
||||
let applicableCols :: Maybe (NonEmpty (ColumnInfo b)) =
|
||||
nonEmpty . filter updateOperatorApplicableColumn $ columns
|
||||
@ -271,7 +272,8 @@ updateTable backendUpdate scenario sourceInfo tableInfo fieldName description =
|
||||
whereDesc = "filter the rows which have to be updated"
|
||||
viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
|
||||
guard $ isMutable viIsUpdatable viewInfo
|
||||
updatePerms <- MaybeT $ _permUpd <$> tablePermissions tableInfo
|
||||
roleName <- retrieve scRole
|
||||
updatePerms <- hoistMaybe $ _permUpd $ getRolePermInfo roleName tableInfo
|
||||
-- If we're in a frontend scenario, we should not include backend_only updates
|
||||
-- For more info see Note [Backend only permissions]
|
||||
guard $ not $ scenario == Frontend && upiBackendOnly updatePerms
|
||||
@ -308,7 +310,8 @@ updateTableByPk backendUpdate scenario sourceInfo tableInfo fieldName descriptio
|
||||
tableName = tableInfoName tableInfo
|
||||
viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
|
||||
guard $ isMutable viIsUpdatable viewInfo
|
||||
updatePerms <- MaybeT $ _permUpd <$> tablePermissions tableInfo
|
||||
roleName <- retrieve scRole
|
||||
updatePerms <- hoistMaybe $ _permUpd $ getRolePermInfo roleName tableInfo
|
||||
-- If we're in a frontend scenario, we should not include backend_only updates
|
||||
-- For more info see Note [Backend only permissions]
|
||||
guard $ not $ scenario == Frontend && upiBackendOnly updatePerms
|
||||
|
@ -125,8 +125,7 @@ buildQueryParsers introspection = do
|
||||
-- test, we are free to give 'undefined' for such fields, as they won't be
|
||||
-- evaluated.
|
||||
schemaInfo =
|
||||
( adminRoleName :: RoleName,
|
||||
mempty :: CustomizeRemoteFieldName,
|
||||
( mempty :: CustomizeRemoteFieldName,
|
||||
mempty :: MkTypename,
|
||||
mempty :: MkRootFieldName,
|
||||
HasuraCase :: NamingCase,
|
||||
@ -134,6 +133,7 @@ buildQueryParsers introspection = do
|
||||
SchemaContext
|
||||
HasuraSchema
|
||||
ignoreRemoteRelationship
|
||||
adminRoleName
|
||||
)
|
||||
RemoteSchemaParser query _ _ <-
|
||||
runError $
|
||||
|
@ -25,7 +25,7 @@ import Hasura.GraphQL.Schema.Options qualified as Options
|
||||
import Hasura.GraphQL.Schema.Typename
|
||||
import Hasura.Prelude
|
||||
import Hasura.RQL.Types.SourceCustomization (CustomizeRemoteFieldName, MkRootFieldName)
|
||||
import Hasura.Session (RoleName, adminRoleName)
|
||||
import Hasura.Session (adminRoleName)
|
||||
import Language.Haskell.TH.Syntax qualified as TH
|
||||
import Test.Hspec
|
||||
|
||||
@ -51,13 +51,6 @@ instance Has NamingCase SchemaEnvironment where
|
||||
modifier :: (NamingCase -> NamingCase) -> SchemaEnvironment -> SchemaEnvironment
|
||||
modifier = notImplemented "modifier<Has NamingCase SchemaEnvironment>"
|
||||
|
||||
instance Has RoleName SchemaEnvironment where
|
||||
getter :: SchemaEnvironment -> RoleName
|
||||
getter = const adminRoleName
|
||||
|
||||
modifier :: (RoleName -> RoleName) -> SchemaEnvironment -> SchemaEnvironment
|
||||
modifier = notImplemented "modifier<Has RoleName SchemaEnvironment>"
|
||||
|
||||
instance Has SchemaOptions SchemaEnvironment where
|
||||
getter :: SchemaEnvironment -> SchemaOptions
|
||||
getter =
|
||||
@ -78,7 +71,8 @@ instance Has SchemaContext SchemaEnvironment where
|
||||
const
|
||||
SchemaContext
|
||||
{ scSchemaKind = HasuraSchema,
|
||||
scRemoteRelationshipParserBuilder = ignoreRemoteRelationship
|
||||
scRemoteRelationshipParserBuilder = ignoreRemoteRelationship,
|
||||
scRole = adminRoleName
|
||||
}
|
||||
|
||||
modifier :: (SchemaContext -> SchemaContext) -> SchemaEnvironment -> SchemaEnvironment
|
||||
|
Loading…
Reference in New Issue
Block a user