138 lines
4.0 KiB
Ruby
138 lines
4.0 KiB
Ruby
class CreateSharedExtensionsSchema < ActiveRecord::Migration[6.0]
|
|
def up
|
|
unless schema_exists?(extensions_schema)
|
|
execute_or_log_create_schema_warning("CREATE SCHEMA #{extensions_schema}")
|
|
end
|
|
|
|
%w[unaccent pg_trgm].each do |extension|
|
|
if extension_enabled?(extension)
|
|
unless extension_already_in_extensions_schema?(extension)
|
|
execute_or_log_extension_warning("ALTER EXTENSION #{extension} SET SCHEMA #{extensions_schema}")
|
|
end
|
|
else
|
|
execute_or_log_extension_warning("CREATE EXTENSION #{extension} SCHEMA #{extensions_schema}")
|
|
end
|
|
end
|
|
|
|
unless schema_exists?(extensions_schema) && public_has_usage_privilege_on_extensions_schema?
|
|
execute_or_log_grant_usage_warning("GRANT usage ON SCHEMA #{extensions_schema} TO public")
|
|
end
|
|
|
|
show_full_warning_message if warning_messages.any?
|
|
end
|
|
|
|
def down
|
|
%w[unaccent pg_trgm].each do |extension|
|
|
unless extension_already_in_public_schema?(extension)
|
|
execute "ALTER EXTENSION #{extension} SET SCHEMA public;"
|
|
end
|
|
end
|
|
|
|
execute "DROP SCHEMA #{extensions_schema};" if schema_exists?(extensions_schema)
|
|
end
|
|
|
|
private
|
|
|
|
def extensions_schema
|
|
"shared_extensions"
|
|
end
|
|
|
|
def extension_already_in_extensions_schema?(extension)
|
|
associated_schema_id_for(extension) == extensions_schema_id
|
|
end
|
|
|
|
def extension_already_in_public_schema?(extension)
|
|
associated_schema_id_for(extension) == public_schema_id
|
|
end
|
|
|
|
def associated_schema_id_for(extension)
|
|
query_value("SELECT extnamespace FROM pg_extension WHERE extname=#{quote(extension)}")
|
|
end
|
|
|
|
def extensions_schema_id
|
|
schema_id_for(extensions_schema)
|
|
end
|
|
|
|
def public_schema_id
|
|
schema_id_for("public")
|
|
end
|
|
|
|
def schema_id_for(schema)
|
|
query_value("SELECT oid FROM pg_namespace WHERE nspname=#{quote(schema)}")
|
|
end
|
|
|
|
def execute_or_log_create_schema_warning(statement)
|
|
if create_permission?
|
|
execute statement
|
|
else
|
|
log_warning(
|
|
"GRANT CREATE ON DATABASE #{query_value("SELECT CURRENT_DATABASE()")} " \
|
|
"TO #{query_value("SELECT CURRENT_USER")}"
|
|
)
|
|
log_warning(statement)
|
|
end
|
|
end
|
|
|
|
def execute_or_log_extension_warning(statement)
|
|
if superuser?
|
|
execute statement
|
|
else
|
|
log_warning(statement)
|
|
end
|
|
end
|
|
|
|
def execute_or_log_grant_usage_warning(statement)
|
|
if schema_exists?(extensions_schema) && grant_usage_permission?
|
|
execute statement
|
|
else
|
|
log_warning(statement)
|
|
end
|
|
end
|
|
|
|
def create_permission?
|
|
query_value("SELECT has_database_privilege(CURRENT_USER, CURRENT_DATABASE(), 'CREATE');")
|
|
end
|
|
|
|
def superuser?
|
|
query_value("SELECT usesuper FROM pg_user WHERE usename = CURRENT_USER")
|
|
end
|
|
|
|
def grant_usage_permission?
|
|
query_value("SELECT has_schema_privilege(CURRENT_USER, '#{extensions_schema}', 'CREATE');")
|
|
end
|
|
|
|
def public_has_usage_privilege_on_extensions_schema?
|
|
query_value("SELECT has_schema_privilege('public', '#{extensions_schema}', 'USAGE');")
|
|
end
|
|
|
|
def log_warning(statement)
|
|
warning_messages.push(statement)
|
|
end
|
|
|
|
def warning_messages
|
|
@warning_messages ||= []
|
|
end
|
|
|
|
def show_full_warning_message
|
|
message = <<~WARNING
|
|
---------------------- Multitenancy Warning ----------------------
|
|
Multitenancy is a feature that allows managing multiple
|
|
institutions in a completely independent way using just one
|
|
CONSUL DEMOCRACY installation.
|
|
|
|
NOTE: If you aren't going to use multitenancy, you can safely
|
|
ignore this warning.
|
|
|
|
If you'd like to enable this feature, first run:
|
|
#{warning_messages.join(";\n ")};
|
|
using a user with enough database privileges.
|
|
|
|
Check the CONSUL DEMOCRACY release notes for more information.
|
|
------------------------------------------------------------------
|
|
WARNING
|
|
|
|
puts message
|
|
Rails.logger.warn(message)
|
|
end
|
|
end
|