Skip to content
Open
Show file tree
Hide file tree
Changes from 165 commits
Commits
Show all changes
170 commits
Select commit Hold shift + click to select a range
8d81f51
Added the changes for the sending notification at time of registerati…
Ankit-lab809 Jul 1, 2025
3531c83
added changes to add snippet to manage message and title
Ankit-lab809 Jul 3, 2025
8627650
Notifications WIP
Jul 4, 2025
338f10f
added changes for enable/diable notifications
Ankit-lab809 Jul 4, 2025
916a7f3
added changes for enable/diable notifications
Ankit-lab809 Jul 4, 2025
7d30506
Added the js of notificationpreference
Ankit-lab809 Jul 7, 2025
aa6ffd6
WIP notifications frontend
Jul 9, 2025
ebeacb1
Notifications frontend WIP
Jul 9, 2025
06cae38
Notifications Frontend
Jul 9, 2025
de03ba7
changes to send notifiation to opt in users
Ankit-lab809 Jul 11, 2025
bdaf6d7
changes of celery image and configuration
Ankit-lab809 Jul 11, 2025
23edd28
URL clickable and sendign data to push notifications
Jul 15, 2025
2837c7e
Notifications url changes
Jul 16, 2025
8f73f97
Show description as well in Notifications
Jul 16, 2025
e954dc5
Added changes to create page of the notification preference and also …
Ankit-lab809 Jul 16, 2025
a455865
Merge branch 'main' of github.com:unicef/iogt into feature/registrati…
Ankit-lab809 Jul 16, 2025
2a85409
Reverted commented code
Jul 16, 2025
f4969b8
wagtail upgrade 1
kushvah-ajaysingh-nagarro Jul 16, 2025
6f9ab6e
Upgraded required packages, made fix in code
Jul 17, 2025
2d6b42a
Added redirect url for artilce and survey
Ankit-lab809 Jul 18, 2025
a42c8fa
Merged changesMerge branch 'feature/registration_notification_to_user…
Ankit-lab809 Jul 18, 2025
ba839ce
Generated hashes
Jul 21, 2025
0e28a2a
Fixed issue on new Article page
Jul 22, 2025
ce55828
included modeladmin in installed apps
Jul 22, 2025
ae3d267
Added notify and publish button on article and survey
Ankit-lab809 Jul 24, 2025
77d39b0
added checkbox
Ankit-lab809 Jul 28, 2025
d817983
3.0.8-rc.3
shubhamgoel02 Jul 28, 2025
b21741b
Notifications post demo changes
Jul 28, 2025
77239a2
Shown call out at notification symbol and also sent artcile/survey name
Ankit-lab809 Jul 30, 2025
0a9b112
notifications demo feedback completed
Jul 30, 2025
7091962
Changed icon on profile page
Jul 30, 2025
b38e9a1
Include name in notification and corrected designs
Ankit-lab809 Jul 31, 2025
37b136f
Commiting updated requirements file
Aug 1, 2025
8ff7a63
Merge branch 'feature/registration_notification_to_users' into wagtai…
Aug 1, 2025
710cd3b
Replaced field_as_li to field.html and removed cache for notifications
Aug 4, 2025
89c1cec
Merge branch 'main' into feature/registration_notification_to_users
Aug 7, 2025
74ee706
3.0.9-rc.1
shubhamgoel02 Aug 7, 2025
a50bf74
added dependencies of celery
Ankit-lab809 Aug 7, 2025
a2f6b69
recreated admin_notificaitons migrations
Aug 8, 2025
daa2f41
3.0.9-rc.2
shubhamgoel02 Aug 8, 2025
9ae9e79
Added svg icon
Ankit-lab809 Aug 11, 2025
004ff10
bell icon was not showing up because of library security issue
Aug 11, 2025
7db29e5
added po files for nigeria countries
Ankit-lab809 Aug 11, 2025
8cc9959
added changes in the csv files
Ankit-lab809 Aug 11, 2025
9c3771d
3.0.9-rc.3
shubhamgoel02 Aug 12, 2025
2f9d009
added celery configs
Ankit-lab809 Aug 12, 2025
60cdbd0
Merged changes Merge branch 'feature/registration_notification_to_use…
Ankit-lab809 Aug 12, 2025
c835896
3.0.9-rc.4
shubhamgoel02 Aug 12, 2025
2ddc186
chnaged redis image name
Ankit-lab809 Aug 12, 2025
7425da1
Merged changes Merge branch 'feature/registration_notification_to_use…
Ankit-lab809 Aug 12, 2025
6ef03a8
3.0.9-rc.5
shubhamgoel02 Aug 12, 2025
30ed0d0
added translations
Ankit-lab809 Aug 17, 2025
6438995
fixed issues of media, images pages
Ankit-lab809 Aug 18, 2025
827a00d
done changes in po files
Ankit-lab809 Aug 18, 2025
57c1b4f
removed unnecessary code
Ankit-lab809 Aug 18, 2025
cddc5c3
Merged with nigeria languages Merge branch 'nigerian_languages_integr…
Ankit-lab809 Aug 18, 2025
0c16535
changed in po files
Ankit-lab809 Aug 18, 2025
39ad40d
Merge code Merge branch 'feature/registration_notification_to_users' …
Ankit-lab809 Aug 18, 2025
4ba9f60
3.0.9-rc.6
shubhamgoel02 Aug 18, 2025
8479aaa
Added css for collection dropdown
Ankit-lab809 Aug 20, 2025
6102a20
Added css for translation and media page
Ankit-lab809 Aug 21, 2025
cb0f81b
changed in the remember me text
Ankit-lab809 Aug 21, 2025
8c70877
Update base.py
shubhamgoel02 Aug 21, 2025
b52995c
3.0.9-rc.7
shubhamgoel02 Aug 21, 2025
4d87206
Update celery.py
shubhamgoel02 Aug 21, 2025
1ca566e
3.0.9-rc.8
shubhamgoel02 Aug 21, 2025
e49a1d4
Merged code
Ankit-lab809 Aug 21, 2025
cf3a70c
MergedMerge branch 'feature/merge_notification_and_nigeria_translatio…
Ankit-lab809 Aug 21, 2025
fc79146
Update celery.py
shubhamgoel02 Aug 21, 2025
5393608
3.0.9-rc.9
shubhamgoel02 Aug 21, 2025
27701ab
Create start.sh
shubhamgoel02 Aug 21, 2025
9d3fc29
Update Dockerfile
shubhamgoel02 Aug 21, 2025
8015044
3.0.9-rc.10
shubhamgoel02 Aug 21, 2025
583f771
Update Dockerfile
shubhamgoel02 Aug 25, 2025
4e03e3e
Delete scripts/start.sh
shubhamgoel02 Aug 25, 2025
e92a9f1
3.0.9-rc.11
shubhamgoel02 Aug 25, 2025
55b5311
Changed in the image section
Ankit-lab809 Aug 25, 2025
f27e697
Merged Merge branch 'nigerian_languages_integration' of https://githu…
Ankit-lab809 Aug 25, 2025
39dd13d
Merged Merge branch 'feature/merge_notification_and_nigeria_translati…
Ankit-lab809 Aug 25, 2025
0043d13
removed unused code and also added translation for remove me text
Ankit-lab809 Aug 25, 2025
2ddee6b
3.0.9-rc.12
shubhamgoel02 Aug 26, 2025
38dd2c9
Changed class_name to classname, fixing css for headers WIP
Aug 26, 2025
708b171
3.0.9-rc.13
shubhamgoel02 Aug 26, 2025
4aad964
3.0.9-rc.14
shubhamgoel02 Aug 27, 2025
5bd2a5f
Fixed push notifications
Aug 29, 2025
853c5fc
Moved variables to env file
Ankit-lab809 Aug 29, 2025
e7be763
3.0.9-rc.15
shubhamgoel02 Sep 1, 2025
2e1f376
Fixed the layout
Ankit-lab809 Sep 1, 2025
80a2548
CSS of dropdown and header
Sep 2, 2025
87a72f6
fixed css of form data and import export users page
Sep 2, 2025
2830273
removed top padding from header
Sep 2, 2025
9355bc7
fixed user page and layout
Ankit-lab809 Sep 2, 2025
d99b16b
Merge branch 'feature/fix_upgrade_issues' of https://github.com/unice…
Ankit-lab809 Sep 2, 2025
6fdd65b
Merge branch 'feature/merge_notification_and_nigeria_translations' of…
Ankit-lab809 Sep 2, 2025
460898a
Merge branches
Ankit-lab809 Sep 2, 2025
928f9d0
Merge
Ankit-lab809 Sep 2, 2025
c0be3ec
added margin on top of right sided headers button
Sep 2, 2025
b157e7a
fixed packages versions
Sep 2, 2025
847df71
added margin-top on right sided buttons on header
Sep 2, 2025
6a1ff0f
Changed in the user feature
Ankit-lab809 Sep 2, 2025
84c2092
Removed spaces
Ankit-lab809 Sep 2, 2025
cfa2614
3.0.9-rc.16
shubhamgoel02 Sep 3, 2025
11dad54
Update base.py
shubhamgoel02 Sep 3, 2025
147c4b6
3.0.9-rc.17
shubhamgoel02 Sep 3, 2025
0f8a558
3.0.9-rc.18
shubhamgoel02 Sep 4, 2025
363367c
Updated CACHE_LOCATION
shubhamgoel02 Sep 4, 2025
e993467
Updated CACHE
shubhamgoel02 Sep 4, 2025
bc7021b
Updated cache
shubhamgoel02 Sep 4, 2025
19e6ad4
3.0.9-rc.22
shubhamgoel02 Sep 4, 2025
526fc9a
Cache details updated
shubhamgoel02 Sep 4, 2025
13b4924
UAT feedback: Add Notification Preference on Users page
Sep 4, 2025
80c330c
UAT feedback: Removed add, edit, delete permission from notificaitons…
Sep 4, 2025
7676e28
Removed create_view_class because that should be handled with Permiss…
Sep 4, 2025
aae76f5
UAT feedback: Redirect users to notification preferences page after r…
Sep 4, 2025
f0561fb
Update base.py
shubhamgoel02 Sep 5, 2025
22011a7
3.0.9-rc.24
shubhamgoel02 Sep 5, 2025
3af5dfb
Update base.py
shubhamgoel02 Sep 5, 2025
7b33490
3.0.9-rc.25
shubhamgoel02 Sep 5, 2025
8440434
Merged and also done added on notify and publish button
Ankit-lab809 Sep 5, 2025
4432279
Merged changes Merge branch 'feature/merge_notification_languages_upg…
Ankit-lab809 Sep 5, 2025
3ba363e
Removed extra spaces
Ankit-lab809 Sep 5, 2025
5433be3
3.0.9-rc.26
shubhamgoel02 Sep 5, 2025
21af449
removed same name migration
Ankit-lab809 Sep 5, 2025
7cbd74c
Merged Merge branch 'feature/uat_notification_recommendations' of htt…
Ankit-lab809 Sep 5, 2025
31d5b5c
3.0.9-rc.27
shubhamgoel02 Sep 5, 2025
27d6143
Added new script to copy data of page revision to revison
Ankit-lab809 Sep 8, 2025
2682c97
3.0.9-rc.28
shubhamgoel02 Sep 8, 2025
389bc91
Added new column in user listing page
Ankit-lab809 Sep 15, 2025
f88e1a8
Update production.py
shubhamgoel02 Sep 15, 2025
4e5ba19
Corrected typo
Ankit-lab809 Sep 15, 2025
c14707b
Merged Merge branch 'feature/uat_notification_recommendations' of htt…
Ankit-lab809 Sep 15, 2025
d0f9fc3
3.0.9-rc.30
shubhamgoel02 Sep 15, 2025
175f32b
Added autocomplete search on users and content tags in notification p…
sachin-mehta Sep 15, 2025
1b7b778
changed color of autocomplete options
sachin-mehta Sep 15, 2025
06da97a
3.0.9-rc.31
shubhamgoel02 Sep 16, 2025
6213035
Added locale column and sorting and search feature
Ankit-lab809 Sep 17, 2025
9bd519b
Deleted unused migration
Ankit-lab809 Sep 17, 2025
9bc799a
Merged the changes of uat notification branch
Ankit-lab809 Sep 17, 2025
9ac477e
changed in the model
Ankit-lab809 Sep 17, 2025
2323795
3.0.9-rc.32
shubhamgoel02 Sep 17, 2025
951d9b2
Added migration
Ankit-lab809 Sep 18, 2025
6466ab2
Merged Merge branch 'feature/add_upgrade_features' of https://github.…
Ankit-lab809 Sep 18, 2025
934bb1a
3.0.9-rc.33
shubhamgoel02 Sep 18, 2025
03256ef
Added css
Ankit-lab809 Sep 24, 2025
9782c74
Merged Merge branch 'feature/add_upgrade_features' of https://github.…
Ankit-lab809 Sep 24, 2025
d4e6db1
3.0.9-rc.34
shubhamgoel02 Sep 24, 2025
88637eb
3.0.9-rc.35
shubhamgoel02 Sep 25, 2025
17af8f7
Update base.py
shubhamgoel02 Sep 25, 2025
d898761
3.0.9-rc.36
shubhamgoel02 Sep 25, 2025
7dd36bf
Update base.py
shubhamgoel02 Sep 25, 2025
ba6fb30
3.0.9-rc.37
shubhamgoel02 Sep 25, 2025
1f38808
removed django cache middleware
Ankit-lab809 Sep 26, 2025
7665d81
Merged Merge branch 'feature/add_upgrade_features' of https://github.…
Ankit-lab809 Sep 26, 2025
9b852b5
changed in base file
Ankit-lab809 Sep 26, 2025
cc68d5b
Update production.py
shubhamgoel02 Sep 26, 2025
4fc870e
Merged and added changes of the wagtail transfer
Ankit-lab809 Sep 29, 2025
fe328fe
Resolved conflict
Ankit-lab809 Sep 29, 2025
5e0c3d5
Changed in prod file
Ankit-lab809 Oct 6, 2025
edbba9e
added changes of the user activites, quiz results and edit prfoile
Ankit-lab809 Oct 15, 2025
70a376b
Merge branch 'main' of https://github.com/unicef/iogt into feature/us…
Ankit-lab809 Oct 15, 2025
dc17a0e
Added quiz feedback inline
Ankit-lab809 Oct 29, 2025
6d4382f
reoved extra migrations and unused code
Ankit-lab809 Oct 29, 2025
9ffe869
Added external css
Ankit-lab809 Oct 29, 2025
26aeb33
Removed cdn link
Ankit-lab809 Oct 29, 2025
a6fa9d9
Removed extra space
Ankit-lab809 Oct 29, 2025
336fd96
Added ajax to show messages in reposne
Ankit-lab809 Oct 30, 2025
0b4f317
changed svg icon and css
Ankit-lab809 Oct 30, 2025
1757fb0
Remved extra space
Ankit-lab809 Oct 31, 2025
3e6229a
removed extra spaces
Ankit-lab809 Oct 31, 2025
092acdc
removed extra import
Ankit-lab809 Oct 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions home/static/css/global/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -2377,4 +2377,71 @@ div.notification-confirmation{
color: #555;
margin: 0;
margin-bottom: 5px;
}
.btn-danger {
padding: 6px 14px; /* reduces height and width */
font-size: 0.9rem; /* slightly smaller text */
line-height: 1.2; /* tighter vertical spacing */
}

.btn-danger {
display: inline-block !important;
width: auto !important;
}
.activity-table {
width: 150%;
border-collapse: collapse;
border: 1px solid #ddd !important;
}

.activity-table th,
.activity-table td {
padding: 10px;
border: 1px solid #ddd;
text-align: left;
}

.activity-table thead {
background-color: #f2f2f2;
}

.quiz-results-title {
text-align: center;
margin-bottom: 1em;
}

.quiz-results-table {
border-collapse: collapse;
width: 100%;
border: 1px solid #ccc;
}

.quiz-results-table th,
.quiz-results-table td {
padding: 8px;
border: 1px solid #ccc;
}

.quiz-results-table thead {
background-color: #f5f5f5;
font-weight: bold;
}

.center-text {
text-align: center;
}

.quiz-link {
text-decoration: none;
color: #007BFF;
}

.quiz-link:hover {
text-decoration: underline;
}

.no-quiz-text {
text-align: center;
color: #666;
font-style: italic;
}
1 change: 1 addition & 0 deletions iogt/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
"iogt.middleware.AdminLocaleMiddleware",
'iogt.middleware.CustomRedirectMiddleware',
'iogt_users.middlewares.RegistrationSurveyRedirectMiddleware',
'iogt_users.middlewares.TrackFrontendPageVisitsMiddleware',
'external_links.middleware.RewriteExternalLinksMiddleware',
'iogt.middleware.GlobalDataMiddleware',
# 'admin_login.middleware.CustomAdminLoginRequiredMiddleware',
Expand Down
8 changes: 6 additions & 2 deletions iogt/static/css/accounts.css
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ form label[for='id_terms_accepted'], form label[for='id_remember'], form span[id
margin-right: 10px;
}

form input {
form input, #id_gender {
background-color: #f7f7f9;
border: 1px solid #efefef;
border-radius: 8px;
Expand Down Expand Up @@ -131,4 +131,8 @@ form input[type="checkbox"] {

.dropdown-content label:hover {
background-color: #f0f0f0;
}
}

.edit-profile input{
font-size: 14px; /* Only font-size changes */
}
1 change: 1 addition & 0 deletions iogt/static/icons/quiz-answer-banner.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 28 additions & 3 deletions iogt_users/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,25 @@ class AccountSignupForm(SignupForm):
),
required=False,
)
date_of_birth = forms.DateField(
required=True,
widget=forms.DateInput(attrs={"type": "date"})
)
gender = forms.ChoiceField(
choices=[("male", "Male"), ("female", "Female"), ("other", "Other")],
required=True,
)
location = forms.CharField(
required=False, # optional field
max_length=255
)
terms_accepted = forms.BooleanField(label=_('I accept the Terms and Conditions.'))

field_order = [
"username",
"display_name",
"date_of_birth",
"gender",
"location",
"password1",
"password2",
"terms_accepted",
Expand All @@ -44,14 +58,25 @@ def __init__(self, *args, **kwargs):
self.fields["username"].widget = forms.TextInput(attrs={
"placeholder": _("Choose a username that you will use to login to IoGT")
})
self.fields["location"].widget = forms.TextInput(attrs={
"placeholder": _("Enter a location")
})
self.fields["gender"].widget = forms.Select(
choices=self.fields["gender"].choices,
attrs={
"class": "form-control w-100", # Bootstrap full width
}
)

if hasattr(self, "field_order"):
set_form_field_order(self, self.field_order)

def save(self, request):
user = super().save(request)
# 🔁 Run this logic in background
send_app_notifications.delay(user.id, notification_type='signup')
user.date_of_birth = self.cleaned_data["date_of_birth"]
user.gender = self.cleaned_data["gender"]
user.location = self.cleaned_data["location"]
user.save()
return user

def clean_username(self):
Expand Down
40 changes: 40 additions & 0 deletions iogt_users/middlewares.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from django.urls import resolve, Resolver404, translate_url
from django.utils import translation
from django.utils.translation import gettext as _
from django.utils.timezone import now
from .models import PageVisit

from home.models import SiteSettings

Expand Down Expand Up @@ -65,3 +67,41 @@ def __call__(self, request):
return redirect(registration_survey.localized.url)

return self.get_response(request)



class TrackFrontendPageVisitsMiddleware:
def __init__(self, get_response):
self.get_response = get_response

def __call__(self, request):
response = self.get_response(request)
if request.user.is_authenticated:
path = request.path
if request.method != "GET":
return response
excluded_paths = [
"/admin",
"/static",
"/media",
"/api",
"/my-activity",
"/users/profile/my-activity"
]
if "my-activity" in path or path.startswith("/admin") or path.startswith("/static") or path.startswith("/media") or path.startswith("/api"):
return response
if request.headers.get("x-requested-with") == "XMLHttpRequest":
return response
accept_header = request.headers.get("Accept", "")
if "text/html" not in accept_header:
return response
last_visit = PageVisit.objects.filter(user=request.user, page_slug=path)\
.order_by("-timestamp").first()
if not last_visit or (now() - last_visit.timestamp).total_seconds() > 10:
PageVisit.objects.create(
user=request.user,
page_slug=path,
timestamp=now()
)
return response

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Generated by Django 5.2.4 on 2025-10-01 06:27

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('iogt_users', '0006_user_interactive_uuid'),
]

operations = [
migrations.AddField(
model_name='user',
name='date_of_birth',
field=models.DateField(blank=True, null=True),
),
migrations.AddField(
model_name='user',
name='gender',
field=models.CharField(blank=True, choices=[('male', 'Male'), ('female', 'Female'), ('other', 'Other')], max_length=10, null=True),
),
migrations.AddField(
model_name='user',
name='location',
field=models.CharField(blank=True, max_length=255, null=True),
),
migrations.CreateModel(
name='PageVisit',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('page_slug', models.CharField(max_length=500)),
('timestamp', models.DateTimeField(auto_now_add=True)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='page_visits', to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['-timestamp'],
},
),
]
23 changes: 23 additions & 0 deletions iogt_users/migrations/0008_deleteduserlog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 5.2.4 on 2025-10-07 10:47

import django.utils.timezone
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('iogt_users', '0007_user_date_of_birth_user_gender_user_location_and_more'),
]

operations = [
migrations.CreateModel(
name='DeletedUserLog',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('user_id', models.IntegerField(help_text='Internal user ID (non-identifiable)')),
('deletion_time', models.DateTimeField(default=django.utils.timezone.now)),
('reason', models.TextField(blank=True, null=True)),
],
),
]
31 changes: 31 additions & 0 deletions iogt_users/migrations/0009_quizattempt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Generated by Django 5.2.4 on 2025-10-08 03:19

import django.db.models.deletion
import django.utils.timezone
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('iogt_users', '0008_deleteduserlog'),
('questionnaires', '0033_survey_notification_tags'),
]

operations = [
migrations.CreateModel(
name='QuizAttempt',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('score', models.FloatField()),
('attempt_number', models.PositiveIntegerField(default=1)),
('completed_at', models.DateTimeField(default=django.utils.timezone.now)),
('quiz', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='questionnaires.quiz')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['-completed_at'],
},
),
]
47 changes: 46 additions & 1 deletion iogt_users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils import timezone
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework_simplejwt.tokens import RefreshToken


class User(AbstractUser):
Expand All @@ -22,6 +23,14 @@ class User(AbstractUser):
has_viewed_registration_survey = models.BooleanField(default=False)

interactive_uuid = models.CharField(max_length=255, null=True, blank=True)
date_of_birth = models.DateField(null=True, blank=True)
gender = models.CharField(
max_length=10,
choices=[("male", "Male"), ("female", "Female"), ("other", "Other")],
null=True, blank=True
)
location = models.CharField(max_length=255, null=True, blank=True)


autocomplete_search_field = 'username'

Expand Down Expand Up @@ -86,3 +95,39 @@ def __str__(self):
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)


class PageVisit(models.Model):
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name="page_visits")
page_slug = models.CharField(max_length=500) # URL path
timestamp = models.DateTimeField(auto_now_add=True)

class Meta:
ordering = ["-timestamp"]

def __str__(self):
return f"{self.user.username} visited {self.page_slug} at {self.timestamp}"


class DeletedUserLog(models.Model):
user_id = models.IntegerField(help_text="Internal user ID (non-identifiable)")
deletion_time = models.DateTimeField(default=timezone.now)
reason = models.TextField(blank=True, null=True)

def __str__(self):
return f"User ID {self.user_id} deleted at {self.deletion_time}"


class QuizAttempt(models.Model):
from questionnaires.models import Quiz
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE)
score = models.FloatField()
attempt_number = models.PositiveIntegerField(default=1)
completed_at = models.DateTimeField(default=timezone.now)

class Meta:
ordering = ["-completed_at"] # latest first

def __str__(self):
return f"{self.user.username} - {self.quiz.title} (Attempt {self.attempt_number})"
Loading