Implement major changes

This commit is contained in:
Keannu Bernasol 2025-01-19 20:18:19 +08:00
parent 60eadbed64
commit 63f3bd0eab
16 changed files with 357 additions and 40 deletions

View file

@ -3,6 +3,7 @@ from rest_framework import serializers
from django.contrib.auth.password_validation import validate_password from django.contrib.auth.password_validation import validate_password
from django.core import exceptions as django_exceptions from django.core import exceptions as django_exceptions
from rest_framework.settings import api_settings from rest_framework.settings import api_settings
from django.utils.timezone import now, localdate
class CustomUserUpdateSerializer(serializers.ModelSerializer): class CustomUserUpdateSerializer(serializers.ModelSerializer):
@ -15,7 +16,7 @@ class CustomUserUpdateSerializer(serializers.ModelSerializer):
class CustomUserSerializer(serializers.ModelSerializer): class CustomUserSerializer(serializers.ModelSerializer):
birthday = serializers.DateField(format="%Y-%m-%d") birthday = serializers.DateField(format="%m-%d-%Y")
class Meta: class Meta:
model = CustomUser model = CustomUser
@ -52,7 +53,7 @@ class CustomUserRegistrationSerializer(serializers.ModelSerializer):
) )
first_name = serializers.CharField(required=True) first_name = serializers.CharField(required=True)
last_name = serializers.CharField(required=True) last_name = serializers.CharField(required=True)
birthday = serializers.DateField(format="%Y-%m-%d", required=True) birthday = serializers.DateField(format="%m-%d-%Y", required=True)
class Meta: class Meta:
model = CustomUser model = CustomUser
@ -76,6 +77,30 @@ class CustomUserRegistrationSerializer(serializers.ModelSerializer):
if self.Meta.model.objects.filter(username=attrs.get("email")).exists(): if self.Meta.model.objects.filter(username=attrs.get("email")).exists():
raise serializers.ValidationError( raise serializers.ValidationError(
"A user with that email already exists.") "A user with that email already exists.")
# Only allow major email providers
email = attrs.get("email")
allowed_email_domains = ["gmail.com", "outlook.com", "ustp.edu.ph"]
if not any(provider in email for provider in allowed_email_domains):
raise serializers.ValidationError(
"Non-major email providers are not supported")
# Validate age based on birthday
birthday = attrs.get("birthday")
date_now = localdate(now())
age = (
date_now.year
- birthday.year
- (
(date_now.month, date_now.day)
< (birthday.month, birthday.day)
)
)
if age < 16:
raise serializers.ValidationError(
"You need to be at least 16 years old to avail of this USTP service")
return super().validate(attrs) return super().validate(attrs)
def create(self, validated_data): def create(self, validated_data):

View file

@ -12,13 +12,18 @@ def create_admin_user(sender, **kwargs):
if sender.name == "accounts": if sender.name == "accounts":
users = [{ users = [{
"email": get_secret("ADMIN_EMAIL"), "email": get_secret("ADMIN_EMAIL"),
"role": "head", "role": "admin",
"admin": True, "admin": True,
}, { }, {
"email": "staff@test.com", "email": "staff@test.com",
"role": "staff", "role": "staff",
"admin": False, "admin": False,
}, { }, {
"email": "head@test.com",
"role": "head",
"admin": False,
},
{
"email": "planning@test.com", "email": "planning@test.com",
"role": "planning", "role": "planning",
"admin": False, "admin": False,

View file

@ -1,6 +1,6 @@
from django.contrib import admin from django.contrib import admin
from unfold.admin import ModelAdmin from unfold.admin import ModelAdmin
from .models import AuthorizationRequest from .models import AuthorizationRequest, AuthorizationRequestUnit
# Register your models here. # Register your models here.
@ -9,3 +9,9 @@ from .models import AuthorizationRequest
class AuthorizationRequestAdmin(ModelAdmin): class AuthorizationRequestAdmin(ModelAdmin):
search_fields = ["id"] search_fields = ["id"]
list_display = ["id", "date_requested", "status", "college"] list_display = ["id", "date_requested", "status", "college"]
@admin.register(AuthorizationRequestUnit)
class AuthorizationRequestUnitAdmin(ModelAdmin):
search_fields = ["id"]
list_display = ["id", "status", "document", "pages", "copies"]

View file

@ -0,0 +1,63 @@
# Generated by Django 5.1.3 on 2025-01-17 15:41
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authorization_requests", "0001_initial"),
]
operations = [
migrations.RemoveField(
model_name="authorizationrequest",
name="documents",
),
migrations.AlterField(
model_name="authorizationrequest",
name="status",
field=models.CharField(
choices=[
("pending", "Pending"),
("approved", "Approved"),
("denied", "Denied"),
("claimed", "Claimed"),
("unclaimed", "Unclaimed"),
],
default="pending",
max_length=32,
),
),
migrations.CreateModel(
name="AuthorizationRequestUnit",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("document", models.TextField(max_length=256)),
("copies", models.IntegerField(default=1)),
(
"authorization_request",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="authorization_requests.authorizationrequest",
),
),
],
),
migrations.AddField(
model_name="authorizationrequest",
name="documents",
field=models.ManyToManyField(
to="authorization_requests.authorizationrequestunit"
),
),
]

View file

@ -0,0 +1,21 @@
# Generated by Django 5.1.3 on 2025-01-17 16:11
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
(
"authorization_requests",
"0002_remove_authorizationrequest_documents_and_more",
),
]
operations = [
migrations.AddField(
model_name="authorizationrequestunit",
name="pages",
field=models.IntegerField(default=1),
),
]

View file

@ -0,0 +1,22 @@
# Generated by Django 5.1.3 on 2025-01-19 10:33
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authorization_requests", "0003_authorizationrequestunit_pages"),
]
operations = [
migrations.AddField(
model_name="authorizationrequestunit",
name="status",
field=models.CharField(
choices=[("pending", "Pending"), ("checked", "Checked")],
default="pending",
max_length=32,
),
),
]

View file

@ -2,10 +2,27 @@ from django.db import models
from django.utils.timezone import now from django.utils.timezone import now
class AuthorizationRequestUnit(models.Model):
authorization_request = models.ForeignKey(
"authorization_requests.AuthorizationRequest", on_delete=models.CASCADE
)
document = models.TextField(max_length=256)
pages = models.IntegerField(default=1, null=False, blank=False)
copies = models.IntegerField(default=1, null=False, blank=False)
STATUS_CHOICES = (
("pending", "Pending"),
("checked", "Checked"),
)
status = models.CharField(
max_length=32, choices=STATUS_CHOICES, default="pending")
class AuthorizationRequest(models.Model): class AuthorizationRequest(models.Model):
requester = models.ForeignKey( requester = models.ForeignKey(
"accounts.CustomUser", on_delete=models.CASCADE) "accounts.CustomUser", on_delete=models.CASCADE)
documents = models.TextField(max_length=2048, blank=False, null=False) documents = models.ManyToManyField(
"authorization_requests.AuthorizationRequestUnit")
date_requested = models.DateTimeField(default=now, editable=False) date_requested = models.DateTimeField(default=now, editable=False)
college = models.CharField(max_length=64, blank=False, null=False) college = models.CharField(max_length=64, blank=False, null=False)
purpose = models.TextField(max_length=512, blank=False, null=False) purpose = models.TextField(max_length=512, blank=False, null=False)
@ -14,6 +31,8 @@ class AuthorizationRequest(models.Model):
("pending", "Pending"), ("pending", "Pending"),
("approved", "Approved"), ("approved", "Approved"),
("denied", "Denied"), ("denied", "Denied"),
("claimed", "Claimed"),
("unclaimed", "Unclaimed"),
) )
remarks = models.TextField(max_length=512, blank=True, null=True) remarks = models.TextField(max_length=512, blank=True, null=True)

View file

@ -1,14 +1,33 @@
from rest_framework import serializers from rest_framework import serializers
from accounts.models import CustomUser from accounts.models import CustomUser
from emails.templates import RequestUpdateEmail from emails.templates import RequestUpdateEmail
from .models import AuthorizationRequest from .models import AuthorizationRequest, AuthorizationRequestUnit
class AuthorizationRequestUnitCreationSerializer(serializers.ModelSerializer):
document = serializers.CharField()
copies = serializers.IntegerField(min_value=1)
pages = serializers.IntegerField(min_value=1)
class Meta:
model = AuthorizationRequestUnit
fields = ["document", "copies", "pages", "status"]
class AuthorizationRequestUnitSerializer(serializers.ModelSerializer):
class Meta:
model = AuthorizationRequestUnit
fields = ["id", "document", "status", "copies", "pages"]
read_only_fields = ["id", "document", "status," "copies", "pages"]
class AuthorizationRequestCreationSerializer(serializers.ModelSerializer): class AuthorizationRequestCreationSerializer(serializers.ModelSerializer):
requester = serializers.SlugRelatedField( requester = serializers.SlugRelatedField(
many=False, slug_field="id", queryset=CustomUser.objects.all(), required=False many=False, slug_field="id", queryset=CustomUser.objects.all(), required=False
) )
documents = serializers.CharField(max_length=2048, required=True) documents = AuthorizationRequestUnitCreationSerializer(
many=True, required=True)
college = serializers.CharField(max_length=64) college = serializers.CharField(max_length=64)
purpose = serializers.CharField(max_length=512) purpose = serializers.CharField(max_length=512)
@ -18,11 +37,31 @@ class AuthorizationRequestCreationSerializer(serializers.ModelSerializer):
def create(self, validated_data): def create(self, validated_data):
user = self.context["request"].user user = self.context["request"].user
documents_data = validated_data.pop("documents")
if not documents_data:
raise serializers.ValidationError(
{"error": "No documents provided"}
)
# Set requester to user who sent HTTP request to prevent spoofing # Set requester to user who sent HTTP request to prevent spoofing
validated_data["requester"] = user validated_data["requester"] = user
return AuthorizationRequest.objects.create(**validated_data) AUTHORIZATION_REQUEST = AuthorizationRequest.objects.create(
**validated_data)
AUTHORIZATION_REQUEST_UNITS = []
for AUTHORIZATION_REQUEST_UNIT in documents_data:
AUTHORIZATION_REQUEST_UNIT = AuthorizationRequestUnit.objects.create(
authorization_request=AUTHORIZATION_REQUEST,
document=AUTHORIZATION_REQUEST_UNIT["document"],
copies=AUTHORIZATION_REQUEST_UNIT["copies"],
pages=AUTHORIZATION_REQUEST_UNIT["pages"]
)
AUTHORIZATION_REQUEST_UNITS.append(AUTHORIZATION_REQUEST_UNIT)
AUTHORIZATION_REQUEST.documents.set(AUTHORIZATION_REQUEST_UNITS)
AUTHORIZATION_REQUEST.save()
return AUTHORIZATION_REQUEST
class AuthorizationRequestSerializer(serializers.ModelSerializer): class AuthorizationRequestSerializer(serializers.ModelSerializer):
@ -34,6 +73,7 @@ class AuthorizationRequestSerializer(serializers.ModelSerializer):
date_requested = serializers.DateTimeField( date_requested = serializers.DateTimeField(
format="%m-%d-%Y %I:%M %p", read_only=True format="%m-%d-%Y %I:%M %p", read_only=True
) )
documents = AuthorizationRequestUnitSerializer(many=True)
class Meta: class Meta:
model = AuthorizationRequest model = AuthorizationRequest
@ -59,6 +99,59 @@ class AuthorizationRequestSerializer(serializers.ModelSerializer):
] ]
class AuthorizationRequestUnitUpdateSerializer(serializers.ModelSerializer):
status = serializers.ChoiceField(
choices=AuthorizationRequestUnit.STATUS_CHOICES, required=True
)
class Meta:
model = AuthorizationRequestUnit
fields = ["id", "status"]
read_only_fields = ["id"]
def update(self, instance, validated_data):
if instance.authorization_request.status != "pending":
raise serializers.ValidationError(
{
"error": "Already approved/denied requests cannot be updated. You should instead create a new request and approve it from there"
}
)
if instance.status == "checked":
raise serializers.ValidationError(
{
"error": "Already approved/denied request units cannot be updated. You should instead create a new request and approve it from there"
}
)
elif "status" not in validated_data:
raise serializers.ValidationError(
{
"error": "No status value update provided"
}
)
elif validated_data["status"] == instance.status:
raise serializers.ValidationError(
{"error": "Request unit status provided is the same as current status"}
)
representation = super().update(instance, validated_data)
# Check if the parent Authorization Request has had all its documents approved
approved_all = True
for AUTHORIZATION_REQUEST_UNIT in instance.authorization_request.documents.all():
if AUTHORIZATION_REQUEST_UNIT.status != "checked":
approved_all = False
# If all documents have been checked
if approved_all:
# Set the parent request as approved
instance.authorization_request.status = "approved"
instance.authorization_request.save()
# And send an email notification
email = RequestUpdateEmail()
email.context = {"request_status": "approved"}
email.send(to=[instance.authorization_request.requester.email])
return representation
class AuthorizationRequestUpdateSerializer(serializers.ModelSerializer): class AuthorizationRequestUpdateSerializer(serializers.ModelSerializer):
status = serializers.ChoiceField( status = serializers.ChoiceField(
choices=AuthorizationRequest.STATUS_CHOICES, required=True choices=AuthorizationRequest.STATUS_CHOICES, required=True
@ -70,23 +163,30 @@ class AuthorizationRequestUpdateSerializer(serializers.ModelSerializer):
read_only_fields = ["id"] read_only_fields = ["id"]
def update(self, instance, validated_data): def update(self, instance, validated_data):
print(validated_data) if "status" not in validated_data:
if instance.status == "denied" or instance.status == "approved":
raise serializers.ValidationError(
{
"error": "Already approved/denied requests cannot be updated. You should instead create a new request and approve it from there"
}
)
elif "status" not in validated_data:
raise serializers.ValidationError( raise serializers.ValidationError(
{ {
"error": "No status value update provided" "error": "No status value update provided"
} }
) )
elif instance.status == "denied" or instance.status == "claimed":
raise serializers.ValidationError(
{
"error": "Already claimed/denied requests cannot be updated. You should instead create a new request and approve it from there"
}
)
elif validated_data["status"] == instance.status: elif validated_data["status"] == instance.status:
raise serializers.ValidationError( raise serializers.ValidationError(
{"error": "Request form status provided is the same as current status"} {"error": "Request form status provided is the same as current status"}
) )
elif instance.status == "approved" and validated_data["status"] not in ["claimed", "unclaimed"]:
raise serializers.ValidationError(
{"error": "Approved request forms can only be marked as claimed or unclaimed"}
)
elif instance.status == "unclaimed" and validated_data["status"] not in ["claimed"]:
raise serializers.ValidationError(
{"error": "Unclaimed request forms can only be marked as claimed"}
)
elif validated_data["status"] == "denied" and "remarks" not in validated_data: elif validated_data["status"] == "denied" and "remarks" not in validated_data:
raise serializers.ValidationError( raise serializers.ValidationError(
{"error": "Request denial requires remarks"} {"error": "Request denial requires remarks"}
@ -96,14 +196,16 @@ class AuthorizationRequestUpdateSerializer(serializers.ModelSerializer):
# Send an email on request status update # Send an email on request status update
try: try:
email = RequestUpdateEmail() email = RequestUpdateEmail()
email.context = {"request_status": validated_data["status"]}
if validated_data["status"] == "denied": if validated_data["status"] == "denied":
email.context = {"request_status": "denied"}
email.context = {"remarks": validated_data["remarks"]} email.context = {"remarks": validated_data["remarks"]}
else: else:
email.context = {"request_status": "approved"}
email.context = {"remarks": "N/A"} email.context = {"remarks": "N/A"}
email.send(to=[instance.requester.email]) email.send(to=[instance.requester.email])
except: except Exception as e:
# Silence out errors if email sending fails # Silence out errors if email sending fails
print(e)
pass pass
return representation return representation

View file

@ -3,10 +3,13 @@ from .views import (
AuthorizationRequestCreateView, AuthorizationRequestCreateView,
AuthorizationRequestUpdateView, AuthorizationRequestUpdateView,
AuthorizationRequestListView, AuthorizationRequestListView,
AuthorizationRequestUnitUpdateView
) )
urlpatterns = [ urlpatterns = [
path("create/", AuthorizationRequestCreateView.as_view()), path("create/", AuthorizationRequestCreateView.as_view()),
path("list/", AuthorizationRequestListView.as_view()), path("list/", AuthorizationRequestListView.as_view()),
path("update/<int:pk>/", AuthorizationRequestUpdateView.as_view()), path("update/<int:pk>/", AuthorizationRequestUpdateView.as_view()),
path("authorization_request_units/update/<int:pk>/",
AuthorizationRequestUnitUpdateView.as_view()),
] ]

View file

@ -6,10 +6,11 @@ from rest_framework.pagination import PageNumberPagination
from .serializers import ( from .serializers import (
AuthorizationRequestCreationSerializer, AuthorizationRequestCreationSerializer,
AuthorizationRequestSerializer, AuthorizationRequestSerializer,
AuthorizationRequestUpdateSerializer AuthorizationRequestUpdateSerializer,
AuthorizationRequestUnitUpdateSerializer
) )
from .models import AuthorizationRequest from .models import AuthorizationRequest, AuthorizationRequestUnit
class AuthorizationRequestCreateView(generics.CreateAPIView): class AuthorizationRequestCreateView(generics.CreateAPIView):
@ -51,3 +52,14 @@ class AuthorizationRequestUpdateView(generics.UpdateAPIView):
serializer_class = AuthorizationRequestUpdateSerializer serializer_class = AuthorizationRequestUpdateSerializer
permission_classes = [IsAuthenticated, IsHead] permission_classes = [IsAuthenticated, IsHead]
queryset = AuthorizationRequest.objects.all() queryset = AuthorizationRequest.objects.all()
class AuthorizationRequestUnitUpdateView(generics.UpdateAPIView):
"""
Used by head approve or deny authorization request units.
"""
http_method_names = ["patch"]
serializer_class = AuthorizationRequestUnitUpdateSerializer
permission_classes = [IsAuthenticated, IsHead]
queryset = AuthorizationRequestUnit.objects.all()

View file

@ -18,9 +18,8 @@ import logging
import time import time
from ollama import Client from ollama import Client
from pydantic import BaseModel from pydantic import BaseModel
from datetime import date, datetime from datetime import date
from typing import Optional from typing import Optional
import calendar
class PDFHandler(FileSystemEventHandler): class PDFHandler(FileSystemEventHandler):
@ -237,10 +236,10 @@ class PDFHandler(FileSystemEventHandler):
# Open the file for instance creation # Open the file for instance creation
DOCUMENT = Document.objects.filter( DOCUMENT = Document.objects.filter(
name=filename.replace(".pdf", "")).first() name=document_subject).first()
if not DOCUMENT: if not DOCUMENT:
DOCUMENT = Document.objects.create( DOCUMENT = Document.objects.create(
name=filename.replace(".pdf", ""), name=document_subject,
number_pages=num_pages, number_pages=num_pages,
ocr_metadata=metadata, ocr_metadata=metadata,
document_type=document_type, document_type=document_type,
@ -254,12 +253,13 @@ class PDFHandler(FileSystemEventHandler):
name=filename, content=File(open(file_path, "rb"))) name=filename, content=File(open(file_path, "rb")))
self.logger.info( self.logger.info(
f"Document '{filename}' created successfully with type '{ f"Document created successfully from '{filename}' with type '{
document_type}'. sent_from: {sent_from}, document_month: {document_month}, document_year: {document_year}" document_type}'. sent_from: {sent_from}, document_month: {document_month}, document_year: {document_year}"
) )
else: else:
self.logger.info(f"Document '{filename}' already exists.") self.logger.info(
f"Document '{document_subject}' already exists.")
os.remove(file_path) os.remove(file_path)
except Exception as e: except Exception as e:

View file

@ -0,0 +1,28 @@
# Generated by Django 5.1.3 on 2025-01-17 15:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("document_requests", "0004_rename_denied_remarks_documentrequest_remarks"),
]
operations = [
migrations.AlterField(
model_name="documentrequest",
name="status",
field=models.CharField(
choices=[
("pending", "Pending"),
("approved", "Approved"),
("denied", "Denied"),
("claimed", "Claimed"),
("unclaimed", "Unclaimed"),
],
default="pending",
max_length=32,
),
),
]

View file

@ -25,6 +25,8 @@ class DocumentRequest(models.Model):
("pending", "Pending"), ("pending", "Pending"),
("approved", "Approved"), ("approved", "Approved"),
("denied", "Denied"), ("denied", "Denied"),
("claimed", "Claimed"),
("unclaimed", "Unclaimed"),
) )
remarks = models.TextField(max_length=512, blank=True, null=True) remarks = models.TextField(max_length=512, blank=True, null=True)

View file

@ -182,23 +182,30 @@ class DocumentRequestUpdateSerializer(serializers.ModelSerializer):
read_only_fields = ["id"] read_only_fields = ["id"]
def update(self, instance, validated_data): def update(self, instance, validated_data):
print(validated_data) if "status" not in validated_data:
if instance.status == "denied" or instance.status == "approved":
raise serializers.ValidationError(
{
"error": "Already approved/denied requests cannot be updated. You should instead create a new request and approve it from there"
}
)
elif "status" not in validated_data:
raise serializers.ValidationError( raise serializers.ValidationError(
{ {
"error": "No status value update provided" "error": "No status value update provided"
} }
) )
elif instance.status == "denied" or instance.status == "claimed":
raise serializers.ValidationError(
{
"error": "Already claimed/denied requests cannot be updated. You should instead create a new request and approve it from there"
}
)
elif validated_data["status"] == instance.status: elif validated_data["status"] == instance.status:
raise serializers.ValidationError( raise serializers.ValidationError(
{"error": "Request form status provided is the same as current status"} {"error": "Request form status provided is the same as current status"}
) )
elif instance.status == "approved" and validated_data["status"] not in ["claimed", "unclaimed"]:
raise serializers.ValidationError(
{"error": "Approved request forms can only be marked as claimed or unclaimed"}
)
elif instance.status == "unclaimed" and validated_data["status"] not in ["claimed"]:
raise serializers.ValidationError(
{"error": "Unclaimed request forms can only be marked as claimed"}
)
elif validated_data["status"] == "denied" and "remarks" not in validated_data: elif validated_data["status"] == "denied" and "remarks" not in validated_data:
raise serializers.ValidationError( raise serializers.ValidationError(
{"error": "Request denial requires remarks"} {"error": "Request denial requires remarks"}
@ -208,10 +215,11 @@ class DocumentRequestUpdateSerializer(serializers.ModelSerializer):
# Send an email on request status update # Send an email on request status update
try: try:
email = RequestUpdateEmail() email = RequestUpdateEmail()
email.context = {"request_status": validated_data["status"]}
if validated_data["status"] == "denied": if validated_data["status"] == "denied":
email.context = {"request_status": "denied"}
email.context = {"remarks": validated_data["remarks"]} email.context = {"remarks": validated_data["remarks"]}
else: else:
email.context = {"request_status": "approved"}
email.context = {"remarks": "N/A"} email.context = {"remarks": "N/A"}
email.send(to=[instance.requester.email]) email.send(to=[instance.requester.email])
except: except:

View file

@ -7,7 +7,8 @@ class RequestUpdateEmail(email.BaseEmailMessage):
def get_context_data(self): def get_context_data(self):
context = super().get_context_data() context = super().get_context_data()
context["request_status"] = context.get("request_status") # Dirty fix since approved statuses don't seem to be read properly for some reason
context["request_status"] = context.get("request_status", "denied")
context["remarks"] = context.get("remarks") context["remarks"] = context.get("remarks")
context["url"] = FRONTEND_URL context["url"] = FRONTEND_URL
context.update(self.context) context.update(self.context)

View file

@ -1,11 +1,11 @@
{% load i18n %} {% load i18n %}
{% block subject %} {% block subject %}
{% blocktrans %}USTP - Document Request Form Update{% endblocktrans %} {% blocktrans %}USTP - Request Form Update{% endblocktrans %}
{% endblock %} {% endblock %}
{% block text_body %} {% block text_body %}
{% blocktrans %}You're receiving this email because your document request has been {{ request_status }}.{% endblocktrans %} {% blocktrans %}You're receiving this email because your request form has been {{ request_status }}.{% endblocktrans %}
{% blocktrans %}Remarks: {{ remarks }}{% endblocktrans %} {% blocktrans %}Remarks: {{ remarks }}{% endblocktrans %}
@ -17,7 +17,7 @@
{% block html_body %} {% block html_body %}
<p> <p>
{% blocktrans %}You're receiving this email because your document request has been {{ request_status }}.{% endblocktrans %} {% blocktrans %}You're receiving this email because your request form has been {{ request_status }}.{% endblocktrans %}
</p> </p>
<p> <p>