diff --git a/twisted/twisted_site/templates/admin/user.html b/twisted/twisted_site/templates/admin/user.html
index d06857a..d3c8f6b 100644
--- a/twisted/twisted_site/templates/admin/user.html
+++ b/twisted/twisted_site/templates/admin/user.html
@@ -202,9 +202,64 @@
Admin
Not an admin!
This user is not an admin yet!
{% if request.user.profile.staff_permissions.superuser %}
-
- Make admin
-
+
+
+ Make admin
+
+
+
+
+
+
+
+
+
+
+
+
Type the text in the input above to confirm this action
+
+
+
+
+ Confirm
+
+
+
+
+
{% endif %}
{% endif %}
diff --git a/twisted/twisted_site/templates/client/projects/detail.html b/twisted/twisted_site/templates/client/projects/detail.html
index 0bdf44f..99b0aa1 100644
--- a/twisted/twisted_site/templates/client/projects/detail.html
+++ b/twisted/twisted_site/templates/client/projects/detail.html
@@ -132,11 +132,13 @@ {{ project.project_name }}
Log more time!
Log atleast 60 minutes before shipping your project.
+ {% if project.user == user %}
+ {% endif %}
{% endif %}
{% endif %}
diff --git a/twisted/twisted_site/templates/cotton/admin/dialog.html b/twisted/twisted_site/templates/cotton/admin/dialog.html
new file mode 100644
index 0000000..55ffe44
--- /dev/null
+++ b/twisted/twisted_site/templates/cotton/admin/dialog.html
@@ -0,0 +1,39 @@
+
+
+ {{ trigger }}
+
+
+
+
+
+
+
+
+
{{ title }}
+
+
+
+ {{ slot }}
+
+
+
+
\ No newline at end of file
diff --git a/twisted/twisted_site/views/admin/admin.py b/twisted/twisted_site/views/admin/admin.py
index f63e369..097650e 100644
--- a/twisted/twisted_site/views/admin/admin.py
+++ b/twisted/twisted_site/views/admin/admin.py
@@ -1,6 +1,7 @@
from dataclasses import dataclass
from typing import Any, override
+from django.contrib import messages
from django.http import HttpRequest, HttpResponseBase
from django.shortcuts import redirect, resolve_url
from django.views import View
@@ -19,58 +20,84 @@ class SidebarLink:
# Create your views here.
class AdminView(View):
audit_log: AuditLog # pyright: ignore[reportUninitializedInstanceVariable]
- perms: ProfileStaffPermissions | None # pyright: ignore[reportUninitializedInstanceVariable]
+ perms: ProfileStaffPermissions # pyright: ignore[reportUninitializedInstanceVariable]
+ allowed = False
def get_context_data(self, page: str, subpage: str | None = None) -> dict[str, Any]: # pyrefly: ignore[explicit-any]
context: dict[str, Any] = {} # pyrefly: ignore[explicit-any]
context["page"] = page
context["subpage"] = subpage
- context["sidebar_links"] = [
+ sidebar_links = [
SidebarLink(
name="dashboard",
icon="analytics",
text="Analytics",
href=resolve_url("admin.dash"),
),
- SidebarLink(
- name="users",
- icon="profile",
- text="Users",
- href=resolve_url("admin.users"),
- ),
- SidebarLink(
- name="pathways",
- icon="controls",
- text="Pathways",
- href=resolve_url("admin.pathways"),
- ),
- SidebarLink(
- name="fulfillment",
- icon="list",
- text="Fulfillment",
- href=resolve_url("admin.fulfillment"),
- ),
- SidebarLink(name="shop", icon="bag-add", text="Shop", href=resolve_url("admin.shop")),
- SidebarLink(
- name="review",
- icon="message-new",
- text="Review",
- href=resolve_url("admin.review"),
- ),
- SidebarLink(
- name="announcements",
- icon="important",
- text="Announcements",
- href=resolve_url("admin.announcements"),
- ),
- SidebarLink(
- name="logs",
- icon="view",
- text="Audit Logs",
- href=resolve_url("admin.logs") + "?page=1",
- ),
]
- context["profile"] = self.request.user.profile # ty:ignore[unresolved-attribute] # pyright: ignore[reportAttributeAccessIssue] # pyrefly: ignore[missing-attribute]
+ if self.perms.view_users:
+ sidebar_links.append(
+ SidebarLink(
+ name="users",
+ icon="profile",
+ text="Users",
+ href=resolve_url("admin.users"),
+ ),
+ )
+ if self.perms.view_pathways:
+ sidebar_links.append(
+ SidebarLink(
+ name="pathways",
+ icon="controls",
+ text="Pathways",
+ href=resolve_url("admin.pathways"),
+ ),
+ )
+ if self.perms.manage_fulfillments:
+ sidebar_links.append(
+ SidebarLink(
+ name="fulfillment",
+ icon="list",
+ text="Fulfillment",
+ href=resolve_url("admin.fulfillment"),
+ ),
+ )
+ if self.perms.manage_shop:
+ sidebar_links.append(
+ SidebarLink(
+ name="shop", icon="bag-add", text="Shop", href=resolve_url("admin.shop"),
+ ),
+ )
+ if self.perms.view_review:
+ sidebar_links.append(
+ SidebarLink(
+ name="review",
+ icon="message-new",
+ text="Review",
+ href=resolve_url("admin.review"),
+ ),
+ )
+ if self.perms.manage_announcements:
+ sidebar_links.append(
+ SidebarLink(
+ name="announcements",
+ icon="important",
+ text="Announcements",
+ href=resolve_url("admin.announcements"),
+ ),
+ )
+ if self.perms.view_auditlogs:
+ sidebar_links.append(
+ SidebarLink(
+ name="logs",
+ icon="view",
+ text="Audit Logs",
+ href=resolve_url("admin.logs") + "?page=1",
+ ),
+ )
+
+ context["sidebar_links"] = sidebar_links
+ context["profile"] = self.request.user.profile # pyright: ignore[reportAttributeAccessIssue] # pyrefly: ignore[missing-attribute]
return context
@override
@@ -86,13 +113,18 @@ def dispatch(self, request: HttpRequest, *args: object, **kwargs: object) -> Htt
additional_context={},
)
- perms = self.request.user.profile.staff_permissions # ty:ignore[unresolved-attribute] # pyright: ignore[reportAttributeAccessIssue] # pyrefly: ignore[missing-attribute]
+ perms = self.request.user.profile.staff_permissions # pyright: ignore[reportAttributeAccessIssue] # pyrefly: ignore[missing-attribute]
if perms is None:
- profile = self.request.user.profile # ty:ignore[unresolved-attribute] # pyright: ignore[reportAttributeAccessIssue] # pyrefly: ignore[missing-attribute]
+ profile = self.request.user.profile # pyright: ignore[reportAttributeAccessIssue] # pyrefly: ignore[missing-attribute]
profile.staff_permissions = ProfileStaffPermissions.objects.create()
profile.save()
self.perms = perms
response = super().dispatch(request, *args, **kwargs)
+
+ if not self.allowed:
+ messages.error(request, "You arent allowed to visit this page!")
+ return redirect("admin.dash")
+
self.audit_log.save()
return response
diff --git a/twisted/twisted_site/views/admin/announcements.py b/twisted/twisted_site/views/admin/announcements.py
index 35bdf22..7b4b546 100644
--- a/twisted/twisted_site/views/admin/announcements.py
+++ b/twisted/twisted_site/views/admin/announcements.py
@@ -8,7 +8,13 @@
# Create your views here.
class AnnouncementsView(AdminView):
def get(self, request: HttpRequest) -> HttpResponse:
+ if self.perms.manage_announcements:
+ self.allowed = True
+ else:
+ return HttpResponse("err")
+
context = self.get_context_data(page="announcements")
+
if self.request.user.is_anonymous:
return redirect("homepage")
return TemplateResponse(request, "admin/announcements.html", context=context)
diff --git a/twisted/twisted_site/views/admin/dashboard.py b/twisted/twisted_site/views/admin/dashboard.py
index b683718..3d9e41c 100644
--- a/twisted/twisted_site/views/admin/dashboard.py
+++ b/twisted/twisted_site/views/admin/dashboard.py
@@ -11,6 +11,7 @@
# Create your views here.
class DashboardView(AdminView):
+ allowed = True
def get(self, request: HttpRequest) -> HttpResponse:
context = self.get_context_data(page="dashboard")
if self.request.user.is_anonymous:
diff --git a/twisted/twisted_site/views/admin/fulfillment.py b/twisted/twisted_site/views/admin/fulfillment.py
index 5aaf1ab..bb7067f 100644
--- a/twisted/twisted_site/views/admin/fulfillment.py
+++ b/twisted/twisted_site/views/admin/fulfillment.py
@@ -7,5 +7,10 @@
# Create your views here.
class FulfillmentView(AdminView):
def get(self, request: HttpRequest) -> HttpResponse:
+ if self.perms.manage_fulfillments:
+ self.allowed = True
+ else:
+ return HttpResponse("err")
+
context = self.get_context_data(page="fulfillment")
return render(request, "admin/fulfillment.html", context=context)
diff --git a/twisted/twisted_site/views/admin/pathways.py b/twisted/twisted_site/views/admin/pathways.py
index 2c6c586..081ccb9 100644
--- a/twisted/twisted_site/views/admin/pathways.py
+++ b/twisted/twisted_site/views/admin/pathways.py
@@ -14,6 +14,12 @@
# Create your views here.
class PathwayListView(AdminView):
def get(self, request: HttpRequest) -> HttpResponse:
+ if self.perms.view_pathways:
+ self.allowed = True
+ else:
+ return HttpResponse("err")
+
+
context = self.get_context_data(page="pathways")
context["pathways"] = Pathway.objects.all().order_by("start")
@@ -46,6 +52,11 @@ def get(
error: str | None = None,
extracontext: dict[str, Any] | None = None, # pyrefly: ignore[explicit-any]
) -> HttpResponse:
+ if self.perms.manage_pathways:
+ self.allowed = True
+ else:
+ return HttpResponse("err")
+
if extracontext is None:
extracontext = {}
@@ -58,6 +69,11 @@ def get(
return render(request, "admin/pathways/create.html", context=context)
def post(self, request: HttpRequest) -> HttpResponse:
+ if self.perms.manage_pathways:
+ self.allowed = True
+ else:
+ return HttpResponse("err")
+
pathway_name: str | None = request.POST.get("name")
start_date: str | None = request.POST.get("startDate")
@@ -113,6 +129,11 @@ def post(self, request: HttpRequest) -> HttpResponse:
class PathwayDetailView(AdminView):
def get(self, request: HttpRequest, pathway_id: int) -> HttpResponse:
+ if self.perms.view_pathways:
+ self.allowed = True
+ else:
+ return HttpResponse("err")
+
context = self.get_context_data(page="pathways", subpage="detail")
pathway = get_object_or_404(Pathway, id=pathway_id)
context["pathway"] = pathway
diff --git a/twisted/twisted_site/views/admin/review.py b/twisted/twisted_site/views/admin/review.py
index ca63ed2..af37097 100644
--- a/twisted/twisted_site/views/admin/review.py
+++ b/twisted/twisted_site/views/admin/review.py
@@ -11,6 +11,11 @@
# Create your views here.
class ReviewView(AdminView):
def get(self, request: HttpRequest) -> HttpResponse:
+ if self.perms.view_review:
+ self.allowed = True
+ else:
+ return HttpResponse("err")
+
if settings.DEBUG_REVIEW:
return self.debug_get(request)
@@ -18,6 +23,11 @@ def get(self, request: HttpRequest) -> HttpResponse:
return render(request, "admin/review.html", context=context)
def post(self, request: HttpRequest) -> HttpResponse:
+ if self.perms.manage_review:
+ self.allowed = True
+ else:
+ return HttpResponse("err")
+
if settings.DEBUG_REVIEW:
return self.debug_post(request)
diff --git a/twisted/twisted_site/views/admin/shop.py b/twisted/twisted_site/views/admin/shop.py
index aa2d2a4..6e7a5a0 100644
--- a/twisted/twisted_site/views/admin/shop.py
+++ b/twisted/twisted_site/views/admin/shop.py
@@ -7,5 +7,10 @@
# Create your views here.
class ShopView(AdminView):
def get(self, request: HttpRequest) -> HttpResponse:
+ if self.perms.manage_shop:
+ self.allowed = True
+ else:
+ return HttpResponse("err")
+
context = self.get_context_data(page="shop")
return render(request, "admin/shop.html", context=context)
diff --git a/twisted/twisted_site/views/admin/users.py b/twisted/twisted_site/views/admin/users.py
index 8c5c7fa..6802665 100644
--- a/twisted/twisted_site/views/admin/users.py
+++ b/twisted/twisted_site/views/admin/users.py
@@ -9,7 +9,7 @@
from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse
-from twisted_site.models import User
+from twisted_site.models import User, ProfileStaffPermissions
from .admin import AdminView
@@ -17,6 +17,11 @@
# Create your views here.
class UsersView(AdminView):
def get(self, request: HttpRequest) -> HttpResponse:
+ if self.perms.view_users:
+ self.allowed = True
+ else:
+ return HttpResponse("err")
+
context = self.get_context_data(page="users")
if request.GET.get("search") not in (None, ""):
query: str = request.GET["search"]
@@ -34,6 +39,11 @@ def get(self, request: HttpRequest) -> HttpResponse:
def post(self, request: HttpRequest) -> HttpResponse:
if request.POST.get("action") == "logoutall":
+ if self.perms.superuser:
+ self.allowed = True
+ else:
+ return HttpResponse("err")
+
session_count = Session.objects.count()
_ = Session.objects.all().delete()
if not isinstance(self.audit_log.additional_context, dict):
@@ -47,6 +57,11 @@ def post(self, request: HttpRequest) -> HttpResponse:
class UserDetailView(AdminView):
def get(self, request: HttpRequest, user_id: int) -> HttpResponse:
+ if self.perms.view_users:
+ self.allowed = True
+ else:
+ return HttpResponse("err")
+
context = self.get_context_data(page="users", subpage="detail")
user = get_object_or_404(User, id=user_id)
@@ -66,6 +81,11 @@ def get(self, request: HttpRequest, user_id: int) -> HttpResponse:
return TemplateResponse(request, "admin/user.html", context)
def post(self, request: HttpRequest, user_id: int) -> HttpResponse | None:
+ if self.perms.superuser:
+ self.allowed = True
+ else:
+ return HttpResponse("err")
+
user = get_object_or_404(User, id=user_id)
if not isinstance(self.audit_log.additional_context, dict):
@@ -91,8 +111,9 @@ def post(self, request: HttpRequest, user_id: int) -> HttpResponse | None:
return resp
if request.POST.get("action") == "change_permissions":
if not request.user.profile.staff_permissions.superuser:
- return None
- key = request.POST["key"]
+ messages.error(request, "You are not allowed to change the permissions!")
+ return redirect(self.request.path)
+ key:str = request.POST["key"] # pyright: ignore[reportAssignmentType]
value = request.POST.get("value") == "True"
perms = user.profile.staff_permissions
setattr(perms, key, value)
@@ -102,4 +123,13 @@ def post(self, request: HttpRequest, user_id: int) -> HttpResponse | None:
messages.success(request, f"Set permission '{key}' to '{value}' successfully.")
return redirect(self.request.path+"#adminperms")
+ if request.POST.get("action") == "make_admin":
+ profile = user.profile
+ profile.is_staff = True
+ profile.staff_permissions = ProfileStaffPermissions.objects.create()
+ self.audit_log.pii = True
+ self.audit_log.additional_context["permission_changed"] = "Made user an admin"
+ messages.success(request, f"Made @{user.profile.slack_username} an admin.")
+ profile.save()
+
return redirect(self.request.path)
diff --git a/twisted/twisted_site/views/client/journal.py b/twisted/twisted_site/views/client/journal.py
index 9c47fe3..96c5298 100644
--- a/twisted/twisted_site/views/client/journal.py
+++ b/twisted/twisted_site/views/client/journal.py
@@ -32,6 +32,7 @@ def get(
context["project"] = project
context["max_minutes"] = HACKATIME_MAX_LOGGABLE_MINUTES
+ context["info"] = info
if project.is_shipped():
return redirect("fr.projects.detail", project_id)