- LIKE wildcard injection: sanitize %, _ in search queries (devices, sites, gaiia) - Jason.decode! → Jason.decode with error handling for untrusted input - inspect() leak: replace with generic error messages, log details server-side - SSRF protection: URL validator blocks private IPs, localhost, non-HTTP schemes - SSRF validation added to HTTP monitoring executor and integration credentials - GraphQL complexity limits: always applied, not just in prod - GraphQL introspection: also check GET query params, not just body - Stripe webhook: explicit nil/empty checks for signature and body - Cookie security: secure flag for session (prod), http_only+secure for remember_me - Honeybadger API key: read from env var with fallback - String.to_integer → Integer.parse with fallback for URL params - String.to_atom → whitelist map for HTTP methods - Gaiia webhook: remove secret_len and expected signature from log - Admin API: add rate limiting pipeline - to_atom_keys: per-key fallback instead of all-or-nothing rescue
84 lines
2.3 KiB
Elixir
84 lines
2.3 KiB
Elixir
defmodule ToweropsWeb.ScheduleLive.Form do
|
|
@moduledoc false
|
|
use ToweropsWeb, :live_view
|
|
|
|
alias Towerops.OnCall
|
|
alias Towerops.OnCall.Schedule
|
|
|
|
@impl true
|
|
def mount(_params, _session, socket) do
|
|
{:ok, assign(socket, :active_page, "schedules")}
|
|
end
|
|
|
|
@impl true
|
|
def handle_params(params, _url, socket) do
|
|
case socket.assigns.live_action do
|
|
:new ->
|
|
schedule = %Schedule{}
|
|
changeset = Schedule.changeset(schedule, %{})
|
|
|
|
{:noreply,
|
|
socket
|
|
|> assign(:page_title, t("New Schedule"))
|
|
|> assign(:schedule, schedule)
|
|
|> assign(:form, to_form(changeset))}
|
|
|
|
:edit ->
|
|
org_id = socket.assigns.current_scope.organization.id
|
|
schedule = OnCall.get_schedule!(params["id"], org_id)
|
|
changeset = Schedule.changeset(schedule, %{})
|
|
|
|
{:noreply,
|
|
socket
|
|
|> assign(:page_title, t("Edit Schedule"))
|
|
|> assign(:schedule, schedule)
|
|
|> assign(:form, to_form(changeset))}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_event("validate", %{"schedule" => params}, socket) do
|
|
changeset =
|
|
socket.assigns.schedule
|
|
|> Schedule.changeset(params)
|
|
|> Map.put(:action, :validate)
|
|
|
|
{:noreply, assign(socket, :form, to_form(changeset))}
|
|
end
|
|
|
|
def handle_event("save", %{"schedule" => params}, socket) do
|
|
org_id = socket.assigns.current_scope.organization.id
|
|
params = Map.put(params, "organization_id", org_id)
|
|
|
|
case socket.assigns.live_action do
|
|
:new -> save_schedule(socket, :create, params)
|
|
:edit -> save_schedule(socket, :update, params)
|
|
end
|
|
end
|
|
|
|
defp save_schedule(socket, :create, params) do
|
|
case OnCall.create_schedule(params) do
|
|
{:ok, schedule} ->
|
|
{:noreply,
|
|
socket
|
|
|> put_flash(:info, t("Schedule created"))
|
|
|> push_navigate(to: ~p"/schedules/#{schedule.id}")}
|
|
|
|
{:error, changeset} ->
|
|
{:noreply, assign(socket, :form, to_form(changeset))}
|
|
end
|
|
end
|
|
|
|
defp save_schedule(socket, :update, params) do
|
|
case OnCall.update_schedule(socket.assigns.schedule, params) do
|
|
{:ok, schedule} ->
|
|
{:noreply,
|
|
socket
|
|
|> put_flash(:info, t("Schedule updated"))
|
|
|> push_navigate(to: ~p"/schedules/#{schedule.id}")}
|
|
|
|
{:error, changeset} ->
|
|
{:noreply, assign(socket, :form, to_form(changeset))}
|
|
end
|
|
end
|
|
end
|