110 lines
3 KiB
Ruby
110 lines
3 KiB
Ruby
class API::V2::Context < GraphQL::Query::Context
|
||
# This method is used to check if a given fragment is used in the given query. We need that in
|
||
# order to maintain backward compatibility for Types de Champ that we extended in later iterations
|
||
# of our schema. If it is an introspection query, we assume all fragments are present.
|
||
def has_fragment?(fragment_name)
|
||
return true if query.nil?
|
||
return true if introspection?
|
||
|
||
self[:has_fragment] ||= Hash.new do |hash, fragment_name|
|
||
visitor = HasFragment.new(query.document, fragment_name)
|
||
visitor.visit
|
||
hash[fragment_name] = visitor.found
|
||
end
|
||
self[:has_fragment][fragment_name]
|
||
end
|
||
|
||
def has_fragments?(fragment_names)
|
||
fragment_names.any? { has_fragment?(_1) }
|
||
end
|
||
|
||
def introspection?
|
||
query.selected_operation.name == "IntrospectionQuery"
|
||
end
|
||
|
||
def internal_use?
|
||
self[:internal_use]
|
||
end
|
||
|
||
def write_access?
|
||
self[:write_access]
|
||
end
|
||
|
||
def current_administrateur
|
||
unless self[:administrateur_id]
|
||
raise GraphQL::ExecutionError.new("Pour effectuer cette opération, vous avez besoin d’un jeton au nouveau format. Vous pouvez l’obtenir dans votre interface administrateur.", extensions: { code: :deprecated_token })
|
||
end
|
||
Administrateur.find(self[:administrateur_id])
|
||
end
|
||
|
||
def authorized_demarche?(demarche, opendata: false)
|
||
if internal_use?
|
||
return true
|
||
end
|
||
|
||
if opendata && demarche.opendata?
|
||
return true
|
||
end
|
||
|
||
self[:authorized] ||= {}
|
||
|
||
if self[:authorized][demarche.id].nil?
|
||
self[:authorized][demarche.id] = compute_demarche_authorization(demarche)
|
||
end
|
||
|
||
self[:authorized][demarche.id]
|
||
end
|
||
|
||
def query_info
|
||
{
|
||
graphql_query: query.query_string,
|
||
graphql_variables: query.provided_variables&.to_json,
|
||
graphql_mutation: mutation?,
|
||
graphql_null_error: errors.any? { _1.is_a? GraphQL::InvalidNullError }.presence,
|
||
graphql_timeout_error: errors.any? { _1.is_a? GraphQL::Schema::Timeout::TimeoutError }.presence,
|
||
graphql_api_token_id: self[:api_token_id]
|
||
}.compact
|
||
end
|
||
|
||
private
|
||
|
||
def mutation?
|
||
query.lookahead.selections.any? { _1.field.type.respond_to?(:mutation) }.presence
|
||
rescue
|
||
false
|
||
end
|
||
|
||
def compute_demarche_authorization(demarche)
|
||
# procedure_ids and token are passed from graphql controller
|
||
self[:procedure_ids].include?(demarche.id)
|
||
end
|
||
|
||
# This is a query AST visitor that we use to check
|
||
# if a fragment with a given name is used in the given document.
|
||
# We check for both inline and standalone fragments.
|
||
class HasFragment < GraphQL::Language::Visitor
|
||
def initialize(document, fragment_name)
|
||
super(document)
|
||
@fragment_name = fragment_name.to_s
|
||
@found = false
|
||
end
|
||
|
||
attr_reader :found
|
||
|
||
def on_inline_fragment(node, parent)
|
||
if node.type.name == @fragment_name
|
||
@found = true
|
||
end
|
||
|
||
super
|
||
end
|
||
|
||
def on_fragment_definition(node, parent)
|
||
if node.type.name == @fragment_name
|
||
@found = true
|
||
end
|
||
|
||
super
|
||
end
|
||
end
|
||
end
|