diff --git a/apps/__init__.py b/apps/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/core/__init__.py b/apps/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/core/admin.py b/apps/core/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/apps/core/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps/core/apps.py b/apps/core/apps.py new file mode 100644 index 0000000..4143768 --- /dev/null +++ b/apps/core/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CoreConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'apps.core' diff --git a/apps/core/migrations/__init__.py b/apps/core/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/core/models.py b/apps/core/models.py new file mode 100644 index 0000000..158280a --- /dev/null +++ b/apps/core/models.py @@ -0,0 +1,9 @@ +# apps/core/models.py +from django.db import models + +class TimeStampedModel(models.Model): + created = models.DateTimeField(auto_now_add=True) + updated = models.DateTimeField(auto_now=True) + + class Meta: + abstract = True diff --git a/apps/core/tests.py b/apps/core/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/apps/core/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/core/views.py b/apps/core/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/apps/core/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/apps/participants/__init__.py b/apps/participants/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/participants/admin.py b/apps/participants/admin.py new file mode 100644 index 0000000..f701c10 --- /dev/null +++ b/apps/participants/admin.py @@ -0,0 +1,9 @@ +# apps/participants/admin.py +from django.contrib import admin +from .models import Participant # ✅ Participant es el único modelo en esta app + + +@admin.register(Participant) +class ParticipantAdmin(admin.ModelAdmin): + list_display = ("group_name", "score", "s_vol_over_eta") + readonly_fields = ("score",) diff --git a/apps/participants/apps.py b/apps/participants/apps.py new file mode 100644 index 0000000..dd961f2 --- /dev/null +++ b/apps/participants/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ParticipantsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'apps.participants' diff --git a/apps/participants/forms.py b/apps/participants/forms.py new file mode 100644 index 0000000..b748798 --- /dev/null +++ b/apps/participants/forms.py @@ -0,0 +1,10 @@ +from django import forms +from .models import Participant + +class ParticipantForm(forms.ModelForm): + class Meta: + model = Participant + fields = ["group_name","R_diff","L_diff","Ph_diff","Pcu_diff","s_vol_over_eta"] + widgets = {f: forms.NumberInput(attrs={"step": "0.1", "class": "input"}) + for f in fields if f!="group_name"} + widgets["group_name"]= forms.TextInput(attrs={"class":"input"}) diff --git a/apps/participants/migrations/0001_initial.py b/apps/participants/migrations/0001_initial.py new file mode 100644 index 0000000..0ad3bce --- /dev/null +++ b/apps/participants/migrations/0001_initial.py @@ -0,0 +1,32 @@ +# Generated by Django 4.2.4 on 2025-05-12 16:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Participant', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(auto_now_add=True)), + ('updated', models.DateTimeField(auto_now=True)), + ('group_name', models.CharField(max_length=80, unique=True)), + ('R_diff', models.FloatField()), + ('L_diff', models.FloatField()), + ('Ph_diff', models.FloatField()), + ('Pcu_diff', models.FloatField()), + ('s_vol_over_eta', models.FloatField(help_text='S*Vol/η')), + ('score', models.FloatField(default=0)), + ], + options={ + 'ordering': ['-score'], + }, + ), + ] diff --git a/apps/participants/migrations/__init__.py b/apps/participants/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/participants/models.py b/apps/participants/models.py new file mode 100644 index 0000000..11a3b34 --- /dev/null +++ b/apps/participants/models.py @@ -0,0 +1,21 @@ +# apps/participants/models.py +from django.db import models +from apps.core.models import TimeStampedModel + +class Participant(TimeStampedModel): + group_name = models.CharField(max_length=80, unique=True) + + # diffs en porcentaje + R_diff = models.FloatField() + L_diff = models.FloatField() + Ph_diff = models.FloatField() + Pcu_diff= models.FloatField() + + s_vol_over_eta = models.FloatField(help_text="S*Vol/η") # métrica objetiva + score = models.FloatField(default=0) + + class Meta: + ordering = ["-score"] + + def __str__(self): + return self.group_name diff --git a/apps/participants/services.py b/apps/participants/services.py new file mode 100644 index 0000000..0a36c65 --- /dev/null +++ b/apps/participants/services.py @@ -0,0 +1,39 @@ +# apps/participants/services.py +from django.db import transaction +from .models import Participant +from apps.settingsapp.models import GradingSettings + +def _factor(diff: float) -> float: + if diff <= 10: + return 1.0 + elif diff <= 20: + return 0.8 + return 0.6 + +def calculate_scores(): + """Recalcula y persiste 'score' para todos los participantes""" + settings = GradingSettings.get() + participants = list(Participant.objects.all()) + + # 1) Base Entregable + Presentación + for p in participants: + p.score = settings.report_weight + settings.presentation_weight + + # 2) Similitud + for diff, weight in [ + (p.R_diff, settings.R_weight), + (p.L_diff, settings.L_weight), + (p.Ph_diff, settings.Ph_weight), + (p.Pcu_diff,settings.Pcu_weight), + ]: + p.score += _factor(diff) * weight + + # 3) Objetivo (rank por métrica) + sorted_by_obj = sorted(participants, key=lambda x: x.s_vol_over_eta) + for idx, p in enumerate(sorted_by_obj, start=1): + p.score += max(settings.objective_weight - (idx - 1), 0) + + # 4) Persistimos en batch + with transaction.atomic(): + for p in participants: + p.save(update_fields=["score"]) diff --git a/apps/participants/tests.py b/apps/participants/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/apps/participants/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/participants/urls.py b/apps/participants/urls.py new file mode 100644 index 0000000..6ff159a --- /dev/null +++ b/apps/participants/urls.py @@ -0,0 +1,8 @@ +from django.urls import path +from .views import ParticipantCreateView, CalculateView, ResultsView + +urlpatterns = [ + path("", ParticipantCreateView.as_view(), name="participant_new"), + path("calcular/", CalculateView.as_view(), name="calculate"), + path("resultados/", ResultsView.as_view(), name="results"), +] diff --git a/apps/participants/views.py b/apps/participants/views.py new file mode 100644 index 0000000..46882f7 --- /dev/null +++ b/apps/participants/views.py @@ -0,0 +1,23 @@ +# apps/participants/views.py +from django.views.generic import ListView, CreateView, View, TemplateView +from django.urls import reverse_lazy +from django.shortcuts import redirect +from .models import Participant +from .forms import ParticipantForm +from .services import calculate_scores + +class ParticipantCreateView(CreateView): + model = Participant + form_class = ParticipantForm + template_name = "participants/form.html" + success_url = reverse_lazy("participant_new") # vuelve a sí misma + +class CalculateView(View): + def post(self, request, *args, **kwargs): + calculate_scores() + return redirect("results") + +class ResultsView(ListView): + model = Participant + template_name = "participants/results.html" + context_object_name = "participants" diff --git a/apps/scoring/__init__.py b/apps/scoring/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/scoring/admin.py b/apps/scoring/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/apps/scoring/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps/scoring/apps.py b/apps/scoring/apps.py new file mode 100644 index 0000000..e902cff --- /dev/null +++ b/apps/scoring/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ScoringConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'apps.scoring' diff --git a/apps/scoring/migrations/__init__.py b/apps/scoring/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/scoring/models.py b/apps/scoring/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/apps/scoring/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/apps/scoring/tests.py b/apps/scoring/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/apps/scoring/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/scoring/views.py b/apps/scoring/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/apps/scoring/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/apps/settingsapp/__init__.py b/apps/settingsapp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/settingsapp/admin.py b/apps/settingsapp/admin.py new file mode 100644 index 0000000..7651f87 --- /dev/null +++ b/apps/settingsapp/admin.py @@ -0,0 +1,9 @@ +# apps/settingsapp/admin.py +from django.contrib import admin +from .models import GradingSettings + + +@admin.register(GradingSettings) +class SettingsAdmin(admin.ModelAdmin): + def has_add_permission(self, *_): + return False # solo debe existir una instancia diff --git a/apps/settingsapp/apps.py b/apps/settingsapp/apps.py new file mode 100644 index 0000000..3fbf8ed --- /dev/null +++ b/apps/settingsapp/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class SettingsappConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'apps.settingsapp' diff --git a/apps/settingsapp/forms.py b/apps/settingsapp/forms.py new file mode 100644 index 0000000..b9909e7 --- /dev/null +++ b/apps/settingsapp/forms.py @@ -0,0 +1,9 @@ +from django import forms +from .models import GradingSettings + +class GradingSettingsForm(forms.ModelForm): + class Meta: + model = GradingSettings + fields = "__all__" + widgets = {f: forms.NumberInput(attrs={"step": "0.1", "class": "input"}) + for f in fields} diff --git a/apps/settingsapp/migrations/0001_initial.py b/apps/settingsapp/migrations/0001_initial.py new file mode 100644 index 0000000..72dd9ef --- /dev/null +++ b/apps/settingsapp/migrations/0001_initial.py @@ -0,0 +1,27 @@ +# Generated by Django 4.2.4 on 2025-05-12 16:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='GradingSettings', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('report_weight', models.FloatField(default=2)), + ('presentation_weight', models.FloatField(default=1)), + ('objective_weight', models.FloatField(default=3)), + ('R_weight', models.FloatField(default=1)), + ('L_weight', models.FloatField(default=1)), + ('Ph_weight', models.FloatField(default=1)), + ('Pcu_weight', models.FloatField(default=1)), + ], + ), + ] diff --git a/apps/settingsapp/migrations/__init__.py b/apps/settingsapp/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/settingsapp/models.py b/apps/settingsapp/models.py new file mode 100644 index 0000000..b44540d --- /dev/null +++ b/apps/settingsapp/models.py @@ -0,0 +1,29 @@ +# apps/settingsapp/models.py +from django.db import models +from django.core.exceptions import ValidationError + +class GradingSettings(models.Model): + # NOTAS + report_weight = models.FloatField(default=2) # Entregable + presentation_weight = models.FloatField(default=1) # Presentación + objective_weight = models.FloatField(default=3) # Objetivo max + + # SIMILITUD + R_weight = models.FloatField(default=1) + L_weight = models.FloatField(default=1) + Ph_weight = models.FloatField(default=1) + Pcu_weight= models.FloatField(default=1) + + def clean(self): + if GradingSettings.objects.exclude(pk=self.pk).exists(): + raise ValidationError("Solo puede existir un GradingSettings") + + def save(self, *args, **kwargs): + self.full_clean() + super().save(*args, **kwargs) + + @classmethod + def get(cls): + # devuelve la única instancia (la crea si no existe) + obj, _ = cls.objects.get_or_create(pk=1) + return obj diff --git a/apps/settingsapp/tests.py b/apps/settingsapp/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/apps/settingsapp/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/settingsapp/urls.py b/apps/settingsapp/urls.py new file mode 100644 index 0000000..7e26ba8 --- /dev/null +++ b/apps/settingsapp/urls.py @@ -0,0 +1,4 @@ +from django.urls import path +from .views import SettingsUpdateView + +urlpatterns = [ path("", SettingsUpdateView.as_view(), name="settings") ] diff --git a/apps/settingsapp/views.py b/apps/settingsapp/views.py new file mode 100644 index 0000000..3b5158b --- /dev/null +++ b/apps/settingsapp/views.py @@ -0,0 +1,16 @@ +from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin +from django.views.generic import UpdateView +from .models import GradingSettings +from .forms import GradingSettingsForm + +class SettingsUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView): + model = GradingSettings + form_class = GradingSettingsForm + template_name = "settingsapp/form.html" + success_url = "/" + + def get_object(self, queryset=None): + return GradingSettings.get() + + def test_func(self): + return self.request.user.is_staff diff --git a/dev/Trafoking.drawio b/dev/Trafoking.drawio new file mode 100644 index 0000000..5cc7798 --- /dev/null +++ b/dev/Trafoking.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/dev/TrafokingBack.pdf b/dev/TrafokingBack.pdf new file mode 100644 index 0000000..4dbdcdc Binary files /dev/null and b/dev/TrafokingBack.pdf differ diff --git a/dev/TrafokingFront.png b/dev/TrafokingFront.png new file mode 100644 index 0000000..bd003e3 Binary files /dev/null and b/dev/TrafokingFront.png differ diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..b67963f --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'trafoking.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..7d206ad --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +# requirements.txt +Django==4.2.4 +psycopg2-binary==2.9.* +python-dotenv==1.0.* +django-htmx==1.15.* +pytest==8.1.* +pytest-django==4.7.* diff --git a/templates/auth/login.html b/templates/auth/login.html new file mode 100644 index 0000000..3263493 --- /dev/null +++ b/templates/auth/login.html @@ -0,0 +1,9 @@ + +{% extends "base.html" %} +{% block content %} +
+ {% csrf_token %} + {{ form.as_p }} + +
+{% endblock %} diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..48f92bd --- /dev/null +++ b/templates/base.html @@ -0,0 +1,14 @@ + + + + + + Trafoking + + + + +

Trafoking ⚡👑

+ {% block content %}{% endblock %} + + diff --git a/templates/participants/form.html b/templates/participants/form.html new file mode 100644 index 0000000..fe29b37 --- /dev/null +++ b/templates/participants/form.html @@ -0,0 +1,22 @@ + +{% extends "base.html" %} +{% block content %} + + +
+ {% csrf_token %} + {{ form.as_p }} + +
+ + +
+ {% csrf_token %} + +
+ +{% endblock %} diff --git a/templates/participants/results.html b/templates/participants/results.html new file mode 100644 index 0000000..8f56a07 --- /dev/null +++ b/templates/participants/results.html @@ -0,0 +1,18 @@ + +{% extends "base.html" %} +{% block content %} + + + + {% for p in participants %} + + + + + + {% empty %} + + {% endfor %} + +
#GrupoPuntuación
{{ forloop.counter }}{{ p.group_name }}{{ p.score|floatformat:2 }}
Sin participantes todavía.
+{% endblock %} diff --git a/templates/settingsapp/form.html b/templates/settingsapp/form.html new file mode 100644 index 0000000..7508849 --- /dev/null +++ b/templates/settingsapp/form.html @@ -0,0 +1,10 @@ + +{% extends "base.html" %} +{% block content %} +

Ajustes de calificación

+
+ {% csrf_token %} + {{ form.as_p }} + +
+{% endblock %} diff --git a/trafoking/__init__.py b/trafoking/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/trafoking/asgi.py b/trafoking/asgi.py new file mode 100644 index 0000000..1a2fc40 --- /dev/null +++ b/trafoking/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for trafoking project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'trafoking.settings') + +application = get_asgi_application() diff --git a/trafoking/settings.py b/trafoking/settings.py new file mode 100644 index 0000000..bf8d3d5 --- /dev/null +++ b/trafoking/settings.py @@ -0,0 +1,85 @@ +# trafoking/settings.py +import os +from pathlib import Path +from dotenv import load_dotenv + +load_dotenv() + +BASE_DIR = Path(__file__).resolve().parent.parent +SECRET_KEY = os.getenv("DJANGO_SECRET_KEY") +DEBUG = False +ALLOWED_HOSTS = ["*"] + +INSTALLED_APPS = [ + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "django_htmx", + "apps.core", + "apps.participants", + "apps.settingsapp", +] + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django_htmx.middleware.HtmxMiddleware", +] + +ROOT_URLCONF = "trafoking.urls" +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [BASE_DIR / "templates"], + "APP_DIRS": True, + "OPTIONS": {"context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ]}, + } +] +WSGI_APPLICATION = "trafoking.wsgi.application" + +DB_ENGINE = os.getenv("DB_ENGINE", "sqlite") # sqlite | postgres +if DB_ENGINE == "postgres": + DATABASES = { + "default": { + "ENGINE": "django.db.backends.postgresql", + "NAME": os.getenv("DB_NAME", "trafoking"), + "USER": os.getenv("DB_USER", "postgres"), + "PASSWORD": os.getenv("DB_PASSWORD", "postgres"), + "HOST": os.getenv("DB_HOST", "db"), + "PORT": os.getenv("DB_PORT", "5432"), + } + } +else: # SQLite por defecto + DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", + } + } + +AUTH_PASSWORD_VALIDATORS = [ + {"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"}, + {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"}, +] + +LANGUAGE_CODE = "es-es" +TIME_ZONE = "Europe/Madrid" +USE_I18N = USE_L10N = USE_TZ = True + +STATIC_URL = "/static/" +STATIC_ROOT = BASE_DIR / "staticfiles" +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" +LOGIN_URL = "/login/" +LOGIN_REDIRECT_URL = "/" diff --git a/trafoking/urls.py b/trafoking/urls.py new file mode 100644 index 0000000..4241f38 --- /dev/null +++ b/trafoking/urls.py @@ -0,0 +1,11 @@ +from django.contrib import admin +from django.urls import path, include +from django.contrib.auth.views import LoginView, LogoutView + +urlpatterns = [ + path("admin/", admin.site.urls), + path("login/", LoginView.as_view(template_name="auth/login.html"), name="login"), + path("logout/", LogoutView.as_view(), name="logout"), + path("", include("apps.participants.urls")), + path("ajustes/", include("apps.settingsapp.urls")), +] diff --git a/trafoking/wsgi.py b/trafoking/wsgi.py new file mode 100644 index 0000000..c5cceff --- /dev/null +++ b/trafoking/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for trafoking project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'trafoking.settings') + +application = get_wsgi_application()