defmodule BallsPDS.Ecto.Schema.Object do use Ecto.Schema import Ecto.Changeset import Ecto.Query alias BallsPDS.Ecto.Schema.ObjectReadAgent alias BallsPDS.Repo alias BallsPDS.Util.ACL schema "objects" do field(:path, :string) field(:content_type, :string) field(:activitypub_type, :string) field(:storage_key, :string) field(:public, :boolean, default: false) field(:total_items, :integer) timestamps() end def changeset(struct, params \\ %{}) do struct |> cast(params, [ :path, :content_type, :activitypub_type, :storage_key, :public, :total_items ]) |> validate_required([ :path, :public ]) |> validate_format(:path, ~r/^[^<>:"\\|\?\*\0]+$/, message: "Invalid characters") |> validate_format(:path, ~r/^\/$|^\/.*[^\/]$/, message: "Must have leading slash but no trailing slash" ) |> validate_format(:path, ~r/(? validate_format( :content_type, ~r/^(application|audio|font|image|message|model|multipart|text|video)\/[\w\-\+\.]+(?:;\s*charset=[\w\-]+)?$/i, allow_nil: true ) |> validate_format(:activitypub_type, ~r/[A-Z][a-zA-Z0-9]*/, allow_nil: true) |> validate_format(:storage_key, ~r/^[0-9a-f]{64}$/, allow_nil: true, message: "Invalid 256-bit hexadecimal string" ) |> validate_inclusion(:public, [true, false]) |> validate_number(:total_items, greater_than: -1, allow_nil: true) |> unique_constraint(:path) end def get_by_path(path) when is_binary(path) do query = from(o in __MODULE__, where: o.path == ^path ) Repo.one(query) end def get_ap_id(object_id) do from(o in __MODULE__, where: o.id == ^object_id, select: o.path ) |> Repo.one() |> case do nil -> nil path -> ACL.make_object_url(path) end end def get_all_by_paths(paths) when is_list(paths) do from(o in __MODULE__, where: o.path in ^paths ) |> Repo.all() end def is_authorized_read?(%__MODULE__{public: true}, _), do: true def is_authorized_read?(%__MODULE__{}, nil), do: false def is_authorized_read?(%__MODULE__{} = object, acl) when is_binary(acl), do: ObjectReadAgent.is_authorized_read?(object, acl) end