From 95a06953923abe097acfca00b62e02d863901819 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 27 Feb 2025 23:26:44 -0300 Subject: [PATCH] SMTP Configuration view and form --- vpn_invite/forms.py | 79 +++++++++++++++++++ vpn_invite/views.py | 23 +++++- wireguard_tools/admin.py | 3 +- .../migrations/0002_emailsettings_enabled.py | 18 +++++ wireguard_tools/models.py | 1 + wireguard_webadmin/urls.py | 3 +- 6 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 wireguard_tools/migrations/0002_emailsettings_enabled.py diff --git a/vpn_invite/forms.py b/vpn_invite/forms.py index 378e877..4cb6226 100644 --- a/vpn_invite/forms.py +++ b/vpn_invite/forms.py @@ -4,6 +4,7 @@ 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 wireguard_tools.models import EmailSettings class InviteSettingsForm(forms.ModelForm): @@ -253,3 +254,81 @@ class InviteSettingsForm(forms.ModelForm): self.add_error(field, "The template must include the placeholder '{invite_url}'.") return cleaned_data + + +class EmailSettingsForm(forms.ModelForm): + class Meta: + model = EmailSettings + fields = [ + 'smtp_username', + 'smtp_password', + 'smtp_host', + 'smtp_port', + 'smtp_encryption', + 'smtp_from_address', + 'enabled', + ] + + def __init__(self, *args, **kwargs): + 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_password'].required = True + self.fields['smtp_host'].required = True + self.fields['smtp_port'].required = True + self.fields['smtp_encryption'].required = True + self.fields['smtp_from_address'].required = True + self.fields['smtp_username'].required = True + + # Use PasswordInput widget to hide the password + self.fields['smtp_password'].widget = forms.PasswordInput(render_value=False) + + # Ensure that during edit the saved password is not displayed + if self.instance and self.instance.pk: + self.fields['smtp_password'].initial = '' + + self.helper = FormHelper() + self.helper.form_method = 'post' + self.helper.layout = Layout( + HTML("

SMTP Settings

"), + Row( + Column('smtp_username', css_class='form-group col-md-4 mb-0'), + Column('smtp_password', css_class='form-group col-md-4 mb-0'), + Column('smtp_from_address', css_class='form-group col-md-4 mb-0'), + css_class='form-row' + ), + Row( + Column('smtp_host', css_class='form-group col-md-4 mb-0'), + Column('smtp_port', css_class='form-group col-md-4 mb-0'), + Column('smtp_encryption', css_class='form-group col-md-4 mb-0'), + css_class='form-row' + ), + Row( + Column('enabled', css_class='form-group col-md-4 mb-0'), + css_class='form-row' + ), + Row( + Column( + Submit('submit', 'Save', css_class='btn btn-success'), + HTML(' Back '), + css_class='col-md-12' + ), + css_class='form-row' + ) + ) + + def clean(self): + 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.") + + return cleaned_data + diff --git a/vpn_invite/views.py b/vpn_invite/views.py index f03d801..b4fc329 100644 --- a/vpn_invite/views.py +++ b/vpn_invite/views.py @@ -4,8 +4,9 @@ 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 +from .forms import InviteSettingsForm, EmailSettingsForm from django.contrib import messages +from wireguard_tools.models import EmailSettings @login_required @@ -56,3 +57,23 @@ def view_vpn_invite_settings(request): 'form_size': 'col-lg-12' } return render(request, 'generic_form.html', context=data) + + +@login_required +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') + + form = EmailSettingsForm(request.POST or None, instance=email_settings) + if form.is_valid(): + form.save() + messages.success(request, 'Email Settings|Settings saved successfully.') + return redirect('/vpn_invite/') + data = { + 'email_settings': email_settings, + 'page_title': 'Email Settings', + 'form': form, + 'form_size': 'col-lg-12' + } + return render(request, 'generic_form.html', context=data) diff --git a/wireguard_tools/admin.py b/wireguard_tools/admin.py index 8c38f3f..b341834 100644 --- a/wireguard_tools/admin.py +++ b/wireguard_tools/admin.py @@ -1,3 +1,4 @@ from django.contrib import admin - +from .models import EmailSettings # Register your models here. +admin.site.register(EmailSettings) \ No newline at end of file diff --git a/wireguard_tools/migrations/0002_emailsettings_enabled.py b/wireguard_tools/migrations/0002_emailsettings_enabled.py new file mode 100644 index 0000000..4d554bd --- /dev/null +++ b/wireguard_tools/migrations/0002_emailsettings_enabled.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.5 on 2025-02-28 02:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wireguard_tools', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='emailsettings', + name='enabled', + field=models.BooleanField(default=True), + ), + ] diff --git a/wireguard_tools/models.py b/wireguard_tools/models.py index 3239918..c63cf4a 100644 --- a/wireguard_tools/models.py +++ b/wireguard_tools/models.py @@ -10,6 +10,7 @@ class EmailSettings(models.Model): smtp_port = models.IntegerField(default=587) smtp_encryption = models.CharField(default='tls', choices=(('ssl', 'SSL'), ('tls', 'TLS')), max_length=3) smtp_from_address = models.EmailField(blank=True, null=True) + enabled = models.BooleanField(default=True) uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) created = models.DateTimeField(auto_now_add=True) diff --git a/wireguard_webadmin/urls.py b/wireguard_webadmin/urls.py index bfe9782..806bc58 100644 --- a/wireguard_webadmin/urls.py +++ b/wireguard_webadmin/urls.py @@ -27,7 +27,7 @@ from api.views import wireguard_status, cron_check_updates, cron_update_peer_lat from firewall.views import view_redirect_rule_list, manage_redirect_rule, view_firewall_rule_list, manage_firewall_rule, view_manage_firewall_settings, view_generate_iptables_script, view_reset_firewall, view_firewall_migration_required from dns.views import view_static_host_list, view_manage_static_host, view_manage_dns_settings, view_apply_dns_config from wgrrd.views import view_rrd_graph -from vpn_invite.views import view_vpn_invite_list, view_vpn_invite_settings +from vpn_invite.views import view_vpn_invite_list, view_vpn_invite_settings, view_email_settings urlpatterns = [ path('admin/', admin.site.urls), @@ -70,4 +70,5 @@ urlpatterns = [ path('firewall/migration_required/', view_firewall_migration_required, name='firewall_migration_required'), path('vpn_invite/', view_vpn_invite_list, name='vpn_invite_list'), path('vpn_invite/settings/', view_vpn_invite_settings, name='vpn_invite_settings'), + path('vpn_invite/smtp_settings/', view_email_settings, name='email_settings'), ]