···2323 |> Atvouch.Repo.insert()
2424 end
25252626+ def upsert(attrs) do
2727+ case one(attrs[:did] || attrs["did"]) do
2828+ nil ->
2929+ create(attrs)
3030+3131+ existing ->
3232+ existing
3333+ |> changeset(attrs)
3434+ |> Atvouch.Repo.update()
3535+ end
3636+ end
3737+2638 def one(did) do
2739 Atvouch.Repo.get(__MODULE__, did)
2840 end
+78-27
appview/lib/atvouch/tap_handler.ex
···22 @behaviour Atvouch.Tap.Handler
33 require Logger
4455- # TODO: implement vouch creation from tap events
66- # @impl true
77- # def handle_record(%{collection: "dev.atvouch.graph.vouch", action: :create} = event) do
88- # Logger.info("tap record: #{event.action} #{event.collection}/#{event.rkey} from #{event.did}")
99- #
1010- # # Ensure the creator identity exists
1111- # case Atvouch.Identity.one(event.did) do
1212- # nil -> Atvouch.Identity.create(%{did: event.did})
1313- # identity -> {:ok, identity}
1414- # end
1515- #
1616- # at_uri = "at://#{event.did}/#{event.collection}/#{event.rkey}"
1717- #
1818- # case Atvouch.Vouch.create(%{
1919- # at_uri: at_uri,
2020- # creator_did: event.did,
2121- # target_did: event.record["subject"],
2222- # created_at: event.record["createdAt"]
2323- # }) do
2424- # {:ok, _vouch} -> :ok
2525- # {:error, reason} -> {:error, reason}
2626- # end
2727- # end
55+ @collection "dev.atvouch.graph.vouch"
286297 @impl true
88+ def handle_record(%{collection: @collection, action: :create} = event) do
99+ at_uri = "at://#{event.did}/#{@collection}/#{event.rkey}"
1010+ created_at = event.record["createdAt"]
1111+ target_did = event.record["subject"]
1212+1313+ # Ensure both identities exist
1414+ ensure_identity(event.did)
1515+ ensure_identity(target_did)
1616+1717+ case Atvouch.Vouch.create(%{
1818+ at_uri: at_uri,
1919+ creator_did: event.did,
2020+ target_did: target_did,
2121+ original_created_at: created_at,
2222+ remote_created_at: created_at,
2323+ remote_updated_timestamp: false,
2424+ at_cid: event.cid,
2525+ live: event.live
2626+ }) do
2727+ {:ok, _vouch} -> :ok
2828+ {:error, reason} -> {:error, reason}
2929+ end
3030+ end
3131+3232+ def handle_record(%{collection: @collection, action: :update} = event) do
3333+ at_uri = "at://#{event.did}/#{@collection}/#{event.rkey}"
3434+ created_at = event.record["createdAt"]
3535+3636+ case Atvouch.Vouch.one(at_uri) do
3737+ nil ->
3838+ {:error, :not_found}
3939+4040+ vouch ->
4141+ updated_timestamp = created_at != vouch.original_created_at
4242+4343+ case Atvouch.Vouch.update(vouch, %{
4444+ remote_created_at: created_at,
4545+ remote_updated_timestamp: updated_timestamp,
4646+ at_cid: event.cid,
4747+ live: event.live
4848+ }) do
4949+ {:ok, _vouch} -> :ok
5050+ {:error, reason} -> {:error, reason}
5151+ end
5252+ end
5353+ end
5454+5555+ def handle_record(%{collection: @collection, action: :delete} = event) do
5656+ at_uri = "at://#{event.did}/#{@collection}/#{event.rkey}"
5757+5858+ case Atvouch.Vouch.delete(at_uri) do
5959+ {:ok, _vouch} -> :ok
6060+ {:error, reason} -> {:error, reason}
6161+ end
6262+ end
6363+3064 def handle_record(event) do
3131- Logger.info("tap record: #{event.action} #{event.collection}/#{event.rkey} from #{event.did}")
3232- {:error, :skip}
6565+ Logger.debug(
6666+ "explicit skip for record event #{inspect(event)}, not handled by others. is tap misconfigured?"
6767+ )
6868+6969+ {:error, :invalid_collection_or_action}
3370 end
34713572 @impl true
3673 def handle_identity(event) do
3737- Logger.info("tap identity: #{event.did} handle=#{event.handle} active=#{event.is_active}")
3838- {:error, :skip}
7474+ case Atvouch.Identity.upsert(%{
7575+ did: event.did,
7676+ handle: event.handle,
7777+ active: event.is_active,
7878+ status: event.status
7979+ }) do
8080+ {:ok, _identity} -> :ok
8181+ {:error, reason} -> {:error, reason}
8282+ end
8383+ end
8484+8585+ defp ensure_identity(did) do
8686+ case Atvouch.Identity.one(did) do
8787+ nil -> Atvouch.Identity.create(%{did: did})
8888+ _existing -> :ok
8989+ end
3990 end
4091end
+13
appview/lib/atvouch/vouch.ex
···2828 |> Atvouch.Repo.insert()
2929 end
30303131+ def update(vouch, attrs) do
3232+ vouch
3333+ |> changeset(attrs)
3434+ |> Atvouch.Repo.update()
3535+ end
3636+3737+ def delete(at_uri) do
3838+ case one(at_uri) do
3939+ nil -> {:error, :not_found}
4040+ vouch -> Atvouch.Repo.delete(vouch)
4141+ end
4242+ end
4343+3144 def one(at_uri) do
3245 Atvouch.Repo.get(__MODULE__, at_uri)
3346 end