/*-snippet
{
  "body": [
    "SELECT ax_utils.user_has_setting(${1:'ENTITIES_VIEW,ADMIN'}, '${2:mosaic.auth.permissions}');"
  ],
  "description": [
    "Checks if a user has one of the given settings in a local variable."
  ]
}
snippet-*/
create or replace function ax_utils.user_has_setting(required_settings text, local_variable_field text) returns boolean
	LANGUAGE plpgsql	
	as $$
DECLARE
	v_part text;
	v_user_settings text = ',' || pg_catalog.current_setting(local_variable_field, true) || ',';
BEGIN
   foreach v_part in array string_to_array(required_settings, ',')
   loop
       if v_user_settings like '%,' || v_part || ',%' then
           return true;
       end if;
   end loop;
   return false;
END;
$$;

/*-snippet
{
  "body": [
    "SELECT ax_utils.user_has_permission(${1:'ENTITIES_VIEW,ADMIN'});"
  ],
  "description": [
    "Checks if a user has at least one of the given permissions.",
    "For example, user_has_permission('ENTITIES_VIEW,ADMIN') would return true if he has either the permission 'ENTITIES_VIEW' and/or 'ADMIN'.",
    "If the user has no required permission, it throws an error with the 'PERMI' error code value.",
    "You will use this function most often in policies like:\n",
    "CREATE POLICY my_table_authorization ON app_public.my_table FOR SELECT USING ((SELECT ax_utils.user_has_permission('ENTITIES_VIEW,ADMIN')));"
  ]
}
snippet-*/
create or replace function ax_utils.user_has_permission(required_permissions text) returns boolean
	LANGUAGE plpgsql	
	as $$
BEGIN
   if ax_utils.user_has_setting(required_permissions, 'mosaic.auth.permissions') = false then
    PERFORM ax_utils.raise_error('At least one of these permissions must be granted: %s', 'PERMI', required_permissions);
   end if;
   return true;
END;
$$;

/*-snippet
{
  "body": [
    "SELECT ax_utils.user_has_tag(${1:'tag1,tag2'});"
  ],
  "description": [
    "Checks if a user has one of the specified tags.\n",
    "Returns true if the user has at least one of the tags from provided comma-separated string. Returns false otherwise."
  ]
}
snippet-*/
create or replace function ax_utils.user_has_tag(required_permissions text) returns boolean
	LANGUAGE plpgsql	
	as $$
BEGIN
   return ax_utils.user_has_setting(required_permissions, 'mosaic.auth.tags');
END;
$$;

/*-snippet
{
  "body": [
    "SELECT ax_utils.user_has_permission_and_tag(${1:'ENTITIES_VIEW,ADMIN'}, ${2:column_value});"
  ],
  "description": [
    "Checks if a user has a specific permission.",
    "If he has such permission, he also needs a tag that is part of a specific database column.\n",
    "For example, user_has_permission_and_tag('COUNTRIES_VIEW,ADMIN', country) would allow a user with permission 'COUNTRIES_VIEW' or 'ADMIN' to use a row when ",
    "the column 'country' contains a value that is part of the users 'mosaic.auth.tags' - e.g. \"us\"/\"uk\"."
  ]
}
snippet-*/
create or replace function ax_utils.user_has_permission_and_tag(required_permissions text, fieldValue text) returns boolean
	LANGUAGE plpgsql	
	as $$
DECLARE
	v_part text;
	v_user_permissions text = ',' || pg_catalog.current_setting('mosaic.auth.permissions', true) || ',';
	v_user_tags text = pg_catalog.current_setting('mosaic.auth.tags', true);
BEGIN
   -- check if the user has the needed permission - otherwise skip
   if ax_utils.user_has_setting(required_permissions, 'mosaic.auth.permissions') = false then
       RAISE EXCEPTION 'At least one of these permissions must be granted: (%)', required_permissions using errcode = 'PERMI'; 
   end if;   
   -- check if any tag matches the discrete column value
   foreach v_part in array string_to_array(v_user_tags, ',')
   loop
       if v_part = CAST (fieldValue AS TEXT) then
           return true;
       end if;
   end loop;
   return false;
END;
$$;

/*-snippet
{
  "body": [
    "SELECT ax_utils.current_tenant_id();"
  ],
  "description": [
    "Gets the tenant ID from the context of the current user.",
    "This is needed for multitenancy systems."
  ]
}
snippet-*/
CREATE OR REPLACE FUNCTION ax_utils.current_tenant_id() RETURNS UUID AS $$
  SELECT coalesce(nullif(current_setting('mosaic.tenant_id', TRUE), ''), 'ffffffff-ffff-ffff-ffff-ffffffffffff')::UUID;
$$ LANGUAGE sql STABLE;

/*-snippet
{
  "body": [
    "SELECT ax_utils.current_environment_id();"
  ],
  "description": [
    "Gets the environment ID from the context of the current user.",
    "This is needed for multitenancy systems."
  ]
}
snippet-*/
CREATE OR REPLACE FUNCTION ax_utils.current_environment_id() RETURNS UUID AS $$
  SELECT coalesce(nullif(current_setting('mosaic.environment_id', TRUE), ''), 'ffffffff-ffff-ffff-ffff-ffffffffffff')::UUID;
$$ LANGUAGE sql STABLE;

/*-snippet
{
  "body": [
    "SELECT ax_utils.current_user_id();"
  ],
  "description": [
    "Gets the User ID from the context of the current user.",
    "This is needed when end-user RLS is needed."
  ]
}
snippet-*/
CREATE OR REPLACE FUNCTION ax_utils.current_user_id()
 RETURNS UUID
 LANGUAGE sql
 STABLE
AS $$
  SELECT coalesce(nullif(current_setting('mosaic.auth.user_id', TRUE), ''), uuid_nil()::TEXT)::UUID;
$$
;
