diff --git a/home/management/commands/delete_expired_accounts.py b/home/management/commands/delete_expired_accounts.py new file mode 100644 index 00000000..859df59d --- /dev/null +++ b/home/management/commands/delete_expired_accounts.py @@ -0,0 +1,31 @@ +from django.core.management.base import BaseCommand +from django.utils import timezone +from django.contrib.auth.models import User +from home.models import UserDeletionRequest + +class Command(BaseCommand): + help = "Deletes user accounts that have been scheduled for deletion after 30 days" + + def handle(self, *args, **kwargs): + now = timezone.now() + expired_requests = UserDeletionRequest.objects.filter( + scheduled_for__lte=now, + is_executed=False + ) + if not expired_requests.exists(): + self.stdout.write("No expired deletion requests to process.") + return + + for deletion_request in expired_requests: + user = deletion_request.user + self.stdout.write( + f"Deleting user {user.username} (scheduled for {deletion_request.scheduled_for})" + ) + + user.delete() #user is deleted + + deletion_request.is_executed = True + deletion_request.executed_at = now + deletion_request.save() + + self.stdout.write(self.style.SUCCESS("Expired accounts deletion task complete.")) \ No newline at end of file diff --git a/home/migrations/0001_initial.py b/home/migrations/0001_initial.py index 1a3c7e61..73419598 100644 --- a/home/migrations/0001_initial.py +++ b/home/migrations/0001_initial.py @@ -609,4 +609,25 @@ class Migration(migrations.Migration): 'ordering': ['-published_at'], }, ), + + migrations.CreateModel( + name='UserDeletionRequest', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('requested_at', models.DateTimeField(default=django.utils.timezone.now)), + ('scheduled_for', models.DateTimeField()), + ('is_executed', models.BooleanField(default=False)), + ('executed_at', models.DateTimeField(blank=True, null=True)), + ('user', models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name='deletion_request', + to=settings.AUTH_USER_MODEL + )), + ], + ), + + + + + ] diff --git a/home/templates/accounts/confirm_delete.html b/home/templates/accounts/confirm_delete.html index 45b45ad8..3bf3e0b3 100644 --- a/home/templates/accounts/confirm_delete.html +++ b/home/templates/accounts/confirm_delete.html @@ -1,8 +1,73 @@ -

Are you sure you want to delete your account?

-

This action cannot be undone.

- -
- {% csrf_token %} - - Cancel -
+{% load static %} + +{% block content %} +
+
+

Confirm Account Action

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

Select an action:

+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ Cancel + +
+
+
+
+ + +{% endblock %} \ No newline at end of file diff --git a/home/views.py b/home/views.py index 111e0dfb..7266f4b0 100644 --- a/home/views.py +++ b/home/views.py @@ -50,10 +50,11 @@ from .models import Article, Student, Project, Contact, Smishingdetection_join_us, Projects_join_us, Webpage, Profile, User, Course, Skill, Experience, Job, JobAlert, UserBlogPage, VaultDocument #Feedback - +from django.contrib.auth.hashers import check_password from django.contrib.auth import get_user_model from .models import User from django.utils import timezone +from datetime import timedelta from django.core.mail import send_mail from django.core.exceptions import ValidationError from django.utils.http import urlsafe_base64_encode @@ -173,6 +174,8 @@ def wrapped_view(request, *args, **kwargs): from .forms import PenTestingRequestForm, SecureCodeReviewRequestForm from .models import AppAttackReport +from .models import UserDeletionRequest + from home.models import TeamMember @@ -3631,11 +3634,60 @@ def secure_code_review_form_view(request): def delete_account(request): if request.method == 'POST': user = request.user - user.delete() - logout(request) - messages.success(request, "Your account has been deleted.") - return redirect('login') - return HttpResponseNotAllowed(['POST']) + choice = request.POST.get("choice") + password = request.POST.get("password") + + if not password: + messages.error(request, "Password Required") + return render(request, "accounts/confirm_delete.html") + + if not check_password(password, user.password): + messages.error(request, "Incorrect password. Please try again.") + return redirect('delete-account') + + if choice == "deactivate": + logout(request) + send_mail( + "Account Deactivated", + "Your account has been temporarily deactivated. Log in again to reactivate.", + "admin@example.com", + [user.email], + ) + messages.success(request, "Your account has been deactivated.") + return redirect('login') + + elif choice == "delete_now": + email = user.email + user.delete() + send_mail( + "Account Deleted", + "Your account has been permanently deleted.", + "admin@example.com", + [email], + ) + messages.success(request, "Your account has been permanently deleted.") + return redirect('login') + + elif choice == "delete_30days": + UserDeletionRequest.objects.update_or_create( + user=user, + defaults={"scheduled_for": timezone.now() + timedelta(days=30)} + ) + logout(request) + send_mail( + "Account Scheduled for Deletion", + "Your account is deactivated and will be permanently deleted in 30 days unless reactivated.", + "admin@example.com", + [user.email], + ) + messages.success(request, "Your account is scheduled for deletion in 30 days.") + return redirect('login') + + else: + messages.error(request, "Invalid option.") + return redirect('delete-account') + + return render(request, "accounts/confirm_delete.html") def tools_home(request): return render(request, 'pages/pt_gui/tools/index.html')