Packages
phoenix_kit
1.7.206
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/modules/storage/etcher_adapter.ex
defmodule PhoenixKit.Modules.Storage.EtcherAdapter do
@moduledoc """
Persistence helper for the MediaBrowser's annotation flow.
Etcher 0.3 dropped the `Etcher.Storage` behaviour entirely — annotations
now live inside the host `<Fresco.canvas>`'s `extensions.etcher` blob
and the library doesn't reach into the consumer's DB anymore. PhoenixKit
still needs to persist its annotations (they're per-file, not per-canvas-
file-on-disk), so this module survives as a thin helper module called
from the MediaBrowser LV's `etcher:annotations-changed` event handler —
not as a behaviour implementation.
The four public functions (`create/1`, `list_for/2`, `update/2`,
`delete/1`) keep their pre-0.3 signatures so the diff in MediaBrowser
stays small. None of them are `@impl` annotations anymore; they're
just plain helpers wrapping the `PhoenixKit.Annotations` context.
Etcher's generic API is keyed by `target_type` + `target_uuid` so the
library can annotate any kind of resource. In PhoenixKit the only
target is a media File, so this adapter requires `target_type ==
"file"` and maps `target_uuid` to `file_uuid`.
## Comment threads
An annotation's discussion thread is **not** created at draw time —
it's instantiated lazily when the user posts the first comment on the
annotation. The comments are anchored to the **file**
(`resource_type = "file"`, `resource_uuid = file_uuid`) with
`metadata.annotation_uuid` carrying the back-reference, so they
appear in the file's main thread alongside non-annotated discussion.
No `comment_uuid` column on annotations is needed.
"""
alias PhoenixKit.Annotations
alias PhoenixKit.Annotations.Annotation
# Whitelist of annotation schema fields the helper accepts from event
# payloads, sourced from `Annotation.adapter_writable_fields/0` so the
# set stays in sync with the schema's `@cast_fields`. Anything else
# (Etcher routing keys, JS-side anchor coords, comment-derived metadata
# we hydrate server-side) is silently dropped — `String.to_existing_atom`
# on unknown payload keys used to crash the LV when Etcher's payload
# shape grew new client-side keys. Stored as strings here since the
# filter compares against `to_string(payload_key)`.
@schema_keys Enum.map(Annotation.adapter_writable_fields(), &Atom.to_string/1)
def create(attrs) do
with {:ok, file_uuid} <- target_uuid(attrs) do
attrs
|> filter_to_schema()
|> Map.put(:file_uuid, file_uuid)
|> Annotations.create()
end
end
def list_for(target_type, target_uuid)
def list_for("file", file_uuid) when is_binary(file_uuid) do
Annotations.list_for_file(file_uuid)
end
def list_for(_other, _uuid), do: []
def update(uuid, attrs) do
attrs
|> filter_to_schema()
|> then(&Annotations.update(uuid, &1))
end
def delete(uuid), do: Annotations.delete(uuid)
# ---------------------------------------------------------------------------
defp target_uuid(%{"target_type" => "file", "target_uuid" => uuid}) when is_binary(uuid),
do: {:ok, uuid}
defp target_uuid(%{target_type: "file", target_uuid: uuid}) when is_binary(uuid),
do: {:ok, uuid}
defp target_uuid(_attrs), do: {:error, :unsupported_target}
defp filter_to_schema(attrs) do
Enum.reduce(attrs, %{}, fn {k, v}, acc ->
key = to_string(k)
if key in @schema_keys, do: Map.put(acc, String.to_existing_atom(key), v), else: acc
end)
end
end