diff --git a/misdghs/__pycache__/settings.cpython-311.pyc b/misdghs/__pycache__/settings.cpython-311.pyc index 27bd9e5..bd32c1b 100644 Binary files a/misdghs/__pycache__/settings.cpython-311.pyc and b/misdghs/__pycache__/settings.cpython-311.pyc differ diff --git a/misdghs/__pycache__/urls.cpython-311.pyc b/misdghs/__pycache__/urls.cpython-311.pyc index 2fa248f..b504b8a 100644 Binary files a/misdghs/__pycache__/urls.cpython-311.pyc and b/misdghs/__pycache__/urls.cpython-311.pyc differ diff --git a/misdghs/settings.py b/misdghs/settings.py index a35aa1e..2144ead 100644 --- a/misdghs/settings.py +++ b/misdghs/settings.py @@ -12,6 +12,7 @@ https://docs.djangoproject.com/en/5.1/ref/settings/ from pathlib import Path import os +from django.urls import reverse_lazy # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -141,3 +142,20 @@ MEDIA_ROOT = BASE_DIR / 'media' # https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + + +AUTH_URLS = { + 'login': reverse_lazy('login'), + 'logout': reverse_lazy('logout'), + 'password_reset': reverse_lazy('password_reset'), + # ... other auth URLs +} + +#email Setup + +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +EMAIL_HOST = 'smtp.gmail.com' # Or your SMTP host +EMAIL_PORT = 587 +EMAIL_USE_TLS = True +EMAIL_HOST_USER = 'dpmehealth@gmail.com' +EMAIL_HOST_PASSWORD = 'qxyt faeu uioy jbjs' \ No newline at end of file diff --git a/misdghs/urls.py b/misdghs/urls.py index d9d916a..cadcbe8 100644 --- a/misdghs/urls.py +++ b/misdghs/urls.py @@ -17,7 +17,9 @@ Including another URLconf from django.contrib import admin from django.urls import path, include import resulation +from django.contrib.auth.views import LoginView, LogoutView urlpatterns = [ path('admin/', admin.site.urls), path('rcm/', include('resulation.urls')), + path('rcm/', include('django.contrib.auth.urls')), ] diff --git a/resulation/__pycache__/forms.cpython-311.pyc b/resulation/__pycache__/forms.cpython-311.pyc new file mode 100644 index 0000000..d1e5f31 Binary files /dev/null and b/resulation/__pycache__/forms.cpython-311.pyc differ diff --git a/resulation/__pycache__/models.cpython-311.pyc b/resulation/__pycache__/models.cpython-311.pyc index 6a0f5f1..1354397 100644 Binary files a/resulation/__pycache__/models.cpython-311.pyc and b/resulation/__pycache__/models.cpython-311.pyc differ diff --git a/resulation/__pycache__/urls.cpython-311.pyc b/resulation/__pycache__/urls.cpython-311.pyc index 303e692..50bf90b 100644 Binary files a/resulation/__pycache__/urls.cpython-311.pyc and b/resulation/__pycache__/urls.cpython-311.pyc differ diff --git a/resulation/__pycache__/views.cpython-311.pyc b/resulation/__pycache__/views.cpython-311.pyc index d1f3530..27b38af 100644 Binary files a/resulation/__pycache__/views.cpython-311.pyc and b/resulation/__pycache__/views.cpython-311.pyc differ diff --git a/resulation/forms.py b/resulation/forms.py new file mode 100644 index 0000000..9218616 --- /dev/null +++ b/resulation/forms.py @@ -0,0 +1,8 @@ +from django import forms +from django.contrib.auth.forms import UserCreationForm +from django.contrib.auth.models import User + +class SignupForm(UserCreationForm): + class Meta: + model = User + fields = ['username', 'email'] \ No newline at end of file diff --git a/resulation/migrations/0010_verification.py b/resulation/migrations/0010_verification.py new file mode 100644 index 0000000..16b7a61 --- /dev/null +++ b/resulation/migrations/0010_verification.py @@ -0,0 +1,39 @@ +# Generated by Django 5.1.5 on 2025-02-20 03:07 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("resulation", "0009_alter_resulation_attendance_file_and_more"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="Verification", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("key", models.CharField(max_length=50)), + ("verified", models.BooleanField(default=False)), + ( + "user", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + ] diff --git a/resulation/migrations/__pycache__/0010_verification.cpython-311.pyc b/resulation/migrations/__pycache__/0010_verification.cpython-311.pyc new file mode 100644 index 0000000..a917926 Binary files /dev/null and b/resulation/migrations/__pycache__/0010_verification.cpython-311.pyc differ diff --git a/resulation/models.py b/resulation/models.py index 1811880..fa507f2 100644 --- a/resulation/models.py +++ b/resulation/models.py @@ -27,4 +27,13 @@ class resulation(models.Model): verbose_name_plural = "PDF Documents" - \ No newline at end of file +from django.db import models +from django.contrib.auth.models import User + +class Verification(models.Model): + user = models.OneToOneField(User, on_delete=models.CASCADE) + key = models.CharField(max_length=50) + verified = models.BooleanField(default=False) + + def __str__(self): + return f"{self.user.username}'s verification" \ No newline at end of file diff --git a/resulation/urls.py b/resulation/urls.py index fca90b2..920c8c0 100644 --- a/resulation/urls.py +++ b/resulation/urls.py @@ -6,6 +6,9 @@ from django.conf.urls.static import static from django.urls import path, re_path from . import views from django.views.static import serve +from .views import SignupView +from django.contrib.auth.views import LoginView, LogoutView + urlpatterns = [ path('', resulation.views.Home, name='home'), @@ -17,6 +20,10 @@ urlpatterns = [ path('viewmou/', resulation.views.Viewmou, name='viewmou'), path('/', resulation.views.file_download, name='file-download'), path('rcm/', resulation.views.file_download, name='download_file'), + path('signup/', SignupView.as_view(), name='signup'), + path('verify//', resulation.views.Verify, name='verify'), + path('login/', resulation.views.signin, name='login'), + path('logout/', resulation.views.signout, name='logout'), ] if settings.DEBUG: diff --git a/resulation/views.py b/resulation/views.py index 968daec..289ffb9 100644 --- a/resulation/views.py +++ b/resulation/views.py @@ -7,11 +7,151 @@ from django.http import FileResponse, StreamingHttpResponse from urllib.parse import unquote from misdghs import settings from django.core.files.storage import default_storage +from django.shortcuts import render, redirect +from django.urls import reverse_lazy, reverse +from django.contrib.auth.views import LoginView +from django.contrib.auth.models import User +from django.contrib.messages.views import SuccessMessageMixin +from django.views.generic.edit import CreateView +from .models import Verification +from .forms import SignupForm +from django.contrib.auth import authenticate, login, logout +from django.contrib.auth.decorators import login_required +from django.contrib import messages + + +class SignupView(SuccessMessageMixin, CreateView): + form_class = SignupForm + template_name = 'registration/signup.html' + success_url = reverse_lazy('login') + success_message = "Registration successful! Please verify your email." + + def form_valid(self, form): + print("=== Checking form validity in SignupView ===") + + # Check if the username already exists + existing_username = User.objects.filter(username=form.cleaned_data['username']) + if existing_username.exists(): + print(f"Username '{form.cleaned_data['username']}' already exists.") + form.add_error('username', 'Username already taken.') + return super().form_invalid(form) + + # Check if the email already exists + existing_email = User.objects.filter(email=form.cleaned_data['email']) + if existing_email.exists(): + print(f"Email '{form.cleaned_data['email']}' already registered.") + form.add_error('email', 'Email already registered.') + return super().form_invalid(form) + + # Form is valid, proceed to create user + print("Form validation passed. Proceeding to create user...") + response = super().form_valid(form) + print(f"User created successfully. User object: {self.object}") + + # Verify that self.object exists and has the correct fields + if self.object: + print(f"New user details - Username: {self.object.username}, Email: {self.object.email}") + print("Proceeding to send verification email.") + self.send_verification_email() + else: + print("Error: User object is not created after form submission.") + + return response + + def send_verification_email(self): + print("\n=== Entering send_verification_email method ===") + try: + # Create a new Verification instance + verification = Verification.objects.create(user=self.object) + print(f"Verification object created with key: {verification.key}") + + # Generate the verification key (you can improve this by using a more secure method) + import uuid + key = str(uuid.uuid4()) + print(f"Generated verification key: {key}") + + # Prepare email content + subject = 'Verify your email' + body = ( + f'Please verify your account by clicking this link: ' + f'{self.request.build_absolute_uri(reverse("verify", kwargs={"key": key}))}' + ) + html_body = ( + f'' + 'Verify Email' + ) + + # Send email using Django's send_mail function + print(f"Attempting to send verification email to: {self.object.email}") + from django.core.mail import send_mail + send_mail( + subject, + body, + 'dpmehealth@gmail.com', + [self.object.email], + fail_silently=False + ) + print("Verification email sent successfully.") + + except Exception as e: + print(f"Error sending verification email: {str(e)}") + raise # Re-raise the exception to see it in logs or handle appropriately + + def generate_key(self): + import uuid + return str(uuid.uuid4()) + +def Verify(request, key): + try: + print(f"\n=== Verification view called with key: {key} ===") + verification = Verification.objects.get(key=key) + if not verification.verified: + print(f"Verification found and unverified. Proceeding to verify.") + verification.verified = True + verification.save() + user = verification.user + print(f"User associated with this verification: {user.username}") + user.is_active = True + user.save() + messages.success(request, 'Email verified successfully!') + return redirect('login') + else: + print("Verification link already used.") + messages.error(request, 'Already verified.') + except Verification.DoesNotExist: + print(f"Invalid verification key: {key}") + messages.error(request, 'Invalid verification link.') + return redirect('home') + + +def signin(request): + if request.method == "POST": + username = request.POST.get("username") + password = request.POST.get("password") + user = authenticate(request, username=username, password=password) + if user is not None: + login(request, user) + messages.success(request, "You have successfully logged in!") + return redirect("home") + messages.error(request, "Invalid username or password.") + else: + return render(request, "registration/signin.html") + +@login_required +def signout(request): + logout(request) + messages.info(request, "You have successfully logged out.") + return redirect("home") + + + # Create your views here. def Home(request): return render(request,'resulation/home.html') + +@login_required def Savepdf(request): if request.method == 'POST': try: @@ -71,12 +211,13 @@ def Savepdf(request): # Render the form template return render(request, 'resulation/resulation.html') +@login_required def Viewresulation(request): # Get all records from database pdf_records = resulation.objects.filter(pdftype='Meeting Minutes').order_by('-m_date') # Latest first return render(request, 'resulation/viewresulation.html', {'pdf_records': pdf_records}) - +@login_required def file_download(request, type, filename): # Construct the full path to the file if type== 'attendance': @@ -89,8 +230,7 @@ def file_download(request, type, filename): return FileResponse(open(file_path, 'rb'), content_type='application/pdf') - - +@login_required def Mou(request): if request.method == 'POST': try: @@ -131,6 +271,8 @@ def Mou(request): # Render the form template return render(request, 'resulation/mou.html') + +@login_required def Viewmou(request): # Get all records from database pdf_records = resulation.objects.filter(pdftype='MoU').order_by('-m_date') # Latest first @@ -138,7 +280,7 @@ def Viewmou(request): return render(request, 'resulation/viewmou.html', {'pdf_records': pdf_records}) - +@login_required def Contract(request): if request.method == 'POST': try: @@ -185,6 +327,8 @@ def Contract(request): # Render the form template return render(request, 'resulation/contract.html') + +@login_required def Viewcontract(request): # Get all records from database pdf_records = resulation.objects.filter(pdftype='Contract').order_by('-m_date') # Latest first diff --git a/templates/base.html b/templates/base.html index dfc48f4..de3a98a 100644 --- a/templates/base.html +++ b/templates/base.html @@ -19,9 +19,13 @@ diff --git a/templates/registration/signin.html b/templates/registration/signin.html new file mode 100644 index 0000000..383c69b --- /dev/null +++ b/templates/registration/signin.html @@ -0,0 +1,29 @@ +{% extends "base.html" %} + +{% block content %} +
+

Login

+ {% if messages %} +
    + {% for message in messages %} + {{ message }} + {% endfor %} +
+ {% endif %} + +
+ +
+ + +
+
+ + +
+ {% csrf_token %} + +
+

Don't have an account? Register here

+
+{% endblock %} \ No newline at end of file diff --git a/templates/registration/signup.html b/templates/registration/signup.html new file mode 100644 index 0000000..131d809 --- /dev/null +++ b/templates/registration/signup.html @@ -0,0 +1,220 @@ +{% extends "base.html" %} +{% block content %} + + {% if messages %} +
+ {% for message in messages %} + {{ message }}
+ {% endfor %} + +{% endif %} +
+

Sign Up

+
+ + + + + + + + + + + + + + + + + + {% csrf_token %} + + + + + + + +
Userneme:
Email:
Password:
Confirm Password:
Already have an account? Login here
+
+
+{% endblock content %} \ No newline at end of file diff --git a/templates/registration/verification_email.html b/templates/registration/verification_email.html new file mode 100644 index 0000000..b3e9814 --- /dev/null +++ b/templates/registration/verification_email.html @@ -0,0 +1,14 @@ + + + + + Email Verification + + +

Please verify your email

+

Click this link to verify your account:

+ Verify Now +
+

If you didn't request this, you can safely ignore this email.

+ + \ No newline at end of file diff --git a/templates/resulation/home.html b/templates/resulation/home.html index 26c2f9d..9aeae8b 100644 --- a/templates/resulation/home.html +++ b/templates/resulation/home.html @@ -1,7 +1,8 @@ {% extends "base.html" %} {% block content %} {% if message %} -
+
{{ message }}
{% endif %} @@ -86,6 +87,7 @@ list li::before { } +

Archiving and Timely Upload of Meeting Minutes, Deeds, and MoUs


To ensure seamless access and efficient management of critical documents within the Directorate General of Health Services (DGHS), it is essential to archive and upload Meeting Minutes, Deeds, and Memorandums of Understanding (MOUs) in a timely manner.