summaryrefslogtreecommitdiff
path: root/app/graphql/resolvers/design_management
diff options
context:
space:
mode:
Diffstat (limited to 'app/graphql/resolvers/design_management')
-rw-r--r--app/graphql/resolvers/design_management/design_at_version_resolver.rb46
-rw-r--r--app/graphql/resolvers/design_management/design_resolver.rb57
-rw-r--r--app/graphql/resolvers/design_management/designs_resolver.rb50
-rw-r--r--app/graphql/resolvers/design_management/version/design_at_version_resolver.rb95
-rw-r--r--app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb60
-rw-r--r--app/graphql/resolvers/design_management/version_in_collection_resolver.rb45
-rw-r--r--app/graphql/resolvers/design_management/version_resolver.rb25
-rw-r--r--app/graphql/resolvers/design_management/versions_resolver.rb76
8 files changed, 454 insertions, 0 deletions
diff --git a/app/graphql/resolvers/design_management/design_at_version_resolver.rb b/app/graphql/resolvers/design_management/design_at_version_resolver.rb
new file mode 100644
index 00000000000..fd9b349f974
--- /dev/null
+++ b/app/graphql/resolvers/design_management/design_at_version_resolver.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module DesignManagement
+ class DesignAtVersionResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ type Types::DesignManagement::DesignAtVersionType, null: false
+
+ authorize :read_design
+
+ argument :id, GraphQL::ID_TYPE,
+ required: true,
+ description: 'The Global ID of the design at this version'
+
+ def resolve(id:)
+ authorized_find!(id: id)
+ end
+
+ def find_object(id:)
+ dav = GitlabSchema.object_from_id(id, expected_type: ::DesignManagement::DesignAtVersion)
+ return unless consistent?(dav)
+
+ dav
+ end
+
+ def self.single
+ self
+ end
+
+ private
+
+ # If this resolver is mounted on something that has an issue
+ # (such as design collection for instance), then we should check
+ # that the DesignAtVersion as found by its ID does in fact belong
+ # to this issue.
+ def consistent?(dav)
+ issue.nil? || (dav&.design&.issue_id == issue.id)
+ end
+
+ def issue
+ object&.issue
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/design_management/design_resolver.rb b/app/graphql/resolvers/design_management/design_resolver.rb
new file mode 100644
index 00000000000..05bdbbbe407
--- /dev/null
+++ b/app/graphql/resolvers/design_management/design_resolver.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module DesignManagement
+ class DesignResolver < BaseResolver
+ argument :id, GraphQL::ID_TYPE,
+ required: false,
+ description: 'Find a design by its ID'
+
+ argument :filename, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Find a design by its filename'
+
+ def resolve(filename: nil, id: nil)
+ params = parse_args(filename, id)
+
+ build_finder(params).execute.first
+ end
+
+ def self.single
+ self
+ end
+
+ private
+
+ def issue
+ object.issue
+ end
+
+ def build_finder(params)
+ ::DesignManagement::DesignsFinder.new(issue, current_user, params)
+ end
+
+ def error(msg)
+ raise ::Gitlab::Graphql::Errors::ArgumentError, msg
+ end
+
+ def parse_args(filename, id)
+ provided = [filename, id].map(&:present?)
+
+ if provided.none?
+ error('one of id or filename must be passed')
+ elsif provided.all?
+ error('only one of id or filename may be passed')
+ elsif filename.present?
+ { filenames: [filename] }
+ else
+ { ids: [parse_gid(id)] }
+ end
+ end
+
+ def parse_gid(gid)
+ GitlabSchema.parse_gid(gid, expected_type: ::DesignManagement::Design).model_id
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/design_management/designs_resolver.rb b/app/graphql/resolvers/design_management/designs_resolver.rb
new file mode 100644
index 00000000000..81f94d5cb30
--- /dev/null
+++ b/app/graphql/resolvers/design_management/designs_resolver.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module DesignManagement
+ class DesignsResolver < BaseResolver
+ argument :ids,
+ [GraphQL::ID_TYPE],
+ required: false,
+ description: 'Filters designs by their ID'
+ argument :filenames,
+ [GraphQL::STRING_TYPE],
+ required: false,
+ description: 'Filters designs by their filename'
+ argument :at_version,
+ GraphQL::ID_TYPE,
+ required: false,
+ description: 'Filters designs to only those that existed at the version. ' \
+ 'If argument is omitted or nil then all designs will reflect the latest version'
+
+ def self.single
+ ::Resolvers::DesignManagement::DesignResolver
+ end
+
+ def resolve(ids: nil, filenames: nil, at_version: nil)
+ ::DesignManagement::DesignsFinder.new(
+ issue,
+ current_user,
+ ids: design_ids(ids),
+ filenames: filenames,
+ visible_at_version: version(at_version),
+ order: :id
+ ).execute
+ end
+
+ private
+
+ def version(at_version)
+ GitlabSchema.object_from_id(at_version)&.sync if at_version
+ end
+
+ def design_ids(ids)
+ ids&.map { |id| GlobalID.parse(id).model_id }
+ end
+
+ def issue
+ object.issue
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/design_management/version/design_at_version_resolver.rb b/app/graphql/resolvers/design_management/version/design_at_version_resolver.rb
new file mode 100644
index 00000000000..03f7908780c
--- /dev/null
+++ b/app/graphql/resolvers/design_management/version/design_at_version_resolver.rb
@@ -0,0 +1,95 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module DesignManagement
+ module Version
+ # Resolver for a DesignAtVersion object given an implicit version context
+ class DesignAtVersionResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ type Types::DesignManagement::DesignAtVersionType, null: true
+
+ authorize :read_design
+
+ argument :id, GraphQL::ID_TYPE,
+ required: false,
+ as: :design_at_version_id,
+ description: 'The ID of the DesignAtVersion'
+ argument :design_id, GraphQL::ID_TYPE,
+ required: false,
+ description: 'The ID of a specific design'
+ argument :filename, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'The filename of a specific design'
+
+ def self.single
+ self
+ end
+
+ def resolve(design_id: nil, filename: nil, design_at_version_id: nil)
+ validate_arguments(design_id, filename, design_at_version_id)
+
+ return unless Ability.allowed?(current_user, :read_design, issue)
+ return specific_design_at_version(design_at_version_id) if design_at_version_id
+
+ find(design_id, filename).map { |d| make(d) }.first
+ end
+
+ private
+
+ def validate_arguments(design_id, filename, design_at_version_id)
+ args = { filename: filename, id: design_at_version_id, design_id: design_id }
+ passed = args.compact.keys
+
+ return if passed.size == 1
+
+ msg = "Exactly one of #{args.keys.join(', ')} expected, got #{passed}"
+
+ raise Gitlab::Graphql::Errors::ArgumentError, msg
+ end
+
+ def specific_design_at_version(id)
+ dav = GitlabSchema.object_from_id(id, expected_type: ::DesignManagement::DesignAtVersion)
+ return unless consistent?(dav)
+
+ dav
+ end
+
+ # Test that the DAV found by ID actually belongs on this version, and
+ # that it is visible at this version.
+ def consistent?(dav)
+ return false unless dav.present?
+
+ dav.design.issue_id == issue.id &&
+ dav.version.id == version.id &&
+ dav.design.visible_in?(version)
+ end
+
+ def find(id, filename)
+ ids = [parse_design_id(id).model_id] if id
+ filenames = [filename] if filename
+
+ ::DesignManagement::DesignsFinder
+ .new(issue, current_user, ids: ids, filenames: filenames, visible_at_version: version)
+ .execute
+ end
+
+ def parse_design_id(id)
+ GitlabSchema.parse_gid(id, expected_type: ::DesignManagement::Design)
+ end
+
+ def issue
+ version.issue
+ end
+
+ def version
+ object
+ end
+
+ def make(design)
+ ::DesignManagement::DesignAtVersion.new(design: design, version: version)
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb b/app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb
new file mode 100644
index 00000000000..5ccb2f3e311
--- /dev/null
+++ b/app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module DesignManagement
+ module Version
+ # Resolver for DesignAtVersion objects given an implicit version context
+ class DesignsAtVersionResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ type Types::DesignManagement::DesignAtVersionType, null: true
+
+ authorize :read_design
+
+ argument :ids,
+ [GraphQL::ID_TYPE],
+ required: false,
+ description: 'Filters designs by their ID'
+ argument :filenames,
+ [GraphQL::STRING_TYPE],
+ required: false,
+ description: 'Filters designs by their filename'
+
+ def self.single
+ ::Resolvers::DesignManagement::Version::DesignAtVersionResolver
+ end
+
+ def resolve(ids: nil, filenames: nil)
+ find(ids, filenames).execute.map { |d| make(d) }
+ end
+
+ private
+
+ def find(ids, filenames)
+ ids = ids&.map { |id| parse_design_id(id).model_id }
+
+ ::DesignManagement::DesignsFinder.new(issue, current_user,
+ ids: ids,
+ filenames: filenames,
+ visible_at_version: version)
+ end
+
+ def parse_design_id(id)
+ GitlabSchema.parse_gid(id, expected_type: ::DesignManagement::Design)
+ end
+
+ def issue
+ version.issue
+ end
+
+ def version
+ object
+ end
+
+ def make(design)
+ ::DesignManagement::DesignAtVersion.new(design: design, version: version)
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/design_management/version_in_collection_resolver.rb b/app/graphql/resolvers/design_management/version_in_collection_resolver.rb
new file mode 100644
index 00000000000..9e729172881
--- /dev/null
+++ b/app/graphql/resolvers/design_management/version_in_collection_resolver.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module DesignManagement
+ class VersionInCollectionResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ type Types::DesignManagement::VersionType, null: true
+
+ authorize :read_design
+
+ alias_method :collection, :object
+
+ argument :sha, GraphQL::STRING_TYPE,
+ required: false,
+ description: "The SHA256 of a specific version"
+ argument :id, GraphQL::ID_TYPE,
+ required: false,
+ description: 'The Global ID of the version'
+
+ def resolve(id: nil, sha: nil)
+ check_args(id, sha)
+
+ gid = GitlabSchema.parse_gid(id, expected_type: ::DesignManagement::Version) if id
+
+ ::DesignManagement::VersionsFinder
+ .new(collection, current_user, sha: sha, version_id: gid&.model_id)
+ .execute
+ .first
+ end
+
+ def self.single
+ self
+ end
+
+ private
+
+ def check_args(id, sha)
+ return if id.present? || sha.present?
+
+ raise ::Gitlab::Graphql::Errors::ArgumentError, 'one of id or sha is required'
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/design_management/version_resolver.rb b/app/graphql/resolvers/design_management/version_resolver.rb
new file mode 100644
index 00000000000..b0e0843e6c8
--- /dev/null
+++ b/app/graphql/resolvers/design_management/version_resolver.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module DesignManagement
+ class VersionResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ type Types::DesignManagement::VersionType, null: true
+
+ authorize :read_design
+
+ argument :id, GraphQL::ID_TYPE,
+ required: true,
+ description: 'The Global ID of the version'
+
+ def resolve(id:)
+ authorized_find!(id: id)
+ end
+
+ def find_object(id:)
+ GitlabSchema.object_from_id(id, expected_type: ::DesignManagement::Version)
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/design_management/versions_resolver.rb b/app/graphql/resolvers/design_management/versions_resolver.rb
new file mode 100644
index 00000000000..a62258dad5c
--- /dev/null
+++ b/app/graphql/resolvers/design_management/versions_resolver.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module DesignManagement
+ class VersionsResolver < BaseResolver
+ type Types::DesignManagement::VersionType.connection_type, null: false
+
+ alias_method :design_or_collection, :object
+
+ argument :earlier_or_equal_to_sha, GraphQL::STRING_TYPE,
+ as: :sha,
+ required: false,
+ description: 'The SHA256 of the most recent acceptable version'
+
+ argument :earlier_or_equal_to_id, GraphQL::ID_TYPE,
+ as: :id,
+ required: false,
+ description: 'The Global ID of the most recent acceptable version'
+
+ # This resolver has a custom singular resolver
+ def self.single
+ ::Resolvers::DesignManagement::VersionInCollectionResolver
+ end
+
+ def resolve(parent: nil, id: nil, sha: nil)
+ version = cutoff(parent, id, sha)
+
+ raise ::Gitlab::Graphql::Errors::ResourceNotAvailable, 'cutoff not found' unless version.present?
+
+ if version == :unconstrained
+ find
+ else
+ find(earlier_or_equal_to: version)
+ end
+ end
+
+ private
+
+ # Find the most recent version that the client will accept
+ def cutoff(parent, id, sha)
+ if sha.present? || id.present?
+ specific_version(id, sha)
+ elsif at_version = at_version_arg(parent)
+ by_id(at_version)
+ else
+ :unconstrained
+ end
+ end
+
+ def specific_version(id, sha)
+ gid = GitlabSchema.parse_gid(id, expected_type: ::DesignManagement::Version) if id
+ find(sha: sha, version_id: gid&.model_id).first
+ end
+
+ def find(**params)
+ ::DesignManagement::VersionsFinder
+ .new(design_or_collection, current_user, params)
+ .execute
+ end
+
+ def by_id(id)
+ GitlabSchema.object_from_id(id, expected_type: ::DesignManagement::Version).sync
+ end
+
+ # Find an `at_version` argument passed to a parent node.
+ #
+ # If one is found, then a design collection further up the AST
+ # has been filtered to reflect designs at that version, and so
+ # for consistency we should only present versions up to the given
+ # version here.
+ def at_version_arg(parent)
+ ::Gitlab::Graphql::FindArgumentInParent.find(parent, :at_version, limit_depth: 4)
+ end
+ end
+ end
+end