defmodule Supabase.Storage.BucketHandler do
@moduledoc """
Provides low-level API functions for managing Supabase Storage buckets.
The `BucketHandler` module offers a collection of functions that directly interact with the Supabase Storage API for managing buckets. This module works closely with the `Supabase.Fetcher` for sending HTTP requests and the `Supabase.Storage.Cache` for caching bucket information.
## Features
- **Bucket Listing**: Fetch a list of all the buckets available in the storage.
- **Bucket Retrieval**: Retrieve detailed information about a specific bucket.
- **Bucket Creation**: Create a new bucket with specified attributes.
- **Bucket Update**: Modify the attributes of an existing bucket.
- **Bucket Emptying**: Empty the contents of a bucket without deleting the bucket itself.
- **Bucket Deletion**: Permanently remove a bucket and its contents.
## Caution
This module provides a low-level interface to Supabase Storage buckets and is designed for internal use by the `Supabase.Storage` module. Direct use is discouraged unless you need to perform custom or unsupported actions that are not available through the higher-level API. Incorrect use can lead to unexpected results or data loss.
## Implementation Details
All functions within the module expect a base URL, API key, and access token as their initial arguments, followed by any additional arguments required for the specific operation. Responses are usually in the form of `{:ok, result}` or `{:error, message}` tuples.
"""
alias Supabase.Connection, as: Conn
alias Supabase.Fetcher
alias Supabase.Storage.Bucket
alias Supabase.Storage.Cache
alias Supabase.Storage.Endpoints
@type bucket_id :: String.t()
@type bucket_name :: String.t()
@type create_attrs :: %{
id: String.t(),
name: String.t(),
file_size_limit: integer | nil,
allowed_mime_types: list(String.t()) | nil,
public: boolean
}
@type update_attrs :: %{
public: boolean | nil,
file_size_limit: integer | nil,
allowed_mime_types: list(String.t()) | nil
}
@spec list(Conn.base_url(), Conn.api_key(), Conn.access_token()) ::
{:ok, [Bucket.t()]} | {:error, String.t()}
def list(base_url, api_key, token) do
url = Fetcher.get_full_url(base_url, Endpoints.bucket_path())
headers = Fetcher.apply_headers(api_key, token)
url
|> Fetcher.get(headers)
|> case do
{:ok, body} -> {:ok, Enum.map(body, &Bucket.parse!/1)}
{:error, msg} -> {:error, msg}
end
end
@spec retrieve_info(Conn.base_url(), Conn.api_key(), Conn.access_token(), bucket_id) ::
{:ok, Bucket.t()} | {:error, String.t()}
def retrieve_info(base_url, api_key, token, bucket_id) do
if bucket = Cache.find_bucket_by_id(bucket_id) do
{:ok, bucket}
else
url = Fetcher.get_full_url(base_url, Endpoints.bucket_path_with_id(bucket_id))
headers = Fetcher.apply_headers(api_key, token)
url
|> Fetcher.get(headers)
|> case do
{:ok, body} -> {:ok, Bucket.parse!(body)}
{:error, msg} -> {:error, msg}
end
end
end
@spec create(Conn.base_url(), Conn.api_key(), Conn.access_token(), create_attrs) ::
{:ok, Bucket.t()} | {:error, String.t()}
def create(base_url, api_key, token, attrs) do
url = Fetcher.get_full_url(base_url, Endpoints.bucket_path())
headers = Fetcher.apply_headers(api_key, token)
url
|> Fetcher.post(attrs, headers)
|> case do
{:ok, resp} -> {:ok, resp}
{:error, msg} -> {:error, msg}
end
end
@spec update(Conn.base_url(), Conn.api_key(), Conn.access_token(), bucket_id, update_attrs) ::
{:ok, Bucket.t()} | {:error, String.t()}
def update(base_url, api_key, token, id, attrs) do
url = Fetcher.get_full_url(base_url, Endpoints.bucket_path_with_id(id))
headers = Fetcher.apply_headers(api_key, token)
url
|> Fetcher.put(attrs, headers)
|> case do
{:ok, message} -> {:ok, message}
{:error, msg} -> {:error, msg}
end
end
@spec empty(Conn.base_url(), Conn.api_key(), Conn.access_token(), bucket_id) ::
{:ok, :successfully_emptied} | {:error, String.t()}
def empty(base_url, api_key, token, id) do
url = Fetcher.get_full_url(base_url, Endpoints.bucket_path_to_empty(id))
headers = Fetcher.apply_headers(api_key, token)
url
|> Fetcher.post(nil, headers)
|> case do
{:ok, _message} -> {:ok, :successfully_emptied}
{:error, msg} -> {:error, msg}
end
end
@spec delete(Conn.base_url(), Conn.api_key(), Conn.access_token(), bucket_id) ::
{:ok, String.t()} | {:error, String.t()}
def delete(base_url, api_key, token, id) do
url = Fetcher.get_full_url(base_url, Endpoints.bucket_path_with_id(id))
headers = Fetcher.apply_headers(api_key, token)
url
|> Fetcher.delete(nil, headers)
|> case do
{:ok, body} -> {:ok, body}
{:error, msg} -> {:error, msg}
end
end
end