Skip to content

Commit

Permalink
Update backend to latest developments
Browse files Browse the repository at this point in the history
  • Loading branch information
vjousse committed Jun 5, 2024
1 parent 36c446e commit 901e886
Show file tree
Hide file tree
Showing 12 changed files with 607 additions and 347 deletions.
2 changes: 1 addition & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ name = "pypi"
[packages]
django = ">=5,<6"
django-mail-auth = ">=3.2,<3.3"
gunicorn = ">=21,<22"
gunicorn = ">=22,<23"
psycopg = ">=3.1,<3.2"
python-decouple = ">=3,<4"
ruff = "*"
Expand Down
16 changes: 8 additions & 8 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 25 additions & 4 deletions backend/authentication/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,28 @@


def init():
# create initial admins given by an env var. Mails separated by comma
for email in [m.strip() for m in config("BACKEND_ADMINS", "").split(",")]:
if not get_user_model().objects.filter(email=email):
get_user_model().objects.create_superuser(email, terms_of_use=True)
# create initial admins given by an env var. Mails separated by comma, with optional token
# So the env var can be in the form: [email protected]=ABCDEFGH,[email protected],[email protected]
# this allows a user to have a persistent token among all the deployments
for admin in [
m.strip().split("=") for m in config("BACKEND_ADMINS", "").split(",")
]:
if len(admin) > 1:
# we specified the mail and token
(email, token) = admin
if not get_user_model().objects.filter(email=email):
# user not found by mail, create it
get_user_model().objects.create_superuser(
email, terms_of_use=True, token=token
)
elif not get_user_model().objects.filter(email=email, token=token):
# user found by mail but not by token, update the token
user = get_user_model().objects.filter(email=email).first()
if user:
user.token = token
user.save()
else:
# we specified only the mail
(email,) = admin
if not get_user_model().objects.filter(email=email):
get_user_model().objects.create_superuser(email, terms_of_use=True)
10 changes: 4 additions & 6 deletions backend/authentication/models.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import uuid

from django.db import models
from django.db.models import BooleanField, CharField
from django.utils.translation import gettext_lazy as _
from mailauth.contrib.user.models import AbstractEmailUser


class EcobalyseUser(AbstractEmailUser):
organization = models.CharField(
_("Organization"), max_length=150, blank=True, default=""
)
terms_of_use = models.BooleanField(default=False)
token = models.CharField(
organization = CharField(_("Organization"), max_length=150, blank=True, default="")
terms_of_use = BooleanField(default=False)
token = CharField(
_("TOKEN"), max_length=36, default=uuid.uuid4, editable=False, db_index=True
)
3 changes: 1 addition & 2 deletions backend/backend/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@
# # don't use the provided mailauth user, it's redefined in the authentication module
# "mailauth.contrib.user",
"authentication.apps.AuthenticationConfig",
# # disable textile for now
# "textile.apps.TextileConfig",
# "textile.apps.TextileConfig", # TODO disable textile for now
# # the original admin config is replaced by custom AdminConfig
# "django.contrib.admin",
"backend.apps.AdminConfig",
Expand Down
11 changes: 11 additions & 0 deletions backend/templates/admin/textile/example/change_list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% extends "admin/change_list.html" %}
{% load i18n static %}

{% block object-tools-items %}
{{ block.super }}
<li>
<a href="{% url 'admin:from-json' %}" class="button">
{% trans "Create from JSON" %}
</a>
</li>
{% endblock %}
13 changes: 13 additions & 0 deletions backend/templates/admin/textile/example/from_json.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{% extends "admin/base_site.html" %}
{% load i18n static %}
{% block content %}
<h1>{% trans "Create the Example from the provided JSON block in Ecobalyse" %}</h1>
<div class="module">
<form method="post">
{% csrf_token %}
{{ form.as_p }}

<input type="submit" value="{% trans 'Submit' %}">
</form>
</div>
{% endblock %}
223 changes: 219 additions & 4 deletions backend/textile/admin.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,247 @@
from django.contrib import admin
import json

from django import forms
from django.contrib import admin, messages
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import path, reverse
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _

from backend.admin import admin_site
from textile.models import Example, Material, Process, Product


class ProductAdmin(admin.ModelAdmin):
save_on_top = True
search_fields = ["name"]
list_display = ("name", "id", "mass", "volume")
fieldsets = [
(None, {"fields": ("name", "id", "mass", "surfaceMass", "yarnSize", "fabric")}),
(
_("Economics"),
{
"fields": (
"business",
"marketingDuration",
"numberOfReferences",
"price",
"repairCost",
"traceability",
)
},
),
(_("Dyeing"), {"fields": ("defaultMedium",)}),
(_("Making"), {"fields": ("pcrWaste", "complexity")}),
(
_("Use"),
{
"fields": (
"ironingElecInMJ",
"nonIroningProcessUuid",
"daysOfWear",
"defaultNbCycles",
"ratioDryer",
"ratioIroning",
"timeIroning",
"wearsPerCycle",
)
},
),
(_("End Of Life"), {"fields": ("volume",)}),
]


class MaterialsInline(admin.TabularInline):
model = Example.materials.through


class MaterialAdmin(admin.ModelAdmin):
save_on_top = True
search_fields = ["name"]
# inlines = [MaterialsInline]
list_display = ("name", "shortName", "id", "related_process")

def related_process(self, obj):
url = reverse(
"admin:textile_process_change", args=(obj.materialProcessUuid.pk,)
)
return format_html(f'<a href="{url}">{obj.materialProcessUuid.name}</a>')

related_process.allow_tags = True
fieldsets = [
(None, {"fields": ("name", "shortName", "origin", "priority")}),
(
_("Processes"),
{"fields": ("materialProcessUuid", "recycledProcessUuid", "recycledFrom")},
),
(_("Geography"), {"fields": ("geographicOrigin", "defaultCountry")}),
(_("Other"), {"fields": ("manufacturerAllocation", "recycledQualityRatio")}),
]


class ProcessAdmin(admin.ModelAdmin):
save_on_top = True
search_fields = ["name"]
list_display = ("name", "source", "uuid", "step_usage")
fieldsets = [
(
None,
{
"fields": (
"name",
"uuid",
"source",
"search",
"info",
"unit",
"step_usage",
"correctif",
)
},
),
(_("Energy"), {"fields": ("heat_MJ", "elec_pppm", "elec_MJ")}),
(_("Scores"), {"fields": ("pef", "ecs")}),
(
_("Impacts"),
{
"fields": (
"acd",
"cch",
"etf",
"etfc",
"fru",
"fwe",
"htc",
"htcc",
"htn",
"htnc",
"ior",
"ldu",
"mru",
"ozd",
"pco",
"pma",
"swe",
"tre",
"wtu",
)
},
),
]


class ExampleJSONForm(forms.ModelForm):
class Meta:
model = Example
fields = ["id", "name", "product"]

query = forms.JSONField()

class ExempleAdmin(admin.ModelAdmin):

class ExampleAdmin(admin.ModelAdmin):
search_fields = ["name"]
inlines = [MaterialsInline]
change_list_template = "admin/textile/example/change_list.html"
save_on_top = True
list_display = ("name", "id", "product")
fieldsets = [
(None, {"fields": ["id", "name", "mass"]}),
(
"Durabilité non-physique",
{
"fields": [
"product",
"numberOfReferences",
"price",
"marketingDuration",
"business",
"traceability",
"repairCost",
],
"description": "Paramètres de durabilité non-physique. Voir la <a href='https://fabrique-numerique.gitbook.io/ecobalyse/textile/durabilite'>Documentation</a>",
},
),
(
"Filature",
{
"fields": [
"countrySpinning",
],
"description": "<a href='https://fabrique-numerique.gitbook.io/ecobalyse/textile/etapes-du-cycle-de-vie/etape-2-fabrication-du-fil-new'>Documentation</a>",
},
),
(
"Fabrication",
{
"fields": [
"fabricProcess",
"countryFabric",
],
"description": "<a href='https://fabrique-numerique.gitbook.io/ecobalyse/textile/cycle-de-vie-des-produits-textiles/etape-2-fabrication-du-fil'>Documentation</a>",
},
),
(
"Confection",
{
"fields": [
"airTransportRatio",
"countryMaking",
],
"description": "<a href='https://fabrique-numerique.gitbook.io/ecobalyse/textile/etapes-du-cycle-de-vie/confection'>Documentation</a>",
},
),
(
"Ennoblissement",
{
"fields": [
"countryDyeing",
],
"description": "<a href='https://fabrique-numerique.gitbook.io/ecobalyse/textile/etapes-du-cycle-de-vie/ennoblissement'>Documentation</a>",
},
),
]

def get_urls(self):
return [
path(
"from-json/",
self.admin_site.admin_view(self.from_json),
name="from-json",
)
] + super().get_urls()

def from_json(self, request):
"""/admin/textile/example/from-json/ form"""
if request.method == "POST":
form = ExampleJSONForm(request.POST)
if form.is_valid():
json_example = {
"id": request.POST["id"],
"name": request.POST["name"],
"product": request.POST["product"],
"query": json.loads(request.POST["query"]),
}
try:
example = Example._fromJSON(json_example)
example.save()

for share in json_example["query"]["materials"]:
example.add_material(share)
self.message_user(request, _("Your Example has been recorded"))
return HttpResponseRedirect("..")
except TypeError:
self.message_user(
request,
_("Your JSON doesn't look like a valid example"),
level=messages.ERROR,
)
else:
form = ExampleJSONForm()
context = dict(self.admin_site.each_context(request), form=form)
return render(request, "admin/textile/example/from_json.html", context)


admin_site.register(Product, ProductAdmin)
admin_site.register(Material, MaterialAdmin)
admin_site.register(Process, ProcessAdmin)
admin_site.register(Example, ExempleAdmin)
admin_site.register(Example, ExampleAdmin)
Loading

0 comments on commit 901e886

Please sign in to comment.