Add audit log (#214)

* Add audit log

* Update translation files

* Improve Audit queries

* Improve Audit.Log schema

* Make user auth audit logs async

* Relax Flop and Flop Phoenix dep specs

* Make Flop.validate!/2 call more robust

* Improve a11y and UI for audit log live view

* Improve audit_logs indexes

* Fix formatting

* Fix async_log_action and tests

* Add remote_ip

* Update translation files
This commit is contained in:
Raúl R Pearson
2026-03-19 17:29:09 +00:00
committed by GitHub
parent 4a1af7d341
commit 4bbf9742c5
31 changed files with 2148 additions and 106 deletions

View File

@@ -75,6 +75,14 @@ MAIL_FROM_NAME=Claper
# GS_JPG_RESOLUTION=300x300
# LANGUAGES=en,fr,es,it,nl,de
# == Reverse proxy / IP forwarding (set these if Claper runs behind a load balancer or reverse proxy)
# Comma-separated list of trusted proxy IPs or CIDR ranges whose forwarding headers will be trusted
# REMOTE_IP_PROXIES=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
# Comma-separated list of headers to inspect for the real client IP (replaces the defaults: forwarded, x-forwarded-for, x-client-ip, x-real-ip)
# REMOTE_IP_HEADERS=forwarded,x-forwarded-for,x-client-ip,x-real-ip
# === OIDC configuration ===

View File

@@ -75,6 +75,8 @@ config :porcelain, driver: Porcelain.Driver.Basic
config :claper, :storage_dir, System.get_env("PRESENTATION_STORAGE_DIR", "priv/static")
config :flop, repo: Claper.Repo
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{config_env()}.exs"

View File

@@ -110,6 +110,22 @@ s3_public_url =
)
)
remote_ip_proxies =
get_var_from_path_or_env(config_dir, "REMOTE_IP_PROXIES", "")
|> String.split(",")
|> Enum.map(&String.trim/1)
|> Enum.reject(&(&1 == ""))
remote_ip_headers =
get_var_from_path_or_env(
config_dir,
"REMOTE_IP_HEADERS",
"forwarded,x-forwarded-for,x-client-ip,x-real-ip"
)
|> String.split(",")
|> Enum.map(&String.trim/1)
|> Enum.reject(&(&1 == ""))
same_site_cookie = get_var_from_path_or_env(config_dir, "SAME_SITE_COOKIE", "Lax")
secure_cookie =
@@ -192,7 +208,9 @@ config :claper,
email_confirmation: email_confirmation,
allow_unlink_external_provider: allow_unlink_external_provider,
logout_redirect_url: logout_redirect_url,
languages: languages
languages: languages,
remote_ip_proxies: remote_ip_proxies,
remote_ip_headers: remote_ip_headers
config :claper, :presentations,
max_file_size: max_file_size,

125
lib/claper/audit.ex Normal file
View File

@@ -0,0 +1,125 @@
defmodule Claper.Audit do
@moduledoc """
The Audit context for tracking actions in the system.
"""
import Ecto.Query, only: [from: 2]
alias Claper.{Accounts, Repo}
alias Claper.Audit.Log
@doc """
Logs an action.
## Examples
iex> log_action(user, "user.login", %{ip_address: "127.0.0.1"})
{:ok, %Log{}}
iex> log_action(nil, "system.startup", %{})
{:ok, %Log{}}
"""
def log_action(user, action, metadata \\ %{})
def log_action(%Accounts.User{} = user, action, metadata) do
create_log(%{
user_id: user.id,
action: action,
metadata: metadata
})
end
def log_action(nil, action, metadata) do
create_log(%{
action: action,
metadata: metadata
})
end
@doc """
Logs an action related to a specific resource.
## Examples
iex> log_resource_action(user, "event.create", "event", 123, %{})
{:ok, %Log{}}
"""
def log_resource_action(
%Accounts.User{} = user,
action,
resource_type,
resource_id,
metadata \\ %{}
) do
create_log(%{
user_id: user.id,
action: action,
resource_type: resource_type,
resource_id: resource_id,
metadata: metadata
})
end
@doc """
Returns a paginated, optionally filtered and sorted, list of audit logs.
"""
def list_logs(params \\ %{}) do
query = from l in Log, left_join: u in assoc(l, :user), as: :user, preload: [user: u]
Flop.validate_and_run!(query, params, for: Log, replace_invalid_params: true)
end
@doc """
Returns a list of distinct action types for filtering.
"""
def list_action_types do
from(l in Log,
distinct: true,
select: l.action,
order_by: l.action
)
|> Repo.all()
end
@doc """
Gets a single log.
Raises `Ecto.NoResultsError` if the Log does not exist.
## Examples
iex> get_log!(123)
%Log{}
iex> get_log!(456)
** (Ecto.NoResultsError)
"""
def get_log!(id) do
Repo.one!(
from l in Log, left_join: u in assoc(l, :user), where: l.id == ^id, preload: [user: u]
)
end
@doc """
Creates a log entry.
This is a simple wrapper over a low-level insert. You likely want to use
`log_action/3` and `log_resource_action/5` instead.
## Examples
iex> create_log(%{action: "user.login"})
{:ok, %Log{}}
iex> create_log(%{action: nil})
{:error, %Ecto.Changeset{}}
"""
def create_log(attrs \\ %{}) do
%Log{}
|> Log.changeset(attrs)
|> Repo.insert()
end
end

45
lib/claper/audit/log.ex Normal file
View File

@@ -0,0 +1,45 @@
defmodule Claper.Audit.Log do
use Ecto.Schema
import Ecto.Changeset
@derive {
Flop.Schema,
max_limit: 100,
filterable: [:action, :user_email],
sortable: [:inserted_at, :action],
default_order: %{
order_by: [:inserted_at],
order_directions: [:desc]
},
adapter_opts: [
join_fields: [
user_email: [
binding: :user,
field: :email,
path: [:user, :email]
]
]
]
}
schema "audit_logs" do
field :action, :string
field :resource_type, :string
field :resource_id, :integer
field :metadata, :map, default: %{}
belongs_to :user, Claper.Accounts.User
timestamps(updated_at: false)
end
@doc false
def changeset(log, attrs) do
log
|> cast(attrs, [:action, :resource_type, :resource_id, :metadata, :user_id])
|> validate_required([:action])
|> validate_length(:action, max: 255)
|> validate_length(:resource_type, max: 255)
|> assoc_constraint(:user)
end
end

View File

@@ -0,0 +1,498 @@
defmodule ClaperWeb.CoreComponents do
@moduledoc """
Provides core UI components.
At first glance, this module may seem daunting, but its goal is to provide
core building blocks for your application, such as tables, forms, and
inputs. The components consist mostly of markup and are well-documented
with doc strings and declarative assigns. You may customize and style
them in any way you want, based on your application growth and needs.
The foundation for styling is Tailwind CSS, a utility-first CSS framework,
augmented with daisyUI, a Tailwind CSS plugin that provides UI components
and themes. Here are useful references:
* [daisyUI](https://daisyui.com/docs/intro/) - a good place to get
started and see the available components.
* [Tailwind CSS](https://tailwindcss.com) - the foundational framework
we build on. You will use it for layout, sizing, flexbox, grid, and
spacing.
* [Heroicons](https://heroicons.com) - see `icon/1` for usage.
* [Phoenix.Component](https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html) -
the component system used by Phoenix. Some components, such as `<.link>`
and `<.form>`, are defined there.
"""
use Phoenix.Component
use Gettext, backend: ClaperWeb.Gettext
alias Phoenix.LiveView.JS
@doc """
Renders flash notices.
## Examples
<.flash kind={:info} flash={@flash} />
<.flash kind={:info} phx-mounted={show("#flash")}>Welcome Back!</.flash>
"""
attr :id, :string, doc: "the optional id of flash container"
attr :flash, :map, default: %{}, doc: "the map of flash messages to display"
attr :title, :string, default: nil
attr :kind, :atom, values: [:info, :error], doc: "used for styling and flash lookup"
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the flash container"
slot :inner_block, doc: "the optional inner block that renders the flash message"
def flash(assigns) do
assigns = assign_new(assigns, :id, fn -> "flash-#{assigns.kind}" end)
~H"""
<div
:if={msg = render_slot(@inner_block) || Phoenix.Flash.get(@flash, @kind)}
id={@id}
phx-click={JS.push("lv:clear-flash", value: %{key: @kind}) |> hide("##{@id}")}
role="alert"
class="toast toast-top toast-end z-50"
{@rest}
>
<div class={[
"alert w-80 sm:w-96 max-w-80 sm:max-w-96 text-wrap",
@kind == :info && "alert-info",
@kind == :error && "alert-error"
]}>
<.icon :if={@kind == :info} name="hero-information-circle" class="size-5 shrink-0" />
<.icon :if={@kind == :error} name="hero-exclamation-circle" class="size-5 shrink-0" />
<div>
<p :if={@title} class="font-semibold">{@title}</p>
<p>{msg}</p>
</div>
<div class="flex-1" />
<button type="button" class="group self-start cursor-pointer" aria-label={gettext("close")}>
<.icon name="hero-x-mark" class="size-5 opacity-40 group-hover:opacity-70" />
</button>
</div>
</div>
"""
end
@doc """
Renders a button with navigation support.
## Examples
<.button>Send!</.button>
<.button phx-click="go" variant="primary">Send!</.button>
<.button navigate={~p"/"}>Home</.button>
"""
attr :rest, :global, include: ~w(href navigate patch method download name value disabled)
attr :class, :any
attr :variant, :string, values: ~w(primary)
slot :inner_block, required: true
def button(%{rest: rest} = assigns) do
variants = %{"primary" => "btn-primary", nil => "btn-primary btn-soft"}
assigns =
assign_new(assigns, :class, fn ->
["btn", Map.fetch!(variants, assigns[:variant])]
end)
if rest[:href] || rest[:navigate] || rest[:patch] do
~H"""
<.link class={@class} {@rest}>
{render_slot(@inner_block)}
</.link>
"""
else
~H"""
<button class={@class} {@rest}>
{render_slot(@inner_block)}
</button>
"""
end
end
@doc """
Renders an input with label and error messages.
A `Phoenix.HTML.FormField` may be passed as argument,
which is used to retrieve the input name, id, and values.
Otherwise all attributes may be passed explicitly.
## Types
This function accepts all HTML input types, considering that:
* You may also set `type="select"` to render a `<select>` tag
* `type="checkbox"` is used exclusively to render boolean values
* For live file uploads, see `Phoenix.Component.live_file_input/1`
See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input
for more information. Unsupported types, such as radio, are best
written directly in your templates.
## Examples
```heex
<.input field={@form[:email]} type="email" />
<.input name="my-input" errors={["oh no!"]} />
```
## Select type
When using `type="select"`, you must pass the `options` and optionally
a `value` to mark which option should be preselected.
```heex
<.input field={@form[:user_type]} type="select" options={["Admin": "admin", "User": "user"]} />
```
For more information on what kind of data can be passed to `options` see
[`options_for_select`](https://hexdocs.pm/phoenix_html/Phoenix.HTML.Form.html#options_for_select/2).
"""
attr :id, :any, default: nil
attr :name, :any
attr :label, :string, default: nil
attr :value, :any
attr :type, :string,
default: "text",
values: ~w(checkbox color date datetime-local email file month number password
search select tel text textarea time url week hidden)
attr :field, Phoenix.HTML.FormField,
doc: "a form field struct retrieved from the form, for example: @form[:email]"
attr :errors, :list, default: []
attr :checked, :boolean, doc: "the checked flag for checkbox inputs"
attr :prompt, :string, default: nil, doc: "the prompt for select inputs"
attr :options, :list, doc: "the options to pass to Phoenix.HTML.Form.options_for_select/2"
attr :multiple, :boolean, default: false, doc: "the multiple flag for select inputs"
attr :class, :any, default: nil, doc: "the input class to use over defaults"
attr :error_class, :any, default: nil, doc: "the input error class to use over defaults"
attr :rest, :global,
include: ~w(accept autocomplete capture cols disabled form list max maxlength min minlength
multiple pattern placeholder readonly required rows size step)
def input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do
errors = if Phoenix.Component.used_input?(field), do: field.errors, else: []
assigns
|> assign(field: nil, id: assigns.id || field.id)
|> assign(:errors, Enum.map(errors, &translate_error(&1)))
|> assign_new(:name, fn -> if assigns.multiple, do: field.name <> "[]", else: field.name end)
|> assign_new(:value, fn -> field.value end)
|> input()
end
def input(%{type: "hidden"} = assigns) do
~H"""
<input type="hidden" id={@id} name={@name} value={@value} {@rest} />
"""
end
def input(%{type: "checkbox"} = assigns) do
assigns =
assign_new(assigns, :checked, fn ->
Phoenix.HTML.Form.normalize_value("checkbox", assigns[:value])
end)
~H"""
<div>
<label>
<input
type="hidden"
name={@name}
value="false"
disabled={@rest[:disabled]}
form={@rest[:form]}
/>
<span class="label">
<input
type="checkbox"
id={@id}
name={@name}
value="true"
checked={@checked}
class={@class || "checkbox checkbox-sm"}
{@rest}
/>{@label}
</span>
</label>
<.error :for={msg <- @errors}>{msg}</.error>
</div>
"""
end
def input(%{type: "select"} = assigns) do
~H"""
<div>
<label>
<span :if={@label} class="label mb-1">{@label}</span>
<select
id={@id}
name={@name}
class={[@class || "w-full select", @errors != [] && (@error_class || "select-error")]}
multiple={@multiple}
{@rest}
>
<option :if={@prompt} value="">{@prompt}</option>
{Phoenix.HTML.Form.options_for_select(@options, @value)}
</select>
</label>
<.error :for={msg <- @errors}>{msg}</.error>
</div>
"""
end
def input(%{type: "textarea"} = assigns) do
~H"""
<div>
<label>
<span :if={@label} class="label mb-1">{@label}</span>
<textarea
id={@id}
name={@name}
class={[
@class || "w-full textarea",
@errors != [] && (@error_class || "textarea-error")
]}
{@rest}
>{Phoenix.HTML.Form.normalize_value("textarea", @value)}</textarea>
</label>
<.error :for={msg <- @errors}>{msg}</.error>
</div>
"""
end
# All other inputs text, datetime-local, url, password, etc. are handled here...
def input(assigns) do
~H"""
<div>
<label>
<span :if={@label} class="label mb-1">{@label}</span>
<input
type={@type}
name={@name}
id={@id}
value={Phoenix.HTML.Form.normalize_value(@type, @value)}
class={[
@class || "w-full input",
@errors != [] && (@error_class || "input-error")
]}
{@rest}
/>
</label>
<.error :for={msg <- @errors}>{msg}</.error>
</div>
"""
end
# Helper used by inputs to generate form errors
defp error(assigns) do
~H"""
<p class="mt-1.5 flex gap-2 items-center text-sm text-error">
<.icon name="hero-exclamation-circle" class="size-5" />
{render_slot(@inner_block)}
</p>
"""
end
@doc """
Renders a header with title.
"""
slot :inner_block, required: true
slot :subtitle
slot :actions
def header(assigns) do
~H"""
<header class={[@actions != [] && "flex items-center justify-between gap-6", "pb-4"]}>
<div>
<h1 class="text-lg font-semibold leading-8">
{render_slot(@inner_block)}
</h1>
<p :if={@subtitle != []} class="text-sm text-base-content/70">
{render_slot(@subtitle)}
</p>
</div>
<div class="flex-none">{render_slot(@actions)}</div>
</header>
"""
end
@doc """
Renders a table with generic styling.
## Examples
<.table id="users" rows={@users}>
<:col :let={user} label="id">{user.id}</:col>
<:col :let={user} label="username">{user.username}</:col>
</.table>
"""
attr :id, :string, required: true
attr :rows, :list, required: true
attr :row_id, :any, default: nil, doc: "the function for generating the row id"
attr :row_click, :any, default: nil, doc: "the function for handling phx-click on each row"
attr :row_item, :any,
default: &Function.identity/1,
doc: "the function for mapping each row before calling the :col and :action slots"
slot :col, required: true do
attr :label, :string
end
slot :action, doc: "the slot for showing user actions in the last table column"
def table(assigns) do
assigns =
with %{rows: %Phoenix.LiveView.LiveStream{}} <- assigns do
assign(assigns, row_id: assigns.row_id || fn {id, _item} -> id end)
end
~H"""
<table class="table table-zebra">
<thead>
<tr>
<th :for={col <- @col}>{col[:label]}</th>
<th :if={@action != []}>
<span class="sr-only">{gettext("Actions")}</span>
</th>
</tr>
</thead>
<tbody id={@id} phx-update={is_struct(@rows, Phoenix.LiveView.LiveStream) && "stream"}>
<tr :for={row <- @rows} id={@row_id && @row_id.(row)}>
<td
:for={col <- @col}
phx-click={@row_click && @row_click.(row)}
class={@row_click && "hover:cursor-pointer"}
>
{render_slot(col, @row_item.(row))}
</td>
<td :if={@action != []} class="w-0 font-semibold">
<div class="flex gap-4">
<%= for action <- @action do %>
{render_slot(action, @row_item.(row))}
<% end %>
</div>
</td>
</tr>
</tbody>
</table>
"""
end
@doc """
Renders a data list.
## Examples
<.list>
<:item title="Title">{@post.title}</:item>
<:item title="Views">{@post.views}</:item>
</.list>
"""
slot :item, required: true do
attr :title, :string, required: true
end
def list(assigns) do
~H"""
<ul class="list">
<li :for={item <- @item} class="list-row">
<div class="list-col-grow">
<div class="font-bold">{item.title}</div>
<div>{render_slot(item)}</div>
</div>
</li>
</ul>
"""
end
@doc """
Renders a [Heroicon](https://heroicons.com).
Heroicons come in three styles outline, solid, and mini.
By default, the outline style is used, but solid and mini may
be applied by using the `-solid` and `-mini` suffix.
You can customize the size and colors of the icons by setting
width, height, and background color classes.
Icons are extracted from the `deps/heroicons` directory and bundled within
your compiled app.css by the plugin in `assets/vendor/heroicons.js`.
## Examples
<.icon name="hero-x-mark" />
<.icon name="hero-arrow-path" class="ml-1 size-3 motion-safe:animate-spin" />
"""
attr :name, :string, required: true
attr :class, :any, default: "size-4"
def icon(%{name: "hero-" <> _} = assigns) do
~H"""
<span class={[@name, @class]} />
"""
end
## JS Commands
def show(js \\ %JS{}, selector) do
JS.show(js,
to: selector,
time: 300,
transition:
{"transition-all ease-out duration-300",
"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95",
"opacity-100 translate-y-0 sm:scale-100"}
)
end
def hide(js \\ %JS{}, selector) do
JS.hide(js,
to: selector,
time: 200,
transition:
{"transition-all ease-in duration-200", "opacity-100 translate-y-0 sm:scale-100",
"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"}
)
end
@doc """
Translates an error message using gettext.
"""
def translate_error({msg, opts}) do
# When using gettext, we typically pass the strings we want
# to translate as a static argument:
#
# # Translate the number of files with plural rules
# dngettext("errors", "1 file", "%{count} files", count)
#
# However the error messages in our forms and APIs are generated
# dynamically, so we need to translate them by calling Gettext
# with our gettext backend as first argument. Translations are
# available in the errors.po file (as we use the "errors" domain).
if count = opts[:count] do
Gettext.dngettext(ClaperWeb.Gettext, "errors", msg, msg, count, opts)
else
Gettext.dgettext(ClaperWeb.Gettext, "errors", msg, opts)
end
end
@doc """
Translates the errors for a field from a keyword list of errors.
"""
def translate_errors(errors, field) when is_list(errors) do
for {^field, {msg, opts}} <- errors, do: translate_error({msg, opts})
end
end

View File

@@ -0,0 +1,57 @@
defmodule ClaperWeb.Icons do
use Phoenix.Component
def eye(assigns) do
~H"""
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
class="w-5 h-5"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"
/>
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
"""
end
def arrow_up(assigns) do
~H"""
<svg
class="ml-2 h-5 w-5 text-gray-500 group-hover:text-gray-700 inline"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fill-rule="evenodd"
d="M5.293 7.707a1 1 0 010-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 01-1.414 1.414L11 5.414V17a1 1 0 11-2 0V5.414L6.707 7.707a1 1 0 01-1.414 0z"
clip-rule="evenodd"
/>
</svg>
"""
end
def arrow_down(assigns) do
~H"""
<svg
class="ml-2 h-5 w-5 text-gray-500 group-hover:text-gray-700 inline"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fill-rule="evenodd"
d="M14.707 12.293a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 111.414-1.414L9 14.586V3a1 1 0 012 0v11.586l2.293-2.293a1 1 0 011.414 0z"
clip-rule="evenodd"
/>
</svg>
"""
end
end

View File

@@ -4,10 +4,13 @@ defmodule ClaperWeb.UserAuth do
"""
use ClaperWeb, :controller
require Logger
import Plug.Conn
import Phoenix.Controller
import ClaperWeb.Helpers.ConnUtils, only: [get_client_ip: 1, get_user_agent: 1]
alias Claper.Accounts
alias Claper.{Accounts, Audit}
# Make the remember me cookie valid for 60 days.
# If you want bump or reduce this value, also change
@@ -32,6 +35,11 @@ defmodule ClaperWeb.UserAuth do
token = Accounts.generate_user_session_token(user)
user_return_to = get_session(conn, :user_return_to)
async_log_action(user, "user.login", %{
ip_address: get_client_ip(conn),
user_agent: get_user_agent(conn)
})
conn
|> renew_session()
|> put_session(:user_token, token)
@@ -83,6 +91,11 @@ defmodule ClaperWeb.UserAuth do
ClaperWeb.Endpoint.broadcast(live_socket_id, "disconnect", %{})
end
async_log_action(conn.assigns[:current_user], "user.logout", %{
ip_address: get_client_ip(conn),
user_agent: get_user_agent(conn)
})
conn
|> renew_session()
|> delete_resp_cookie(@remember_me_cookie)
@@ -161,4 +174,14 @@ defmodule ClaperWeb.UserAuth do
defp maybe_store_return_to(conn), do: conn
defp signed_in_path(_conn), do: "/events"
defp async_log_action(user, action, metadata) do
Task.Supervisor.start_child(Claper.TaskSupervisor, fn ->
with {:error, reason} <- Audit.log_action(user, action, metadata) do
Logger.error(
"Error creating #{inspect(action)} audit log for user #{inspect(get_in(user.email))}: #{inspect(reason)}"
)
end
end)
end
end

View File

@@ -60,6 +60,10 @@ defmodule ClaperWeb.Endpoint do
plug(:runtime_session)
plug RemoteIp,
proxies: {Application, :get_env, [:claper, :remote_ip_proxies, []]},
headers: {Application, :get_env, [:claper, :remote_ip_headers, []]}
plug ClaperWeb.Router
def runtime_session(conn, _opts) do

View File

@@ -0,0 +1,31 @@
defmodule ClaperWeb.Helpers.ConnUtils do
@moduledoc """
Utility functions for extracting information from Plug.Conn.
"""
@doc """
Extracts the client IP address from the connection.
The `RemoteIp` plug (configured in the endpoint) resolves the real client IP
by inspecting the headers defined in `REMOTE_IP_HEADERS` and trusting only
the proxies listed in `REMOTE_IP_PROXIES`, then rewrites `conn.remote_ip`
before this is called.
"""
def get_client_ip(conn) do
conn.remote_ip |> :inet.ntoa() |> to_string()
end
@doc """
Extracts the user agent string from the connection.
Returns `nil` if no user agent header is present.
"""
def get_user_agent(conn) do
user_agent = Plug.Conn.get_req_header(conn, "user-agent")
case user_agent do
[ua | _] -> ua
[] -> nil
end
end
end

View File

@@ -0,0 +1,74 @@
defmodule ClaperWeb.AdminLive.AuditLogLive do
use ClaperWeb, :live_view
alias Claper.Audit
@impl Phoenix.LiveView
def mount(_params, session, socket) do
with %{"locale" => locale} <- session do
Gettext.put_locale(ClaperWeb.Gettext, locale)
end
{:ok, socket}
end
@impl Phoenix.LiveView
def handle_params(params, _url, socket) do
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
end
defp apply_action(socket, :index, params) do
{logs, meta} = Audit.list_logs(params)
socket
|> assign(:page_title, gettext("Audit Logs"))
|> assign(:logs, logs)
|> assign(:meta, meta)
|> assign(:form, Phoenix.Component.to_form(meta))
|> assign_new(:action_types, &Audit.list_action_types/0)
|> assign_new(:fields, fn %{action_types: action_types} ->
[
user_email: [
label: nil,
placeholder: gettext("Search by user email"),
type: "text",
op: :ilike_or
],
action: [
label: nil,
prompt: gettext("All actions"),
field: :action,
type: "select",
options: action_types
]
]
end)
end
defp apply_action(socket, :show, %{"id" => id}) do
socket
|> assign(:page_title, gettext("Audit Log Details"))
|> assign(:log, Audit.get_log!(id))
end
@impl Phoenix.LiveView
def handle_event("filter-logs", unsigned_params, socket) do
flop = Flop.validate!(unsigned_params, for: Audit.Log, replace_invalid_params: true)
to = Flop.Phoenix.build_path(~p"/admin/audit_logs", flop)
{:noreply, push_patch(socket, to: to)}
end
defp format_metadata(nil), do: ""
defp format_metadata(metadata) when map_size(metadata) == 0, do: ""
defp format_metadata(metadata) do
Enum.map_join(metadata, ", ", fn {k, v} -> "#{k}: #{v}" end)
end
defp format_timestamp(%NaiveDateTime{} = timestamp) do
Calendar.strftime(timestamp, "%Y-%m-%d %H:%M:%S\u00A0UTC")
end
defp format_timestamp(timestamp), do: inspect(timestamp)
end

View File

@@ -0,0 +1,169 @@
<h1 class="text-3xl font-bold mb-24">{@page_title}</h1>
<%= if @live_action == :index do %>
<div class="flex flex-col sm:flex-row items-stretch gap-3 @container/controls">
<.form
for={@form}
class="grow flex flex-col sm:flex-row gap-3 sm:[&>div]:basis-[250px]"
phx-change="filter-logs"
>
<Flop.Phoenix.filter_fields :let={i} form={@form} fields={@fields}>
<ClaperWeb.CoreComponents.input field={i.field} label={i.label} type={i.type} {i.rest} />
</Flop.Phoenix.filter_fields>
</.form>
<Flop.Phoenix.pagination
meta={@meta}
path={~p"/admin/audit_logs"}
class="flex [&>ul]:mr-3 justify-end"
page_list_attrs={[class: "hidden @4xl/controls:flex"]}
page_list_item_attrs={[
class:
"grid place-content-stretch min-h-10 min-w-10 border-t border-r border-b border-gray-300 first:border-l first:rounded-l-full last:rounded-r-full first:[&>*]:rounded-l-full last:[&>*]:rounded-r-full text-gray-500 bg-white [&>*]:grid [&>*]:place-content-center"
]}
page_link_attrs={[
class: "hover:text-black hover:bg-gray-200"
]}
current_page_link_attrs={[
class: "pointer-events-none font-bold text-black"
]}
>
<:previous attrs={[
class:
"order-1 border border-gray-300 rounded-l-full h-10 p-5 bg-white flex items-center justify-center aria-disabled:text-gray-300 hover:not-aria-disabled:bg-gray-200"
]}>
{gettext("Previous")}
</:previous>
<:next attrs={[
class:
"order-2 border-t border-r border-b border-gray-300 rounded-r-full h-10 p-5 bg-white flex items-center justify-center aria-disabled:text-gray-300 hover:not-aria-disabled:bg-gray-200"
]}>
{gettext("Next")}
</:next>
<:ellipsis>
<span aria-hidden="true" class="text-gray-300">•••</span>
</:ellipsis>
</Flop.Phoenix.pagination>
</div>
<Flop.Phoenix.table
items={@logs}
meta={@meta}
path={~p"/admin/audit_logs"}
opts={[
container: true,
container_attrs: [class: "card bg-base-100 shadow-xl overflow-x-auto my-5"],
no_results_content: ~H"""
<p class="text-center py-10">{gettext("No results.")}</p>
""",
table_attrs: [class: "table table-zebra w-full"],
symbol_asc: ~H"""
<span aria-hidden="true"><ClaperWeb.Icons.arrow_up /></span>
""",
symbol_desc: ~H"""
<span aria-hidden="true"><ClaperWeb.Icons.arrow_down /></span>
"""
]}
>
<:col :let={log} label={gettext("ID")} field={:id}>{log.id}</:col>
<:col :let={log} label={gettext("Action")} field={:action}>
<span class="badge badge-outline">{log.action}</span>
</:col>
<:col :let={log} label={gettext("User")} field={:user_email}>
{get_in(log.user.email) || "—"}
</:col>
<:col :let={log} label={gettext("Timestamp")} field={:inserted_at}>
{format_timestamp(log.inserted_at)}
</:col>
<:col
:let={log}
label={gettext("Metadata")}
field={:metadata}
tbody_td_attrs={[class: "max-w-xs truncate text-sm text-base-content/70"]}
>
{format_metadata(log.metadata)}
</:col>
<:action :let={log} tbody_td_attrs={[class: "text-right"]}>
<.link
patch={~p"/admin/audit_logs/#{log}"}
class="btn btn-link btn-sm"
aria-label={gettext("View details for log #%{id}", id: log.id)}
>
<ClaperWeb.Icons.eye />
</.link>
</:action>
</Flop.Phoenix.table>
<% end %>
<%= if @live_action == :show do %>
<dl class="card card-body bg-base-100 shadow-xl grid grid-cols-1 sm:grid-cols-[auto_1fr] gap-5">
<div class="col-span-full grid grid-cols-subgrid gap-y-1 items-baseline">
<dt class="font-medium sm:text-right">{gettext("ID")}</dt>
<dd class="bg-base-200 p-3 rounded-lg inset-shadow-sm overflow-x-auto">
{@log.id}
</dd>
</div>
<div class="col-span-full grid grid-cols-subgrid gap-y-1 items-baseline">
<dt class="font-medium sm:text-right">{gettext("Action")}</dt>
<dd class="bg-base-200 p-3 rounded-lg inset-shadow-sm overflow-x-auto">
<span class="badge badge-outline">{@log.action}</span>
</dd>
</div>
<div class="col-span-full grid grid-cols-subgrid gap-y-1 items-baseline">
<dt class="font-medium sm:text-right">{gettext("User")}</dt>
<dd class="bg-base-200 p-3 rounded-lg inset-shadow-sm overflow-x-auto">
<%= if @log.user do %>
<span class="space-x-2">
<a href={"mailto:#{@log.user.email}"} class="link link-primary">{@log.user.email}</a>
<.link
navigate={~p"/admin/users/#{@log.user}"}
class="link link-primary *:inline"
aria-label={gettext("View profile for %{email}", email: @log.user.email)}
>
<ClaperWeb.Icons.eye />
</.link>
</span>
<% else %>
<% end %>
</dd>
</div>
<div class="col-span-full grid grid-cols-subgrid gap-y-1 items-baseline">
<dt class="font-medium sm:text-right">{gettext("Timestamp")}</dt>
<dd class="bg-base-200 p-3 rounded-lg inset-shadow-sm overflow-x-auto">
{format_timestamp(@log.inserted_at)}
</dd>
</div>
<%= if @log.resource_type do %>
<div class="col-span-full grid grid-cols-subgrid gap-y-1 items-baseline">
<dt class="font-medium sm:text-right">{gettext("Resource Type")}</dt>
<dd class="bg-base-200 p-3 rounded-lg inset-shadow-sm overflow-x-auto">
{@log.resource_type}
</dd>
</div>
<% end %>
<%= if @log.resource_id do %>
<div class="col-span-full grid grid-cols-subgrid gap-y-1 items-baseline">
<dt class="font-medium sm:text-right">{gettext("Resource ID")}</dt>
<dd class="bg-base-200 p-3 rounded-lg inset-shadow-sm overflow-x-auto">
{@log.resource_id}
</dd>
</div>
<% end %>
<div class="col-span-full grid grid-cols-subgrid gap-y-1 items-baseline">
<dt class="font-medium sm:text-right">{gettext("Metadata")}</dt>
<dd class="bg-base-200 p-3 rounded-lg inset-shadow-sm overflow-x-auto">
<%= if @log.metadata && map_size(@log.metadata) > 0 do %>
<dl class="space-y-2 min-w-min">
<%= for {key, value} <- @log.metadata do %>
<div class="ml-5 -indent-5">
<dt class="inline font-medium">{key}:</dt>
<dd class="inline">{value}</dd>
</div>
<% end %>
</dl>
<% else %>
<% end %>
</dd>
</div>
</dl>
<% end %>

View File

@@ -198,6 +198,9 @@ defmodule ClaperWeb.Router do
live "/oidc_providers/new", OidcProviderLive, :new
live "/oidc_providers/:id/edit", OidcProviderLive, :edit
live "/oidc_providers/:id", OidcProviderLive, :show
live "/audit_logs", AuditLogLive, :index
live "/audit_logs/:id", AuditLogLive, :show
end
end
end

View File

@@ -18,7 +18,7 @@
<div class="drawer lg:drawer-open">
<input id="drawer-toggle" type="checkbox" class="drawer-toggle" />
<div class="drawer-content flex flex-col">
<div class="drawer-content flex flex-col min-h-screen">
<!-- Navbar for mobile -->
<div class="navbar lg:hidden bg-base-100 shadow-lg">
<div class="flex-none">
@@ -230,6 +230,22 @@
{gettext("Users")}
</.link>
</li>
<li>
<.link
patch={~p"/admin/audit_logs"}
class={"#{if @conn.path_info == ["admin", "audit_logs"], do: "active", else: ""}"}
>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
/>
</svg>
{gettext("Audit Logs")}
</.link>
</li>
<%!-- <li>
<.link
patch={~p"/admin/oidc_providers"}

View File

@@ -115,6 +115,9 @@ defmodule Claper.MixProject do
{:oidcc, "~> 3.5"},
{:oban, "~> 2.19"},
{:hammer, "~> 7.0"},
{:flop, "~> 0.26"},
{:flop_phoenix, "~> 0.25"},
{:remote_ip, "~> 1.2"},
{:tailwind, "~> 0.3", runtime: Mix.env() == :dev}
]
end

View File

@@ -2,6 +2,7 @@
"bcrypt_elixir": {:hex, :bcrypt_elixir, "3.3.2", "d50091e3c9492d73e17fc1e1619a9b09d6a5ef99160eb4d736926fd475a16ca3", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "471be5151874ae7931911057d1467d908955f93554f7a6cd1b7d804cac8cef53"},
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
"castore": {:hex, :castore, "1.0.14", "4582dd7d630b48cf5e1ca8d3d42494db51e406b7ba704e81fbd401866366896a", [:mix], [], "hexpm", "7bc1b65249d31701393edaaac18ec8398d8974d52c647b7904d01b964137b9f4"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
"comeonin": {:hex, :comeonin, "5.5.1", "5113e5f3800799787de08a6e0db307133850e635d34e9fab23c70b6501669510", [:mix], [], "hexpm", "65aac8f19938145377cee73973f192c5645873dcf550a8a6b18187d17c13ccdb"},
"cowboy": {:hex, :cowboy, "2.13.0", "09d770dd5f6a22cc60c071f432cd7cb87776164527f205c5a6b0f24ff6b38990", [:make, :rebar3], [{:cowlib, ">= 2.14.0 and < 3.0.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, ">= 1.8.0 and < 3.0.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "e724d3a70995025d654c1992c7b11dbfea95205c047d86ff9bf1cda92ddc5614"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
@@ -23,6 +24,8 @@
"file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"},
"finch": {:hex, :finch, "0.19.0", "c644641491ea854fc5c1bbaef36bfc764e3f08e7185e1f084e35e0672241b76d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "fc5324ce209125d1e2fa0fcd2634601c52a787aff1cd33ee833664a5af4ea2b6"},
"floki": {:hex, :floki, "0.38.0", "62b642386fa3f2f90713f6e231da0fa3256e41ef1089f83b6ceac7a3fd3abf33", [:mix], [], "hexpm", "a5943ee91e93fb2d635b612caf5508e36d37548e84928463ef9dd986f0d1abd9"},
"flop": {:hex, :flop, "0.26.3", "9bc700b34f96a57e56aaa89b850926356311372556eacd5a1abe0fdd0ea40bf2", [:mix], [{:ecto, "~> 3.11", [hex: :ecto, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}], "hexpm", "cd77588229778ac55560c90dfbe15ab6486773f067d6e52db9fa703b8c9a9d2d"},
"flop_phoenix": {:hex, :flop_phoenix, "0.25.3", "a623649f6cd00ce3be1eac8dbd6d4fadf47a3212c7d2fc4701f6f2f90f347549", [:mix], [{:flop, ">= 0.23.0 and < 0.27.0", [hex: :flop, repo: "hexpm", optional: false]}, {:phoenix, ">= 1.6.0 and < 1.9.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 1.0.6 or ~> 1.1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "912fae3c343dde43c5ea4f642275793d9dbef32989bf200013e12b85adb93b9c"},
"gen_smtp": {:hex, :gen_smtp, "1.3.0", "62c3d91f0dcf6ce9db71bcb6881d7ad0d1d834c7f38c13fa8e952f4104a8442e", [:rebar3], [{:ranch, ">= 1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "0b73fbf069864ecbce02fe653b16d3f35fd889d0fdd4e14527675565c39d84e6"},
"gettext": {:hex, :gettext, "0.26.2", "5978aa7b21fada6deabf1f6341ddba50bc69c999e812211903b169799208f2a8", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "aa978504bcf76511efdc22d580ba08e2279caab1066b76bb9aa81c4a1e0a32a5"},
"hammer": {:hex, :hammer, "7.2.0", "73113eca87f0fd20a6d3679c1182e8c4c1778266f61de4e9dc8c589dee156c30", [:mix], [], "hexpm", "c50fa865ddfe7b3d4f8a6941f56940679e02a9a1465b00668a95d140b101d828"},
@@ -60,6 +63,7 @@
"porcelain": {:hex, :porcelain, "2.0.3", "2d77b17d1f21fed875b8c5ecba72a01533db2013bd2e5e62c6d286c029150fdc", [:mix], [], "hexpm", "dc996ab8fadbc09912c787c7ab8673065e50ea1a6245177b0c24569013d23620"},
"postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"},
"ranch": {:hex, :ranch, "2.2.0", "25528f82bc8d7c6152c57666ca99ec716510fe0925cb188172f41ce93117b1b0", [:make, :rebar3], [], "hexpm", "fa0b99a1780c80218a4197a59ea8d3bdae32fbff7e88527d7d8a4787eff4f8e7"},
"remote_ip": {:hex, :remote_ip, "1.2.0", "fb078e12a44414f4cef5a75963c33008fe169b806572ccd17257c208a7bc760f", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "2ff91de19c48149ce19ed230a81d377186e4412552a597d6a5137373e5877cb7"},
"req": {:hex, :req, "0.5.14", "521b449fa0bf275e6d034c05f29bec21789a0d6cd6f7a1c326c7bee642bf6e07", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "b7b15692071d556c73432c7797aa7e96b51d1a2db76f746b976edef95c930021"},
"sweet_xml": {:hex, :sweet_xml, "0.7.5", "803a563113981aaac202a1dbd39771562d0ad31004ddbfc9b5090bdcd5605277", [:mix], [], "hexpm", "193b28a9b12891cae351d81a0cead165ffe67df1b73fe5866d10629f4faefb12"},
"swoosh": {:hex, :swoosh, "1.19.3", "02ad4455939f502386e4e1443d4de94c514995fd0e51b3cafffd6bd270ffe81c", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.3", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5.10 or ~> 0.6 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "04a10f8496786b744b84130e3510eb53ca51e769c39511b65023bdf4136b732f"},

View File

@@ -18,7 +18,7 @@ msgstr "Einstellungen"
#: lib/claper_web/live/admin_live/user_live.html.heex:74
#: lib/claper_web/live/admin_live/user_live.html.heex:254
#: lib/claper_web/live/admin_live/user_live/form_component.ex:18
#: lib/claper_web/live/event_live/manage.ex:838
#: lib/claper_web/live/event_live/manage.ex:844
#: lib/claper_web/live/form_live/form_component.html.heex:32
#: lib/claper_web/live/user_settings_live/show.html.heex:34
#: lib/claper_web/templates/user_registration/new.html.heex:29
@@ -476,9 +476,9 @@ msgstr "Interaktion hinzufügen"
msgid "Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
msgstr "Wenn Sie diesen Benutzer sperren, werden alle seine Nachrichten gelöscht, und er kann nicht mehr beitreten. Bestätigen?"
#: lib/claper_web/live/event_live/show.ex:51
#: lib/claper_web/live/event_live/show.ex:206
#: lib/claper_web/live/event_live/show.ex:221
#: lib/claper_web/live/event_live/show.ex:64
#: lib/claper_web/live/event_live/show.ex:219
#: lib/claper_web/live/event_live/show.ex:234
#, elixir-autogen, elixir-format
msgid "You have been banned from this event"
msgstr "Sie wurden von dieser Veranstaltung ausgeschlossen"
@@ -705,7 +705,7 @@ msgstr "Formulareinsendungen der Teilnehmer werden hier angezeigt."
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:74
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:254
#: lib/claper_web/live/admin_live/oidc_provider_live/form_component.ex:24
#: lib/claper_web/live/event_live/manage.ex:837
#: lib/claper_web/live/event_live/manage.ex:843
#, elixir-autogen, elixir-format
msgid "Name"
msgstr "Name"
@@ -1068,6 +1068,7 @@ msgstr "Hier finden Sie alle Interaktionen Ihrer Teilnehmer. Sie können Nachric
msgid "Identify users by their unique avatars."
msgstr "Identifizieren Sie Benutzer anhand ihrer einzigartigen Avatare."
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:40
#: lib/claper_web/live/event_live/event_form_component.html.heex:5
#: lib/claper_web/live/event_live/index.html.heex:106
#: lib/claper_web/live/event_live/manage.html.heex:427
@@ -1194,7 +1195,7 @@ msgstr "Wählen Sie Ihre Präsentation aus (optional)"
msgid "This code will be used by your attendees to access the event. You have the option to create a custom code."
msgstr "Dieser Code wird von Ihren Teilnehmern verwendet, um auf die Veranstaltung zuzugreifen. Sie haben die Möglichkeit, einen benutzerdefinierten Code zu erstellen."
#: lib/claper_web/live/event_live/show.ex:193
#: lib/claper_web/live/event_live/show.ex:206
#, elixir-autogen, elixir-format
msgid "This event has been terminated"
msgstr "Diese Veranstaltung wurde beendet"
@@ -1216,7 +1217,7 @@ msgstr "Erstellen Sie Ihre nächste Präsentation mit"
#: lib/claper_web/live/event_live/manage.ex:23
#: lib/claper_web/live/event_live/presenter.ex:26
#: lib/claper_web/live/event_live/show.ex:25
#: lib/claper_web/live/event_live/show.ex:38
#, elixir-autogen, elixir-format
msgid "Event doesn't exist"
msgstr "Veranstaltung existiert nicht"
@@ -1272,7 +1273,7 @@ msgid "Event manager"
msgstr "Veranstaltungsmanager"
#: lib/claper_web/templates/layout/_user_menu.html.heex:19
#: lib/claper_web/templates/layout/admin.html.heex:262
#: lib/claper_web/templates/layout/admin.html.heex:278
#, elixir-autogen, elixir-format
msgid "Documentation"
msgstr "Dokumentation"
@@ -1475,6 +1476,7 @@ msgid "Please enter a valid link starting with http:// or https://"
msgstr "Bitte geben Sie einen gültigen Link ein, der mit http:// oder https:// beginnt"
#: lib/claper/embeds/embed.ex:98
#: lib/claper/embeds/embed.ex:122
#, elixir-autogen, elixir-format
msgid "Please enter valid HTML content with an iframe tag"
msgstr "Bitte geben Sie gültigen HTML-Inhalt mit einem iframe-Tag ein"
@@ -1564,12 +1566,12 @@ msgstr "Beenden"
msgid "More options"
msgstr "Weitere Optionen"
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "No"
msgstr "Nein"
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "Yes"
msgstr "Ja"
@@ -1718,6 +1720,7 @@ msgstr "Neues Quiz"
msgid "Presentation"
msgstr "Präsentation"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:34
#: lib/claper_web/live/event_live/manager_settings_component.ex:168
#, elixir-autogen, elixir-format
msgid "Previous"
@@ -1932,6 +1935,7 @@ msgstr "Ein eindeutiger Name zur Identifikation dieses OIDC-Anbieters"
msgid "Account is confirmed and active"
msgstr "Konto ist bestätigt und aktiv"
#: lib/claper_web/components/core_components.ex:368
#: lib/claper_web/live/admin_live/event_live.html.heex:126
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:108
#: lib/claper_web/live/admin_live/user_live.html.heex:111
@@ -2639,7 +2643,7 @@ msgstr "Anbieter"
msgid "Admin"
msgstr "Admin"
#: lib/claper_web/templates/layout/admin.html.heex:285
#: lib/claper_web/templates/layout/admin.html.heex:301
#, elixir-autogen, elixir-format
msgid "Back to app"
msgstr "Zurück zur App"
@@ -2679,3 +2683,84 @@ msgstr "Erforderlich"
#, elixir-autogen, elixir-format
msgid "(optional)"
msgstr "(optional)"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:67
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:105
#, elixir-autogen, elixir-format, fuzzy
msgid "Action"
msgstr "Aktion"
#: lib/claper_web/live/admin_live/audit_log_live.ex:39
#, elixir-autogen, elixir-format, fuzzy
msgid "All actions"
msgstr "Alle Aktionen"
#: lib/claper_web/live/admin_live/audit_log_live.ex:50
#, elixir-autogen, elixir-format
msgid "Audit Log Details"
msgstr "Details zum Überwachungsprotokoll"
#: lib/claper_web/live/admin_live/audit_log_live.ex:24
#: lib/claper_web/templates/layout/admin.html.heex:246
#, elixir-autogen, elixir-format
msgid "Audit Logs"
msgstr "Überwachungsprotokolle"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:66
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:99
#, elixir-autogen, elixir-format
msgid "ID"
msgstr "ID"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:78
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:152
#, elixir-autogen, elixir-format
msgid "Metadata"
msgstr "Metadaten"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:55
#, elixir-autogen, elixir-format, fuzzy
msgid "No results."
msgstr "Keine Ergebnisse."
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:145
#, elixir-autogen, elixir-format
msgid "Resource ID"
msgstr "Ressourcen-ID"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:137
#, elixir-autogen, elixir-format, fuzzy
msgid "Resource Type"
msgstr "Ressourcentyp"
#: lib/claper_web/live/admin_live/audit_log_live.ex:33
#, elixir-autogen, elixir-format
msgid "Search by user email"
msgstr "Suche nach Benutzer-E-Mail"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:73
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:130
#, elixir-autogen, elixir-format
msgid "Timestamp"
msgstr "Zeitstempel"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:70
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:111
#, elixir-autogen, elixir-format, fuzzy
msgid "User"
msgstr "Benutzer"
#: lib/claper_web/components/core_components.ex:74
#, elixir-autogen, elixir-format, fuzzy
msgid "close"
msgstr "schließen"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:88
#, elixir-autogen, elixir-format
msgid "View details for log #%{id}"
msgstr "Details für Protokoll Nr. %{id} anzeigen"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:119
#, elixir-autogen, elixir-format
msgid "View profile for %{email}"
msgstr "Profil für %{email} anzeigen"

View File

@@ -20,7 +20,7 @@ msgstr ""
#: lib/claper_web/live/admin_live/user_live.html.heex:74
#: lib/claper_web/live/admin_live/user_live.html.heex:254
#: lib/claper_web/live/admin_live/user_live/form_component.ex:18
#: lib/claper_web/live/event_live/manage.ex:838
#: lib/claper_web/live/event_live/manage.ex:844
#: lib/claper_web/live/form_live/form_component.html.heex:32
#: lib/claper_web/live/user_settings_live/show.html.heex:34
#: lib/claper_web/templates/user_registration/new.html.heex:29
@@ -478,9 +478,9 @@ msgstr ""
msgid "Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
msgstr ""
#: lib/claper_web/live/event_live/show.ex:51
#: lib/claper_web/live/event_live/show.ex:206
#: lib/claper_web/live/event_live/show.ex:221
#: lib/claper_web/live/event_live/show.ex:64
#: lib/claper_web/live/event_live/show.ex:219
#: lib/claper_web/live/event_live/show.ex:234
#, elixir-autogen, elixir-format
msgid "You have been banned from this event"
msgstr ""
@@ -707,7 +707,7 @@ msgstr ""
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:74
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:254
#: lib/claper_web/live/admin_live/oidc_provider_live/form_component.ex:24
#: lib/claper_web/live/event_live/manage.ex:837
#: lib/claper_web/live/event_live/manage.ex:843
#, elixir-autogen, elixir-format
msgid "Name"
msgstr ""
@@ -1070,6 +1070,7 @@ msgstr ""
msgid "Identify users by their unique avatars."
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:40
#: lib/claper_web/live/event_live/event_form_component.html.heex:5
#: lib/claper_web/live/event_live/index.html.heex:106
#: lib/claper_web/live/event_live/manage.html.heex:427
@@ -1196,7 +1197,7 @@ msgstr ""
msgid "This code will be used by your attendees to access the event. You have the option to create a custom code."
msgstr ""
#: lib/claper_web/live/event_live/show.ex:193
#: lib/claper_web/live/event_live/show.ex:206
#, elixir-autogen, elixir-format
msgid "This event has been terminated"
msgstr ""
@@ -1218,7 +1219,7 @@ msgstr ""
#: lib/claper_web/live/event_live/manage.ex:23
#: lib/claper_web/live/event_live/presenter.ex:26
#: lib/claper_web/live/event_live/show.ex:25
#: lib/claper_web/live/event_live/show.ex:38
#, elixir-autogen, elixir-format
msgid "Event doesn't exist"
msgstr ""
@@ -1274,7 +1275,7 @@ msgid "Event manager"
msgstr ""
#: lib/claper_web/templates/layout/_user_menu.html.heex:19
#: lib/claper_web/templates/layout/admin.html.heex:262
#: lib/claper_web/templates/layout/admin.html.heex:278
#, elixir-autogen, elixir-format
msgid "Documentation"
msgstr ""
@@ -1477,6 +1478,7 @@ msgid "Please enter a valid link starting with http:// or https://"
msgstr ""
#: lib/claper/embeds/embed.ex:98
#: lib/claper/embeds/embed.ex:122
#, elixir-autogen, elixir-format
msgid "Please enter valid HTML content with an iframe tag"
msgstr ""
@@ -1566,12 +1568,12 @@ msgstr ""
msgid "More options"
msgstr ""
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "No"
msgstr ""
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "Yes"
msgstr ""
@@ -1720,6 +1722,7 @@ msgstr ""
msgid "Presentation"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:34
#: lib/claper_web/live/event_live/manager_settings_component.ex:168
#, elixir-autogen, elixir-format
msgid "Previous"
@@ -1934,6 +1937,7 @@ msgstr ""
msgid "Account is confirmed and active"
msgstr ""
#: lib/claper_web/components/core_components.ex:368
#: lib/claper_web/live/admin_live/event_live.html.heex:126
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:108
#: lib/claper_web/live/admin_live/user_live.html.heex:111
@@ -2641,7 +2645,7 @@ msgstr ""
msgid "Admin"
msgstr ""
#: lib/claper_web/templates/layout/admin.html.heex:285
#: lib/claper_web/templates/layout/admin.html.heex:301
#, elixir-autogen, elixir-format
msgid "Back to app"
msgstr ""
@@ -2681,3 +2685,84 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "(optional)"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:67
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:105
#, elixir-autogen, elixir-format
msgid "Action"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.ex:39
#, elixir-autogen, elixir-format
msgid "All actions"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.ex:50
#, elixir-autogen, elixir-format
msgid "Audit Log Details"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.ex:24
#: lib/claper_web/templates/layout/admin.html.heex:246
#, elixir-autogen, elixir-format
msgid "Audit Logs"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:66
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:99
#, elixir-autogen, elixir-format
msgid "ID"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:78
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:152
#, elixir-autogen, elixir-format
msgid "Metadata"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:55
#, elixir-autogen, elixir-format
msgid "No results."
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:145
#, elixir-autogen, elixir-format
msgid "Resource ID"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:137
#, elixir-autogen, elixir-format
msgid "Resource Type"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.ex:33
#, elixir-autogen, elixir-format
msgid "Search by user email"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:73
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:130
#, elixir-autogen, elixir-format
msgid "Timestamp"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:70
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:111
#, elixir-autogen, elixir-format
msgid "User"
msgstr ""
#: lib/claper_web/components/core_components.ex:74
#, elixir-autogen, elixir-format
msgid "close"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:88
#, elixir-autogen, elixir-format
msgid "View details for log #%{id}"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:119
#, elixir-autogen, elixir-format
msgid "View profile for %{email}"
msgstr ""

View File

@@ -18,7 +18,7 @@ msgstr ""
#: lib/claper_web/live/admin_live/user_live.html.heex:74
#: lib/claper_web/live/admin_live/user_live.html.heex:254
#: lib/claper_web/live/admin_live/user_live/form_component.ex:18
#: lib/claper_web/live/event_live/manage.ex:838
#: lib/claper_web/live/event_live/manage.ex:844
#: lib/claper_web/live/form_live/form_component.html.heex:32
#: lib/claper_web/live/user_settings_live/show.html.heex:34
#: lib/claper_web/templates/user_registration/new.html.heex:29
@@ -476,9 +476,9 @@ msgstr ""
msgid "Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
msgstr ""
#: lib/claper_web/live/event_live/show.ex:51
#: lib/claper_web/live/event_live/show.ex:206
#: lib/claper_web/live/event_live/show.ex:221
#: lib/claper_web/live/event_live/show.ex:64
#: lib/claper_web/live/event_live/show.ex:219
#: lib/claper_web/live/event_live/show.ex:234
#, elixir-autogen, elixir-format
msgid "You have been banned from this event"
msgstr ""
@@ -705,7 +705,7 @@ msgstr ""
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:74
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:254
#: lib/claper_web/live/admin_live/oidc_provider_live/form_component.ex:24
#: lib/claper_web/live/event_live/manage.ex:837
#: lib/claper_web/live/event_live/manage.ex:843
#, elixir-autogen, elixir-format
msgid "Name"
msgstr ""
@@ -1068,6 +1068,7 @@ msgstr ""
msgid "Identify users by their unique avatars."
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:40
#: lib/claper_web/live/event_live/event_form_component.html.heex:5
#: lib/claper_web/live/event_live/index.html.heex:106
#: lib/claper_web/live/event_live/manage.html.heex:427
@@ -1194,7 +1195,7 @@ msgstr ""
msgid "This code will be used by your attendees to access the event. You have the option to create a custom code."
msgstr ""
#: lib/claper_web/live/event_live/show.ex:193
#: lib/claper_web/live/event_live/show.ex:206
#, elixir-autogen, elixir-format
msgid "This event has been terminated"
msgstr ""
@@ -1216,7 +1217,7 @@ msgstr ""
#: lib/claper_web/live/event_live/manage.ex:23
#: lib/claper_web/live/event_live/presenter.ex:26
#: lib/claper_web/live/event_live/show.ex:25
#: lib/claper_web/live/event_live/show.ex:38
#, elixir-autogen, elixir-format
msgid "Event doesn't exist"
msgstr ""
@@ -1272,7 +1273,7 @@ msgid "Event manager"
msgstr ""
#: lib/claper_web/templates/layout/_user_menu.html.heex:19
#: lib/claper_web/templates/layout/admin.html.heex:262
#: lib/claper_web/templates/layout/admin.html.heex:278
#, elixir-autogen, elixir-format
msgid "Documentation"
msgstr ""
@@ -1475,6 +1476,7 @@ msgid "Please enter a valid link starting with http:// or https://"
msgstr ""
#: lib/claper/embeds/embed.ex:98
#: lib/claper/embeds/embed.ex:122
#, elixir-autogen, elixir-format
msgid "Please enter valid HTML content with an iframe tag"
msgstr ""
@@ -1564,12 +1566,12 @@ msgstr ""
msgid "More options"
msgstr ""
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "No"
msgstr ""
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "Yes"
msgstr ""
@@ -1718,6 +1720,7 @@ msgstr ""
msgid "Presentation"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:34
#: lib/claper_web/live/event_live/manager_settings_component.ex:168
#, elixir-autogen, elixir-format
msgid "Previous"
@@ -1932,6 +1935,7 @@ msgstr ""
msgid "Account is confirmed and active"
msgstr ""
#: lib/claper_web/components/core_components.ex:368
#: lib/claper_web/live/admin_live/event_live.html.heex:126
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:108
#: lib/claper_web/live/admin_live/user_live.html.heex:111
@@ -2639,7 +2643,7 @@ msgstr ""
msgid "Admin"
msgstr ""
#: lib/claper_web/templates/layout/admin.html.heex:285
#: lib/claper_web/templates/layout/admin.html.heex:301
#, elixir-autogen, elixir-format
msgid "Back to app"
msgstr ""
@@ -2679,3 +2683,84 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "(optional)"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:67
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:105
#, elixir-autogen, elixir-format, fuzzy
msgid "Action"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.ex:39
#, elixir-autogen, elixir-format, fuzzy
msgid "All actions"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.ex:50
#, elixir-autogen, elixir-format
msgid "Audit Log Details"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.ex:24
#: lib/claper_web/templates/layout/admin.html.heex:246
#, elixir-autogen, elixir-format
msgid "Audit Logs"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:66
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:99
#, elixir-autogen, elixir-format
msgid "ID"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:78
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:152
#, elixir-autogen, elixir-format
msgid "Metadata"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:55
#, elixir-autogen, elixir-format, fuzzy
msgid "No results."
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:145
#, elixir-autogen, elixir-format
msgid "Resource ID"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:137
#, elixir-autogen, elixir-format, fuzzy
msgid "Resource Type"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.ex:33
#, elixir-autogen, elixir-format
msgid "Search by user email"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:73
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:130
#, elixir-autogen, elixir-format
msgid "Timestamp"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:70
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:111
#, elixir-autogen, elixir-format, fuzzy
msgid "User"
msgstr ""
#: lib/claper_web/components/core_components.ex:74
#, elixir-autogen, elixir-format, fuzzy
msgid "close"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:88
#, elixir-autogen, elixir-format
msgid "View details for log #%{id}"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:119
#, elixir-autogen, elixir-format
msgid "View profile for %{email}"
msgstr ""

View File

@@ -18,7 +18,7 @@ msgstr "Configuración"
#: lib/claper_web/live/admin_live/user_live.html.heex:74
#: lib/claper_web/live/admin_live/user_live.html.heex:254
#: lib/claper_web/live/admin_live/user_live/form_component.ex:18
#: lib/claper_web/live/event_live/manage.ex:838
#: lib/claper_web/live/event_live/manage.ex:844
#: lib/claper_web/live/form_live/form_component.html.heex:32
#: lib/claper_web/live/user_settings_live/show.html.heex:34
#: lib/claper_web/templates/user_registration/new.html.heex:29
@@ -476,9 +476,9 @@ msgstr "Añadir interacción"
msgid "Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
msgstr "Bloquear este usuario borrará todos sus mensajes y él no será capaz de unirse de nuevo, ¿estás seguro?"
#: lib/claper_web/live/event_live/show.ex:51
#: lib/claper_web/live/event_live/show.ex:206
#: lib/claper_web/live/event_live/show.ex:221
#: lib/claper_web/live/event_live/show.ex:64
#: lib/claper_web/live/event_live/show.ex:219
#: lib/claper_web/live/event_live/show.ex:234
#, elixir-autogen, elixir-format
msgid "You have been banned from this event"
msgstr "Has sido excluido/a de este evento"
@@ -705,7 +705,7 @@ msgstr "Los envíos de formulario de los asistentes aparecerán aquí."
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:74
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:254
#: lib/claper_web/live/admin_live/oidc_provider_live/form_component.ex:24
#: lib/claper_web/live/event_live/manage.ex:837
#: lib/claper_web/live/event_live/manage.ex:843
#, elixir-autogen, elixir-format
msgid "Name"
msgstr "Nombre"
@@ -1068,6 +1068,7 @@ msgstr "Aquí encontrarás todas las interacciones de tus asistentes. Puedes ges
msgid "Identify users by their unique avatars."
msgstr "Identificar usuarios por sus avatares únicos."
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:40
#: lib/claper_web/live/event_live/event_form_component.html.heex:5
#: lib/claper_web/live/event_live/index.html.heex:106
#: lib/claper_web/live/event_live/manage.html.heex:427
@@ -1194,7 +1195,7 @@ msgstr "Selecciona tu presentación (opcional)"
msgid "This code will be used by your attendees to access the event. You have the option to create a custom code."
msgstr "Este código será usado por tus asistentes para acceder al evento. Tienes la opción de crear un código personalizado."
#: lib/claper_web/live/event_live/show.ex:193
#: lib/claper_web/live/event_live/show.ex:206
#, elixir-autogen, elixir-format
msgid "This event has been terminated"
msgstr "Este evento ha sido terminado"
@@ -1216,7 +1217,7 @@ msgstr "Crea tu siguiente presentación con"
#: lib/claper_web/live/event_live/manage.ex:23
#: lib/claper_web/live/event_live/presenter.ex:26
#: lib/claper_web/live/event_live/show.ex:25
#: lib/claper_web/live/event_live/show.ex:38
#, elixir-autogen, elixir-format
msgid "Event doesn't exist"
msgstr "El evento no existe"
@@ -1272,7 +1273,7 @@ msgid "Event manager"
msgstr "Gestor de evento"
#: lib/claper_web/templates/layout/_user_menu.html.heex:19
#: lib/claper_web/templates/layout/admin.html.heex:262
#: lib/claper_web/templates/layout/admin.html.heex:278
#, elixir-autogen, elixir-format
msgid "Documentation"
msgstr "Documentación"
@@ -1475,6 +1476,7 @@ msgid "Please enter a valid link starting with http:// or https://"
msgstr "Por favor, introduce un enlace válido que comience con http:// o https://"
#: lib/claper/embeds/embed.ex:98
#: lib/claper/embeds/embed.ex:122
#, elixir-autogen, elixir-format
msgid "Please enter valid HTML content with an iframe tag"
msgstr "Por favor, introduce contenido HTML válido con una etiqueta iframe"
@@ -1564,12 +1566,12 @@ msgstr "Finalizar"
msgid "More options"
msgstr "Más opciones"
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "No"
msgstr "No"
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "Yes"
msgstr "Sí"
@@ -1718,6 +1720,7 @@ msgstr "Nuevo cuestionario"
msgid "Presentation"
msgstr "Presentación"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:34
#: lib/claper_web/live/event_live/manager_settings_component.ex:168
#, elixir-autogen, elixir-format
msgid "Previous"
@@ -1932,6 +1935,7 @@ msgstr "Un nombre único para identificar este proveedor OIDC"
msgid "Account is confirmed and active"
msgstr "La cuenta está confirmada y activa"
#: lib/claper_web/components/core_components.ex:368
#: lib/claper_web/live/admin_live/event_live.html.heex:126
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:108
#: lib/claper_web/live/admin_live/user_live.html.heex:111
@@ -2639,7 +2643,7 @@ msgstr "Proveedor"
msgid "Admin"
msgstr "Admin"
#: lib/claper_web/templates/layout/admin.html.heex:285
#: lib/claper_web/templates/layout/admin.html.heex:301
#, elixir-autogen, elixir-format
msgid "Back to app"
msgstr "Volver a la aplicación"
@@ -2679,3 +2683,84 @@ msgstr "Obligatorio"
#, elixir-autogen, elixir-format
msgid "(optional)"
msgstr "(opcional)"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:67
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:105
#, elixir-autogen, elixir-format, fuzzy
msgid "Action"
msgstr "Acciones"
#: lib/claper_web/live/admin_live/audit_log_live.ex:39
#, elixir-autogen, elixir-format, fuzzy
msgid "All actions"
msgstr "Todas las acciones"
#: lib/claper_web/live/admin_live/audit_log_live.ex:50
#, elixir-autogen, elixir-format
msgid "Audit Log Details"
msgstr "Detalles del registro de auditoría"
#: lib/claper_web/live/admin_live/audit_log_live.ex:24
#: lib/claper_web/templates/layout/admin.html.heex:246
#, elixir-autogen, elixir-format
msgid "Audit Logs"
msgstr "Registros de auditoría"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:66
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:99
#, elixir-autogen, elixir-format
msgid "ID"
msgstr "ID"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:78
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:152
#, elixir-autogen, elixir-format
msgid "Metadata"
msgstr "Metadatos"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:55
#, elixir-autogen, elixir-format, fuzzy
msgid "No results."
msgstr "Sin resultados."
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:145
#, elixir-autogen, elixir-format
msgid "Resource ID"
msgstr "ID del recurso"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:137
#, elixir-autogen, elixir-format, fuzzy
msgid "Resource Type"
msgstr "Tipo de recurso"
#: lib/claper_web/live/admin_live/audit_log_live.ex:33
#, elixir-autogen, elixir-format
msgid "Search by user email"
msgstr "Buscar por email de usuario"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:73
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:130
#, elixir-autogen, elixir-format
msgid "Timestamp"
msgstr "Fecha y hora"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:70
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:111
#, elixir-autogen, elixir-format, fuzzy
msgid "User"
msgstr "Usuario"
#: lib/claper_web/components/core_components.ex:74
#, elixir-autogen, elixir-format, fuzzy
msgid "close"
msgstr "cerrar"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:88
#, elixir-autogen, elixir-format
msgid "View details for log #%{id}"
msgstr "Ver detalles del registro nº %{id}"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:119
#, elixir-autogen, elixir-format
msgid "View profile for %{email}"
msgstr "Ver perfil de %{email}"

View File

@@ -18,7 +18,7 @@ msgstr "Paramètres"
#: lib/claper_web/live/admin_live/user_live.html.heex:74
#: lib/claper_web/live/admin_live/user_live.html.heex:254
#: lib/claper_web/live/admin_live/user_live/form_component.ex:18
#: lib/claper_web/live/event_live/manage.ex:838
#: lib/claper_web/live/event_live/manage.ex:844
#: lib/claper_web/live/form_live/form_component.html.heex:32
#: lib/claper_web/live/user_settings_live/show.html.heex:34
#: lib/claper_web/templates/user_registration/new.html.heex:29
@@ -477,9 +477,9 @@ msgstr "Ajouter une interaction"
msgid "Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
msgstr "Bloquer cet utilisateur supprimera tous ses messages et il ne pourra pas rejoindre à nouveau, confirmer ?"
#: lib/claper_web/live/event_live/show.ex:51
#: lib/claper_web/live/event_live/show.ex:206
#: lib/claper_web/live/event_live/show.ex:221
#: lib/claper_web/live/event_live/show.ex:64
#: lib/claper_web/live/event_live/show.ex:219
#: lib/claper_web/live/event_live/show.ex:234
#, elixir-autogen, elixir-format
msgid "You have been banned from this event"
msgstr "Vous avez été banni de cet événement"
@@ -709,7 +709,7 @@ msgstr "Les formulaires soumis par les participants apparaîtront ici."
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:74
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:254
#: lib/claper_web/live/admin_live/oidc_provider_live/form_component.ex:24
#: lib/claper_web/live/event_live/manage.ex:837
#: lib/claper_web/live/event_live/manage.ex:843
#, elixir-autogen, elixir-format
msgid "Name"
msgstr "Nom"
@@ -1072,6 +1072,7 @@ msgstr "Ici, vous trouverez toutes les interactions de vos participants. Vous po
msgid "Identify users by their unique avatars."
msgstr "Identifiez les utilisateurs par leurs avatars uniques."
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:40
#: lib/claper_web/live/event_live/event_form_component.html.heex:5
#: lib/claper_web/live/event_live/index.html.heex:106
#: lib/claper_web/live/event_live/manage.html.heex:427
@@ -1198,7 +1199,7 @@ msgstr "Sélectionnez votre présentation (facultatif)"
msgid "This code will be used by your attendees to access the event. You have the option to create a custom code."
msgstr "Ce code sera utilisé par vos participants pour accéder à l'événement. Vous avez la possibilité de créer un code personnalisé."
#: lib/claper_web/live/event_live/show.ex:193
#: lib/claper_web/live/event_live/show.ex:206
#, elixir-autogen, elixir-format
msgid "This event has been terminated"
msgstr "Cet événement viens d'être terminé"
@@ -1220,7 +1221,7 @@ msgstr "Créez votre prochaine présentation avec"
#: lib/claper_web/live/event_live/manage.ex:23
#: lib/claper_web/live/event_live/presenter.ex:26
#: lib/claper_web/live/event_live/show.ex:25
#: lib/claper_web/live/event_live/show.ex:38
#, elixir-autogen, elixir-format
msgid "Event doesn't exist"
msgstr "L'événement n'existe pas"
@@ -1276,7 +1277,7 @@ msgid "Event manager"
msgstr "Gestionnaire d'événement"
#: lib/claper_web/templates/layout/_user_menu.html.heex:19
#: lib/claper_web/templates/layout/admin.html.heex:262
#: lib/claper_web/templates/layout/admin.html.heex:278
#, elixir-autogen, elixir-format
msgid "Documentation"
msgstr "Documentation"
@@ -1479,6 +1480,7 @@ msgid "Please enter a valid link starting with http:// or https://"
msgstr "Veuillez entrer un lien valide commençant par http:// ou https://"
#: lib/claper/embeds/embed.ex:98
#: lib/claper/embeds/embed.ex:122
#, elixir-autogen, elixir-format
msgid "Please enter valid HTML content with an iframe tag"
msgstr "Veuillez entrer un contenu HTML valide avec une balise iframe"
@@ -1568,12 +1570,12 @@ msgstr "Terminer"
msgid "More options"
msgstr "Plus d'options"
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "No"
msgstr "Non"
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "Yes"
msgstr "Oui"
@@ -1722,6 +1724,7 @@ msgstr "Nouveau quiz"
msgid "Presentation"
msgstr "Présentation"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:34
#: lib/claper_web/live/event_live/manager_settings_component.ex:168
#, elixir-autogen, elixir-format
msgid "Previous"
@@ -1936,6 +1939,7 @@ msgstr "Un nom unique pour identifier ce fournisseur OIDC"
msgid "Account is confirmed and active"
msgstr "Le compte est confirmé et actif"
#: lib/claper_web/components/core_components.ex:368
#: lib/claper_web/live/admin_live/event_live.html.heex:126
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:108
#: lib/claper_web/live/admin_live/user_live.html.heex:111
@@ -2643,7 +2647,7 @@ msgstr "Détails du fournisseur"
msgid "Admin"
msgstr "Admin"
#: lib/claper_web/templates/layout/admin.html.heex:285
#: lib/claper_web/templates/layout/admin.html.heex:301
#, elixir-autogen, elixir-format
msgid "Back to app"
msgstr "Retour à l'app"
@@ -2683,3 +2687,84 @@ msgstr "Obligatoire"
#, elixir-autogen, elixir-format
msgid "(optional)"
msgstr "(facultatif)"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:67
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:105
#, elixir-autogen, elixir-format, fuzzy
msgid "Action"
msgstr "Action"
#: lib/claper_web/live/admin_live/audit_log_live.ex:39
#, elixir-autogen, elixir-format, fuzzy
msgid "All actions"
msgstr "Toutes les actions"
#: lib/claper_web/live/admin_live/audit_log_live.ex:50
#, elixir-autogen, elixir-format
msgid "Audit Log Details"
msgstr "Détails du journal d'audit"
#: lib/claper_web/live/admin_live/audit_log_live.ex:24
#: lib/claper_web/templates/layout/admin.html.heex:246
#, elixir-autogen, elixir-format
msgid "Audit Logs"
msgstr "Journaux d'audit"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:66
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:99
#, elixir-autogen, elixir-format
msgid "ID"
msgstr "ID"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:78
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:152
#, elixir-autogen, elixir-format
msgid "Metadata"
msgstr "Métadonnées"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:55
#, elixir-autogen, elixir-format, fuzzy
msgid "No results."
msgstr "Aucun résultat."
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:145
#, elixir-autogen, elixir-format
msgid "Resource ID"
msgstr "ID de ressource"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:137
#, elixir-autogen, elixir-format, fuzzy
msgid "Resource Type"
msgstr "Type de ressource"
#: lib/claper_web/live/admin_live/audit_log_live.ex:33
#, elixir-autogen, elixir-format
msgid "Search by user email"
msgstr "Recherche par e-mail de l'utilisateur"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:73
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:130
#, elixir-autogen, elixir-format
msgid "Timestamp"
msgstr "Horodatage"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:70
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:111
#, elixir-autogen, elixir-format, fuzzy
msgid "User"
msgstr "Utilisateur"
#: lib/claper_web/components/core_components.ex:74
#, elixir-autogen, elixir-format, fuzzy
msgid "close"
msgstr "fermer"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:88
#, elixir-autogen, elixir-format
msgid "View details for log #%{id}"
msgstr "Afficher les détails du journal nº %{id}"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:119
#, elixir-autogen, elixir-format
msgid "View profile for %{email}"
msgstr "Voir le profil pour %{email}"

View File

@@ -18,7 +18,7 @@ msgstr "Beállítások"
#: lib/claper_web/live/admin_live/user_live.html.heex:74
#: lib/claper_web/live/admin_live/user_live.html.heex:254
#: lib/claper_web/live/admin_live/user_live/form_component.ex:18
#: lib/claper_web/live/event_live/manage.ex:838
#: lib/claper_web/live/event_live/manage.ex:844
#: lib/claper_web/live/form_live/form_component.html.heex:32
#: lib/claper_web/live/user_settings_live/show.html.heex:34
#: lib/claper_web/templates/user_registration/new.html.heex:29
@@ -476,9 +476,9 @@ msgstr "Interakció hozzáadása"
msgid "Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
msgstr "Ezen felhasználó blokkolásával az üzenetei törlődnek, és nem fog tudni újra csatlakozni. Biztos benne?"
#: lib/claper_web/live/event_live/show.ex:51
#: lib/claper_web/live/event_live/show.ex:206
#: lib/claper_web/live/event_live/show.ex:221
#: lib/claper_web/live/event_live/show.ex:64
#: lib/claper_web/live/event_live/show.ex:219
#: lib/claper_web/live/event_live/show.ex:234
#, elixir-autogen, elixir-format
msgid "You have been banned from this event"
msgstr "Ki van tiltva erről az eseményről"
@@ -705,7 +705,7 @@ msgstr "A résztvevők által beküldött űrlapok itt fognak megjelenni."
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:74
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:254
#: lib/claper_web/live/admin_live/oidc_provider_live/form_component.ex:24
#: lib/claper_web/live/event_live/manage.ex:837
#: lib/claper_web/live/event_live/manage.ex:843
#, elixir-autogen, elixir-format
msgid "Name"
msgstr "Név"
@@ -1068,6 +1068,7 @@ msgstr "Itt találhatóak majd a résztvevők interakciói. Lehetőség van az
msgid "Identify users by their unique avatars."
msgstr "Azonosítsa a felhasználókat egyedi profilképeik alapján."
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:40
#: lib/claper_web/live/event_live/event_form_component.html.heex:5
#: lib/claper_web/live/event_live/index.html.heex:106
#: lib/claper_web/live/event_live/manage.html.heex:427
@@ -1194,7 +1195,7 @@ msgstr "Válassza ki a prezentációt (opcionális)"
msgid "This code will be used by your attendees to access the event. You have the option to create a custom code."
msgstr "A résztvevők ezt a kódot fogják használni a csatlakozáshoz. Lehetőség van egyéni kódot is létrehozni."
#: lib/claper_web/live/event_live/show.ex:193
#: lib/claper_web/live/event_live/show.ex:206
#, elixir-autogen, elixir-format
msgid "This event has been terminated"
msgstr "Az esemény befejeződött"
@@ -1216,7 +1217,7 @@ msgstr "Hozza létre következő prezentációját ezzel:"
#: lib/claper_web/live/event_live/manage.ex:23
#: lib/claper_web/live/event_live/presenter.ex:26
#: lib/claper_web/live/event_live/show.ex:25
#: lib/claper_web/live/event_live/show.ex:38
#, elixir-autogen, elixir-format
msgid "Event doesn't exist"
msgstr "Az esemény nem található"
@@ -1272,7 +1273,7 @@ msgid "Event manager"
msgstr "Eseménykezelő"
#: lib/claper_web/templates/layout/_user_menu.html.heex:19
#: lib/claper_web/templates/layout/admin.html.heex:262
#: lib/claper_web/templates/layout/admin.html.heex:278
#, elixir-autogen, elixir-format
msgid "Documentation"
msgstr "Dokumentáció"
@@ -1475,6 +1476,7 @@ msgid "Please enter a valid link starting with http:// or https://"
msgstr "Adjon meg egy http:// vagy https:// előtaggal kezdődő érvényes linket"
#: lib/claper/embeds/embed.ex:98
#: lib/claper/embeds/embed.ex:122
#, elixir-autogen, elixir-format
msgid "Please enter valid HTML content with an iframe tag"
msgstr "Adjon meg érvényes HTML tartalmat iframe taggel"
@@ -1564,12 +1566,12 @@ msgstr "Befejezés"
msgid "More options"
msgstr "További lehetőségek"
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "No"
msgstr "Nem"
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "Yes"
msgstr "Igen"
@@ -1718,6 +1720,7 @@ msgstr "Új kvíz"
msgid "Presentation"
msgstr "Prezentáció"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:34
#: lib/claper_web/live/event_live/manager_settings_component.ex:168
#, elixir-autogen, elixir-format
msgid "Previous"
@@ -1932,6 +1935,7 @@ msgstr ""
msgid "Account is confirmed and active"
msgstr ""
#: lib/claper_web/components/core_components.ex:368
#: lib/claper_web/live/admin_live/event_live.html.heex:126
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:108
#: lib/claper_web/live/admin_live/user_live.html.heex:111
@@ -2639,10 +2643,10 @@ msgstr "Szolgáltató"
msgid "Admin"
msgstr ""
#: lib/claper_web/templates/layout/admin.html.heex:285
#: lib/claper_web/templates/layout/admin.html.heex:301
#, elixir-autogen, elixir-format
msgid "Back to app"
msgstr ""
msgstr "Vissza az alkalmazáshoz"
#: lib/claper_web/templates/user_notifier/change.html.heex:17
#, elixir-autogen, elixir-format, fuzzy
@@ -2679,3 +2683,84 @@ msgstr "Kötelező"
#, elixir-autogen, elixir-format
msgid "(optional)"
msgstr "(opcionális)"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:67
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:105
#, elixir-autogen, elixir-format, fuzzy
msgid "Action"
msgstr "Művelet"
#: lib/claper_web/live/admin_live/audit_log_live.ex:39
#, elixir-autogen, elixir-format, fuzzy
msgid "All actions"
msgstr "Összes művelet"
#: lib/claper_web/live/admin_live/audit_log_live.ex:50
#, elixir-autogen, elixir-format
msgid "Audit Log Details"
msgstr "Auditnapló részletei"
#: lib/claper_web/live/admin_live/audit_log_live.ex:24
#: lib/claper_web/templates/layout/admin.html.heex:246
#, elixir-autogen, elixir-format
msgid "Audit Logs"
msgstr "Auditnaplók"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:66
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:99
#, elixir-autogen, elixir-format
msgid "ID"
msgstr "Azonosító"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:78
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:152
#, elixir-autogen, elixir-format
msgid "Metadata"
msgstr "Metaadatok"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:55
#, elixir-autogen, elixir-format, fuzzy
msgid "No results."
msgstr "Nincsenek találatok."
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:145
#, elixir-autogen, elixir-format
msgid "Resource ID"
msgstr "Erőforrás-azonosító"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:137
#, elixir-autogen, elixir-format, fuzzy
msgid "Resource Type"
msgstr "Erőforrás típusa"
#: lib/claper_web/live/admin_live/audit_log_live.ex:33
#, elixir-autogen, elixir-format
msgid "Search by user email"
msgstr "Keresés e-mail cím alapján"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:73
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:130
#, elixir-autogen, elixir-format
msgid "Timestamp"
msgstr "Időbélyeg"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:70
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:111
#, elixir-autogen, elixir-format, fuzzy
msgid "User"
msgstr "Felhasználó"
#: lib/claper_web/components/core_components.ex:74
#, elixir-autogen, elixir-format, fuzzy
msgid "close"
msgstr "bezárás"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:88
#, elixir-autogen, elixir-format
msgid "View details for log #%{id}"
msgstr "Az %{id}. napló részleteinek megtekintése"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:119
#, elixir-autogen, elixir-format
msgid "View profile for %{email}"
msgstr "Az %{email} profil megtekintése"

View File

@@ -19,7 +19,7 @@ msgstr "Impostazioni"
#: lib/claper_web/live/admin_live/user_live.html.heex:74
#: lib/claper_web/live/admin_live/user_live.html.heex:254
#: lib/claper_web/live/admin_live/user_live/form_component.ex:18
#: lib/claper_web/live/event_live/manage.ex:838
#: lib/claper_web/live/event_live/manage.ex:844
#: lib/claper_web/live/form_live/form_component.html.heex:32
#: lib/claper_web/live/user_settings_live/show.html.heex:34
#: lib/claper_web/templates/user_registration/new.html.heex:29
@@ -477,9 +477,9 @@ msgstr "Aggiungi interazione"
msgid "Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
msgstr "Bloccando questo utente verranno eliminati tutti i suoi messaggi e non potrà più iscriversi, confermi?"
#: lib/claper_web/live/event_live/show.ex:51
#: lib/claper_web/live/event_live/show.ex:206
#: lib/claper_web/live/event_live/show.ex:221
#: lib/claper_web/live/event_live/show.ex:64
#: lib/claper_web/live/event_live/show.ex:219
#: lib/claper_web/live/event_live/show.ex:234
#, elixir-autogen, elixir-format
msgid "You have been banned from this event"
msgstr "Sei stato bandito da questo evento"
@@ -706,7 +706,7 @@ msgstr "I moduli compilati dai partecipanti appariranno qui."
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:74
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:254
#: lib/claper_web/live/admin_live/oidc_provider_live/form_component.ex:24
#: lib/claper_web/live/event_live/manage.ex:837
#: lib/claper_web/live/event_live/manage.ex:843
#, elixir-autogen, elixir-format
msgid "Name"
msgstr "Nome"
@@ -1069,6 +1069,7 @@ msgstr "Qui troverai tutte le interazioni dei tuoi partecipanti. Puoi gestire me
msgid "Identify users by their unique avatars."
msgstr "Identifica gli utenti tramite i loro avatar unici."
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:40
#: lib/claper_web/live/event_live/event_form_component.html.heex:5
#: lib/claper_web/live/event_live/index.html.heex:106
#: lib/claper_web/live/event_live/manage.html.heex:427
@@ -1195,7 +1196,7 @@ msgstr "Seleziona la tua presentazione (facoltativo)"
msgid "This code will be used by your attendees to access the event. You have the option to create a custom code."
msgstr "Questo codice verrà utilizzato dai tuoi partecipanti per accedere all'evento. Hai la possibilità di creare un codice personalizzato."
#: lib/claper_web/live/event_live/show.ex:193
#: lib/claper_web/live/event_live/show.ex:206
#, elixir-autogen, elixir-format
msgid "This event has been terminated"
msgstr "Questo evento è stato terminato"
@@ -1217,7 +1218,7 @@ msgstr "Crea la tua prossima presentazione con"
#: lib/claper_web/live/event_live/manage.ex:23
#: lib/claper_web/live/event_live/presenter.ex:26
#: lib/claper_web/live/event_live/show.ex:25
#: lib/claper_web/live/event_live/show.ex:38
#, elixir-autogen, elixir-format
msgid "Event doesn't exist"
msgstr "L'evento non esiste"
@@ -1273,7 +1274,7 @@ msgid "Event manager"
msgstr "Responsabile eventi"
#: lib/claper_web/templates/layout/_user_menu.html.heex:19
#: lib/claper_web/templates/layout/admin.html.heex:262
#: lib/claper_web/templates/layout/admin.html.heex:278
#, elixir-autogen, elixir-format
msgid "Documentation"
msgstr "Documentazione"
@@ -1476,6 +1477,7 @@ msgid "Please enter a valid link starting with http:// or https://"
msgstr "Inserisci un collegamento valido che inizia con http:// o https://"
#: lib/claper/embeds/embed.ex:98
#: lib/claper/embeds/embed.ex:122
#, elixir-autogen, elixir-format
msgid "Please enter valid HTML content with an iframe tag"
msgstr "Inserisci un contenuto HTML valido con un tag iframe"
@@ -1565,12 +1567,12 @@ msgstr "Fine"
msgid "More options"
msgstr "Altre opzioni"
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "No"
msgstr "No"
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "Yes"
msgstr "Sì"
@@ -1719,6 +1721,7 @@ msgstr "Nuovo quiz"
msgid "Presentation"
msgstr "Presentazione"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:34
#: lib/claper_web/live/event_live/manager_settings_component.ex:168
#, elixir-autogen, elixir-format
msgid "Previous"
@@ -1933,6 +1936,7 @@ msgstr "Un nome unico per identificare questo provider OIDC"
msgid "Account is confirmed and active"
msgstr "L'account è confermato e attivo"
#: lib/claper_web/components/core_components.ex:368
#: lib/claper_web/live/admin_live/event_live.html.heex:126
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:108
#: lib/claper_web/live/admin_live/user_live.html.heex:111
@@ -2640,7 +2644,7 @@ msgstr "Dettagli provider"
msgid "Admin"
msgstr "Admin"
#: lib/claper_web/templates/layout/admin.html.heex:285
#: lib/claper_web/templates/layout/admin.html.heex:301
#, elixir-autogen, elixir-format
msgid "Back to app"
msgstr "Torna all'app"
@@ -2680,3 +2684,84 @@ msgstr "Obbligatorio"
#, elixir-autogen, elixir-format
msgid "(optional)"
msgstr "(facoltativo)"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:67
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:105
#, elixir-autogen, elixir-format, fuzzy
msgid "Action"
msgstr "Azione"
#: lib/claper_web/live/admin_live/audit_log_live.ex:39
#, elixir-autogen, elixir-format, fuzzy
msgid "All actions"
msgstr "Tutte le azioni"
#: lib/claper_web/live/admin_live/audit_log_live.ex:50
#, elixir-autogen, elixir-format
msgid "Audit Log Details"
msgstr "Dettagli del registro di controllo"
#: lib/claper_web/live/admin_live/audit_log_live.ex:24
#: lib/claper_web/templates/layout/admin.html.heex:246
#, elixir-autogen, elixir-format
msgid "Audit Logs"
msgstr "Registri di controllo"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:66
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:99
#, elixir-autogen, elixir-format
msgid "ID"
msgstr "ID"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:78
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:152
#, elixir-autogen, elixir-format
msgid "Metadata"
msgstr "Metadati"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:55
#, elixir-autogen, elixir-format, fuzzy
msgid "No results."
msgstr "Nessun risultato."
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:145
#, elixir-autogen, elixir-format
msgid "Resource ID"
msgstr "ID risorsa"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:137
#, elixir-autogen, elixir-format, fuzzy
msgid "Resource Type"
msgstr "Tipo di risorsa"
#: lib/claper_web/live/admin_live/audit_log_live.ex:33
#, elixir-autogen, elixir-format
msgid "Search by user email"
msgstr ""
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:73
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:130
#, elixir-autogen, elixir-format
msgid "Timestamp"
msgstr "Timestamp"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:70
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:111
#, elixir-autogen, elixir-format, fuzzy
msgid "User"
msgstr "Utente"
#: lib/claper_web/components/core_components.ex:74
#, elixir-autogen, elixir-format, fuzzy
msgid "close"
msgstr "chiudi"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:88
#, elixir-autogen, elixir-format
msgid "View details for log #%{id}"
msgstr "Visualizza i dettagli per il registro n. %{id}"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:119
#, elixir-autogen, elixir-format
msgid "View profile for %{email}"
msgstr "Visualizza ir profilo per %{email}"

View File

@@ -18,7 +18,7 @@ msgstr "Iestatījumi"
#: lib/claper_web/live/admin_live/user_live.html.heex:74
#: lib/claper_web/live/admin_live/user_live.html.heex:254
#: lib/claper_web/live/admin_live/user_live/form_component.ex:18
#: lib/claper_web/live/event_live/manage.ex:838
#: lib/claper_web/live/event_live/manage.ex:844
#: lib/claper_web/live/form_live/form_component.html.heex:32
#: lib/claper_web/live/user_settings_live/show.html.heex:34
#: lib/claper_web/templates/user_registration/new.html.heex:29
@@ -477,9 +477,9 @@ msgstr "Pievienot mijiedarbību"
msgid "Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
msgstr "Bloķējot šo lietotāju, tiks dzēsti visi lietotāja ziņojumi un viņš vairs nevarēs pievienoties, apstipriniet?"
#: lib/claper_web/live/event_live/show.ex:51
#: lib/claper_web/live/event_live/show.ex:206
#: lib/claper_web/live/event_live/show.ex:221
#: lib/claper_web/live/event_live/show.ex:64
#: lib/claper_web/live/event_live/show.ex:219
#: lib/claper_web/live/event_live/show.ex:234
#, elixir-autogen, elixir-format
msgid "You have been banned from this event"
msgstr "Jums ir aizliegts piedalīties šajā pasākumā"
@@ -709,7 +709,7 @@ msgstr "Dalībnieku iesniegtās veidlapas parādīsies šeit."
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:74
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:254
#: lib/claper_web/live/admin_live/oidc_provider_live/form_component.ex:24
#: lib/claper_web/live/event_live/manage.ex:837
#: lib/claper_web/live/event_live/manage.ex:843
#, elixir-autogen, elixir-format
msgid "Name"
msgstr "Nosaukums"
@@ -1072,6 +1072,7 @@ msgstr "Šeit atradīsiet visas dalībnieku mijiedarbības. Varat pārvaldīt zi
msgid "Identify users by their unique avatars."
msgstr "Identificēt lietotājus pēc viņu unikālajiem avatariem."
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:40
#: lib/claper_web/live/event_live/event_form_component.html.heex:5
#: lib/claper_web/live/event_live/index.html.heex:106
#: lib/claper_web/live/event_live/manage.html.heex:427
@@ -1198,7 +1199,7 @@ msgstr "Izvēlieties savu prezentāciju (pēc izvēles)"
msgid "This code will be used by your attendees to access the event. You have the option to create a custom code."
msgstr "Šo kodu dalībnieki izmantos, lai piekļūtu pasākumam. Jums ir iespēja izveidot pielāgotu kodu."
#: lib/claper_web/live/event_live/show.ex:193
#: lib/claper_web/live/event_live/show.ex:206
#, elixir-autogen, elixir-format
msgid "This event has been terminated"
msgstr "Šis notikums ir pārtraukts"
@@ -1220,7 +1221,7 @@ msgstr "Izveidojiet nākamo prezentāciju, izmantojot"
#: lib/claper_web/live/event_live/manage.ex:23
#: lib/claper_web/live/event_live/presenter.ex:26
#: lib/claper_web/live/event_live/show.ex:25
#: lib/claper_web/live/event_live/show.ex:38
#, elixir-autogen, elixir-format
msgid "Event doesn't exist"
msgstr "Notikums neeksistē"
@@ -1276,7 +1277,7 @@ msgid "Event manager"
msgstr "Pasākumu vadītājs"
#: lib/claper_web/templates/layout/_user_menu.html.heex:19
#: lib/claper_web/templates/layout/admin.html.heex:262
#: lib/claper_web/templates/layout/admin.html.heex:278
#, elixir-autogen, elixir-format
msgid "Documentation"
msgstr "Dokumentācija"
@@ -1479,6 +1480,7 @@ msgid "Please enter a valid link starting with http:// or https://"
msgstr "Lūdzu, ievadiet derīgu saiti, kas sākas ar http:// vai https://"
#: lib/claper/embeds/embed.ex:98
#: lib/claper/embeds/embed.ex:122
#, elixir-autogen, elixir-format
msgid "Please enter valid HTML content with an iframe tag"
msgstr "Lūdzu, ievadiet derīgu HTML saturu ar iframe tagu"
@@ -1568,12 +1570,12 @@ msgstr "Izbeigt"
msgid "More options"
msgstr "Vairāk iespēju"
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "No"
msgstr "Nē"
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "Yes"
msgstr "Jā"
@@ -1722,6 +1724,7 @@ msgstr "Jauna viktorīna"
msgid "Presentation"
msgstr "Prezentācija"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:34
#: lib/claper_web/live/event_live/manager_settings_component.ex:168
#, elixir-autogen, elixir-format
msgid "Previous"
@@ -1936,6 +1939,7 @@ msgstr ""
msgid "Account is confirmed and active"
msgstr ""
#: lib/claper_web/components/core_components.ex:368
#: lib/claper_web/live/admin_live/event_live.html.heex:126
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:108
#: lib/claper_web/live/admin_live/user_live.html.heex:111
@@ -2643,10 +2647,10 @@ msgstr "Nodrošinātājs"
msgid "Admin"
msgstr ""
#: lib/claper_web/templates/layout/admin.html.heex:285
#: lib/claper_web/templates/layout/admin.html.heex:301
#, elixir-autogen, elixir-format
msgid "Back to app"
msgstr ""
msgstr "Atpakaļ uz lietotni"
#: lib/claper_web/templates/user_notifier/change.html.heex:17
#, elixir-autogen, elixir-format, fuzzy
@@ -2683,3 +2687,84 @@ msgstr "Obligāti aizpildāms"
#, elixir-autogen, elixir-format
msgid "(optional)"
msgstr "(pēc izvēles)"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:67
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:105
#, elixir-autogen, elixir-format, fuzzy
msgid "Action"
msgstr "Darbība"
#: lib/claper_web/live/admin_live/audit_log_live.ex:39
#, elixir-autogen, elixir-format, fuzzy
msgid "All actions"
msgstr "Visas darbības"
#: lib/claper_web/live/admin_live/audit_log_live.ex:50
#, elixir-autogen, elixir-format
msgid "Audit Log Details"
msgstr "Audita žurnāla informācija"
#: lib/claper_web/live/admin_live/audit_log_live.ex:24
#: lib/claper_web/templates/layout/admin.html.heex:246
#, elixir-autogen, elixir-format
msgid "Audit Logs"
msgstr "Audita žurnāli"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:66
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:99
#, elixir-autogen, elixir-format
msgid "ID"
msgstr "ID"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:78
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:152
#, elixir-autogen, elixir-format
msgid "Metadata"
msgstr "Metadati"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:55
#, elixir-autogen, elixir-format, fuzzy
msgid "No results."
msgstr "Nav rezultātu."
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:145
#, elixir-autogen, elixir-format
msgid "Resource ID"
msgstr "Resursa ID"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:137
#, elixir-autogen, elixir-format, fuzzy
msgid "Resource Type"
msgstr "Resursa veids"
#: lib/claper_web/live/admin_live/audit_log_live.ex:33
#, elixir-autogen, elixir-format
msgid "Search by user email"
msgstr "Meklēt pēc e-pasta"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:73
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:130
#, elixir-autogen, elixir-format
msgid "Timestamp"
msgstr "Laika zīmogs"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:70
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:111
#, elixir-autogen, elixir-format, fuzzy
msgid "User"
msgstr "Lietotājs"
#: lib/claper_web/components/core_components.ex:74
#, elixir-autogen, elixir-format, fuzzy
msgid "close"
msgstr "aizvērt"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:88
#, elixir-autogen, elixir-format
msgid "View details for log #%{id}"
msgstr "Skatīt žurnāla Nr. %{id} informāciju"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:119
#, elixir-autogen, elixir-format
msgid "View profile for %{email}"
msgstr "Skatīt profilu %{email}"

View File

@@ -18,7 +18,7 @@ msgstr "Instellingen"
#: lib/claper_web/live/admin_live/user_live.html.heex:74
#: lib/claper_web/live/admin_live/user_live.html.heex:254
#: lib/claper_web/live/admin_live/user_live/form_component.ex:18
#: lib/claper_web/live/event_live/manage.ex:838
#: lib/claper_web/live/event_live/manage.ex:844
#: lib/claper_web/live/form_live/form_component.html.heex:32
#: lib/claper_web/live/user_settings_live/show.html.heex:34
#: lib/claper_web/templates/user_registration/new.html.heex:29
@@ -476,9 +476,9 @@ msgstr "Voeg interactie toe"
msgid "Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
msgstr "Als je deze gebruiker blokkeert, worden al zijn berichten verwijderd en kan hij niet meer deelnemen. Bevestigen ?"
#: lib/claper_web/live/event_live/show.ex:51
#: lib/claper_web/live/event_live/show.ex:206
#: lib/claper_web/live/event_live/show.ex:221
#: lib/claper_web/live/event_live/show.ex:64
#: lib/claper_web/live/event_live/show.ex:219
#: lib/claper_web/live/event_live/show.ex:234
#, elixir-autogen, elixir-format
msgid "You have been banned from this event"
msgstr "Je bent uitgesloten van dit evenement"
@@ -705,7 +705,7 @@ msgstr "Formulierinzendingen van deelnemers worden hier weergegeven."
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:74
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:254
#: lib/claper_web/live/admin_live/oidc_provider_live/form_component.ex:24
#: lib/claper_web/live/event_live/manage.ex:837
#: lib/claper_web/live/event_live/manage.ex:843
#, elixir-autogen, elixir-format
msgid "Name"
msgstr "Naam"
@@ -1068,6 +1068,7 @@ msgstr "Hier vind je alle interacties van je bezoekers. Je kunt berichten, vastg
msgid "Identify users by their unique avatars."
msgstr "Identificeer gebruikers aan de hand van hun unieke avatars."
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:40
#: lib/claper_web/live/event_live/event_form_component.html.heex:5
#: lib/claper_web/live/event_live/index.html.heex:106
#: lib/claper_web/live/event_live/manage.html.heex:427
@@ -1194,7 +1195,7 @@ msgstr "Selecteer de presentatie (optioneel)"
msgid "This code will be used by your attendees to access the event. You have the option to create a custom code."
msgstr "Deze code wordt door je bezoekers gebruikt om toegang te krijgen tot het evenement. Je hebt de mogelijkheid om een aangepaste code aan te maken."
#: lib/claper_web/live/event_live/show.ex:193
#: lib/claper_web/live/event_live/show.ex:206
#, elixir-autogen, elixir-format
msgid "This event has been terminated"
msgstr "Dit evenement is gestopt"
@@ -1216,7 +1217,7 @@ msgstr "Maak je volgende presentatie met"
#: lib/claper_web/live/event_live/manage.ex:23
#: lib/claper_web/live/event_live/presenter.ex:26
#: lib/claper_web/live/event_live/show.ex:25
#: lib/claper_web/live/event_live/show.ex:38
#, elixir-autogen, elixir-format
msgid "Event doesn't exist"
msgstr "Evenement bestaat niet"
@@ -1272,7 +1273,7 @@ msgid "Event manager"
msgstr "Evenementmanager"
#: lib/claper_web/templates/layout/_user_menu.html.heex:19
#: lib/claper_web/templates/layout/admin.html.heex:262
#: lib/claper_web/templates/layout/admin.html.heex:278
#, elixir-autogen, elixir-format
msgid "Documentation"
msgstr "Documentatie"
@@ -1475,6 +1476,7 @@ msgid "Please enter a valid link starting with http:// or https://"
msgstr "Voer een geldige link in die begint met http:// of https://"
#: lib/claper/embeds/embed.ex:98
#: lib/claper/embeds/embed.ex:122
#, elixir-autogen, elixir-format
msgid "Please enter valid HTML content with an iframe tag"
msgstr "Voer geldige HTML-inhoud in met een iframe-tag"
@@ -1564,12 +1566,12 @@ msgstr "Beëindigen"
msgid "More options"
msgstr "Meer opties"
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "No"
msgstr "Nee"
#: lib/claper_web/live/event_live/manage.ex:818
#: lib/claper_web/live/event_live/manage.ex:824
#, elixir-autogen, elixir-format
msgid "Yes"
msgstr "Ja"
@@ -1718,6 +1720,7 @@ msgstr "Nieuwe quiz"
msgid "Presentation"
msgstr "Presentatie"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:34
#: lib/claper_web/live/event_live/manager_settings_component.ex:168
#, elixir-autogen, elixir-format
msgid "Previous"
@@ -1932,6 +1935,7 @@ msgstr "Een unieke naam om deze OIDC-aanbieder te identificeren"
msgid "Account is confirmed and active"
msgstr "Account is bevestigd en actief"
#: lib/claper_web/components/core_components.ex:368
#: lib/claper_web/live/admin_live/event_live.html.heex:126
#: lib/claper_web/live/admin_live/oidc_provider_live.html.heex:108
#: lib/claper_web/live/admin_live/user_live.html.heex:111
@@ -2639,7 +2643,7 @@ msgstr "Aanbieder details"
msgid "Admin"
msgstr "Admin"
#: lib/claper_web/templates/layout/admin.html.heex:285
#: lib/claper_web/templates/layout/admin.html.heex:301
#, elixir-autogen, elixir-format
msgid "Back to app"
msgstr "Terug naar app"
@@ -2679,3 +2683,84 @@ msgstr "Verplicht"
#, elixir-autogen, elixir-format
msgid "(optional)"
msgstr "(optioneel)"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:67
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:105
#, elixir-autogen, elixir-format, fuzzy
msgid "Action"
msgstr "Actie"
#: lib/claper_web/live/admin_live/audit_log_live.ex:39
#, elixir-autogen, elixir-format, fuzzy
msgid "All actions"
msgstr "Alle acties"
#: lib/claper_web/live/admin_live/audit_log_live.ex:50
#, elixir-autogen, elixir-format
msgid "Audit Log Details"
msgstr "Details auditlogboek"
#: lib/claper_web/live/admin_live/audit_log_live.ex:24
#: lib/claper_web/templates/layout/admin.html.heex:246
#, elixir-autogen, elixir-format
msgid "Audit Logs"
msgstr "Auditlogboeken"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:66
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:99
#, elixir-autogen, elixir-format
msgid "ID"
msgstr "ID"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:78
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:152
#, elixir-autogen, elixir-format
msgid "Metadata"
msgstr "Metadata"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:55
#, elixir-autogen, elixir-format, fuzzy
msgid "No results."
msgstr "Geen resultaten."
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:145
#, elixir-autogen, elixir-format
msgid "Resource ID"
msgstr "Resource-ID"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:137
#, elixir-autogen, elixir-format, fuzzy
msgid "Resource Type"
msgstr "Resourcetype"
#: lib/claper_web/live/admin_live/audit_log_live.ex:33
#, elixir-autogen, elixir-format
msgid "Search by user email"
msgstr "Zoeken op e-mail"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:73
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:130
#, elixir-autogen, elixir-format
msgid "Timestamp"
msgstr "Tijdstempel"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:70
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:111
#, elixir-autogen, elixir-format, fuzzy
msgid "User"
msgstr "Gebruiker"
#: lib/claper_web/components/core_components.ex:74
#, elixir-autogen, elixir-format, fuzzy
msgid "close"
msgstr "sluiten"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:88
#, elixir-autogen, elixir-format
msgid "View details for log #%{id}"
msgstr "Bekijk details voor logboek #%{id}"
#: lib/claper_web/live/admin_live/audit_log_live.html.heex:119
#, elixir-autogen, elixir-format
msgid "View profile for %{email}"
msgstr "Bekijk profiel voor %{email}"

View File

@@ -0,0 +1,19 @@
defmodule Claper.Repo.Migrations.CreateAuditLogs do
use Ecto.Migration
def change do
create table(:audit_logs) do
add :action, :string, null: false
add :resource_type, :string
add :resource_id, :bigint
add :metadata, :map, default: %{}
add :user_id, references(:users, on_delete: :nilify_all)
timestamps(updated_at: false)
end
create index(:audit_logs, [:inserted_at])
create index(:audit_logs, [:action, :inserted_at])
create index(:audit_logs, [:user_id, :inserted_at])
end
end

View File

@@ -0,0 +1,89 @@
defmodule Claper.AuditTest do
use Claper.DataCase
alias Claper.Audit
describe "audit_logs" do
alias Claper.Audit.Log
import Claper.AuditFixtures
import Claper.AccountsFixtures
@invalid_attrs %{action: nil}
test "list_logs/0 paginates all audit_logs" do
log = log_fixture()
{logs, _meta} = Audit.list_logs()
assert Enum.any?(logs, fn l -> l.id == log.id end)
end
test "get_log!/1 returns the log with given id" do
log = log_fixture()
fetched_log = Audit.get_log!(log.id)
assert fetched_log.id == log.id
assert fetched_log.action == log.action
end
test "create_log/1 with valid data creates a log" do
valid_attrs = %{
metadata: %{},
action: "some action",
resource_type: "some resource_type",
resource_id: 42
}
assert {:ok, %Log{} = log} = Audit.create_log(valid_attrs)
assert log.metadata == %{}
assert log.action == "some action"
assert log.resource_type == "some resource_type"
assert log.resource_id == 42
end
test "create_log/1 with invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = Audit.create_log(@invalid_attrs)
end
test "log_action/3 creates a log for a user" do
user = user_fixture()
metadata = %{ip_address: "127.0.0.1"}
assert {:ok, %Log{} = log} = Audit.log_action(user, "user.login", metadata)
assert log.user_id == user.id
assert log.action == "user.login"
assert log.metadata == metadata
end
test "log_action/3 creates a log without a user" do
metadata = %{reason: "system startup"}
assert {:ok, %Log{} = log} = Audit.log_action(nil, "system.startup", metadata)
assert log.user_id == nil
assert log.action == "system.startup"
assert log.metadata == metadata
end
test "log_resource_action/5 creates a log with resource info" do
user = user_fixture()
metadata = %{}
assert {:ok, %Log{} = log} =
Audit.log_resource_action(user, "event.create", "event", 123, metadata)
assert log.user_id == user.id
assert log.action == "event.create"
assert log.resource_type == "event"
assert log.resource_id == 123
end
test "list_action_types/0 returns distinct action types" do
log_fixture(%{action: "user.login"})
log_fixture(%{action: "user.login"})
log_fixture(%{action: "event.create"})
action_types = Audit.list_action_types()
assert "user.login" in action_types
assert "event.create" in action_types
assert length(action_types) == 2
end
end
end

View File

@@ -0,0 +1,29 @@
defmodule ClaperWeb.Helpers.ConnUtilsTest do
use ClaperWeb.ConnCase, async: true
alias ClaperWeb.Helpers.ConnUtils
describe "get_client_ip/1" do
test "returns the remote_ip from the connection as a string" do
conn = build_conn() |> Map.put(:remote_ip, {93, 184, 216, 34})
assert ConnUtils.get_client_ip(conn) == "93.184.216.34"
end
test "handles IPv6 addresses" do
conn = build_conn() |> Map.put(:remote_ip, {8193, 3512, 0, 0, 0, 0, 0, 1})
assert ConnUtils.get_client_ip(conn) == "2001:db8::1"
end
end
describe "get_user_agent/1" do
test "returns the user agent header when present" do
conn = build_conn() |> put_req_header("user-agent", "Mozilla/5.0")
assert ConnUtils.get_user_agent(conn) == "Mozilla/5.0"
end
test "returns nil when no user agent header is present" do
conn = build_conn()
assert ConnUtils.get_user_agent(conn) == nil
end
end
end

View File

@@ -36,10 +36,29 @@ defmodule ClaperWeb.ConnCase do
setup tags do
pid = Ecto.Adapters.SQL.Sandbox.start_owner!(Claper.Repo, shared: not tags[:async])
on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
on_exit(fn ->
drain_task_supervisor(Claper.TaskSupervisor)
Ecto.Adapters.SQL.Sandbox.stop_owner(pid)
end)
{:ok, conn: Phoenix.ConnTest.build_conn()}
end
defp drain_task_supervisor(supervisor) do
supervisor
|> Task.Supervisor.children()
|> Enum.each(fn pid ->
ref = Process.monitor(pid)
receive do
{:DOWN, ^ref, :process, ^pid, _} -> :ok
after
1_000 -> Process.demonitor(ref, [:flush])
end
end)
end
@doc """
Setup helper that registers and logs in users.

View File

@@ -32,12 +32,30 @@ defmodule Claper.DataCase do
# Don't check out a connection if a setup_all did so already
if context[:sandbox_owner_pid] == nil do
pid = Ecto.Adapters.SQL.Sandbox.start_owner!(Claper.Repo, shared: not context[:async])
on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
on_exit(fn ->
drain_task_supervisor(Claper.TaskSupervisor)
Ecto.Adapters.SQL.Sandbox.stop_owner(pid)
end)
end
:ok
end
defp drain_task_supervisor(supervisor) do
supervisor
|> Task.Supervisor.children()
|> Enum.each(fn pid ->
ref = Process.monitor(pid)
receive do
{:DOWN, ^ref, :process, ^pid, _} -> :ok
after
1_000 -> Process.demonitor(ref, [:flush])
end
end)
end
@doc """
A helper that transforms changeset errors into a map of messages.

View File

@@ -0,0 +1,23 @@
defmodule Claper.AuditFixtures do
@moduledoc """
This module defines test helpers for creating
entities via the `Claper.Audit` context.
"""
@doc """
Generate a log.
"""
def log_fixture(attrs \\ %{}) do
{:ok, log} =
attrs
|> Enum.into(%{
action: "some action",
metadata: %{},
resource_id: 42,
resource_type: "some resource_type"
})
|> Claper.Audit.create_log()
log
end
end