Browse Source

Permission fixes.

pull/636/head
Sebastian 5 years ago
parent
commit
dd6af0eb63
  1. 196
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentActions.cs
  2. 10
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Extensions.cs
  3. 290
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLMutationTests.cs
  4. 2
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs

196
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentActions.cs

@ -16,44 +16,14 @@ using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives; using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Json.Objects;
using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Shared;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
internal static class ContentActions internal static class ContentActions
{ {
private static readonly QueryArgument Id = new QueryArgument(AllTypes.None)
{
Name = "id",
Description = "The id of the content (usually GUID).",
DefaultValue = null,
ResolvedType = AllTypes.NonNullDomainId
};
private static readonly QueryArgument NewId = new QueryArgument(AllTypes.None)
{
Name = "id",
Description = "The optional custom content id.",
DefaultValue = null,
ResolvedType = AllTypes.String
};
private static readonly QueryArgument ExpectedVersion = new QueryArgument(AllTypes.None)
{
Name = "expectedVersion",
Description = "The expected version",
DefaultValue = EtagVersion.Any,
ResolvedType = AllTypes.Int
};
private static readonly QueryArgument Publish = new QueryArgument(AllTypes.None)
{
Name = "publish",
Description = "Set to true to autopublish content on create.",
DefaultValue = false,
ResolvedType = AllTypes.Boolean
};
public static class Json public static class Json
{ {
public static readonly QueryArguments Arguments = new QueryArguments public static readonly QueryArguments Arguments = new QueryArguments
@ -95,7 +65,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
public static readonly QueryArguments Arguments = new QueryArguments public static readonly QueryArguments Arguments = new QueryArguments
{ {
Id, new QueryArgument(AllTypes.None)
{
Name = "id",
Description = "The id of the content (usually GUID).",
DefaultValue = null,
ResolvedType = AllTypes.NonNullDomainId
},
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.None)
{ {
Name = "version", Name = "version",
@ -191,11 +167,24 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
DefaultValue = null, DefaultValue = null,
ResolvedType = new NonNullGraphType(inputType) ResolvedType = new NonNullGraphType(inputType)
}, },
Publish, NewId new QueryArgument(AllTypes.None)
{
Name = "publish",
Description = "Set to true to autopublish content on create.",
DefaultValue = false,
ResolvedType = AllTypes.Boolean
},
new QueryArgument(AllTypes.None)
{
Name = "id",
Description = "The optional custom content id.",
DefaultValue = null,
ResolvedType = AllTypes.String
}
}; };
} }
public static readonly IFieldResolver Resolver = ResolveAsync(c => public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsCreate, c =>
{ {
var contentPublish = c.GetArgument<bool>("publish"); var contentPublish = c.GetArgument<bool>("publish");
var contentData = GetContentData(c); var contentData = GetContentData(c);
@ -220,7 +209,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
return new QueryArguments return new QueryArguments
{ {
Id, new QueryArgument(AllTypes.None)
{
Name = "id",
Description = "The id of the content (usually GUID).",
DefaultValue = null,
ResolvedType = AllTypes.NonNullDomainId
},
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.None)
{ {
Name = "data", Name = "data",
@ -228,12 +223,24 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
DefaultValue = null, DefaultValue = null,
ResolvedType = new NonNullGraphType(inputType) ResolvedType = new NonNullGraphType(inputType)
}, },
Publish, new QueryArgument(AllTypes.None)
ExpectedVersion {
Name = "publish",
Description = "Set to true to autopublish content on create.",
DefaultValue = false,
ResolvedType = AllTypes.Boolean
},
new QueryArgument(AllTypes.None)
{
Name = "expectedVersion",
Description = "The expected version",
DefaultValue = EtagVersion.Any,
ResolvedType = AllTypes.Int
}
}; };
} }
public static readonly IFieldResolver Resolver = ResolveAsync(c => public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsUpsert, c =>
{ {
var contentPublish = c.GetArgument<bool>("publish"); var contentPublish = c.GetArgument<bool>("publish");
var contentData = GetContentData(c); var contentData = GetContentData(c);
@ -251,7 +258,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
return new QueryArguments return new QueryArguments
{ {
Id, new QueryArgument(AllTypes.None)
{
Name = "id",
Description = "The optional custom content id.",
DefaultValue = null,
ResolvedType = AllTypes.String
},
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.None)
{ {
Name = "data", Name = "data",
@ -259,11 +272,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
DefaultValue = null, DefaultValue = null,
ResolvedType = new NonNullGraphType(inputType) ResolvedType = new NonNullGraphType(inputType)
}, },
ExpectedVersion new QueryArgument(AllTypes.None)
{
Name = "expectedVersion",
Description = "The expected version",
DefaultValue = EtagVersion.Any,
ResolvedType = AllTypes.Int
}
}; };
} }
public static readonly IFieldResolver Resolver = ResolveAsync(c => public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsUpdateOwn, c =>
{ {
var contentId = c.GetArgument<DomainId>("id"); var contentId = c.GetArgument<DomainId>("id");
var contentData = GetContentData(c); var contentData = GetContentData(c);
@ -278,7 +297,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
return new QueryArguments return new QueryArguments
{ {
Id, new QueryArgument(AllTypes.None)
{
Name = "id",
Description = "The optional custom content id.",
DefaultValue = null,
ResolvedType = AllTypes.String
},
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.None)
{ {
Name = "data", Name = "data",
@ -286,11 +311,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
DefaultValue = null, DefaultValue = null,
ResolvedType = new NonNullGraphType(inputType) ResolvedType = new NonNullGraphType(inputType)
}, },
ExpectedVersion new QueryArgument(AllTypes.None)
{
Name = "expectedVersion",
Description = "The expected version",
DefaultValue = EtagVersion.Any,
ResolvedType = AllTypes.Int
}
}; };
} }
public static readonly IFieldResolver Resolver = ResolveAsync(c => public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsUpdateOwn, c =>
{ {
var contentId = c.GetArgument<DomainId>("id"); var contentId = c.GetArgument<DomainId>("id");
var contentData = GetContentData(c); var contentData = GetContentData(c);
@ -303,7 +334,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
public static readonly QueryArguments Arguments = new QueryArguments public static readonly QueryArguments Arguments = new QueryArguments
{ {
Id, new QueryArgument(AllTypes.None)
{
Name = "id",
Description = "The id of the content (usually GUID).",
DefaultValue = null,
ResolvedType = AllTypes.NonNullDomainId
},
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.None)
{ {
Name = "status", Name = "status",
@ -318,10 +355,16 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
DefaultValue = null, DefaultValue = null,
ResolvedType = AllTypes.Date ResolvedType = AllTypes.Date
}, },
ExpectedVersion new QueryArgument(AllTypes.None)
{
Name = "expectedVersion",
Description = "The expected version",
DefaultValue = EtagVersion.Any,
ResolvedType = AllTypes.Int
}
}; };
public static readonly IFieldResolver Resolver = ResolveAsync(c => public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsChangeStatusOwn, c =>
{ {
var contentId = c.GetArgument<DomainId>("id"); var contentId = c.GetArgument<DomainId>("id");
var contentStatus = c.GetArgument<Status>("status"); var contentStatus = c.GetArgument<Status>("status");
@ -335,11 +378,23 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
public static readonly QueryArguments Arguments = new QueryArguments public static readonly QueryArguments Arguments = new QueryArguments
{ {
Id, new QueryArgument(AllTypes.None)
ExpectedVersion {
Name = "id",
Description = "The id of the content (usually GUID).",
DefaultValue = null,
ResolvedType = AllTypes.NonNullDomainId
},
new QueryArgument(AllTypes.None)
{
Name = "expectedVersion",
Description = "The expected version",
DefaultValue = EtagVersion.Any,
ResolvedType = AllTypes.Int
}
}; };
public static readonly IFieldResolver Resolver = ResolveAsync(c => public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsDeleteOwn, c =>
{ {
var contentId = c.GetArgument<DomainId>("id"); var contentId = c.GetArgument<DomainId>("id");
@ -354,35 +409,34 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
return source.ToContentData((IComplexGraphType)c.FieldDefinition.Arguments.Find("data").Flatten()); return source.ToContentData((IComplexGraphType)c.FieldDefinition.Arguments.Find("data").Flatten());
} }
private static IFieldResolver ResolveAsync(Func<IResolveFieldContext, ContentCommand> action) private static IFieldResolver ResolveAsync(string permissionId, Func<IResolveFieldContext, ContentCommand> action)
{ {
return Resolvers.Async<object, object>(async (source, fieldContext, context) => return Resolvers.Async<object, object>(async (source, fieldContext, context) =>
{ {
try var schemaId = fieldContext.FieldDefinition.SchemaNamedId();
{
var command = action(fieldContext);
command.AppId = fieldContext.FieldDefinition.AppId(); CheckPermission(permissionId, context, schemaId);
command.SchemaId = fieldContext.FieldDefinition.SchemaNamedId();
command.ExpectedVersion = fieldContext.GetArgument("expectedVersion", EtagVersion.Any);
var commandContext = await context.CommandBus.PublishAsync(command); var contentCommand = action(fieldContext);
return commandContext.PlainResult!; contentCommand.SchemaId = schemaId;
} contentCommand.ExpectedVersion = fieldContext.GetArgument("expectedVersion", EtagVersion.Any);
catch (ValidationException ex)
{
fieldContext.Errors.Add(new ExecutionError(ex.Message));
throw; var commandContext = await context.CommandBus.PublishAsync(contentCommand);
}
catch (DomainException ex)
{
fieldContext.Errors.Add(new ExecutionError(ex.Message));
throw; return commandContext.PlainResult!;
}
}); });
} }
private static void CheckPermission(string permissionId, GraphQLExecutionContext context, NamedId<DomainId> schemaId)
{
var requestContext = context.Context;
var requestPermission = Permissions.ForApp(permissionId, requestContext.App.Name, schemaId.Name);
if (!requestContext.Permissions.Allows(requestPermission))
{
throw new DomainForbiddenException(T.Get("common.errorNoPermission"));
}
}
} }
} }

10
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Extensions.cs

@ -88,16 +88,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
return field.GetMetadata<NamedId<DomainId>>(nameof(SchemaNamedId)); return field.GetMetadata<NamedId<DomainId>>(nameof(SchemaNamedId));
} }
public static FieldType WithAppId(this FieldType field, NamedId<DomainId> value)
{
return field.WithMetadata(nameof(AppId), value);
}
public static NamedId<DomainId> AppId(this FieldType field)
{
return field.GetMetadata<NamedId<DomainId>>(nameof(AppId));
}
private static FieldType WithMetadata(this FieldType field, string key, object value) private static FieldType WithMetadata(this FieldType field, string key, object value)
{ {
if (field is MetadataProvider metadataProvider) if (field is MetadataProvider metadataProvider)

290
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLMutationTests.cs

@ -16,8 +16,10 @@ using Newtonsoft.Json.Linq;
using NodaTime; using NodaTime;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Shared;
using Xunit; using Xunit;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
@ -37,10 +39,49 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
} }
[Fact] [Fact]
public async Task Should_return_single_content_when_creating_content() public async Task Should_return_error_when_user_has_no_permission_to_create()
{ {
var f = new FloatGraphType().ParseValue("12.0"); var query = @"
mutation {
createMySchemaContent(data: { myNumber: { iv: 42 } }) {
id
}
}";
var result = await ExecuteAsync(new GraphQLQuery { Query = query }, Permissions.AppContentsReadOwn);
var expected = new
{
data = new
{
createMySchemaContent = (object?)null,
},
errors = new[]
{
new
{
message = "You do not have the necessary permission.",
locations = new[]
{
new
{
line = 3,
column = 19
}
}
}
}
};
AssertResult(expected, result);
A.CallTo(() => commandBus.PublishAsync(A<ICommand>._))
.MustNotHaveHappened();
}
[Fact]
public async Task Should_return_single_content_when_creating_content()
{
var query = @" var query = @"
mutation { mutation {
createMySchemaContent(data: <DATA>, publish: true) { createMySchemaContent(data: <DATA>, publish: true) {
@ -50,7 +91,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
commandContext.Complete(content); commandContext.Complete(content);
var result = await sut.QueryAsync(requestContext, new GraphQLQuery { Query = query }); var result = await ExecuteAsync(new GraphQLQuery { Query = query }, Permissions.AppContentsCreate);
var expected = new var expected = new
{ {
@ -83,7 +124,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
commandContext.Complete(content); commandContext.Complete(content);
var result = await sut.QueryAsync(requestContext, new GraphQLQuery { Query = query }); var result = await ExecuteAsync(new GraphQLQuery { Query = query }, Permissions.AppContentsCreate);
var expected = new var expected = new
{ {
@ -117,7 +158,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
commandContext.Complete(content); commandContext.Complete(content);
var result = await sut.QueryAsync(requestContext, new GraphQLQuery { Query = query, Inputs = GetInput() }); var result = await ExecuteAsync( new GraphQLQuery { Query = query, Inputs = GetInput() }, Permissions.AppContentsCreate);
var expected = new var expected = new
{ {
@ -138,6 +179,47 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
.MustHaveHappened(); .MustHaveHappened();
} }
[Fact]
public async Task Should_return_error_when_user_has_no_permission_to_update()
{
var query = @"
mutation {
updateMySchemaContent(id: ""<ID>"", data: { myNumber: { iv: 42 } }) {
id
}
}".Replace("<ID>", contentId.ToString());
var result = await ExecuteAsync(new GraphQLQuery { Query = query }, Permissions.AppContentsReadOwn);
var expected = new
{
data = new
{
updateMySchemaContent = (object?)null,
},
errors = new[]
{
new
{
message = "You do not have the necessary permission.",
locations = new[]
{
new
{
line = 3,
column = 19
}
}
}
}
};
AssertResult(expected, result);
A.CallTo(() => commandBus.PublishAsync(A<ICommand>._))
.MustNotHaveHappened();
}
[Fact] [Fact]
public async Task Should_return_single_content_when_updating_content() public async Task Should_return_single_content_when_updating_content()
{ {
@ -150,7 +232,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
commandContext.Complete(content); commandContext.Complete(content);
var result = await sut.QueryAsync(requestContext, new GraphQLQuery { Query = query }); var result = await ExecuteAsync( new GraphQLQuery { Query = query }, Permissions.AppContentsUpdateOwn);
var expected = new var expected = new
{ {
@ -182,7 +264,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
commandContext.Complete(content); commandContext.Complete(content);
var result = await sut.QueryAsync(requestContext, new GraphQLQuery { Query = query, Inputs = GetInput() }); var result = await ExecuteAsync( new GraphQLQuery { Query = query, Inputs = GetInput() }, Permissions.AppContentsUpdateOwn);
var expected = new var expected = new
{ {
@ -202,6 +284,47 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
.MustHaveHappened(); .MustHaveHappened();
} }
[Fact]
public async Task Should_return_error_when_user_has_no_permission_to_upsert()
{
var query = @"
mutation {
upsertMySchemaContent(id: ""<ID>"", data: { myNumber: { iv: 42 } }) {
id
}
}".Replace("<ID>", contentId.ToString());
var result = await ExecuteAsync(new GraphQLQuery { Query = query }, Permissions.AppContentsReadOwn);
var expected = new
{
data = new
{
upsertMySchemaContent = (object?)null,
},
errors = new[]
{
new
{
message = "You do not have the necessary permission.",
locations = new[]
{
new
{
line = 3,
column = 19
}
}
}
}
};
AssertResult(expected, result);
A.CallTo(() => commandBus.PublishAsync(A<ICommand>._))
.MustNotHaveHappened();
}
[Fact] [Fact]
public async Task Should_return_single_content_when_upserting_content() public async Task Should_return_single_content_when_upserting_content()
{ {
@ -214,7 +337,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
commandContext.Complete(content); commandContext.Complete(content);
var result = await sut.QueryAsync(requestContext, new GraphQLQuery { Query = query }); var result = await ExecuteAsync( new GraphQLQuery { Query = query }, Permissions.AppContentsUpsert);
var expected = new var expected = new
{ {
@ -247,7 +370,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
commandContext.Complete(content); commandContext.Complete(content);
var result = await sut.QueryAsync(requestContext, new GraphQLQuery { Query = query, Inputs = GetInput() }); var result = await ExecuteAsync( new GraphQLQuery { Query = query, Inputs = GetInput() }, Permissions.AppContentsUpsert);
var expected = new var expected = new
{ {
@ -268,6 +391,47 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
.MustHaveHappened(); .MustHaveHappened();
} }
[Fact]
public async Task Should_return_error_when_user_has_no_permission_to_patch()
{
var query = @"
mutation {
patchMySchemaContent(id: ""<ID>"", data: { myNumber: { iv: 42 } }) {
id
}
}".Replace("<ID>", contentId.ToString());
var result = await ExecuteAsync(new GraphQLQuery { Query = query }, Permissions.AppContentsReadOwn);
var expected = new
{
data = new
{
patchMySchemaContent = (object?)null,
},
errors = new[]
{
new
{
message = "You do not have the necessary permission.",
locations = new[]
{
new
{
line = 3,
column = 19
}
}
}
}
};
AssertResult(expected, result);
A.CallTo(() => commandBus.PublishAsync(A<ICommand>._))
.MustNotHaveHappened();
}
[Fact] [Fact]
public async Task Should_return_single_content_when_patching_content() public async Task Should_return_single_content_when_patching_content()
{ {
@ -280,7 +444,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
commandContext.Complete(content); commandContext.Complete(content);
var result = await sut.QueryAsync(requestContext, new GraphQLQuery { Query = query }); var result = await ExecuteAsync( new GraphQLQuery { Query = query }, Permissions.AppContentsUpdateOwn);
var expected = new var expected = new
{ {
@ -312,7 +476,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
commandContext.Complete(content); commandContext.Complete(content);
var result = await sut.QueryAsync(requestContext, new GraphQLQuery { Query = query, Inputs = GetInput() }); var result = await ExecuteAsync( new GraphQLQuery { Query = query, Inputs = GetInput() }, Permissions.AppContentsUpdateOwn);
var expected = new var expected = new
{ {
@ -333,7 +497,48 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
} }
[Fact] [Fact]
public async Task Should_publish_command_for_status_change() public async Task Should_return_error_when_user_has_no_permission_to_change_status()
{
var query = @"
mutation {
changeMySchemaContent(id: ""<ID>"", status: ""Published"") {
id
}
}".Replace("<ID>", contentId.ToString());
var result = await ExecuteAsync(new GraphQLQuery { Query = query }, Permissions.AppContentsReadOwn);
var expected = new
{
data = new
{
changeMySchemaContent = (object?)null,
},
errors = new[]
{
new
{
message = "You do not have the necessary permission.",
locations = new[]
{
new
{
line = 3,
column = 19
}
}
}
}
};
AssertResult(expected, result);
A.CallTo(() => commandBus.PublishAsync(A<ICommand>._))
.MustNotHaveHappened();
}
[Fact]
public async Task Should_return_single_content_when_changing_status()
{ {
var dueTime = SystemClock.Instance.GetCurrentInstant().WithoutMs(); var dueTime = SystemClock.Instance.GetCurrentInstant().WithoutMs();
@ -346,7 +551,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
commandContext.Complete(content); commandContext.Complete(content);
var result = await sut.QueryAsync(requestContext, new GraphQLQuery { Query = query }); var result = await ExecuteAsync( new GraphQLQuery { Query = query }, Permissions.AppContentsChangeStatusOwn);
var expected = new var expected = new
{ {
@ -368,7 +573,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
} }
[Fact] [Fact]
public async Task Should_publish_command_for_status_change_without_due_time() public async Task Should_return_single_content_when_changing_status_without_due_time()
{ {
var query = @" var query = @"
mutation { mutation {
@ -379,7 +584,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
commandContext.Complete(content); commandContext.Complete(content);
var result = await sut.QueryAsync(requestContext, new GraphQLQuery { Query = query }); var result = await ExecuteAsync( new GraphQLQuery { Query = query }, Permissions.AppContentsChangeStatusOwn);
var expected = new var expected = new
{ {
@ -401,7 +606,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
} }
[Fact] [Fact]
public async Task Should_publish_command_for_status_change_with_null_due_time() public async Task Should_return_single_content_when_changing_status_with_null_due_time()
{ {
var query = @" var query = @"
mutation { mutation {
@ -412,7 +617,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
commandContext.Complete(content); commandContext.Complete(content);
var result = await sut.QueryAsync(requestContext, new GraphQLQuery { Query = query }); var result = await ExecuteAsync( new GraphQLQuery { Query = query }, Permissions.AppContentsChangeStatusOwn);
var expected = new var expected = new
{ {
@ -434,7 +639,45 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
} }
[Fact] [Fact]
public async Task Should_publish_command_for_delete() public async Task Should_return_error_when_user_has_no_permission_to_delete()
{
var query = @"
mutation {
deleteMySchemaContent(id: ""<ID>"") {
version
}
}".Replace("<ID>", contentId.ToString());
var result = await ExecuteAsync(new GraphQLQuery { Query = query }, Permissions.AppContentsReadOwn);
var expected = new
{
data = (object?)null,
errors = new[]
{
new
{
message = "You do not have the necessary permission.",
locations = new[]
{
new
{
line = 3,
column = 19
}
}
}
}
};
AssertResult(expected, result);
A.CallTo(() => commandBus.PublishAsync(A<ICommand>._))
.MustNotHaveHappened();
}
[Fact]
public async Task Should_return_new_version_when_deleting_content()
{ {
var query = @" var query = @"
mutation { mutation {
@ -445,7 +688,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
commandContext.Complete(new EntitySavedResult(13)); commandContext.Complete(new EntitySavedResult(13));
var result = await sut.QueryAsync(requestContext, new GraphQLQuery { Query = query }); var result = await ExecuteAsync( new GraphQLQuery { Query = query }, Permissions.AppContentsDeleteOwn);
var expected = new var expected = new
{ {
@ -467,6 +710,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
.MustHaveHappened(); .MustHaveHappened();
} }
private Task<(bool HasError, object Response)> ExecuteAsync(GraphQLQuery query, string permissionId)
{
var permission = Permissions.ForApp(permissionId, app.Name, schemaId.Name).Id;
var withPermission = new Context(Mocks.FrontendUser(permission: permission), app);
return sut.QueryAsync(withPermission, query);
}
private Inputs GetInput() private Inputs GetInput()
{ {
var input = new var input = new

2
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs

@ -33,7 +33,7 @@ using Xunit;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
{ {
public class GraphQLTestBase public class GraphQLTestBase : IClassFixture<TranslationsFixture>
{ {
protected readonly IAppEntity app; protected readonly IAppEntity app;
protected readonly IAssetQueryService assetQuery = A.Fake<IAssetQueryService>(); protected readonly IAssetQueryService assetQuery = A.Fake<IAssetQueryService>();

Loading…
Cancel
Save