mikrotik api update

This commit is contained in:
Graham McIntire 2026-02-02 10:35:44 -06:00
parent bd6dad85e1
commit 1ba55ce451
No known key found for this signature in database
6 changed files with 140 additions and 44 deletions

View file

@ -65,38 +65,46 @@ defmodule Mix.Tasks.PopulateEnglish do
defp process_lines([], acc), do: acc
defp process_lines([line | rest], acc) do
# Found msgid line
if String.starts_with?(line, "msgid ") do
{msgid_lines, remaining} = collect_string_lines([line | rest], [])
# Check if this is a plural form (msgid_plural follows)
if is_plural_form?(remaining) do
# Skip plural forms - they need special handling
{plural_lines, remaining2} = skip_plural_translation(remaining, [])
new_acc = Enum.reverse(plural_lines, Enum.reverse(msgid_lines, acc))
process_lines(remaining2, new_acc)
else
{msgstr_lines, remaining2} = collect_msgstr_lines(remaining, [])
msgid_value = extract_string_value(msgid_lines)
# If msgstr is empty and msgid is not empty, populate it
updated_msgstr =
if should_populate?(msgid_value, msgstr_lines) do
populate_msgstr(msgid_lines, msgid_value)
else
msgstr_lines
end
new_acc = Enum.reverse(updated_msgstr, Enum.reverse(msgid_lines, acc))
process_lines(remaining2, new_acc)
end
process_msgid_line([line | rest], acc)
else
# Regular line (comments, metadata, blank lines)
process_lines(rest, [line | acc])
end
end
defp process_msgid_line(lines, acc) do
{msgid_lines, remaining} = collect_string_lines(lines, [])
# Check if this is a plural form (msgid_plural follows)
if plural_form?(remaining) do
process_plural_form(msgid_lines, remaining, acc)
else
process_singular_form(msgid_lines, remaining, acc)
end
end
defp process_plural_form(msgid_lines, remaining, acc) do
{plural_lines, remaining2} = skip_plural_translation(remaining, [])
new_acc = Enum.reverse(plural_lines, Enum.reverse(msgid_lines, acc))
process_lines(remaining2, new_acc)
end
defp process_singular_form(msgid_lines, remaining, acc) do
{msgstr_lines, remaining2} = collect_msgstr_lines(remaining, [])
msgid_value = extract_string_value(msgid_lines)
updated_msgstr =
if should_populate?(msgid_value, msgstr_lines) do
populate_msgstr(msgid_lines, msgid_value)
else
msgstr_lines
end
new_acc = Enum.reverse(updated_msgstr, Enum.reverse(msgid_lines, acc))
process_lines(remaining2, new_acc)
end
# Collect lines that are part of a msgid string (including continuation lines)
defp collect_string_lines([], acc), do: {Enum.reverse(acc), []}
@ -205,9 +213,9 @@ defmodule Mix.Tasks.PopulateEnglish do
end)
end
defp is_plural_form?([]), do: false
defp plural_form?([]), do: false
defp is_plural_form?([line | _rest]) do
defp plural_form?([line | _rest]) do
String.starts_with?(line, "msgid_plural ")
end

View file

@ -222,19 +222,30 @@ defmodule Towerops.Devices.Device do
defp update_mikrotik_credential_source(changeset) do
# If user explicitly set a username, mark source as "device"
# If it's blank/nil, mark source as "site" (will inherit from site or org)
case get_change(changeset, :mikrotik_username) do
nil ->
# No change to username, keep existing source
changeset
# If it's blank/nil/cleared, mark source as "site" (will inherit from site or org)
username_change = get_change(changeset, :mikrotik_username)
current_username = get_field(changeset, :mikrotik_username)
"" ->
# Explicitly cleared, set to inherit from site
cond do
# Explicitly set to empty string - clear and inherit
username_change == "" ->
changeset
|> put_change(:mikrotik_username, nil)
|> put_change(:mikrotik_credential_source, "site")
# Explicitly set to a value - mark as device-specific
username_change != nil && username_change != "" ->
put_change(changeset, :mikrotik_credential_source, "device")
# No change to username, but check if we should reset source
# (This handles cases where other MikroTik fields are cleared)
username_change == nil && (current_username == nil || current_username == "") &&
get_field(changeset, :mikrotik_credential_source) == "device" ->
put_change(changeset, :mikrotik_credential_source, "site")
_value ->
# Explicitly set a value, mark as device-specific
put_change(changeset, :mikrotik_credential_source, "device")
# No change, keep existing
true ->
changeset
end
end
end

View file

@ -115,6 +115,11 @@ defmodule Towerops.Organizations do
"""
def update_organization(%Organization{} = organization, attrs) do
old_community = organization.snmp_community
old_mikrotik_username = organization.mikrotik_username
old_mikrotik_password = organization.mikrotik_password
old_mikrotik_port = organization.mikrotik_port
old_mikrotik_use_ssl = organization.mikrotik_use_ssl
old_mikrotik_enabled = organization.mikrotik_enabled
case organization
|> Organization.changeset(attrs)
@ -128,6 +133,29 @@ defmodule Towerops.Organizations do
)
end
# If any MikroTik settings changed, propagate to inheriting devices
mikrotik_changed =
updated_organization.mikrotik_username != old_mikrotik_username ||
updated_organization.mikrotik_password != old_mikrotik_password ||
updated_organization.mikrotik_port != old_mikrotik_port ||
updated_organization.mikrotik_use_ssl != old_mikrotik_use_ssl ||
updated_organization.mikrotik_enabled != old_mikrotik_enabled
if mikrotik_changed do
mikrotik_attrs = %{
mikrotik_username: updated_organization.mikrotik_username,
mikrotik_password: updated_organization.mikrotik_password,
mikrotik_port: updated_organization.mikrotik_port,
mikrotik_use_ssl: updated_organization.mikrotik_use_ssl,
mikrotik_enabled: updated_organization.mikrotik_enabled
}
Towerops.Devices.propagate_organization_mikrotik_change(
updated_organization.id,
mikrotik_attrs
)
end
result
error ->

View file

@ -107,6 +107,11 @@ defmodule Towerops.Sites do
"""
def update_site(%Site{} = site, attrs) do
old_community = site.snmp_community
old_mikrotik_username = site.mikrotik_username
old_mikrotik_password = site.mikrotik_password
old_mikrotik_port = site.mikrotik_port
old_mikrotik_use_ssl = site.mikrotik_use_ssl
old_mikrotik_enabled = site.mikrotik_enabled
case site
|> Site.changeset(attrs)
@ -117,6 +122,26 @@ defmodule Towerops.Sites do
Towerops.Devices.propagate_site_community_change(updated_site.id, updated_site.snmp_community)
end
# If any MikroTik settings changed, propagate to inheriting devices
mikrotik_changed =
updated_site.mikrotik_username != old_mikrotik_username ||
updated_site.mikrotik_password != old_mikrotik_password ||
updated_site.mikrotik_port != old_mikrotik_port ||
updated_site.mikrotik_use_ssl != old_mikrotik_use_ssl ||
updated_site.mikrotik_enabled != old_mikrotik_enabled
if mikrotik_changed do
mikrotik_attrs = %{
mikrotik_username: updated_site.mikrotik_username,
mikrotik_password: updated_site.mikrotik_password,
mikrotik_port: updated_site.mikrotik_port,
mikrotik_use_ssl: updated_site.mikrotik_use_ssl,
mikrotik_enabled: updated_site.mikrotik_enabled
}
Towerops.Devices.propagate_site_mikrotik_change(updated_site.id, mikrotik_attrs)
end
result
error ->

View file

@ -22,7 +22,10 @@
<%= if @invitation do %>
<div class="mt-6 rounded-lg bg-blue-50 dark:bg-blue-900/20 p-4 border border-blue-200 dark:border-blue-800">
<p class="text-sm text-blue-900 dark:text-blue-100">
{t_auth("You've been invited to join %{organization} as a %{role}.", organization: @invitation.organization.name, role: @invitation.role)}
{t_auth("You've been invited to join %{organization} as a %{role}.",
organization: @invitation.organization.name,
role: @invitation.role
)}
</p>
</div>
<% else %>
@ -86,7 +89,12 @@
</div>
<div class="ml-3 text-sm">
<label for="privacy_policy_consent" class="text-zinc-700 dark:text-zinc-300">
{t_auth("I agree to the %{link}", link: raw(~s(<a href="/privacy" target="_blank" class="font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300">#{t_auth("Privacy Policy")}</a>)))}
{t_auth("I agree to the %{link}",
link:
raw(
~s(<a href="/privacy" target="_blank" class="font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300">#{t_auth("Privacy Policy")}</a>)
)
)}
<span class="text-red-600 dark:text-red-400">*</span>
</label>
</div>
@ -104,15 +112,26 @@
</div>
<div class="ml-3 text-sm">
<label for="terms_of_service_consent" class="text-zinc-700 dark:text-zinc-300">
{t_auth("I agree to the %{link}", link: raw(~s(<a href="/terms" target="_blank" class="font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300">#{t_auth("Terms of Service")}</a>)))}
{t_auth("I agree to the %{link}",
link:
raw(
~s(<a href="/terms" target="_blank" class="font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300">#{t_auth("Terms of Service")}</a>)
)
)}
<span class="text-red-600 dark:text-red-400">*</span>
</label>
</div>
</div>
</div>
<.button phx-disable-with={t_auth("Creating account...")} class="w-full mt-6" variant="primary">
{if @invitation, do: t_auth("Accept invitation and create account"), else: t_auth("Create an account")}
<.button
phx-disable-with={t_auth("Creating account...")}
class="w-full mt-6"
variant="primary"
>
{if @invitation,
do: t_auth("Accept invitation and create account"),
else: t_auth("Create an account")}
</.button>
</.form>
</div>

View file

@ -34,7 +34,12 @@
{t_auth("You are running the local mail adapter.")}
</p>
<p class="mt-1 text-sm text-blue-700 dark:text-blue-200">
{t_auth("To see sent emails, visit %{link}.", link: raw(~s(<a href="/dev/mailbox" class="font-medium underline">#{t_auth("the mailbox page")}</a>)))}
{t_auth("To see sent emails, visit %{link}.",
link:
raw(
~s(<a href="/dev/mailbox" class="font-medium underline">#{t_auth("the mailbox page")}</a>)
)
)}
</p>
</div>
</div>
@ -84,7 +89,7 @@
</span>
</div>
</div>
<!-- Alternative: Email Login Link -->
<.form :let={f} for={@form} as={:user} id="login_form_magic" action={~p"/users/log-in"}>
<.input