132 lines
4.9 KiB
Ruby
132 lines
4.9 KiB
Ruby
|
require_relative './category'
|
||
|
require_relative './scope'
|
||
|
require_relative './default_scope'
|
||
|
require_relative './apis_scope'
|
||
|
require_relative './dataservices_scope'
|
||
|
require_relative './datasets_scope'
|
||
|
require_relative './datasets_metadata_scope'
|
||
|
require_relative './schemas_scope'
|
||
|
require_relative './user_scope'
|
||
|
require_relative './scopes_validator'
|
||
|
|
||
|
module Carto
|
||
|
module OauthProvider
|
||
|
module Scopes
|
||
|
SCOPE_DEFAULT = '_default'.freeze
|
||
|
SCOPE_OFFLINE = 'offline'.freeze
|
||
|
|
||
|
CATEGORY_OFFLINE = Category.new('Offline access').freeze
|
||
|
CATEGORY_USER = Category.new('User and personal data').freeze
|
||
|
CATEGORY_MONEY = Category.new('Features that consume credits', 'money')
|
||
|
CATEGORY_DATASETS = Category.new('Access to your datasets')
|
||
|
CATEGORY_SCHEMA = Category.new('Create tables')
|
||
|
CATEGORY_DATASETS_METADATA = Category.new('List your datasets')
|
||
|
CATEGORY_APIS = Category.new('Access to CARTO APIs')
|
||
|
|
||
|
SCOPES = [
|
||
|
Scope.new(SCOPE_DEFAULT, CATEGORY_USER, 'Username and organization name').freeze,
|
||
|
Scope.new(SCOPE_OFFLINE, CATEGORY_OFFLINE, 'Access CARTO in the background').freeze,
|
||
|
|
||
|
DataservicesScope.new('geocoding', 'Geocoding').freeze,
|
||
|
DataservicesScope.new('isolines', 'Isolines').freeze,
|
||
|
DataservicesScope.new('routing', 'Routing').freeze,
|
||
|
DataservicesScope.new('observatory', 'Data Observatory').freeze,
|
||
|
|
||
|
ApisScope.new('do', 'Data Observatory API').freeze,
|
||
|
|
||
|
UserScope.new('profile', 'User profile (avatar, name, org. owner)').freeze,
|
||
|
DatasetsMetadataScope.new('Table names').freeze
|
||
|
].freeze
|
||
|
|
||
|
SCOPES_BY_NAME = SCOPES.map { |s| [s.name, s] }.to_h.freeze
|
||
|
|
||
|
# The default scope is always granted but cannot be explicitly requested
|
||
|
SUPPORTED_SCOPES = (SCOPES.map(&:name) - [SCOPE_DEFAULT]).freeze
|
||
|
|
||
|
def self.invalid_scopes(scopes)
|
||
|
scopes - SUPPORTED_SCOPES - DatasetsScope.valid_scopes(scopes) - SchemasScope.valid_scopes(scopes)
|
||
|
end
|
||
|
|
||
|
def self.invalid_scopes_and_tables(scopes, user)
|
||
|
scopes - SUPPORTED_SCOPES - DatasetsScope.valid_scopes_with_table(scopes, user) - SchemasScope.valid_scopes_with_schema(scopes, user)
|
||
|
end
|
||
|
|
||
|
def self.build(scope)
|
||
|
result = SCOPES_BY_NAME[scope]
|
||
|
if !result
|
||
|
if DatasetsScope.is_a?(scope)
|
||
|
result = DatasetsScope.new(scope)
|
||
|
elsif SchemasScope.is_a?(scope)
|
||
|
result = SchemasScope.new(scope)
|
||
|
end
|
||
|
end
|
||
|
result
|
||
|
end
|
||
|
|
||
|
def self.scopes_by_category(new_scopes, previous_scopes = [])
|
||
|
# If we had previous scopes, DEFAULT was already granted.
|
||
|
previous_scopes = previous_scopes.blank? ? [] : previous_scopes + [SCOPE_DEFAULT]
|
||
|
|
||
|
new_scopes_filtered = subtract_scopes(new_scopes, previous_scopes)
|
||
|
previous_scopes_filtered = subtract_scopes(previous_scopes, new_scopes_filtered)
|
||
|
|
||
|
all_scopes = ([SCOPE_DEFAULT] + new_scopes_filtered + previous_scopes_filtered).uniq
|
||
|
scopes_by_category = all_scopes.map { |s| build(s) }.group_by(&:category)
|
||
|
scopes_by_category.map do |category, scopes|
|
||
|
{
|
||
|
description: category.description,
|
||
|
icon: category.icon,
|
||
|
scopes: scopes.map do |scope|
|
||
|
{
|
||
|
description: scope.description,
|
||
|
new: !previous_scopes.include?(scope.name)
|
||
|
}
|
||
|
end
|
||
|
}
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def self.subtract_scopes(scopes1, scopes2, user_schema = 'public')
|
||
|
return [] if scopes1.blank?
|
||
|
return scopes1 if scopes2.blank?
|
||
|
|
||
|
datasets1, non_datasets1 = split_dataset_scopes_for_subtract(scopes1, user_schema)
|
||
|
datasets2, non_datasets2 = split_dataset_scopes_for_subtract(scopes2, user_schema)
|
||
|
|
||
|
subtract_dataset_scopes!(datasets1, datasets2)
|
||
|
datasets_results = datasets1.map { |schema_table, permissions| "datasets:#{permissions}:#{schema_table}" }
|
||
|
|
||
|
datasets_results + (non_datasets1 - non_datasets2)
|
||
|
end
|
||
|
|
||
|
private_class_method def self.split_dataset_scopes_for_subtract(scopes, user_schema)
|
||
|
datasets = {}
|
||
|
non_datasets = []
|
||
|
|
||
|
scopes.each do |scope|
|
||
|
if DatasetsScope.is_a?(scope)
|
||
|
table, schema, permissions = DatasetsScope.table_schema_permission(scope)
|
||
|
schema ||= user_schema
|
||
|
schema_table = "#{schema}.#{table}"
|
||
|
|
||
|
datasets[schema_table] = permissions unless datasets[schema_table] == 'rw'
|
||
|
else
|
||
|
non_datasets << scope
|
||
|
end
|
||
|
end
|
||
|
|
||
|
[datasets, non_datasets]
|
||
|
end
|
||
|
|
||
|
private_class_method def self.subtract_dataset_scopes!(datasets1, datasets2)
|
||
|
return [] if datasets1.nil?
|
||
|
return datasets1 if datasets2.nil?
|
||
|
|
||
|
datasets2.each do |schema_table, permissions|
|
||
|
datasets1.delete(schema_table) unless datasets1[schema_table] == 'rw' && permissions == 'r'
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|