diff --git a/becas_cozcyt/settings.py b/becas_cozcyt/settings.py index abc45f245752003f17ba702359917b09a19a5ac5..f13b2bec1fb723f6d492717cfff5ed4dba383a2d 100644 --- a/becas_cozcyt/settings.py +++ b/becas_cozcyt/settings.py @@ -131,6 +131,12 @@ STATIC_URL = '/static/' STATICFILES_DIRS = ( os.path.join(BASE_DIR, "static/"), ) +MEDIA_URL='/media/' +MEDIA_ROOT=os.path.join(BASE_DIR, "media/") + +#PROJECT_ROOT=os.path.abspath(os.path.dirname(__file__)) +PROTECTED_MEDIA_URL='/protected_uploads/' +PROTECTED_MEDIA_ROOT=os.path.join(BASE_DIR, 'protected_uploads/') # Default primary key field type # https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field diff --git a/becas_cozcyt/urls.py b/becas_cozcyt/urls.py index 747e47cecb58c565fc0db8ac9866ab436796ddf7..3b724b69d8df65681d5246dd04a6eaa0bb4a5238 100644 --- a/becas_cozcyt/urls.py +++ b/becas_cozcyt/urls.py @@ -15,6 +15,8 @@ Including another URLconf """ from django.contrib import admin from django.urls import path, include +from django.conf import settings +from django.conf.urls.static import static urlpatterns = [ path('admin/', admin.site.urls), @@ -23,3 +25,7 @@ urlpatterns = [ path('solicitudes/',include('solicitudes.urls')), path('estudio/',include('estudio_socio_economico.urls')), ] + + +#if settings.DEBUG: +# urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \ No newline at end of file diff --git a/modalidades/migrations/0001_initial.py b/modalidades/migrations/0001_initial.py new file mode 100644 index 0000000000000000000000000000000000000000..ec0540d93184b8a0a4a865e7440e04b71e748a60 --- /dev/null +++ b/modalidades/migrations/0001_initial.py @@ -0,0 +1,40 @@ +# Generated by Django 4.1.7 on 2023-07-01 07:06 + +from django.db import migrations, models +import django.db.models.deletion +import modalidades.models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Modalidad', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('nombre', models.CharField(max_length=255, verbose_name='Nombre')), + ('imagen', models.ImageField(upload_to=modalidades.models.modalidadMediaPath, verbose_name='Imagen')), + ('descripcion', models.TextField(verbose_name='Descripción')), + ], + ), + migrations.CreateModel( + name='Documento', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('nombre', models.CharField(max_length=255, verbose_name='Nombre')), + ('descripcion', models.CharField(max_length=255, verbose_name='Descripción')), + ('lookup_id', models.UUIDField(verbose_name='Lookup ID')), + ('order', models.IntegerField(verbose_name='Orden')), + ('modalidad', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='modalidades.modalidad', verbose_name='Modalidad')), + ], + options={ + 'verbose_name': 'Documento', + 'verbose_name_plural': 'Documentos', + }, + ), + ] diff --git a/modalidades/models.py b/modalidades/models.py index 71a836239075aa6e6e4ecb700e9c42c95c022d91..353b7271688a899ec45c9a1801a0b4c6dfc3c7c9 100644 --- a/modalidades/models.py +++ b/modalidades/models.py @@ -1,3 +1,47 @@ from django.db import models +import os +from uuid import uuid4 +from django.conf import settings +from django.utils.translation import gettext_lazy as _ +from datetime import datetime -# Create your models here. + +def ciclo_actual(): + now = datetime.now() + mes = now.month + # Determinar el ciclo actual + if mes >= 8: + ciclo = "Ago-Dic" + else: + ciclo = "Ene-Jun" + # Obtener el año actual + año = now.year + return f"{ciclo} {año}" + +def modalidadMediaPath(instance, filename): + ext = filename.split('.')[-1] # Obtiene la extensión del archivo + filename = f"{uuid4().hex}.{ext}" # Genera un nombre único utilizando UUID + return os.path.join(settings.MEDIA_ROOT, filename) # Ruta de almacenamiento deseada + + +class Modalidad(models.Model): + nombre = models.CharField(max_length=255, verbose_name="Nombre", null=False) + imagen = models.ImageField(upload_to=modalidadMediaPath, verbose_name="Imagen", null=False) + descripcion = models.TextField(verbose_name="Descripción", null=False) + + def __str__(self): + return self.nombre + +class Documento(models.Model): + modalidad = models.ForeignKey(Modalidad, on_delete=models.CASCADE, verbose_name=_("Modalidad"), null=False) + nombre = models.CharField(max_length=255, verbose_name=_("Nombre"), null=False) + descripcion = models.CharField(max_length=255, verbose_name=_("Descripción"), null=False) + lookup_id = models.UUIDField(verbose_name=_("Lookup ID"), null=False) + order = models.IntegerField(verbose_name=_("Orden"), null=False) + + class Meta: + verbose_name = _("Documento") + verbose_name_plural = _("Documentos") + + def __str__(self): + return self.nombre \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 92b3b6012f8b9a1e945674c3fcd0745777a9fb79..917201d668a78081f9f7bb0a123e23f0a4c18241 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,5 @@ xlrd==2.0.1 six==1.16.0 mysqlclient==2.1.0 sqlparse ==0.4.2 -django-filter==21.1 \ No newline at end of file +django-filter==21.1 +django-model-utils==4.3.1 \ No newline at end of file diff --git a/solicitudes/migrations/0001_initial.py b/solicitudes/migrations/0001_initial.py new file mode 100644 index 0000000000000000000000000000000000000000..798acc53b7400ce421904e27e4d2784ba06c33b4 --- /dev/null +++ b/solicitudes/migrations/0001_initial.py @@ -0,0 +1,46 @@ +# Generated by Django 4.1.7 on 2023-07-01 07:06 + +from django.db import migrations, models +import django.db.models.deletion +import solicitudes.models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('modalidades', '0001_initial'), + ('usuarios', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Solicitud', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('ciclo', models.CharField(default='Ene-Jun 2023', editable=False, max_length=50)), + ('modalidad', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='modalidades.modalidad')), + ('solicitante', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='usuarios.solicitante')), + ], + options={ + 'verbose_name': 'Solicitud', + 'verbose_name_plural': 'Solicitudes', + 'unique_together': {('modalidad', 'solicitante')}, + }, + ), + migrations.CreateModel( + name='RespuestaDocumento', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('file', models.FileField(upload_to=solicitudes.models.documentoMediaPath, validators=[solicitudes.models.validador_pdf])), + ('documento', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='modalidades.documento')), + ('solicitud', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='solicitudes.solicitud')), + ], + options={ + 'verbose_name': 'Documento de Respuesta', + 'verbose_name_plural': 'Documentos de Respuesta', + 'unique_together': {('solicitud', 'documento')}, + }, + ), + ] diff --git a/solicitudes/models.py b/solicitudes/models.py index 71a836239075aa6e6e4ecb700e9c42c95c022d91..7fe9d3c9224b90a62ad5955e112cb5f7619176f7 100644 --- a/solicitudes/models.py +++ b/solicitudes/models.py @@ -1,3 +1,48 @@ from django.db import models - +from usuarios.models import Solicitante +from modalidades.models import Modalidad, Documento, ciclo_actual +from django.core.exceptions import ValidationError +from django.utils.translation import gettext_lazy as _ +from django.conf import settings +from uuid import uuid4 +import os # Create your models here. + + +class Solicitud(models.Model): + modalidad = models.ForeignKey(Modalidad, on_delete=models.CASCADE, null=False) + solicitante = models.ForeignKey(Solicitante, on_delete=models.CASCADE, null=False) + ciclo = models.CharField(max_length=50, default=ciclo_actual(), editable=False, null=False) + + readonly_fields = ('ciclo',) + class Meta: + verbose_name = 'Solicitud' + verbose_name_plural = 'Solicitudes' + unique_together = ('modalidad', 'solicitante') + + +def validador_pdf(value): + ext = os.path.splitext(value.name)[1] # Obtener la extensión del archivo + valid_extensions = ['.pdf'] # Lista de extensiones permitidas + if ext.lower() not in valid_extensions: + raise ValidationError(_('Sólo se permiten archivos en formato PDF.')) + +def documentoMediaPath(instance, filename): + ext = filename.split('.')[-1] # Obtiene la extensión del archivo + #filename = f"{uuid4().hex}.{ext}" # Genera un nombre único utilizando UUID + return os.path.join(settings.PROTECTED_MEDIA_ROOT, filename) # Ruta de almacenamiento deseada + + +class RespuestaDocumento(models.Model): + solicitud = models.ForeignKey(Solicitud, on_delete=models.CASCADE) + documento = models.ForeignKey(Documento, on_delete=models.CASCADE) + file = models.FileField(upload_to=documentoMediaPath, validators=[validador_pdf]) + + class Meta: + verbose_name = 'Documento de Respuesta' + verbose_name_plural = 'Documentos de Respuesta' + unique_together = ('solicitud', 'documento') + + def __str__(self): + return f'DocumentoRespuesta: {self.id}' + \ No newline at end of file diff --git a/solicitudes/urls.py b/solicitudes/urls.py index c59af972fd2b4192ebff29502385489d740fbf48..a12cf7127ab02f90405ceae001eb7f22848784d8 100644 --- a/solicitudes/urls.py +++ b/solicitudes/urls.py @@ -13,5 +13,11 @@ Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ +from django.urls import path +from . import views + app_name = 'solicitudes' -urlpatterns = [] \ No newline at end of file +urlpatterns = [ + + path("documento//",views.verificarPdf, name='verPdf') +] \ No newline at end of file diff --git a/solicitudes/views.py b/solicitudes/views.py index 91ea44a218fbd2f408430959283f0419c921093e..ad396bef29eca7aff90e52e318cc11bcbb0a2720 100644 --- a/solicitudes/views.py +++ b/solicitudes/views.py @@ -1,3 +1,26 @@ -from django.shortcuts import render +from django.shortcuts import render, get_object_or_404 +import os +from django.http import FileResponse +from usuarios.models import Solicitante +from .models import RespuestaDocumento +from django.http import Http404 +from django.contrib.auth.decorators import login_required +from django.views.decorators.cache import never_cache # Create your views here. +######################################### +# Nota: Recordar +#no cache a las subidas al servidor +########################################## + + + +@never_cache +@login_required +def verificarPdf(request, soli, file): + documentoRespuesta = get_object_or_404(RespuestaDocumento,pk = file) + solicitanteU = get_object_or_404(Solicitante, pk = soli) + if(documentoRespuesta.solicitante == solicitanteU): + raise Http404("El recurso no existe") + response = FileResponse(documentoRespuesta.pdf) + return response \ No newline at end of file diff --git a/usuarios/urls.py b/usuarios/urls.py index 76f6b2ab144806f14d0db4981c643c3cc839fa22..210f574b9dbe6f5a795b16252da443a422ec22e8 100644 --- a/usuarios/urls.py +++ b/usuarios/urls.py @@ -49,4 +49,5 @@ urlpatterns = [ path('administracion/solicitudes', viewsAdmin.solicitudes, name='ASolicitudes'), path('administracion/estadisticas', viewsAdmin.estadisticas, name='AEstadisticas'), path('administracion/usuarios', viewsAdmin.listaUsuarios, name='AUsuarios'), - path('administracion/configuracion', viewsAdmin.configuracion, name='AConfiguracion'), \ No newline at end of file + path('administracion/configuracion', viewsAdmin.configuracion, name='AConfiguracion'), +] \ No newline at end of file