minor update

This commit is contained in:
2025-08-26 13:59:33 +05:30
parent 657d57df22
commit d1b8889812
11 changed files with 163 additions and 15 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,23 @@
# Generated by Django 5.2.5 on 2025-08-26 08:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='user',
name='banned_until',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AddField(
model_name='user',
name='is_banned',
field=models.BooleanField(default=False),
),
]
+20
View File
@@ -1,7 +1,9 @@
from datetime import timedelta
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.core.validators import FileExtensionValidator from django.core.validators import FileExtensionValidator
from django.conf import settings from django.conf import settings
from django.db import models from django.db import models
from django.utils import timezone
class User(AbstractUser): class User(AbstractUser):
is_citizen = models.BooleanField(default=False) is_citizen = models.BooleanField(default=False)
@@ -25,6 +27,24 @@ class User(AbstractUser):
related_name='core_user_permissions', related_name='core_user_permissions',
related_query_name='core_user', related_query_name='core_user',
) )
is_banned = models.BooleanField(default=False)
banned_until = models.DateTimeField(null=True, blank=True)
def ban(self, days=1):
"""Ban user for given days (default 7 days)."""
self.is_banned = True
self.banned_until = timezone.now() + timedelta(days=days)
self.save()
def unban(self):
self.is_banned = False
self.banned_until = None
self.save()
def is_currently_banned(self):
if self.is_banned and self.banned_until:
return timezone.now() < self.banned_until
return False
class Department(models.Model): class Department(models.Model):
name = models.CharField(max_length=100, unique=True) name = models.CharField(max_length=100, unique=True)
@@ -0,0 +1,60 @@
{% extends "core/base.html" %}
{% block content %}
<div class="container my-5">
<div class="card shadow-lg">
<div class="card-header bg-primary text-white">
<h3><i class="fas fa-users me-2"></i> Manage Citizens</h3>
</div>
<div class="card-body">
{% if citizens %}
<table class="table table-striped table-hover">
<thead class="table-dark">
<tr>
<th>No.</th>
<th>Username</th>
<th>Email</th>
<th>Phone No.</th>
<th>Date Joined</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{% for citizen in citizens %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ citizen.username }}</td>
<td>{{ citizen.email }}</td>
<td>{{ citizen.phone }}</td>
<td>{{ citizen.date_joined|date:"M d, Y" }}</td>
<td>
{% if citizen.is_currently_banned %}
<span class="badge bg-danger">Banned until {{ citizen.banned_until|date:"M d, Y" }}</span>
{% else %}
<span class="badge bg-success">Active</span>
{% endif %}
</td>
<td>
{% if citizen.is_currently_banned %}
<a href="{% url 'unban_user' citizen.id %}" class="btn btn-sm btn-success">
<i class="fas fa-unlock"></i> Unban
</a>
{% else %}
<a href="{% url 'ban_user' citizen.id %}" class="btn btn-sm btn-danger">
<i class="fas fa-ban"></i> Ban
</a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class="text-muted">No citizen users found.</p>
{% endif %}
</div>
</div>
</div>
{% endblock %}
@@ -12,7 +12,7 @@
<ul class="list-group"> <ul class="list-group">
<li class="list-group-item"> <li class="list-group-item">
<i class="fas fa-users me-2 text-primary"></i> <i class="fas fa-users me-2 text-primary"></i>
<a href="#">Manage Users</a> <a href="{% url 'manage_users' %}">Manage Users</a>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
<i class="fas fa-building me-2 text-success"></i> <i class="fas fa-building me-2 text-success"></i>
@@ -16,7 +16,7 @@
<th>Reported By</th> <th>Reported By</th>
<th>Status</th> <th>Status</th>
<th>Created At</th> <th>Created At</th>
<th>Assign Department</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -41,22 +41,29 @@
<td>{{ issue.created_at|date:"M d, Y H:i" }}</td> <td>{{ issue.created_at|date:"M d, Y H:i" }}</td>
<td> <td>
{% if issue.department %} {% if issue.department %}
<span class="fw-bold text-primary">{{ issue.department.name }}</span> <span class="fw-bold text-primary">{{ issue.department.name }}</span>
{% else %} {% else %}
<form method="post" action=""> <!-- Assign Department Form -->
{% csrf_token %} <form method="post" action="" class="d-inline">
<input type="hidden" name="issue_id" value="{{ issue.id }}"> {% csrf_token %}
<select name="department" class="form-select form-select-sm"> <input type="hidden" name="issue_id" value="{{ issue.id }}">
<option value="">— Select Department —</option> <select name="department" class="form-select form-select-sm d-inline w-auto">
{% for dept in departments %} <option value="">— Select Department —</option>
<option value="{{ dept.id }}">{{ dept.name }}</option> {% for dept in departments %}
{% endfor %} <option value="{{ dept.id }}">{{ dept.name }}</option>
</select> {% endfor %}
<button type="submit" class="btn btn-sm btn-primary mt-1">Assign</button> </select>
</form> <button type="submit" class="btn btn-sm btn-primary">Assign</button>
</form>
<!-- Report Fake Button -->
<a href="{% url 'delete_fake_issue' issue.id %}"
class="btn btn-sm btn-danger ms-1"
onclick="return confirm('Are you sure you want to delete this issue as FAKE?');">
<i class="fas fa-ban"></i> Report Fake
</a>
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
+4
View File
@@ -21,4 +21,8 @@ urlpatterns = [
path('vote/<int:issue_id>/', views.vote_issue, name='vote_issue'), path('vote/<int:issue_id>/', views.vote_issue, name='vote_issue'),
path("department/", views.department_dashboard, name="department_dashboard"), path("department/", views.department_dashboard, name="department_dashboard"),
path("update-issue-status/<int:issue_id>/", views.update_issue_status, name="update_issue_status"), path("update-issue-status/<int:issue_id>/", views.update_issue_status, name="update_issue_status"),
path('manage-users/', views.manage_users, name='manage_users'),
path('ban-user/<int:user_id>/', views.ban_user, name='ban_user'),
path('unban-user/<int:user_id>/', views.unban_user, name='unban_user'),
path('issues/<int:issue_id>/delete_fake/', views.delete_fake_issue, name='delete_fake_issue'),
] ]
+34
View File
@@ -291,6 +291,40 @@ def assign_department(request, issue_id):
return redirect("manage_issues") return redirect("manage_issues")
@login_required
@user_passes_test(superadmin_check)
def manage_users(request):
citizens = User.objects.filter(is_citizen=True).order_by('-date_joined')
return render(request, 'core/manage_users.html', {'citizens': citizens})
@login_required
@user_passes_test(superadmin_check)
def ban_user(request, user_id):
citizen = get_object_or_404(User, id=user_id, is_citizen=True)
citizen.ban(days=7) # default ban 7 days
messages.warning(request, f"{citizen.username} has been banned for 7 days.")
return redirect('manage_users')
@login_required
@user_passes_test(superadmin_check)
def unban_user(request, user_id):
citizen = get_object_or_404(User, id=user_id, is_citizen=True)
citizen.unban()
messages.success(request, f"{citizen.username} has been unbanned.")
return redirect('manage_users')
# core/views.py
@login_required
@user_passes_test(superadmin_check)
def delete_fake_issue(request, issue_id):
issue = get_object_or_404(Issue, id=issue_id)
reporter = issue.reporter
issue.delete()
messages.error(request, f"Issue by {reporter.username} was reported fake and deleted.")
return redirect('manage_issues')
def resolver_check(user): def resolver_check(user):
return user.is_resolver return user.is_resolver