Skip to content

Commit

Permalink
Transcribe the donor for to the new backend (#138)
Browse files Browse the repository at this point in the history
* Improve form_url constraints

* Fix the user verification

* Code format

* Show the donation success page

* noqa

* noqa... again

* noqa specific warning

* Revert twopercent template and js

* Begin upgrading the PDF generation

* First beta for the PDF generator on Python3

* Code format

* Tweaks & fixes

- add a slug to NGOs
- change fields to the correct form

* Update comment

---------

Co-authored-by: Tudor Amariei <[email protected]>
  • Loading branch information
danniel and tudoramariei authored Jan 11, 2024
1 parent 916a249 commit 5bb648a
Show file tree
Hide file tree
Showing 26 changed files with 1,080 additions and 338 deletions.
2 changes: 1 addition & 1 deletion backend/donations/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class DonorInputForm(forms.ModelForm):
terms = forms.BooleanField(label=_("Terms"), required=True)

ngo_id = forms.IntegerField(widget=forms.HiddenInput(), required=False)
personal_identifier = ROCNPField(label="CNP")
cnp = ROCNPField(label="CNP")

class Meta:
model = Donor
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Generated by Django 4.2.9 on 2024-01-10 04:54

from django.db import migrations, models
import django.db.models.functions.text
import donations.models
import functools


class Migration(migrations.Migration):
dependencies = [
("donations", "0003_donor_initial_donor_personal_identifier_and_more"),
]

operations = [
migrations.AddField(
model_name="ngo",
name="image",
field=models.ImageField(
blank=True,
storage=donations.models.select_public_storage,
upload_to=functools.partial(donations.models.ngo_directory_path, *("images",), **{}),
verbose_name="image",
),
),
migrations.AddField(
model_name="ngo",
name="logo",
field=models.ImageField(
blank=True,
storage=donations.models.select_public_storage,
upload_to=functools.partial(donations.models.ngo_directory_path, *("logos",), **{}),
verbose_name="logo",
),
),
migrations.AlterField(
model_name="ngo",
name="form_url",
field=models.SlugField(max_length=100, null=True, unique=True, verbose_name="form url"),
),
migrations.AddConstraint(
model_name="ngo",
constraint=models.UniqueConstraint(
django.db.models.functions.text.Lower("form_url"), name="form_url_unique"
),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.9 on 2024-01-10 06:07

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("donations", "0004_ngo_image_ngo_logo_alter_ngo_form_url_and_more"),
]

operations = [
migrations.RenameField(
model_name="donor",
old_name="personal_identifier",
new_name="cnp",
),
]
23 changes: 23 additions & 0 deletions backend/donations/migrations/0006_donor_pdf_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.2.9 on 2024-01-11 05:34

from django.db import migrations, models
import donations.models
import functools


class Migration(migrations.Migration):
dependencies = [
("donations", "0005_rename_personal_identifier_donor_cnp"),
]

operations = [
migrations.AddField(
model_name="donor",
name="pdf_file",
field=models.FileField(
blank=True,
upload_to=functools.partial(donations.models.year_directory_path, *("documents",), **{}),
verbose_name="PDF file",
),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Generated by Django 4.2.9 on 2024-01-11 11:38

from django.db import migrations, models
import django.db.models.functions.text
import donations.models
import functools


class Migration(migrations.Migration):
dependencies = [
("donations", "0006_donor_pdf_file"),
]

operations = [
migrations.RemoveConstraint(
model_name="ngo",
name="form_url_unique",
),
migrations.AddField(
model_name="ngo",
name="custom_form",
field=models.FileField(
blank=True,
storage=donations.models.select_public_storage,
upload_to=functools.partial(donations.models.ngo_directory_path, *("forms",), **{}),
verbose_name="form with ngo data",
),
),
migrations.AddField(
model_name="ngo",
name="date_updated",
field=models.DateTimeField(auto_now=True, db_index=True, verbose_name="date updated"),
),
migrations.AddField(
model_name="ngo",
name="slug",
field=models.SlugField(
default="",
max_length=100,
unique=True,
validators=[donations.models.ngo_identifier_validator],
verbose_name="slug",
),
preserve_default=False,
),
migrations.AlterField(
model_name="ngo",
name="form_url",
field=models.URLField(blank=True, default="", max_length=255, verbose_name="form url"),
),
migrations.AddConstraint(
model_name="ngo",
constraint=models.UniqueConstraint(django.db.models.functions.text.Lower("slug"), name="slug__unique"),
),
]
107 changes: 98 additions & 9 deletions backend/donations/models.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,78 @@
import hashlib
from functools import partial

from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.files.storage import storages
from django.db import models
from django.db.models.functions import Lower
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django_cryptography.fields import encrypt


def select_public_storage():
return storages["public"]


def ngo_directory_path(subdir, instance, filename) -> str:
ngo_code: str = hashlib.sha1(f"ngo-{instance.pk}-{settings.SECRET_KEY}".encode()).hexdigest()

# file will be uploaded to MEDIA_ROOT/ngo-<id>-<hash>/<subdir>/<filename>
return "ngo-{0}-{1}/{2}/{3}".format(instance.pk, ngo_code[:10], subdir, filename)


def year_directory_path(subdir, instance, filename) -> str:
timestamp = timezone.now()
return "{0}/{1}/{2}/{3}".format(subdir, timestamp.date().year, instance.pk, filename)


def ngo_identifier_validator(value):
valid_identifier_sample: str = "asociatia-de-exemplu"
error_message = _("%(value)s is not a valid identifier. The identifier must look like %(sample)s") % {
"value": value,
"sample": valid_identifier_sample,
}

if not value.islower():
raise ValidationError(error_message)


class Ngo(models.Model):
# DEFAULT_NGO_LOGO = "https://storage.googleapis.com/redirectioneaza/logo_bw.png"

name = models.CharField(verbose_name=_("Name"), blank=False, null=False, max_length=100, db_index=True)
description = models.TextField(
verbose_name=_("description"),
slug = models.SlugField(
verbose_name=_("slug"),
blank=False,
null=False,
max_length=100,
db_index=True,
unique=True,
validators=[ngo_identifier_validator],
)

name = models.CharField(verbose_name=_("Name"), blank=False, null=False, max_length=100, db_index=True)
description = models.TextField(verbose_name=_("description"))

# originally: logo
logo_url = models.URLField(verbose_name=_("logo url"), blank=True, null=False, default="")
logo = models.ImageField(
verbose_name=_("logo"),
blank=True,
null=False,
storage=select_public_storage,
upload_to=partial(ngo_directory_path, "logos"),
)

# originally: image_url
image_url = models.URLField(verbose_name=_("image url"), blank=True, null=False, default="")
image = models.ImageField(
verbose_name=_("image"),
blank=True,
null=False,
storage=select_public_storage,
upload_to=partial(ngo_directory_path, "images"),
)

# originally: account
bank_account = models.CharField(verbose_name=_("bank account"), max_length=100)
Expand Down Expand Up @@ -70,20 +126,48 @@ class Ngo(models.Model):
# originally: active
is_active = models.BooleanField(verbose_name=_("is active"), db_index=True, default=True)

# url to the ngo's 2% form, that contains only the ngo's details
form_url = models.CharField(
verbose_name=_("form url"), blank=True, null=False, default="", max_length=255, unique=True
# url to the form that contains only the ngo's details
form_url = models.URLField(
verbose_name=_("form url"),
default="",
blank=True,
null=False,
max_length=255,
)
custom_form = models.FileField(
verbose_name=_("form with ngo data"),
blank=True,
null=False,
storage=select_public_storage,
upload_to=partial(ngo_directory_path, "forms"),
)

date_created = models.DateTimeField(verbose_name=_("date created"), db_index=True, auto_now_add=timezone.now)
date_updated = models.DateTimeField(verbose_name=_("date updated"), db_index=True, auto_now=timezone.now)

class Meta:
verbose_name = _("NGO")
verbose_name_plural = _("NGOs")

constraints = [
models.UniqueConstraint(Lower("slug"), name="slug__unique"),
]

def __str__(self):
return f"{self.name}"

def save(self, *args, **kwargs):
# Force the form_url (which acts as an NGO identifier) to lowercase
if self.form_url:
self.form_url = self.form_url.lower().strip()
return super().save(*args, **kwargs)

def get_full_form_url(self):
if self.form_url:
return "https://{}/{}".format(settings.APEX_DOMAIN, self.form_url)
else:
return ""


class Donor(models.Model):
INCOME_CHOICES = (
Expand All @@ -97,9 +181,7 @@ class Donor(models.Model):
last_name = models.CharField(verbose_name=_("last name"), blank=True, null=False, default="", max_length=100)
initial = models.CharField(verbose_name=_("initials"), blank=True, null=False, default="", max_length=5)

personal_identifier = encrypt(
models.CharField(verbose_name=_("CNP"), blank=True, null=False, default="", max_length=13)
)
cnp = encrypt(models.CharField(verbose_name=_("CNP"), blank=True, null=False, default="", max_length=13))

city = models.CharField(
verbose_name=_("city"),
Expand Down Expand Up @@ -152,6 +234,13 @@ class Donor(models.Model):
filename = models.CharField(verbose_name=_("filename"), blank=True, null=False, default="", max_length=100)
has_signed = models.BooleanField(verbose_name=_("has signed"), db_index=True, default=False)

pdf_file = models.FileField(
verbose_name=_("PDF file"),
blank=True,
null=False,
upload_to=partial(year_directory_path, "documents"),
)

date_created = models.DateTimeField(verbose_name=_("date created"), db_index=True, auto_now_add=timezone.now)

class Meta:
Expand Down
Loading

0 comments on commit 5bb648a

Please sign in to comment.