Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
e41d53eb
Commit
e41d53eb
authored
Nov 21, 2019
by
Francisco Javier López
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add Snippet GraphQL API mutation endpoints
Added mutations for snippets GraphQL API endpoints.
parent
066e01de
Changes
20
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
1355 additions
and
14 deletions
+1355
-14
app/graphql/mutations/snippets/base.rb
app/graphql/mutations/snippets/base.rb
+30
-0
app/graphql/mutations/snippets/create.rb
app/graphql/mutations/snippets/create.rb
+77
-0
app/graphql/mutations/snippets/destroy.rb
app/graphql/mutations/snippets/destroy.rb
+33
-0
app/graphql/mutations/snippets/update.rb
app/graphql/mutations/snippets/update.rb
+54
-0
app/graphql/resolvers/base_resolver.rb
app/graphql/resolvers/base_resolver.rb
+10
-0
app/graphql/types/mutation_type.rb
app/graphql/types/mutation_type.rb
+3
-0
app/graphql/types/snippet_type.rb
app/graphql/types/snippet_type.rb
+2
-2
app/graphql/types/visibility_levels_enum.rb
app/graphql/types/visibility_levels_enum.rb
+9
-0
app/presenters/snippet_presenter.rb
app/presenters/snippet_presenter.rb
+1
-1
changelogs/unreleased/fj-36079-snippet-graphql-endpoints-with-mutations.yml
...sed/fj-36079-snippet-graphql-endpoints-with-mutations.yml
+5
-0
doc/api/graphql/reference/gitlab_schema.graphql
doc/api/graphql/reference/gitlab_schema.graphql
+166
-2
doc/api/graphql/reference/gitlab_schema.json
doc/api/graphql/reference/gitlab_schema.json
+528
-4
doc/api/graphql/reference/index.md
doc/api/graphql/reference/index.md
+25
-1
ee/app/graphql/resolvers/epic_resolver.rb
ee/app/graphql/resolvers/epic_resolver.rb
+1
-1
lib/gitlab/graphql/authorize/authorize_resource.rb
lib/gitlab/graphql/authorize/authorize_resource.rb
+7
-2
spec/graphql/resolvers/base_resolver_spec.rb
spec/graphql/resolvers/base_resolver_spec.rb
+26
-0
spec/graphql/types/snippet_type_spec.rb
spec/graphql/types/snippet_type_spec.rb
+1
-1
spec/requests/api/graphql/mutations/snippets/create_spec.rb
spec/requests/api/graphql/mutations/snippets/create_spec.rb
+144
-0
spec/requests/api/graphql/mutations/snippets/destroy_spec.rb
spec/requests/api/graphql/mutations/snippets/destroy_spec.rb
+89
-0
spec/requests/api/graphql/mutations/snippets/update_spec.rb
spec/requests/api/graphql/mutations/snippets/update_spec.rb
+144
-0
No files found.
app/graphql/mutations/snippets/base.rb
0 → 100644
View file @
e41d53eb
# frozen_string_literal: true
module
Mutations
module
Snippets
class
Base
<
BaseMutation
field
:snippet
,
Types
::
SnippetType
,
null:
true
,
description:
'The snippet after mutation'
private
def
find_object
(
id
:)
GitlabSchema
.
object_from_id
(
id
)
end
def
authorized_resource?
(
snippet
)
Ability
.
allowed?
(
context
[
:current_user
],
ability_for
(
snippet
),
snippet
)
end
def
ability_for
(
snippet
)
"
#{
ability_name
}
_
#{
snippet
.
to_ability_name
}
"
.
to_sym
end
def
ability_name
raise
NotImplementedError
end
end
end
end
app/graphql/mutations/snippets/create.rb
0 → 100644
View file @
e41d53eb
# frozen_string_literal: true
module
Mutations
module
Snippets
class
Create
<
BaseMutation
include
Mutations
::
ResolvesProject
graphql_name
'CreateSnippet'
field
:snippet
,
Types
::
SnippetType
,
null:
true
,
description:
'The snippet after mutation'
argument
:title
,
GraphQL
::
STRING_TYPE
,
required:
true
,
description:
'Title of the snippet'
argument
:file_name
,
GraphQL
::
STRING_TYPE
,
required:
false
,
description:
'File name of the snippet'
argument
:content
,
GraphQL
::
STRING_TYPE
,
required:
true
,
description:
'Content of the snippet'
argument
:description
,
GraphQL
::
STRING_TYPE
,
required:
false
,
description:
'Description of the snippet'
argument
:visibility_level
,
Types
::
VisibilityLevelsEnum
,
description:
'The visibility level of the snippet'
,
required:
true
argument
:project_path
,
GraphQL
::
ID_TYPE
,
required:
false
,
description:
'The project full path the snippet is associated with'
def
resolve
(
args
)
project_path
=
args
.
delete
(
:project_path
)
if
project_path
.
present?
project
=
find_project!
(
project_path:
project_path
)
elsif
!
can_create_personal_snippet?
raise_resource_not_avaiable_error!
end
snippet
=
CreateSnippetService
.
new
(
project
,
context
[
:current_user
],
args
).
execute
{
snippet:
snippet
.
valid?
?
snippet
:
nil
,
errors:
errors_on_object
(
snippet
)
}
end
private
def
find_project!
(
project_path
:)
authorized_find!
(
full_path:
project_path
)
end
def
find_object
(
full_path
:)
resolve_project
(
full_path:
full_path
)
end
def
authorized_resource?
(
project
)
Ability
.
allowed?
(
context
[
:current_user
],
:create_project_snippet
,
project
)
end
def
can_create_personal_snippet?
Ability
.
allowed?
(
context
[
:current_user
],
:create_personal_snippet
)
end
end
end
end
app/graphql/mutations/snippets/destroy.rb
0 → 100644
View file @
e41d53eb
# frozen_string_literal: true
module
Mutations
module
Snippets
class
Destroy
<
Base
graphql_name
'DestroySnippet'
ERROR_MSG
=
'Error deleting the snippet'
argument
:id
,
GraphQL
::
ID_TYPE
,
required:
true
,
description:
'The global id of the snippet to destroy'
def
resolve
(
id
:)
snippet
=
authorized_find!
(
id:
id
)
result
=
snippet
.
destroy
errors
=
result
?
[]
:
[
ERROR_MSG
]
{
errors:
errors
}
end
private
def
ability_name
"admin"
end
end
end
end
app/graphql/mutations/snippets/update.rb
0 → 100644
View file @
e41d53eb
# frozen_string_literal: true
module
Mutations
module
Snippets
class
Update
<
Base
graphql_name
'UpdateSnippet'
argument
:id
,
GraphQL
::
ID_TYPE
,
required:
true
,
description:
'The global id of the snippet to update'
argument
:title
,
GraphQL
::
STRING_TYPE
,
required:
false
,
description:
'Title of the snippet'
argument
:file_name
,
GraphQL
::
STRING_TYPE
,
required:
false
,
description:
'File name of the snippet'
argument
:content
,
GraphQL
::
STRING_TYPE
,
required:
false
,
description:
'Content of the snippet'
argument
:description
,
GraphQL
::
STRING_TYPE
,
required:
false
,
description:
'Description of the snippet'
argument
:visibility_level
,
Types
::
VisibilityLevelsEnum
,
description:
'The visibility level of the snippet'
,
required:
false
def
resolve
(
args
)
snippet
=
authorized_find!
(
id:
args
.
delete
(
:id
))
result
=
UpdateSnippetService
.
new
(
snippet
.
project
,
context
[
:current_user
],
snippet
,
args
).
execute
{
snippet:
result
?
snippet
:
snippet
.
reset
,
errors:
errors_on_object
(
snippet
)
}
end
private
def
ability_name
"update"
end
end
end
end
app/graphql/resolvers/base_resolver.rb
View file @
e41d53eb
...
...
@@ -2,6 +2,8 @@
module
Resolvers
class
BaseResolver
<
GraphQL
::
Schema
::
Resolver
extend
::
Gitlab
::
Utils
::
Override
def
self
.
single
@single
||=
Class
.
new
(
self
)
do
def
resolve
(
**
args
)
...
...
@@ -36,5 +38,13 @@ module Resolvers
# complexity difference is minimal in this case.
[
args
[
:iid
],
args
[
:iids
]].
any?
?
0
:
0.01
end
override
:object
def
object
super
.
tap
do
|
obj
|
# If the field this resolver is used in is wrapped in a presenter, go back to it's subject
break
obj
.
subject
if
obj
.
is_a?
(
Gitlab
::
View
::
Presenter
::
Base
)
end
end
end
end
app/graphql/types/mutation_type.rb
View file @
e41d53eb
...
...
@@ -25,6 +25,9 @@ module Types
mount_mutation
Mutations
::
Todos
::
MarkDone
mount_mutation
Mutations
::
Todos
::
Restore
mount_mutation
Mutations
::
Todos
::
MarkAllDone
mount_mutation
Mutations
::
Snippets
::
Destroy
mount_mutation
Mutations
::
Snippets
::
Update
mount_mutation
Mutations
::
Snippets
::
Create
end
end
...
...
app/graphql/types/snippet_type.rb
View file @
e41d53eb
...
...
@@ -44,8 +44,8 @@ module Types
description:
'Description of the snippet'
,
null:
true
field
:visibility
,
GraphQL
::
STRING_TYPE
,
description:
'Visibility of the snippet'
,
field
:visibility
_level
,
Types
::
VisibilityLevelsEnum
,
description:
'Visibility
Level
of the snippet'
,
null:
false
field
:created_at
,
Types
::
TimeType
,
...
...
app/graphql/types/visibility_levels_enum.rb
0 → 100644
View file @
e41d53eb
# frozen_string_literal: true
module
Types
class
VisibilityLevelsEnum
<
BaseEnum
Gitlab
::
VisibilityLevel
.
string_options
.
each
do
|
name
,
int_value
|
value
name
.
downcase
,
value:
int_value
end
end
end
app/presenters/snippet_presenter.rb
View file @
e41d53eb
...
...
@@ -30,6 +30,6 @@ class SnippetPresenter < Gitlab::View::Presenter::Delegated
end
def
ability_name
(
ability_prefix
)
"
#{
ability_prefix
}
_
#{
snippet
.
class
.
underscor
e
}
"
.
to_sym
"
#{
ability_prefix
}
_
#{
snippet
.
to_ability_nam
e
}
"
.
to_sym
end
end
changelogs/unreleased/fj-36079-snippet-graphql-endpoints-with-mutations.yml
0 → 100644
View file @
e41d53eb
---
title
:
Added Snippets GraphQL mutations
merge_request
:
20956
author
:
type
:
added
doc/api/graphql/reference/gitlab_schema.graphql
View file @
e41d53eb
...
...
@@ -442,6 +442,66 @@ type CreateNotePayload {
note
:
Note
}
"""
Autogenerated input type of CreateSnippet
"""
input
CreateSnippetInput
{
"""
A
unique
identifier
for
the
client
performing
the
mutation
.
"""
clientMutationId
:
String
"""
Content
of
the
snippet
"""
content
:
String
!
"""
Description
of
the
snippet
"""
description
:
String
"""
File
name
of
the
snippet
"""
fileName
:
String
"""
The
project
full
path
the
snippet
is
associated
with
"""
projectPath
:
ID
"""
Title
of
the
snippet
"""
title
:
String
!
"""
The
visibility
level
of
the
snippet
"""
visibilityLevel
:
VisibilityLevelsEnum
!
}
"""
Autogenerated return type of CreateSnippet
"""
type
CreateSnippetPayload
{
"""
A
unique
identifier
for
the
client
performing
the
mutation
.
"""
clientMutationId
:
String
"""
Reasons
why
the
mutation
failed
.
"""
errors
:
[
String
!]!
"""
The
snippet
after
mutation
"""
snippet
:
Snippet
}
type
Design
implements
Noteable
{
diffRefs
:
DiffRefs
!
...
...
@@ -861,6 +921,41 @@ type DestroyNotePayload {
note
:
Note
}
"""
Autogenerated input type of DestroySnippet
"""
input
DestroySnippetInput
{
"""
A
unique
identifier
for
the
client
performing
the
mutation
.
"""
clientMutationId
:
String
"""
The
global
id
of
the
snippet
to
destroy
"""
id
:
ID
!
}
"""
Autogenerated return type of DestroySnippet
"""
type
DestroySnippetPayload
{
"""
A
unique
identifier
for
the
client
performing
the
mutation
.
"""
clientMutationId
:
String
"""
Reasons
why
the
mutation
failed
.
"""
errors
:
[
String
!]!
"""
The
snippet
after
mutation
"""
snippet
:
Snippet
}
type
DetailedStatus
{
detailsPath
:
String
!
favicon
:
String
!
...
...
@@ -3737,9 +3832,11 @@ type Mutation {
createEpic
(
input
:
CreateEpicInput
!):
CreateEpicPayload
createImageDiffNote
(
input
:
CreateImageDiffNoteInput
!):
CreateImageDiffNotePayload
createNote
(
input
:
CreateNoteInput
!):
CreateNotePayload
createSnippet
(
input
:
CreateSnippetInput
!):
CreateSnippetPayload
designManagementDelete
(
input
:
DesignManagementDeleteInput
!):
DesignManagementDeletePayload
designManagementUpload
(
input
:
DesignManagementUploadInput
!):
DesignManagementUploadPayload
destroyNote
(
input
:
DestroyNoteInput
!):
DestroyNotePayload
destroySnippet
(
input
:
DestroySnippetInput
!):
DestroySnippetPayload
epicSetSubscription
(
input
:
EpicSetSubscriptionInput
!):
EpicSetSubscriptionPayload
epicTreeReorder
(
input
:
EpicTreeReorderInput
!):
EpicTreeReorderPayload
issueSetConfidential
(
input
:
IssueSetConfidentialInput
!):
IssueSetConfidentialPayload
...
...
@@ -3757,6 +3854,7 @@ type Mutation {
toggleAwardEmoji
(
input
:
ToggleAwardEmojiInput
!):
ToggleAwardEmojiPayload
updateEpic
(
input
:
UpdateEpicInput
!):
UpdateEpicPayload
updateNote
(
input
:
UpdateNoteInput
!):
UpdateNotePayload
updateSnippet
(
input
:
UpdateSnippetInput
!):
UpdateSnippetPayload
}
"""
...
...
@@ -5396,9 +5494,9 @@ type Snippet implements Noteable {
userPermissions
:
SnippetPermissions
!
"""
Visibility
of
the
snippet
Visibility
Level
of
the
snippet
"""
visibility
:
String
!
visibility
Level
:
VisibilityLevelsEnum
!
"""
Web
URL
of
the
snippet
...
...
@@ -6120,6 +6218,66 @@ type UpdateNotePayload {
note
:
Note
}
"""
Autogenerated input type of UpdateSnippet
"""
input
UpdateSnippetInput
{
"""
A
unique
identifier
for
the
client
performing
the
mutation
.
"""
clientMutationId
:
String
"""
Content
of
the
snippet
"""
content
:
String
"""
Description
of
the
snippet
"""
description
:
String
"""
File
name
of
the
snippet
"""
fileName
:
String
"""
The
global
id
of
the
snippet
to
update
"""
id
:
ID
!
"""
Title
of
the
snippet
"""
title
:
String
"""
The
visibility
level
of
the
snippet
"""
visibilityLevel
:
VisibilityLevelsEnum
}
"""
Autogenerated return type of UpdateSnippet
"""
type
UpdateSnippetPayload
{
"""
A
unique
identifier
for
the
client
performing
the
mutation
.
"""
clientMutationId
:
String
"""
Reasons
why
the
mutation
failed
.
"""
errors
:
[
String
!]!
"""
The
snippet
after
mutation
"""
snippet
:
Snippet
}
scalar
Upload
type
User
{
...
...
@@ -6286,6 +6444,12 @@ type UserPermissions {
createSnippet
:
Boolean
!
}
enum
VisibilityLevelsEnum
{
internal
private
public
}
enum
VisibilityScopesEnum
{
internal
private
...
...
doc/api/graphql/reference/gitlab_schema.json
View file @
e41d53eb
...
...
@@ -6442,8 +6442,8 @@
"deprecationReason"
:
null
},
{
"name"
:
"visibility"
,
"description"
:
"Visibility of the snippet"
,
"name"
:
"visibility
Level
"
,
"description"
:
"Visibility
Level
of the snippet"
,
"args"
:
[
],
...
...
@@ -6451,8 +6451,8 @@
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"
SCALAR
"
,
"name"
:
"
String
"
,
"kind"
:
"
ENUM
"
,
"name"
:
"
VisibilityLevelsEnum
"
,
"ofType"
:
null
}
},
...
...
@@ -6828,6 +6828,35 @@
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
"kind"
:
"ENUM"
,
"name"
:
"VisibilityLevelsEnum"
,
"description"
:
null
,
"fields"
:
null
,
"inputFields"
:
null
,
"interfaces"
:
null
,
"enumValues"
:
[
{
"name"
:
"private"
,
"description"
:
null
,
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"internal"
,
"description"
:
null
,
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"public"
,
"description"
:
null
,
"isDeprecated"
:
false
,
"deprecationReason"
:
null
}
],
"possibleTypes"
:
null
},
{
"kind"
:
"ENUM"
,
"name"
:
"VisibilityScopesEnum"
,
...
...
@@ -15804,6 +15833,33 @@
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"createSnippet"
,
"description"
:
null
,
"args"
:
[
{
"name"
:
"input"
,
"description"
:
null
,
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"INPUT_OBJECT"
,
"name"
:
"CreateSnippetInput"
,
"ofType"
:
null
}
},
"defaultValue"
:
null
}
],
"type"
:
{
"kind"
:
"OBJECT"
,
"name"
:
"CreateSnippetPayload"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"designManagementDelete"
,
"description"
:
null
,
...
...
@@ -15885,6 +15941,33 @@
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"destroySnippet"
,
"description"
:
null
,
"args"
:
[
{
"name"
:
"input"
,
"description"
:
null
,
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"INPUT_OBJECT"
,
"name"
:
"DestroySnippetInput"
,
"ofType"
:
null
}
},
"defaultValue"
:
null
}
],
"type"
:
{
"kind"
:
"OBJECT"
,
"name"
:
"DestroySnippetPayload"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"epicSetSubscription"
,
"description"
:
null
,
...
...
@@ -16343,6 +16426,33 @@
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"updateSnippet"
,
"description"
:
null
,
"args"
:
[
{
"name"
:
"input"
,
"description"
:
null
,
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"INPUT_OBJECT"
,
"name"
:
"UpdateSnippetInput"
,
"ofType"
:
null
}
},
"defaultValue"
:
null
}
],
"type"
:
{
"kind"
:
"OBJECT"
,
"name"
:
"UpdateSnippetPayload"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
}
],
"inputFields"
:
null
,
...
...
@@ -19093,6 +19203,420 @@
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
"kind"
:
"OBJECT"
,
"name"
:
"DestroySnippetPayload"
,
"description"
:
"Autogenerated return type of DestroySnippet"
,
"fields"
:
[
{
"name"
:
"clientMutationId"
,
"description"
:
"A unique identifier for the client performing the mutation."
,
"args"
:
[
],
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"errors"
,
"description"
:
"Reasons why the mutation failed."
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"LIST"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
}
}
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"snippet"
,
"description"
:
"The snippet after mutation"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"OBJECT"
,
"name"
:
"Snippet"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
}
],
"inputFields"
:
null
,
"interfaces"
:
[
],
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
"kind"
:
"INPUT_OBJECT"
,
"name"
:
"DestroySnippetInput"
,
"description"
:
"Autogenerated input type of DestroySnippet"
,
"fields"
:
null
,
"inputFields"
:
[
{
"name"
:
"id"
,
"description"
:
"The global id of the snippet to destroy"
,
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"ID"
,
"ofType"
:
null
}
},
"defaultValue"
:
null
},
{
"name"
:
"clientMutationId"
,
"description"
:
"A unique identifier for the client performing the mutation."
,
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"defaultValue"
:
null
}
],
"interfaces"
:
null
,
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
"kind"
:
"OBJECT"
,
"name"
:
"UpdateSnippetPayload"
,
"description"
:
"Autogenerated return type of UpdateSnippet"
,
"fields"
:
[
{
"name"
:
"clientMutationId"
,
"description"
:
"A unique identifier for the client performing the mutation."
,
"args"
:
[
],
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"errors"
,
"description"
:
"Reasons why the mutation failed."
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"LIST"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
}
}
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"snippet"
,
"description"
:
"The snippet after mutation"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"OBJECT"
,
"name"
:
"Snippet"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
}
],
"inputFields"
:
null
,
"interfaces"
:
[
],
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
"kind"
:
"INPUT_OBJECT"
,
"name"
:
"UpdateSnippetInput"
,
"description"
:
"Autogenerated input type of UpdateSnippet"
,
"fields"
:
null
,
"inputFields"
:
[
{
"name"
:
"id"
,
"description"
:
"The global id of the snippet to update"
,
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"ID"
,
"ofType"
:
null
}
},
"defaultValue"
:
null
},
{
"name"
:
"title"
,
"description"
:
"Title of the snippet"
,
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"defaultValue"
:
null
},
{
"name"
:
"fileName"
,
"description"
:
"File name of the snippet"
,
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"defaultValue"
:
null
},
{
"name"
:
"content"
,
"description"
:
"Content of the snippet"
,
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"defaultValue"
:
null
},
{
"name"
:
"description"
,
"description"
:
"Description of the snippet"
,
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"defaultValue"
:
null
},
{
"name"
:
"visibilityLevel"
,
"description"
:
"The visibility level of the snippet"
,
"type"
:
{
"kind"
:
"ENUM"
,
"name"
:
"VisibilityLevelsEnum"
,
"ofType"
:
null
},
"defaultValue"
:
null
},
{
"name"
:
"clientMutationId"
,
"description"
:
"A unique identifier for the client performing the mutation."
,
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"defaultValue"
:
null
}
],
"interfaces"
:
null
,
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
"kind"
:
"OBJECT"
,
"name"
:
"CreateSnippetPayload"
,
"description"
:
"Autogenerated return type of CreateSnippet"
,
"fields"
:
[
{
"name"
:
"clientMutationId"
,
"description"
:
"A unique identifier for the client performing the mutation."
,
"args"
:
[
],
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"errors"
,
"description"
:
"Reasons why the mutation failed."
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"LIST"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
}
}
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"snippet"
,
"description"
:
"The snippet after mutation"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"OBJECT"
,
"name"
:
"Snippet"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
}
],
"inputFields"
:
null
,
"interfaces"
:
[
],
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
"kind"
:
"INPUT_OBJECT"
,
"name"
:
"CreateSnippetInput"
,
"description"
:
"Autogenerated input type of CreateSnippet"
,
"fields"
:
null
,
"inputFields"
:
[
{
"name"
:
"title"
,
"description"
:
"Title of the snippet"
,
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
}
},
"defaultValue"
:
null
},
{
"name"
:
"fileName"
,
"description"
:
"File name of the snippet"
,
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"defaultValue"
:
null
},
{
"name"
:
"content"
,
"description"
:
"Content of the snippet"
,
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
}
},
"defaultValue"
:
null
},
{
"name"
:
"description"
,
"description"
:
"Description of the snippet"
,
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"defaultValue"
:
null
},
{
"name"
:
"visibilityLevel"
,
"description"
:
"The visibility level of the snippet"
,
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"ENUM"
,
"name"
:
"VisibilityLevelsEnum"
,
"ofType"
:
null
}
},
"defaultValue"
:
null
},
{
"name"
:
"projectPath"
,
"description"
:
"The project full path the snippet is associated with"
,
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"ID"
,
"ofType"
:
null
},
"defaultValue"
:
null
},
{
"name"
:
"clientMutationId"
,
"description"
:
"A unique identifier for the client performing the mutation."
,
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"defaultValue"
:
null
}
],
"interfaces"
:
null
,
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
"kind"
:
"OBJECT"
,
"name"
:
"DesignManagementUploadPayload"
,
...
...
doc/api/graphql/reference/index.md
View file @
e41d53eb
...
...
@@ -92,6 +92,14 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
|
`errors`
| String! => Array | Reasons why the mutation failed. |
|
`note`
| Note | The note after mutation |
### CreateSnippetPayload
| Name | Type | Description |
| --- | ---- | ---------- |
|
`clientMutationId`
| String | A unique identifier for the client performing the mutation. |
|
`errors`
| String! => Array | Reasons why the mutation failed. |
|
`snippet`
| Snippet | The snippet after mutation |
### Design
| Name | Type | Description |
...
...
@@ -145,6 +153,14 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
|
`errors`
| String! => Array | Reasons why the mutation failed. |
|
`note`
| Note | The note after mutation |
### DestroySnippetPayload
| Name | Type | Description |
| --- | ---- | ---------- |
|
`clientMutationId`
| String | A unique identifier for the client performing the mutation. |
|
`errors`
| String! => Array | Reasons why the mutation failed. |
|
`snippet`
| Snippet | The snippet after mutation |
### DetailedStatus
| Name | Type | Description |
...
...
@@ -802,7 +818,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
|
`fileName`
| String | File Name of the snippet |
|
`content`
| String! | Content of the snippet |
|
`description`
| String | Description of the snippet |
|
`visibility
`
| String! | Visibility
of the snippet |
|
`visibility
Level`
| VisibilityLevelsEnum! | Visibility Level
of the snippet |
|
`createdAt`
| Time! | Timestamp this snippet was created |
|
`updatedAt`
| Time! | Timestamp this snippet was updated |
|
`webUrl`
| String! | Web URL of the snippet |
...
...
@@ -929,6 +945,14 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
|
`errors`
| String! => Array | Reasons why the mutation failed. |
|
`note`
| Note | The note after mutation |
### UpdateSnippetPayload
| Name | Type | Description |
| --- | ---- | ---------- |
|
`clientMutationId`
| String | A unique identifier for the client performing the mutation. |
|
`errors`
| String! => Array | Reasons why the mutation failed. |
|
`snippet`
| Snippet | The snippet after mutation |
### User
| Name | Type | Description |
...
...
ee/app/graphql/resolvers/epic_resolver.rb
View file @
e41d53eb
...
...
@@ -88,7 +88,7 @@ module Resolvers
# But that's the epic we need in order to scope the find to only children of this epic,
# using the `parent_id`
def
parent
resolver_object
if
resolver_object
.
is_a?
(
Epic
Presenter
)
resolver_object
if
resolver_object
.
is_a?
(
Epic
)
end
def
group
...
...
lib/gitlab/graphql/authorize/authorize_resource.rb
View file @
e41d53eb
...
...
@@ -6,6 +6,8 @@ module Gitlab
module
AuthorizeResource
extend
ActiveSupport
::
Concern
RESOURCE_ACCESS_ERROR
=
"The resource that you are attempting to access does not exist or you don't have permission to perform this action"
class_methods
do
def
required_permissions
# If the `#authorize` call is used on multiple classes, we add the
...
...
@@ -38,8 +40,7 @@ module Gitlab
def
authorize!
(
object
)
unless
authorized_resource?
(
object
)
raise
Gitlab
::
Graphql
::
Errors
::
ResourceNotAvailable
,
"The resource that you are attempting to access does not exist or you don't have permission to perform this action"
raise_resource_not_avaiable_error!
end
end
...
...
@@ -61,6 +62,10 @@ module Gitlab
Ability
.
allowed?
(
current_user
,
ability
,
object
,
scope: :user
)
end
end
def
raise_resource_not_avaiable_error!
raise
Gitlab
::
Graphql
::
Errors
::
ResourceNotAvailable
,
RESOURCE_ACCESS_ERROR
end
end
end
end
...
...
spec/graphql/resolvers/base_resolver_spec.rb
View file @
e41d53eb
...
...
@@ -8,8 +8,12 @@ describe Resolvers::BaseResolver do
let
(
:resolver
)
do
Class
.
new
(
described_class
)
do
def
resolve
(
**
args
)
process
(
object
)
[
args
,
args
]
end
def
process
(
obj
);
end
end
end
...
...
@@ -69,4 +73,26 @@ describe Resolvers::BaseResolver do
expect
(
field
.
to_graphql
.
complexity
.
call
({},
{
sort:
'foo'
,
iids:
[
1
,
2
,
3
]
},
1
)).
to
eq
3
end
end
describe
'#object'
do
let_it_be
(
:user
)
{
create
(
:user
)
}
it
'returns object'
do
expect_next_instance_of
(
resolver
)
do
|
r
|
expect
(
r
).
to
receive
(
:process
).
with
(
user
)
end
resolve
(
resolver
,
obj:
user
)
end
context
'when object is a presenter'
do
it
'returns presented object'
do
expect_next_instance_of
(
resolver
)
do
|
r
|
expect
(
r
).
to
receive
(
:process
).
with
(
user
)
end
resolve
(
resolver
,
obj:
UserPresenter
.
new
(
user
))
end
end
end
end
spec/graphql/types/snippet_type_spec.rb
View file @
e41d53eb
...
...
@@ -6,7 +6,7 @@ describe GitlabSchema.types['Snippet'] do
it
'has the correct fields'
do
expected_fields
=
[
:id
,
:title
,
:project
,
:author
,
:file_name
,
:content
,
:description
,
:visibility
,
:created_at
,
:updated_at
,
:visibility
_level
,
:created_at
,
:updated_at
,
:web_url
,
:raw_url
,
:notes
,
:discussions
,
:user_permissions
,
:description_html
]
...
...
spec/requests/api/graphql/mutations/snippets/create_spec.rb
0 → 100644
View file @
e41d53eb
# frozen_string_literal: true
require
'spec_helper'
describe
'Creating a Snippet'
do
include
GraphqlHelpers
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:project
)
{
create
(
:project
)
}
let
(
:content
)
{
'Initial content'
}
let
(
:description
)
{
'Initial description'
}
let
(
:title
)
{
'Initial title'
}
let
(
:file_name
)
{
'Initial file_name'
}
let
(
:visibility_level
)
{
'public'
}
let
(
:project_path
)
{
nil
}
let
(
:mutation
)
do
variables
=
{
content:
content
,
description:
description
,
visibility_level:
visibility_level
,
file_name:
file_name
,
title:
title
,
project_path:
project_path
}
graphql_mutation
(
:create_snippet
,
variables
)
end
def
mutation_response
graphql_mutation_response
(
:create_snippet
)
end
context
'when the user does not have permission'
do
let
(
:current_user
)
{
nil
}
it_behaves_like
'a mutation that returns top-level errors'
,
errors:
[
Gitlab
::
Graphql
::
Authorize
::
AuthorizeResource
::
RESOURCE_ACCESS_ERROR
]
it
'does not create the Snippet'
do
expect
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
end
.
not_to
change
{
Snippet
.
count
}
end
context
'when user is not authorized in the project'
do
let
(
:project_path
)
{
project
.
full_path
}
it
'does not create the snippet when the user is not authorized'
do
expect
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
end
.
not_to
change
{
Snippet
.
count
}
end
end
end
context
'when the user has permission'
do
let
(
:current_user
)
{
user
}
context
'with PersonalSnippet'
do
it
'creates the Snippet'
do
expect
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
end
.
to
change
{
Snippet
.
count
}.
by
(
1
)
end
it
'returns the created Snippet'
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
expect
(
mutation_response
[
'snippet'
][
'content'
]).
to
eq
(
content
)
expect
(
mutation_response
[
'snippet'
][
'title'
]).
to
eq
(
title
)
expect
(
mutation_response
[
'snippet'
][
'description'
]).
to
eq
(
description
)
expect
(
mutation_response
[
'snippet'
][
'fileName'
]).
to
eq
(
file_name
)
expect
(
mutation_response
[
'snippet'
][
'visibilityLevel'
]).
to
eq
(
visibility_level
)
expect
(
mutation_response
[
'snippet'
][
'project'
]).
to
be_nil
end
end
context
'with ProjectSnippet'
do
let
(
:project_path
)
{
project
.
full_path
}
before
do
project
.
add_developer
(
current_user
)
end
it
'creates the Snippet'
do
expect
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
end
.
to
change
{
Snippet
.
count
}.
by
(
1
)
end
it
'returns the created Snippet'
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
expect
(
mutation_response
[
'snippet'
][
'content'
]).
to
eq
(
content
)
expect
(
mutation_response
[
'snippet'
][
'title'
]).
to
eq
(
title
)
expect
(
mutation_response
[
'snippet'
][
'description'
]).
to
eq
(
description
)
expect
(
mutation_response
[
'snippet'
][
'fileName'
]).
to
eq
(
file_name
)
expect
(
mutation_response
[
'snippet'
][
'visibilityLevel'
]).
to
eq
(
visibility_level
)
expect
(
mutation_response
[
'snippet'
][
'project'
][
'fullPath'
]).
to
eq
(
project_path
)
end
context
'when the project path is invalid'
do
let
(
:project_path
)
{
'foobar'
}
it
'returns an an error'
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
errors
=
json_response
[
'errors'
]
expect
(
errors
.
first
[
'message'
]).
to
eq
(
Gitlab
::
Graphql
::
Authorize
::
AuthorizeResource
::
RESOURCE_ACCESS_ERROR
)
end
end
context
'when the feature is disabled'
do
it
'returns an an error'
do
project
.
project_feature
.
update_attribute
(
:snippets_access_level
,
ProjectFeature
::
DISABLED
)
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
errors
=
json_response
[
'errors'
]
expect
(
errors
.
first
[
'message'
]).
to
eq
(
Gitlab
::
Graphql
::
Authorize
::
AuthorizeResource
::
RESOURCE_ACCESS_ERROR
)
end
end
end
context
'when there are ActiveRecord validation errors'
do
let
(
:title
)
{
''
}
it_behaves_like
'a mutation that returns errors in the response'
,
errors:
[
"Title can't be blank"
]
it
'does not create the Snippet'
do
expect
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
end
.
not_to
change
{
Snippet
.
count
}
end
it
'does not return Snippet'
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
expect
(
mutation_response
[
'snippet'
]).
to
be_nil
end
end
end
end
spec/requests/api/graphql/mutations/snippets/destroy_spec.rb
0 → 100644
View file @
e41d53eb
# frozen_string_literal: true
require
'spec_helper'
describe
'Destroying a Snippet'
do
include
GraphqlHelpers
let
(
:current_user
)
{
snippet
.
author
}
let
(
:mutation
)
do
variables
=
{
id:
snippet
.
to_global_id
.
to_s
}
graphql_mutation
(
:destroy_snippet
,
variables
)
end
def
mutation_response
graphql_mutation_response
(
:destroy_snippet
)
end
shared_examples
'graphql delete actions'
do
context
'when the user does not have permission'
do
let
(
:current_user
)
{
create
(
:user
)
}
it_behaves_like
'a mutation that returns top-level errors'
,
errors:
[
Gitlab
::
Graphql
::
Authorize
::
AuthorizeResource
::
RESOURCE_ACCESS_ERROR
]
it
'does not destroy the Snippet'
do
expect
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
end
.
not_to
change
{
Snippet
.
count
}
end
end
context
'when the user has permission'
do
it
'destroys the Snippet'
do
expect
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
end
.
to
change
{
Snippet
.
count
}.
by
(
-
1
)
end
it
'returns an empty Snippet'
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
expect
(
mutation_response
).
to
have_key
(
'snippet'
)
expect
(
mutation_response
[
'snippet'
]).
to
be_nil
end
end
end
describe
'PersonalSnippet'
do
it_behaves_like
'graphql delete actions'
do
let_it_be
(
:snippet
)
{
create
(
:personal_snippet
)
}
end
end
describe
'ProjectSnippet'
do
let_it_be
(
:project
)
{
create
(
:project
,
:private
)
}
let_it_be
(
:snippet
)
{
create
(
:project_snippet
,
:private
,
project:
project
,
author:
create
(
:user
))
}
context
'when the author is not a member of the project'
do
it
'returns an an error'
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
errors
=
json_response
[
'errors'
]
expect
(
errors
.
first
[
'message'
]).
to
eq
(
Gitlab
::
Graphql
::
Authorize
::
AuthorizeResource
::
RESOURCE_ACCESS_ERROR
)
end
end
context
'when the author is a member of the project'
do
before
do
project
.
add_developer
(
current_user
)
end
it_behaves_like
'graphql delete actions'
context
'when the snippet project feature is disabled'
do
it
'returns an an error'
do
project
.
project_feature
.
update_attribute
(
:snippets_access_level
,
ProjectFeature
::
DISABLED
)
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
errors
=
json_response
[
'errors'
]
expect
(
errors
.
first
[
'message'
]).
to
eq
(
Gitlab
::
Graphql
::
Authorize
::
AuthorizeResource
::
RESOURCE_ACCESS_ERROR
)
end
end
end
end
end
spec/requests/api/graphql/mutations/snippets/update_spec.rb
0 → 100644
View file @
e41d53eb
# frozen_string_literal: true
require
'spec_helper'
describe
'Updating a Snippet'
do
include
GraphqlHelpers
let_it_be
(
:original_content
)
{
'Initial content'
}
let_it_be
(
:original_description
)
{
'Initial description'
}
let_it_be
(
:original_title
)
{
'Initial title'
}
let_it_be
(
:original_file_name
)
{
'Initial file_name'
}
let
(
:updated_content
)
{
'Updated content'
}
let
(
:updated_description
)
{
'Updated description'
}
let
(
:updated_title
)
{
'Updated_title'
}
let
(
:updated_file_name
)
{
'Updated file_name'
}
let
(
:current_user
)
{
snippet
.
author
}
let
(
:mutation
)
do
variables
=
{
id:
GitlabSchema
.
id_from_object
(
snippet
).
to_s
,
content:
updated_content
,
description:
updated_description
,
visibility_level:
'public'
,
file_name:
updated_file_name
,
title:
updated_title
}
graphql_mutation
(
:update_snippet
,
variables
)
end
def
mutation_response
graphql_mutation_response
(
:update_snippet
)
end
shared_examples
'graphql update actions'
do
context
'when the user does not have permission'
do
let
(
:current_user
)
{
create
(
:user
)
}
it_behaves_like
'a mutation that returns top-level errors'
,
errors:
[
Gitlab
::
Graphql
::
Authorize
::
AuthorizeResource
::
RESOURCE_ACCESS_ERROR
]
it
'does not update the Snippet'
do
expect
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
end
.
not_to
change
{
snippet
.
reload
}
end
end
context
'when the user has permission'
do
it
'updates the Snippet'
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
expect
(
snippet
.
reload
.
title
).
to
eq
(
updated_title
)
end
it
'returns the updated Snippet'
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
expect
(
mutation_response
[
'snippet'
][
'content'
]).
to
eq
(
updated_content
)
expect
(
mutation_response
[
'snippet'
][
'title'
]).
to
eq
(
updated_title
)
expect
(
mutation_response
[
'snippet'
][
'description'
]).
to
eq
(
updated_description
)
expect
(
mutation_response
[
'snippet'
][
'fileName'
]).
to
eq
(
updated_file_name
)
expect
(
mutation_response
[
'snippet'
][
'visibilityLevel'
]).
to
eq
(
'public'
)
end
context
'when there are ActiveRecord validation errors'
do
let
(
:updated_title
)
{
''
}
it_behaves_like
'a mutation that returns errors in the response'
,
errors:
[
"Title can't be blank"
]
it
'does not update the Snippet'
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
expect
(
snippet
.
reload
.
title
).
to
eq
(
original_title
)
end
it
'returns the Snippet with its original values'
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
expect
(
mutation_response
[
'snippet'
][
'content'
]).
to
eq
(
original_content
)
expect
(
mutation_response
[
'snippet'
][
'title'
]).
to
eq
(
original_title
)
expect
(
mutation_response
[
'snippet'
][
'description'
]).
to
eq
(
original_description
)
expect
(
mutation_response
[
'snippet'
][
'fileName'
]).
to
eq
(
original_file_name
)
expect
(
mutation_response
[
'snippet'
][
'visibilityLevel'
]).
to
eq
(
'private'
)
end
end
end
end
describe
'PersonalSnippet'
do
it_behaves_like
'graphql update actions'
do
let_it_be
(
:snippet
)
do
create
(
:personal_snippet
,
:private
,
file_name:
original_file_name
,
title:
original_title
,
content:
original_content
,
description:
original_description
)
end
end
end
describe
'ProjectSnippet'
do
let_it_be
(
:project
)
{
create
(
:project
,
:private
)
}
let_it_be
(
:snippet
)
do
create
(
:project_snippet
,
:private
,
project:
project
,
author:
create
(
:user
),
file_name:
original_file_name
,
title:
original_title
,
content:
original_content
,
description:
original_description
)
end
context
'when the author is not a member of the project'
do
it
'returns an an error'
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
errors
=
json_response
[
'errors'
]
expect
(
errors
.
first
[
'message'
]).
to
eq
(
Gitlab
::
Graphql
::
Authorize
::
AuthorizeResource
::
RESOURCE_ACCESS_ERROR
)
end
end
context
'when the author is a member of the project'
do
before
do
project
.
add_developer
(
current_user
)
end
it_behaves_like
'graphql update actions'
context
'when the snippet project feature is disabled'
do
it
'returns an an error'
do
project
.
project_feature
.
update_attribute
(
:snippets_access_level
,
ProjectFeature
::
DISABLED
)
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
errors
=
json_response
[
'errors'
]
expect
(
errors
.
first
[
'message'
]).
to
eq
(
Gitlab
::
Graphql
::
Authorize
::
AuthorizeResource
::
RESOURCE_ACCESS_ERROR
)
end
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment