mirror of
https://github.com/eduardogsilva/wireguard_webadmin.git
synced 2025-06-27 16:57:01 +00:00
VPN Invite app translation
This commit is contained in:
parent
036dcc75da
commit
3cb10b6ec4
Binary file not shown.
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-04-15 14:21-0300\n"
|
||||
"POT-Creation-Date: 2025-04-16 10:17-0300\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -70,7 +70,7 @@ msgstr "DNS Secundário"
|
||||
#: templates/wireguard/wireguard_manage_ip.html:42
|
||||
#: templates/wireguard/wireguard_manage_peer.html:170
|
||||
#: templates/wireguard/wireguard_peer_list.html:166 user_manager/forms.py:49
|
||||
#: user_manager/forms.py:180
|
||||
#: user_manager/forms.py:180 vpn_invite/forms.py:193 vpn_invite/forms.py:327
|
||||
msgid "Back"
|
||||
msgstr "Voltar"
|
||||
|
||||
@ -82,7 +82,8 @@ msgstr "Resolução de DNS"
|
||||
#: templates/wireguard/wireguard_manage_ip.html:41
|
||||
#: templates/wireguard/wireguard_manage_peer.html:168
|
||||
#: templates/wireguard/wireguard_manage_server.html:130
|
||||
#: user_manager/forms.py:98 user_manager/forms.py:205
|
||||
#: user_manager/forms.py:98 user_manager/forms.py:205 vpn_invite/forms.py:192
|
||||
#: vpn_invite/forms.py:326
|
||||
msgid "Save"
|
||||
msgstr "Salvar"
|
||||
|
||||
@ -234,11 +235,13 @@ msgstr ""
|
||||
"que isto é um erro."
|
||||
|
||||
#: templates/accounts/login.html:14 templates/user_manager/list.html:8
|
||||
#: user_manager/forms.py:13
|
||||
#: user_manager/forms.py:13 vpn_invite/forms.py:282
|
||||
msgid "Username"
|
||||
msgstr "Usuário"
|
||||
|
||||
#: templates/accounts/login.html:23 user_manager/forms.py:14
|
||||
#: templates/accounts/login.html:23
|
||||
#: templates/vpn_invite/invite_settings.html:19 user_manager/forms.py:14
|
||||
#: vpn_invite/forms.py:283
|
||||
msgid "Password"
|
||||
msgstr "Senha"
|
||||
|
||||
@ -255,6 +258,8 @@ msgid "Login again"
|
||||
msgstr "Acessar novamente"
|
||||
|
||||
#: templates/base.html:112 templates/dns/static_host_list.html:72
|
||||
#: vpn_invite/forms.py:79 vpn_invite/forms.py:80 vpn_invite/forms.py:81
|
||||
#: vpn_invite/forms.py:82 vpn_invite/forms.py:83
|
||||
msgid "Status"
|
||||
msgstr "Estado"
|
||||
|
||||
@ -263,6 +268,7 @@ msgid "User Manager"
|
||||
msgstr "Configurar Usuários"
|
||||
|
||||
#: templates/base.html:176 templates/wireguard/wireguard_peer_list.html:195
|
||||
#: vpn_invite/views.py:36
|
||||
msgid "VPN Invite"
|
||||
msgstr "Convite para VPN"
|
||||
|
||||
@ -406,6 +412,30 @@ msgstr "Instância do WireGuard"
|
||||
msgid "Users"
|
||||
msgstr "Usuários"
|
||||
|
||||
#: templates/vpn_invite/invite_settings.html:17 user_manager/forms.py:178
|
||||
msgid "Peer"
|
||||
msgstr "Peer"
|
||||
|
||||
#: templates/vpn_invite/invite_settings.html:18
|
||||
msgid "Expiration"
|
||||
msgstr "Expira em"
|
||||
|
||||
#: templates/vpn_invite/invite_settings.html:31
|
||||
msgid "Remove VPN invitation for peer"
|
||||
msgstr "Remover convite para VPN do peer"
|
||||
|
||||
#: templates/vpn_invite/invite_settings.html:38
|
||||
msgid "No active VPN invitations"
|
||||
msgstr "Nenhum convite para VPN ativo"
|
||||
|
||||
#: templates/vpn_invite/invite_settings.html:49 vpn_invite/views.py:76
|
||||
msgid "Email Settings"
|
||||
msgstr "Configurações de Email"
|
||||
|
||||
#: templates/vpn_invite/invite_settings.html:50
|
||||
msgid "Invite Settings"
|
||||
msgstr "Configurações de Convite"
|
||||
|
||||
#: templates/wireguard/wireguard_manage_ip.html:18
|
||||
msgid "Enter Allowed IP"
|
||||
msgstr "Inserir IP Permitido"
|
||||
@ -743,7 +773,7 @@ msgstr "Tráfego da Instância"
|
||||
msgid "Public Address"
|
||||
msgstr "Endereço Público"
|
||||
|
||||
#: templates/wireguard/wireguard_status.html:47
|
||||
#: templates/wireguard/wireguard_status.html:47 vpn_invite/forms.py:285
|
||||
msgid "Port"
|
||||
msgstr "Porta"
|
||||
|
||||
@ -779,10 +809,6 @@ msgstr "As duas senhas não coincidem."
|
||||
msgid "Password must be at least 8 characters long."
|
||||
msgstr "Senha deve ter pelo menos 8 caracteres."
|
||||
|
||||
#: user_manager/forms.py:178
|
||||
msgid "Peer"
|
||||
msgstr "Peer"
|
||||
|
||||
#: user_manager/forms.py:220
|
||||
msgid "A peer group with that name already exists."
|
||||
msgstr "Um grupo de peers com esse nome já existe."
|
||||
@ -791,19 +817,19 @@ msgstr "Um grupo de peers com esse nome já existe."
|
||||
msgid "Debugging Analyst"
|
||||
msgstr "Analista de Debug"
|
||||
|
||||
#: user_manager/models.py:14
|
||||
#: user_manager/models.py:14 vpn_invite/models.py:25
|
||||
msgid "View Only"
|
||||
msgstr "Somente Visualização"
|
||||
|
||||
#: user_manager/models.py:15
|
||||
#: user_manager/models.py:15 vpn_invite/models.py:25
|
||||
msgid "Peer Manager"
|
||||
msgstr "Gerente de Peers"
|
||||
|
||||
#: user_manager/models.py:16
|
||||
#: user_manager/models.py:16 vpn_invite/models.py:25
|
||||
msgid "WireGuard Manager"
|
||||
msgstr "Gerente do WireGuard"
|
||||
|
||||
#: user_manager/models.py:17
|
||||
#: user_manager/models.py:17 vpn_invite/models.py:25
|
||||
msgid "Administrator"
|
||||
msgstr "Administrador"
|
||||
|
||||
@ -955,6 +981,258 @@ msgstr ""
|
||||
msgid "Please type the username to proceed."
|
||||
msgstr "Por favor, digite o nome de usuário para prosseguir."
|
||||
|
||||
#: vpn_invite/forms.py:50 vpn_invite/forms.py:295
|
||||
msgid "Enabled"
|
||||
msgstr "Habilitado"
|
||||
|
||||
#: vpn_invite/forms.py:50
|
||||
msgid "Disabled"
|
||||
msgstr "Desabilitado"
|
||||
|
||||
#: vpn_invite/forms.py:69 vpn_invite/forms.py:70 vpn_invite/forms.py:71
|
||||
#: vpn_invite/forms.py:72 vpn_invite/forms.py:73
|
||||
msgid "URL"
|
||||
msgstr "URL"
|
||||
|
||||
#: vpn_invite/forms.py:74 vpn_invite/forms.py:75 vpn_invite/forms.py:76
|
||||
#: vpn_invite/forms.py:77 vpn_invite/forms.py:78
|
||||
msgid "Text"
|
||||
msgstr "Texto"
|
||||
|
||||
#: vpn_invite/forms.py:84
|
||||
msgid "Web Page Instructions"
|
||||
msgstr "Página Web de Instruções"
|
||||
|
||||
#: vpn_invite/forms.py:85
|
||||
msgid "Email Subject"
|
||||
msgstr "Assunto do Email"
|
||||
|
||||
#: vpn_invite/forms.py:86
|
||||
msgid "Email Message"
|
||||
msgstr "Mensagem do Email"
|
||||
|
||||
#: vpn_invite/forms.py:87
|
||||
msgid "Email Enabled"
|
||||
msgstr "Email Habilitado"
|
||||
|
||||
#: vpn_invite/forms.py:88
|
||||
msgid "WhatsApp Message"
|
||||
msgstr "Mensagem do WhatsApp"
|
||||
|
||||
#: vpn_invite/forms.py:89
|
||||
msgid "WhatsApp Enabled"
|
||||
msgstr "WhatsApp Habilitado"
|
||||
|
||||
#: vpn_invite/forms.py:90
|
||||
msgid "Text Message"
|
||||
msgstr "Mensagem de Texto"
|
||||
|
||||
#: vpn_invite/forms.py:91
|
||||
msgid "Expiration (minutes)"
|
||||
msgstr "Expira em (minutos)"
|
||||
|
||||
#: vpn_invite/forms.py:92
|
||||
msgid "Random Password"
|
||||
msgstr "Senha Aleatória"
|
||||
|
||||
#: vpn_invite/forms.py:93
|
||||
msgid "Invite URL"
|
||||
msgstr "Endereço do Convite"
|
||||
|
||||
#: vpn_invite/forms.py:94
|
||||
msgid "Required User Level"
|
||||
msgstr "Nível de Acesso Requerido"
|
||||
|
||||
#: vpn_invite/forms.py:95
|
||||
msgid "Default Password"
|
||||
msgstr "Senha Padrão"
|
||||
|
||||
#: vpn_invite/forms.py:96
|
||||
msgid "Random Password Length"
|
||||
msgstr "Tamanho da Senha Aleatória"
|
||||
|
||||
#: vpn_invite/forms.py:97
|
||||
msgid "Random Password Complexity"
|
||||
msgstr "Complexidade da Senha Aleatória"
|
||||
|
||||
#: vpn_invite/forms.py:104
|
||||
msgid "General Settings"
|
||||
msgstr "Configuração Geral"
|
||||
|
||||
#: vpn_invite/forms.py:126
|
||||
msgid "Download Buttons"
|
||||
msgstr "Botões de Download"
|
||||
|
||||
#: vpn_invite/forms.py:159
|
||||
msgid "Message templates"
|
||||
msgstr "Modelos de Mensagem"
|
||||
|
||||
#: vpn_invite/forms.py:166
|
||||
msgid "Email Message Template"
|
||||
msgstr "Modelo de Mensagem de Email"
|
||||
|
||||
#: vpn_invite/forms.py:177
|
||||
msgid "WhatsApp Message Template"
|
||||
msgstr "Modelo de Mensagem do WhatsApp"
|
||||
|
||||
#: vpn_invite/forms.py:184
|
||||
msgid "Text Message Template"
|
||||
msgstr "Modelo de Mensagem de Texto"
|
||||
|
||||
#: vpn_invite/forms.py:206
|
||||
msgid "Invite URL must start with 'https://'."
|
||||
msgstr "Endereço do convite deve começar com 'https://'."
|
||||
|
||||
#: vpn_invite/forms.py:208
|
||||
msgid "Invite URL must end with '/invite/'."
|
||||
msgstr "Endereço do convite deve terminar com '/invite/'."
|
||||
|
||||
#: vpn_invite/forms.py:214
|
||||
msgid "Expiration (minutes) must be between 1 and 1440."
|
||||
msgstr "Tempo de expiração (minutos) deve estar entre 1 e 1440."
|
||||
|
||||
#: vpn_invite/forms.py:223
|
||||
msgid "Default password must not be provided when random password is enabled."
|
||||
msgstr ""
|
||||
"Senha padrão não deve ser fornecida quando a senha aleatória está habilitada."
|
||||
|
||||
#: vpn_invite/forms.py:225
|
||||
msgid "Random password length must be at least 6 characters."
|
||||
msgstr "Senha aleatória deve ter pelo menos 6 caracteres."
|
||||
|
||||
#: vpn_invite/forms.py:230
|
||||
msgid "Default password must be provided when random password is disabled."
|
||||
msgstr ""
|
||||
"Senha padrão deve ser fornecida quando a senha aleatória está desabilitada."
|
||||
|
||||
#: vpn_invite/forms.py:232
|
||||
msgid "Default password must be at least 6 characters long."
|
||||
msgstr "Senha padrão deve ter pelo menos 6 caracteres."
|
||||
|
||||
#: vpn_invite/forms.py:242
|
||||
msgid "Text field must not be empty when download button is enabled."
|
||||
msgstr ""
|
||||
"Campo de texto não deve estar vazio quando o botão de download está "
|
||||
"habilitado."
|
||||
|
||||
#: vpn_invite/forms.py:244
|
||||
msgid "URL field must not be empty when download button is enabled."
|
||||
msgstr ""
|
||||
"Campo de URL não deve estar vazio quando o botão de download está habilitado."
|
||||
|
||||
#: vpn_invite/forms.py:253
|
||||
msgid ""
|
||||
"Default password must not be contained in any message template. Found at: "
|
||||
msgstr ""
|
||||
"Senha padrão não deve estar contida em nenhum modelo de mensagem. Encontrado "
|
||||
"em: "
|
||||
|
||||
#: vpn_invite/forms.py:260
|
||||
#, python-brace-format
|
||||
msgid "The template must include the placeholder '{invite_url}'."
|
||||
msgstr "O modelo deve incluir o espaço reservado '{invite_url}'."
|
||||
|
||||
#: vpn_invite/forms.py:284
|
||||
msgid "Host"
|
||||
msgstr "Endereço"
|
||||
|
||||
#: vpn_invite/forms.py:286
|
||||
msgid "Encryption"
|
||||
msgstr "Criptografia"
|
||||
|
||||
#: vpn_invite/forms.py:287
|
||||
msgid "From Address"
|
||||
msgstr "Endereço de Origem"
|
||||
|
||||
#: vpn_invite/forms.py:338
|
||||
msgid "SMTP port must be between 1 and 65535."
|
||||
msgstr "Porta SMTP deve ser entre 1 e 65535."
|
||||
|
||||
#: vpn_invite/models.py:8
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"Hello,\n"
|
||||
"\n"
|
||||
"You're invited to join our secure WireGuard VPN network. Please click the "
|
||||
"link below to access your personalized VPN configuration:\n"
|
||||
"\n"
|
||||
"{invite_url}\n"
|
||||
"\n"
|
||||
"Note: This invitation link will expire in {expire_minutes} minutes. If you "
|
||||
"need a new link after expiration, please request another invite."
|
||||
msgstr ""
|
||||
"Olá,\n"
|
||||
"\n"
|
||||
"Você está convidado a ingressar em nossa rede VPN WireGuard segura. Por "
|
||||
"favor, clique no link abaixo para acessar sua configuração VPN "
|
||||
"personalizada:\n"
|
||||
"\n"
|
||||
"{invite_url}\n"
|
||||
"\n"
|
||||
"Observação: Este link de convite expirará em {expire_minutes} minutos. Se "
|
||||
"você precisar de um novo link após a expiração, por favor, solicite outro "
|
||||
"convite."
|
||||
|
||||
#: vpn_invite/models.py:16
|
||||
msgid ""
|
||||
"<h2>Welcome to Your VPN Setup</h2>\n"
|
||||
"<p>Begin by downloading the WireGuard app for your device using one of the "
|
||||
"links below.</p>\n"
|
||||
"<p>Once installed, you can either <strong>scan the QR code</strong> or "
|
||||
"<strong>download the configuration file</strong> to quickly import your "
|
||||
"settings and start using your secure VPN connection.</p>"
|
||||
msgstr ""
|
||||
"<h2>Bem-vindo à Configuração da Sua VPN</h2>\n"
|
||||
"<p>Comece baixando o aplicativo WireGuard para o seu dispositivo usando um "
|
||||
"dos links abaixo.</p>\n"
|
||||
"<p>Após a instalação, você pode <strong>escanear o código QR</strong> ou "
|
||||
"<strong>baixar o arquivo de configuração</strong> para importar rapidamente "
|
||||
"suas configurações e começar a usar sua conexão VPN segura.</p>"
|
||||
|
||||
#: vpn_invite/models.py:30
|
||||
msgid "Letters, Digits, Special Characters"
|
||||
msgstr "Letras, Dígitos, Caracteres Especiais"
|
||||
|
||||
#: vpn_invite/models.py:31
|
||||
msgid "Letters, Digits"
|
||||
msgstr "Letras, Dígitos"
|
||||
|
||||
#: vpn_invite/models.py:31
|
||||
msgid "Letters"
|
||||
msgstr "Letras"
|
||||
|
||||
#: vpn_invite/models.py:31
|
||||
msgid "Digits"
|
||||
msgstr "Dígitos"
|
||||
|
||||
#: vpn_invite/models.py:55
|
||||
msgid ""
|
||||
"Download the WireGuard app for your device using one of the links below. "
|
||||
"After installation, you can scan the QR code or download the configuration "
|
||||
"file to import on your device."
|
||||
msgstr ""
|
||||
"Baixe o aplicativo WireGuard para o seu dispositivo usando um dos links "
|
||||
"abaixo. Após a instalação, você pode escanear o código QR ou baixar o "
|
||||
"arquivo de configuração para importar no seu dispositivo."
|
||||
|
||||
#: vpn_invite/models.py:61
|
||||
msgid "WireGuard VPN Invite"
|
||||
msgstr "Convite para VPN WireGuard"
|
||||
|
||||
#: vpn_invite/views.py:52
|
||||
msgid "Invite Settings|Settings saved successfully."
|
||||
msgstr "Configurações de Convite|Configurações salvas com sucesso."
|
||||
|
||||
#: vpn_invite/views.py:56
|
||||
msgid "VPN Invite Settings"
|
||||
msgstr "Configurações de Convite para VPN"
|
||||
|
||||
#: vpn_invite/views.py:72
|
||||
#, fuzzy
|
||||
#| msgid "Invite Settings|Settings saved successfully."
|
||||
msgid "Email Settings|Settings saved successfully."
|
||||
msgstr "Configurações de Convite|Configurações salvas com sucesso."
|
||||
|
||||
#: wireguard/forms.py:11
|
||||
msgid "Display Name"
|
||||
msgstr "Nome de Exibição"
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% load i18n %}
|
||||
{% block content %}
|
||||
<div class='row'>
|
||||
<div class='col-xl-8'>
|
||||
@ -14,9 +14,9 @@
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Peer</th>
|
||||
<th>Expiration</th>
|
||||
<th>Password</th>
|
||||
<th>{% trans 'Peer' %}</th>
|
||||
<th>{% trans 'Expiration' %}</th>
|
||||
<th>{% trans 'Password' %}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -28,13 +28,15 @@
|
||||
<td>{{ invite.invite_expiration }}</td>
|
||||
<td>{{ invite.invite_password }}</td>
|
||||
<td class="min-width">
|
||||
<a href="/vpn_invite/?invite={{ invite.uuid }}&action=delete" onclick="return confirm('Remove VPN invitation for peer {{ invite.peer }}?')"><i class="fas fa-trash-alt"></i></a>
|
||||
<a href="/vpn_invite/?invite={{ invite.uuid }}&action=delete" onclick="return confirm('{% trans 'Remove VPN invitation for peer' %} {{ invite.peer }}?')"><i class="fas fa-trash-alt"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4"></td>
|
||||
<td colspan="4" class="text-center text-muted">
|
||||
{% trans 'No active VPN invitations' %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
@ -44,8 +46,8 @@
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<a href="/vpn_invite/smtp_settings/" class="btn btn-primary">SMTP Settings</a>
|
||||
<a href="/vpn_invite/settings/" class="btn btn-primary">Invite Settings</a>
|
||||
<a href="/vpn_invite/smtp_settings/" class="btn btn-primary">{% trans 'Email Settings' %}</a>
|
||||
<a href="/vpn_invite/settings/" class="btn btn-primary">{% trans 'Invite Settings' %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,10 +1,10 @@
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from crispy_forms.helper import FormHelper
|
||||
from crispy_forms.layout import Layout, Row, Column, Submit, HTML
|
||||
from crispy_forms.templatetags.crispy_forms_field import css_class
|
||||
from .models import InviteSettings
|
||||
from crispy_forms.layout import Column, HTML, Layout, Row, Submit
|
||||
from django import forms
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from wireguard_tools.models import EmailSettings
|
||||
from .models import InviteSettings
|
||||
|
||||
|
||||
class InviteSettingsForm(forms.ModelForm):
|
||||
@ -46,7 +46,7 @@ class InviteSettingsForm(forms.ModelForm):
|
||||
super(InviteSettingsForm, self).__init__(*args, **kwargs)
|
||||
|
||||
# Define boolean dropdown choices
|
||||
bool_choices = [(True, 'Enabled'), (False, 'Disabled')]
|
||||
bool_choices = [(True, _('Enabled')), (False, _('Disabled'))]
|
||||
bool_coerce = lambda x: True if x == 'True' else False
|
||||
|
||||
for field_name in [
|
||||
@ -65,37 +65,42 @@ class InviteSettingsForm(forms.ModelForm):
|
||||
initial=self.instance.__dict__.get(field_name, True) if self.instance and self.instance.pk else True,
|
||||
)
|
||||
|
||||
self.fields['download_1_url'].label = 'URL'
|
||||
self.fields['download_2_url'].label = 'URL'
|
||||
self.fields['download_3_url'].label = 'URL'
|
||||
self.fields['download_4_url'].label = 'URL'
|
||||
self.fields['download_5_url'].label = 'URL'
|
||||
self.fields['download_1_label'].label = 'Text'
|
||||
self.fields['download_2_label'].label = 'Text'
|
||||
self.fields['download_3_label'].label = 'Text'
|
||||
self.fields['download_4_label'].label = 'Text'
|
||||
self.fields['download_5_label'].label = 'Text'
|
||||
self.fields['download_1_enabled'].label = 'Status'
|
||||
self.fields['download_2_enabled'].label = 'Status'
|
||||
self.fields['download_3_enabled'].label = 'Status'
|
||||
self.fields['download_4_enabled'].label = 'Status'
|
||||
self.fields['download_5_enabled'].label = 'Status'
|
||||
self.fields['download_instructions'].label = 'Web Page Instructions'
|
||||
self.fields['invite_email_subject'].label = 'Email Subject'
|
||||
self.fields['invite_email_body'].label = 'Email Message'
|
||||
self.fields['invite_email_enabled'].label = 'Email Enabled'
|
||||
self.fields['invite_whatsapp_body'].label = 'WhatsApp Message'
|
||||
self.fields['invite_whatsapp_enabled'].label = 'WhatsApp Enabled'
|
||||
self.fields['invite_text_body'].label = 'Text Message'
|
||||
self.fields['invite_expiration'].label = 'Expiration (minutes)'
|
||||
self.fields['enforce_random_password'].label = 'Random Password'
|
||||
self.fields['download_1_url'].label = _('URL')
|
||||
self.fields['download_2_url'].label = _('URL')
|
||||
self.fields['download_3_url'].label = _('URL')
|
||||
self.fields['download_4_url'].label = _('URL')
|
||||
self.fields['download_5_url'].label = _('URL')
|
||||
self.fields['download_1_label'].label = _('Text')
|
||||
self.fields['download_2_label'].label = _('Text')
|
||||
self.fields['download_3_label'].label = _('Text')
|
||||
self.fields['download_4_label'].label = _('Text')
|
||||
self.fields['download_5_label'].label = _('Text')
|
||||
self.fields['download_1_enabled'].label = _('Status')
|
||||
self.fields['download_2_enabled'].label = _('Status')
|
||||
self.fields['download_3_enabled'].label = _('Status')
|
||||
self.fields['download_4_enabled'].label = _('Status')
|
||||
self.fields['download_5_enabled'].label = _('Status')
|
||||
self.fields['download_instructions'].label = _('Web Page Instructions')
|
||||
self.fields['invite_email_subject'].label = _('Email Subject')
|
||||
self.fields['invite_email_body'].label = _('Email Message')
|
||||
self.fields['invite_email_enabled'].label = _('Email Enabled')
|
||||
self.fields['invite_whatsapp_body'].label = _('WhatsApp Message')
|
||||
self.fields['invite_whatsapp_enabled'].label = _('WhatsApp Enabled')
|
||||
self.fields['invite_text_body'].label = _('Text Message')
|
||||
self.fields['invite_expiration'].label = _('Expiration (minutes)')
|
||||
self.fields['enforce_random_password'].label = _('Random Password')
|
||||
self.fields['invite_url'].label = _('Invite URL')
|
||||
self.fields['required_user_level'].label = _('Required User Level')
|
||||
self.fields['default_password'].label = _('Default Password')
|
||||
self.fields['random_password_length'].label = _('Random Password Length')
|
||||
self.fields['random_password_complexity'].label = _('Random Password Complexity')
|
||||
self.helper = FormHelper()
|
||||
self.helper.form_method = 'post'
|
||||
|
||||
self.helper.layout = Layout(
|
||||
Row(
|
||||
Column(
|
||||
HTML("<h3>General Settings</h3>"),
|
||||
HTML("<h3>" + _("General Settings") + "</h3>"),
|
||||
Row(
|
||||
Column('invite_url', css_class='form-group col-md-12 mb-0'),
|
||||
),
|
||||
@ -117,7 +122,7 @@ class InviteSettingsForm(forms.ModelForm):
|
||||
),
|
||||
HTML("<hr>"),
|
||||
Row(
|
||||
Column(HTML("<h5>Download Buttons</h5>"), css_class='form-group col-md-12 mb-0'),
|
||||
Column(HTML("<h5>" + _("Download Buttons") + "</h5>"), css_class='form-group col-md-12 mb-0'),
|
||||
Column('download_1_label', css_class='form-group col-md-3 mb-0'),
|
||||
Column('download_1_url', css_class='form-group col-md-6 mb-0'),
|
||||
Column('download_1_enabled', css_class='form-group col-md-3 mb-0'),
|
||||
@ -147,24 +152,17 @@ class InviteSettingsForm(forms.ModelForm):
|
||||
Column('download_5_enabled', css_class='form-group col-md-3 mb-0'),
|
||||
css_class='form-row'
|
||||
),
|
||||
Row(
|
||||
Column(
|
||||
Submit('submit', 'Save', css_class='btn btn-success'),
|
||||
HTML(' <a class="btn btn-secondary" href="/vpn_invite/">Back</a> '),
|
||||
css_class='col-md-12'
|
||||
),
|
||||
css_class='form-row'
|
||||
),
|
||||
css_class='col-xl-6'),
|
||||
|
||||
css_class='col-xl-12'),
|
||||
Column(
|
||||
HTML("<h3>Message templates</h3>"),
|
||||
HTML("<h3>" + _('Message templates') + "</h3>"),
|
||||
Row(
|
||||
Column('download_instructions', css_class='form-group col-md-12 mb-0'),
|
||||
css_class='form-row'
|
||||
),
|
||||
HTML("<hr>"),
|
||||
Row(
|
||||
Column(HTML("<h5>Email Message Template</h5>"), css_class='form-group col-md-12 mb-0'),
|
||||
Column(HTML("<h5>" + _("Email Message Template") + "</h5>"), css_class='form-group col-md-12 mb-0'),
|
||||
Column('invite_email_subject', css_class='form-group col-md-12 mb-0'),
|
||||
Column('invite_email_body', css_class='form-group col-md-12 mb-0'),
|
||||
css_class='form-row'
|
||||
@ -175,19 +173,26 @@ class InviteSettingsForm(forms.ModelForm):
|
||||
),
|
||||
HTML("<hr>"),
|
||||
Row(
|
||||
Column(HTML("<h5>WhatsApp Message Template</h5>"), css_class='form-group col-md-12 mb-0'),
|
||||
Column(HTML("<h5>" + _("WhatsApp Message Template") + "</h5>"), css_class='form-group col-md-12 mb-0'),
|
||||
Column('invite_whatsapp_body', css_class='form-group col-md-12 mb-0'),
|
||||
Column('invite_whatsapp_enabled', css_class='form-group col-md-12 mb-0'),
|
||||
css_class='form-row'
|
||||
),
|
||||
HTML("<hr>"),
|
||||
Row(
|
||||
Column(HTML("<h5>Text Message Template</h5>"), css_class='form-group col-md-12 mb-0'),
|
||||
Column(HTML("<h5>" + _("Text Message Template") + "</h5>"), css_class='form-group col-md-12 mb-0'),
|
||||
Column('invite_text_body', css_class='form-group col-md-12 mb-0'),
|
||||
css_class='form-row'
|
||||
),
|
||||
css_class='col-xl-6'),
|
||||
css_class='col-xl-12'),
|
||||
css_class='row'),
|
||||
Row(
|
||||
Column(
|
||||
Submit('submit', _('Save'), css_class='btn btn-success'),
|
||||
HTML(' <a class="btn btn-secondary" href="/vpn_invite/">' + _('Back') + '</a> '),
|
||||
css_class='col-md-12'
|
||||
),
|
||||
css_class='form-row'),
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
@ -197,15 +202,15 @@ class InviteSettingsForm(forms.ModelForm):
|
||||
invite_url = cleaned_data.get('invite_url')
|
||||
if invite_url:
|
||||
if not invite_url.startswith("https://"):
|
||||
self.add_error('invite_url', "Invite URL must start with 'https://'.")
|
||||
self.add_error('invite_url', _("Invite URL must start with 'https://'."))
|
||||
if not invite_url.endswith("/invite/"):
|
||||
self.add_error('invite_url', "Invite URL must end with '/invite/'.")
|
||||
self.add_error('invite_url', _("Invite URL must end with '/invite/'."))
|
||||
|
||||
# Validate invite_expiration: must be between 1 and 1440 minutes
|
||||
invite_expiration = cleaned_data.get('invite_expiration')
|
||||
if invite_expiration is not None:
|
||||
if invite_expiration < 1 or invite_expiration > 1440:
|
||||
self.add_error('invite_expiration', "Expiration (minutes) must be between 1 and 1440.")
|
||||
self.add_error('invite_expiration', _("Expiration (minutes) must be between 1 and 1440."))
|
||||
|
||||
# Validate default_password based on enforce_random_password flag
|
||||
default_password = cleaned_data.get('default_password', '')
|
||||
@ -214,16 +219,16 @@ class InviteSettingsForm(forms.ModelForm):
|
||||
if enforce_random_password is True:
|
||||
if default_password:
|
||||
self.add_error('default_password',
|
||||
"Default password must not be provided when random password is enabled.")
|
||||
_("Default password must not be provided when random password is enabled."))
|
||||
if random_password_length < 6:
|
||||
self.add_error('random_password_length', "Random password length must be at least 6 characters.")
|
||||
self.add_error('random_password_length', _("Random password length must be at least 6 characters."))
|
||||
else:
|
||||
# When random password is disabled, default password must be provided and have at least 6 characters.
|
||||
if not default_password:
|
||||
self.add_error('default_password',
|
||||
"Default password must be provided when random password is disabled.")
|
||||
_("Default password must be provided when random password is disabled."))
|
||||
elif len(default_password) < 6:
|
||||
self.add_error('default_password', "Default password must be at least 6 characters long.")
|
||||
self.add_error('default_password', _("Default password must be at least 6 characters long."))
|
||||
|
||||
# Validate download buttons: if enabled, the respective text and url fields must not be blank.
|
||||
for i in range(1, 6):
|
||||
@ -233,9 +238,9 @@ class InviteSettingsForm(forms.ModelForm):
|
||||
if enabled:
|
||||
if not label:
|
||||
self.add_error(f'download_{i}_label',
|
||||
"Text field must not be empty when download button is enabled.")
|
||||
_("Text field must not be empty when download button is enabled."))
|
||||
if not url:
|
||||
self.add_error(f'download_{i}_url', "URL field must not be empty when download button is enabled.")
|
||||
self.add_error(f'download_{i}_url', _("URL field must not be empty when download button is enabled."))
|
||||
|
||||
# Validate that default_password is not contained in any message templates or the subject
|
||||
message_fields = ['invite_text_body', 'invite_email_subject', 'invite_email_body', 'invite_whatsapp_body']
|
||||
@ -244,14 +249,14 @@ class InviteSettingsForm(forms.ModelForm):
|
||||
content = cleaned_data.get(field, '')
|
||||
if default_password in content:
|
||||
self.add_error('default_password',
|
||||
f"Default password must not be contained in {field.replace('_', ' ')}.")
|
||||
_("Default password must not be contained in any message template. Found at: ") + f"{field.replace('_', ' ')}.")
|
||||
|
||||
# Validate that all message templates include the placeholder '{invite_url}'
|
||||
for field in message_fields:
|
||||
if field != 'invite_email_subject':
|
||||
content = cleaned_data.get(field, '')
|
||||
if '{invite_url}' not in content:
|
||||
self.add_error(field, "The template must include the placeholder '{invite_url}'.")
|
||||
self.add_error(field, _("The template must include the placeholder '{invite_url}'."))
|
||||
|
||||
return cleaned_data
|
||||
|
||||
@ -273,12 +278,12 @@ class EmailSettingsForm(forms.ModelForm):
|
||||
super(EmailSettingsForm, self).__init__(*args, **kwargs)
|
||||
|
||||
# Set custom labels for form fields
|
||||
self.fields['smtp_username'].label = 'Username'
|
||||
self.fields['smtp_password'].label = 'Password'
|
||||
self.fields['smtp_host'].label = 'Host'
|
||||
self.fields['smtp_port'].label = 'Port'
|
||||
self.fields['smtp_encryption'].label = 'Encryption'
|
||||
self.fields['smtp_from_address'].label = 'From Address'
|
||||
self.fields['smtp_username'].label = _('Username')
|
||||
self.fields['smtp_password'].label = _('Password')
|
||||
self.fields['smtp_host'].label = _('Host')
|
||||
self.fields['smtp_port'].label = _('Port')
|
||||
self.fields['smtp_encryption'].label = _('Encryption')
|
||||
self.fields['smtp_from_address'].label = _('From Address')
|
||||
|
||||
self.fields['smtp_password'].required = True
|
||||
self.fields['smtp_host'].required = True
|
||||
@ -286,6 +291,7 @@ class EmailSettingsForm(forms.ModelForm):
|
||||
self.fields['smtp_encryption'].required = True
|
||||
self.fields['smtp_from_address'].required = True
|
||||
self.fields['smtp_username'].required = True
|
||||
self.fields['enabled'].label = _('Enabled')
|
||||
|
||||
# Use PasswordInput widget to hide the password
|
||||
self.fields['smtp_password'].widget = forms.PasswordInput(render_value=False)
|
||||
@ -316,8 +322,8 @@ class EmailSettingsForm(forms.ModelForm):
|
||||
),
|
||||
Row(
|
||||
Column(
|
||||
Submit('submit', 'Save', css_class='btn btn-success'),
|
||||
HTML(' <a class="btn btn-secondary" href="/vpn_invite/">Back</a> '),
|
||||
Submit('submit', _('Save'), css_class='btn btn-success'),
|
||||
HTML(' <a class="btn btn-secondary" href="/vpn_invite/">' + _('Back') + '</a> '),
|
||||
css_class='col-md-12'
|
||||
),
|
||||
css_class='form-row'
|
||||
@ -328,7 +334,7 @@ class EmailSettingsForm(forms.ModelForm):
|
||||
cleaned_data = super().clean()
|
||||
smtp_port = cleaned_data.get('smtp_port')
|
||||
if smtp_port is not None and smtp_port <= 0:
|
||||
self.add_error('smtp_port', "SMTP port must be a positive integer.")
|
||||
self.add_error('smtp_port', _("SMTP port must be between 1 and 65535."))
|
||||
|
||||
return cleaned_data
|
||||
|
||||
|
@ -1,37 +1,34 @@
|
||||
import uuid
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from wireguard.models import Peer
|
||||
|
||||
DEFAULT_INVITE_MESSAGE = '''
|
||||
Hello,
|
||||
DEFAULT_INVITE_MESSAGE = _('''Hello,
|
||||
|
||||
You're invited to join our secure WireGuard VPN network. Please click the link below to access your personalized VPN configuration:
|
||||
|
||||
{invite_url}
|
||||
|
||||
Note: This invitation link will expire in {expire_minutes} minutes. If you need a new link after expiration, please request another invite.
|
||||
'''
|
||||
Note: This invitation link will expire in {expire_minutes} minutes. If you need a new link after expiration, please request another invite.''')
|
||||
|
||||
DEFAULT_HTML_MESSAGE = '''
|
||||
<h2>Welcome to Your VPN Setup</h2>
|
||||
DEFAULT_HTML_MESSAGE = _('''<h2>Welcome to Your VPN Setup</h2>
|
||||
<p>Begin by downloading the WireGuard app for your device using one of the links below.</p>
|
||||
<p>Once installed, you can either <strong>scan the QR code</strong> or <strong>download the configuration file</strong> to quickly import your settings and start using your secure VPN connection.</p>
|
||||
'''
|
||||
<p>Once installed, you can either <strong>scan the QR code</strong> or <strong>download the configuration file</strong> to quickly import your settings and start using your secure VPN connection.</p>''')
|
||||
|
||||
class InviteSettings(models.Model):
|
||||
name = models.CharField(max_length=16, default='default_settings', unique=True)
|
||||
default_password = models.CharField(max_length=32, default='', blank=True, null=True)
|
||||
enforce_random_password = models.BooleanField(default=True)
|
||||
required_user_level = models.PositiveIntegerField(default=50, choices=(
|
||||
(20, 'View Only User'), (30, 'Peer Manager'), (40, 'Wireguard Manager'), (50, 'Administrator'),
|
||||
(20, _('View Only')), (30, _('Peer Manager')), (40, _('WireGuard Manager')), (50, _('Administrator')),
|
||||
))
|
||||
random_password_length = models.IntegerField(default=6)
|
||||
random_password_complexity = models.CharField(
|
||||
max_length=22, default='letters_digits', choices=(
|
||||
('letters_digits_special', 'Letters, Digits, Special Characters'),
|
||||
('letters_digits', 'Letters, Digits'), ('letters', 'Letters'), ('digits', 'Digits')
|
||||
('letters_digits_special', _('Letters, Digits, Special Characters')),
|
||||
('letters_digits', _('Letters, Digits')), ('letters', _('Letters')), ('digits', _('Digits'))
|
||||
)
|
||||
)
|
||||
invite_expiration = models.IntegerField(default=30) # minutes
|
||||
@ -55,13 +52,13 @@ class InviteSettings(models.Model):
|
||||
download_3_enabled = models.BooleanField(default=True)
|
||||
download_4_enabled = models.BooleanField(default=True)
|
||||
download_5_enabled = models.BooleanField(default=True)
|
||||
download_instructions = models.TextField(default='Download the WireGuard app for your device using one of the links below. After installation, you can scan the QR code or download the configuration file to import on your device.')
|
||||
download_instructions = models.TextField(default=_('Download the WireGuard app for your device using one of the links below. After installation, you can scan the QR code or download the configuration file to import on your device.'))
|
||||
|
||||
invite_url = models.URLField(default='')
|
||||
|
||||
invite_text_body = models.TextField(default=DEFAULT_INVITE_MESSAGE)
|
||||
|
||||
invite_email_subject = models.CharField(max_length=64, default='WireGuard VPN Invite', blank=True, null=True)
|
||||
invite_email_subject = models.CharField(max_length=64, default=_('WireGuard VPN Invite'), blank=True, null=True)
|
||||
invite_email_body = models.TextField(default=DEFAULT_INVITE_MESSAGE)
|
||||
invite_email_enabled = models.BooleanField(default=True)
|
||||
|
||||
|
@ -1,12 +1,14 @@
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import render, redirect
|
||||
from user_manager.models import UserAcl
|
||||
from .models import InviteSettings, PeerInvite
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
from .forms import InviteSettingsForm, EmailSettingsForm
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import redirect, render
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from user_manager.models import UserAcl
|
||||
from wireguard_tools.models import EmailSettings
|
||||
from .forms import EmailSettingsForm, InviteSettingsForm
|
||||
from .models import InviteSettings, PeerInvite
|
||||
|
||||
|
||||
@login_required
|
||||
@ -22,7 +24,7 @@ def view_vpn_invite_list(request):
|
||||
except:
|
||||
default_invite_url = 'https://wireguard-webadmin.example.com/invite/'
|
||||
|
||||
invite_settings, _ = InviteSettings.objects.get_or_create(
|
||||
invite_settings, invite_settings_created = InviteSettings.objects.get_or_create(
|
||||
name='default_settings', defaults={'invite_url': default_invite_url,}
|
||||
)
|
||||
|
||||
@ -32,7 +34,7 @@ def view_vpn_invite_list(request):
|
||||
peer_invite_list = PeerInvite.objects.all().order_by('invite_expiration')
|
||||
peer_invite_list.filter(invite_expiration__lt=timezone.now()).delete()
|
||||
data = {
|
||||
'page_title': 'VPN Invite',
|
||||
'page_title': _('VPN Invite'),
|
||||
'peer_invite_list': peer_invite_list,
|
||||
}
|
||||
|
||||
@ -48,11 +50,11 @@ def view_vpn_invite_settings(request):
|
||||
form = InviteSettingsForm(request.POST or None, instance=invite_settings)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(request, 'Invite Settings|Settings saved successfully.')
|
||||
messages.success(request, _('Invite Settings|Settings saved successfully.'))
|
||||
return redirect('/vpn_invite/')
|
||||
data = {
|
||||
'invite_settings': invite_settings,
|
||||
'page_title': 'VPN Invite Settings',
|
||||
'page_title': _('VPN Invite Settings'),
|
||||
'form': form,
|
||||
'form_size': 'col-lg-12'
|
||||
}
|
||||
@ -63,16 +65,16 @@ def view_vpn_invite_settings(request):
|
||||
def view_email_settings(request):
|
||||
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists():
|
||||
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
|
||||
email_settings, _ = EmailSettings.objects.get_or_create(name='email_settings')
|
||||
email_settings, email_settings_created = EmailSettings.objects.get_or_create(name='email_settings')
|
||||
|
||||
form = EmailSettingsForm(request.POST or None, instance=email_settings)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(request, 'Email Settings|Settings saved successfully.')
|
||||
messages.success(request, _('Email Settings|Settings saved successfully.'))
|
||||
return redirect('/vpn_invite/')
|
||||
data = {
|
||||
'email_settings': email_settings,
|
||||
'page_title': 'Email Settings',
|
||||
'page_title': _('Email Settings'),
|
||||
'form': form,
|
||||
'form_size': 'col-lg-12'
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ Including another URLconf
|
||||
1. Import the include() function: from django.urls import include, path
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path
|
||||
|
||||
from accounts.views import view_create_first_user, view_login, view_logout
|
||||
@ -37,7 +38,7 @@ from wireguard_peer.views import view_manage_ip_address, view_wireguard_peer_lis
|
||||
from wireguard_tools.views import download_config_or_qrcode, export_wireguard_configs, restart_wireguard_interfaces
|
||||
|
||||
urlpatterns = [
|
||||
# path('admin/', admin.site.urls),
|
||||
path('admin/', admin.site.urls),
|
||||
path('', view_apply_db_patches, name='apply_db_patches'),
|
||||
path('status/', view_wireguard_status, name='wireguard_status'),
|
||||
path('dns/', view_static_host_list, name='static_host_list'),
|
||||
|
Loading…
x
Reference in New Issue
Block a user