minor update
This commit is contained in:
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),
|
||||
),
|
||||
]
|
||||
BIN
Binary file not shown.
@@ -1,7 +1,9 @@
|
||||
from datetime import timedelta
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.core.validators import FileExtensionValidator
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
|
||||
class User(AbstractUser):
|
||||
is_citizen = models.BooleanField(default=False)
|
||||
@@ -25,6 +27,24 @@ class User(AbstractUser):
|
||||
related_name='core_user_permissions',
|
||||
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):
|
||||
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">
|
||||
<li class="list-group-item">
|
||||
<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 class="list-group-item">
|
||||
<i class="fas fa-building me-2 text-success"></i>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<th>Reported By</th>
|
||||
<th>Status</th>
|
||||
<th>Created At</th>
|
||||
<th>Assign Department</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -41,22 +41,29 @@
|
||||
<td>{{ issue.created_at|date:"M d, Y H:i" }}</td>
|
||||
<td>
|
||||
{% if issue.department %}
|
||||
<span class="fw-bold text-primary">{{ issue.department.name }}</span>
|
||||
<span class="fw-bold text-primary">{{ issue.department.name }}</span>
|
||||
{% else %}
|
||||
<form method="post" action="">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="issue_id" value="{{ issue.id }}">
|
||||
<select name="department" class="form-select form-select-sm">
|
||||
<option value="">— Select Department —</option>
|
||||
{% for dept in departments %}
|
||||
<option value="{{ dept.id }}">{{ dept.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button type="submit" class="btn btn-sm btn-primary mt-1">Assign</button>
|
||||
</form>
|
||||
<!-- Assign Department Form -->
|
||||
<form method="post" action="" class="d-inline">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="issue_id" value="{{ issue.id }}">
|
||||
<select name="department" class="form-select form-select-sm d-inline w-auto">
|
||||
<option value="">— Select Department —</option>
|
||||
{% for dept in departments %}
|
||||
<option value="{{ dept.id }}">{{ dept.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<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 %}
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
@@ -21,4 +21,8 @@ urlpatterns = [
|
||||
path('vote/<int:issue_id>/', views.vote_issue, name='vote_issue'),
|
||||
path("department/", views.department_dashboard, name="department_dashboard"),
|
||||
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'),
|
||||
]
|
||||
@@ -291,6 +291,40 @@ def assign_department(request, issue_id):
|
||||
|
||||
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):
|
||||
return user.is_resolver
|
||||
|
||||
|
||||
Reference in New Issue
Block a user