Packages
phoenix_kit
2.4.0
2.13.1
2.13.0
2.12.1
2.12.0
2.11.0
2.10.0
2.9.0
2.8.1
2.8.0
2.7.0
2.6.0
2.5.0
2.4.0
2.3.0
2.2.0
2.1.0
2.0.1
2.0.0
1.7.236
1.7.235
1.7.234
1.7.233
1.7.232
1.7.231
1.7.230
1.7.229
1.7.228
1.7.227
1.7.226
1.7.225
1.7.224
1.7.223
1.7.222
1.7.221
1.7.220
1.7.219
1.7.218
1.7.217
1.7.216
1.7.215
1.7.214
1.7.213
1.7.212
1.7.211
1.7.210
1.7.209
1.7.208
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/phoenix_kit_web/live/activity/show.ex
defmodule PhoenixKitWeb.Live.Activity.Show do
@moduledoc """
Admin LiveView for viewing a single activity entry.
Provides a shareable URL for individual activity entries with full detail.
"""
use PhoenixKitWeb, :live_view
alias PhoenixKit.Activity
alias PhoenixKit.Settings
alias PhoenixKit.Users.Auth.Scope
alias PhoenixKit.Utils.Routes
@impl true
def mount(%{"uuid" => uuid}, _session, socket) do
scope = socket.assigns[:phoenix_kit_current_scope]
if scope && Scope.has_module_access?(scope, "dashboard") do
entry = Activity.get_entry(uuid)
# A non-administrator may only open their OWN entries. Treat someone
# else's as not-found (same response as a missing uuid) so the detail
# page never leaks another user's audit record via its direct URL.
if is_nil(entry) or not can_view_entry?(scope, entry) do
{:ok,
socket
|> put_flash(:error, gettext("Activity not found"))
|> push_navigate(to: Routes.path("/admin/activity"))}
else
project_title = Settings.get_project_title()
resource_user = resolve_resource_user(entry)
# Resolve deep-links for the resource AND the actor/target (both users),
# so the who-did-it / who-it's-for identities are clickable too.
links =
[entry]
|> Enum.concat(user_items(entry))
|> PhoenixKit.ResourceLinks.resolve()
socket =
socket
|> assign(:page_title, gettext("Activity Detail"))
|> assign(:project_title, project_title)
|> assign(:entry, entry)
|> assign(:resource_user, resource_user)
|> assign(:resource_link, links[{entry.resource_type, entry.resource_uuid}])
|> assign(:actor_link, links[{"user", entry.actor_uuid}])
|> assign(:target_link, links[{"user", entry.target_uuid}])
{:ok, socket}
end
else
{:ok,
socket
|> put_flash(:error, gettext("Access denied"))
|> push_navigate(to: Routes.path("/admin"))}
end
end
@impl true
def handle_params(_params, url, socket) do
{:noreply, assign(socket, :url_path, URI.parse(url).path)}
end
# Synthetic `"user"` items for the actor + target uuids, so ResourceLinks can
# resolve them alongside the entry's own resource in one pass.
defp user_items(entry) do
[entry.actor_uuid, entry.target_uuid]
|> Enum.filter(&is_binary/1)
|> Enum.uniq()
|> Enum.map(&%{resource_type: "user", resource_uuid: &1})
end
defp resolve_resource_user(entry) do
if entry.resource_type == "user" && entry.resource_uuid do
resource_users = Activity.resolve_resource_users([entry])
Map.get(resource_users, entry.resource_uuid)
else
nil
end
end
defp mode_badge_color(mode), do: Activity.mode_badge_color(mode)
defp action_badge_color(action), do: Activity.action_badge_color(action)
# Administrators — Admin or Owner (or any "*" superadmin role) — may open any
# entry; everyone else only their own. Mirrors the list-scoping gate in
# Activity.Index — keep the two in lock-step.
defp can_view_entry?(scope, entry) do
# "Own" == authored by this user (actor), NOT merely targeted at them —
# see Activity.own_entry?/2, the single definition shared with the list.
Activity.full_log_access?(scope) or Activity.own_entry?(scope, entry)
end
end