feat Edición de los campos de una solicitud

parent 008a8a6a
......@@ -14,6 +14,7 @@ social-auth-core = {extras = ["saml"],version = "*"}
python3-saml = "*"
cx-oracle = "*"
django-crispy-forms = "==1.7.2"
django-summernote = "*"
[requires]
python_version = "3.7"
{
"_meta": {
"hash": {
"sha256": "d85ca5d04a37c94a2b3bcfd36a8e581e9a46b7880017b6843060dcba9df97075"
"sha256": "d05b213f72d834190887aacdb1240dc219142503a1657ec9143dad55bb4ed62d"
},
"pipfile-spec": 6,
"requires": {
......@@ -74,6 +74,13 @@
"index": "pypi",
"version": "==1.7.2"
},
"django-summernote": {
"hashes": [
"sha256:7e2a7cfa806dba508aceee872a7a556b0f86ebcc176f9c3951d4ae56871de609"
],
"index": "pypi",
"version": "==0.8.11.4"
},
"idna": {
"hashes": [
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
......@@ -90,34 +97,34 @@
},
"lxml": {
"hashes": [
"sha256:0358b9e9642bc7d39aac5cffe9884a99a5ca68e5e2c1b89e570ed60da9139908",
"sha256:091a359c4dafebbecd3959d9013f1b896b5371859165e4e50b01607a98d9e3e2",
"sha256:1998e4e60603c64bcc35af61b4331ab3af087457900d3980e18d190e17c3a697",
"sha256:2000b4088dee9a41f459fddaf6609bba48a435ce6374bb254c5ccdaa8928c5ba",
"sha256:2afb0064780d8aaf165875be5898c1866766e56175714fa5f9d055433e92d41d",
"sha256:2d8f1d9334a4e3ff176d096c14ded3100547d73440683567d85b8842a53180bb",
"sha256:2e38db22f6a3199fd63675e1b4bd795d676d906869047398f29f38ca55cb453a",
"sha256:3181f84649c1a1ca62b19ddf28436b1b2cb05ae6c7d2628f33872e713994c364",
"sha256:37462170dfd88af8431d04de6b236e6e9c06cda71e2ca26d88ef2332fd2a5237",
"sha256:3a9d8521c89bf6f2a929c3d12ad3ad7392c774c327ea809fd08a13be6b3bc05f",
"sha256:3d0bbd2e1a28b4429f24fd63a122a450ce9edb7a8063d070790092d7343a1aa4",
"sha256:483d60585ce3ee71929cea70949059f83850fa5e12deb9c094ed1c8c2ec73cbd",
"sha256:4888be27d5cba55ce94209baef5bcd7bbd7314a3d17021a5fc10000b3a5f737d",
"sha256:64b0d62e4209170a2a0c404c446ab83b941a0003e96604d2e4f4cb735f8a2254",
"sha256:68010900898fdf139ac08549c4dba8206c584070a960ffc530aebf0c6f2794ef",
"sha256:872ecb066de602a0099db98bd9e57f4cfc1d62f6093d94460c787737aa08f39e",
"sha256:88a32b03f2e4cd0e63f154cac76724709f40b3fc2f30139eb5d6f900521b44ed",
"sha256:b1dc7683da4e67ab2bebf266afa68098d681ae02ce570f0d1117312273d2b2ac",
"sha256:b29e27ce9371810250cb1528a771d047a9c7b0f79630dc7dc5815ff828f4273b",
"sha256:ce197559596370d985f1ce6b7051b52126849d8159040293bf8b98cb2b3e1f78",
"sha256:d45cf6daaf22584eff2175f48f82c4aa24d8e72a44913c5aff801819bb73d11f",
"sha256:e2ff9496322b2ce947ba4a7a5eb048158de9d6f3fe9efce29f1e8dd6878561e6",
"sha256:f7b979518ec1f294a41a707c007d54d0f3b3e1fd15d5b26b7e99b62b10d9a72e",
"sha256:f9c7268e9d16e34e50f8246c4f24cf7353764affd2bc971f0379514c246e3f6b",
"sha256:f9c839806089d79de588ee1dde2dae05dc1156d3355dfeb2b51fde84d9c960ad",
"sha256:ff962953e2389226adc4d355e34a98b0b800984399153c6678f2367b11b4d4b8"
],
"version": "==4.3.2"
"sha256:03984196d00670b2ab14ae0ea83d5cc0cfa4f5a42558afa9ab5fa745995328f5",
"sha256:0815b0c9f897468de6a386dc15917a0becf48cc92425613aa8bbfc7f0f82951f",
"sha256:175f3825f075cf02d15099eb52658457cf0ff103dcf11512b5d2583e1d40f58b",
"sha256:30e14c62d88d1e01a26936ecd1c6e784d4afc9aa002bba4321c5897937112616",
"sha256:3210da6f36cf4b835ff1be853962b22cc354d506f493b67a4303c88bbb40d57b",
"sha256:40f60819fbd5bad6e191ba1329bfafa09ab7f3f174b3d034d413ef5266963294",
"sha256:43b26a865a61549919f8a42e094dfdb62847113cf776d84bd6b60e4e3fc20ea3",
"sha256:4a03dd682f8e35a10234904e0b9508d705ff98cf962c5851ed052e9340df3d90",
"sha256:62f382cddf3d2e52cf266e161aa522d54fd624b8cc567bc18f573d9d50d40e8e",
"sha256:7b98f0325be8450da70aa4a796c4f06852949fe031878b4aa1d6c417a412f314",
"sha256:846a0739e595871041385d86d12af4b6999f921359b38affb99cdd6b54219a8f",
"sha256:a3080470559938a09a5d0ec558c005282e99ac77bf8211fb7b9a5c66390acd8d",
"sha256:ad841b78a476623955da270ab8d207c3c694aa5eba71f4792f65926dc46c6ee8",
"sha256:afdd75d9735e44c639ffd6258ce04a2de3b208f148072c02478162d0944d9da3",
"sha256:b4fbf9b552faff54742bcd0791ab1da5863363fb19047e68f6592be1ac2dab33",
"sha256:b90c4e32d6ec089d3fa3518436bdf5ce4d902a0787dbd9bb09f37afe8b994317",
"sha256:b91cfe4438c741aeff662d413fd2808ac901cc6229c838236840d11de4586d63",
"sha256:bdb0593a42070b0a5f138b79b872289ee73c8e25b3f0bea6564e795b55b6bcdd",
"sha256:c4e4bca2bb68ce22320297dfa1a7bf070a5b20bcbaec4ee023f83d2f6e76496f",
"sha256:cec4ab14af9eae8501be3266ff50c3c2aecc017ba1e86c160209bb4f0423df6a",
"sha256:e83b4b2bf029f5104bc1227dbb7bf5ace6fd8fabaebffcd4f8106fafc69fc45f",
"sha256:e995b3734a46d41ae60b6097f7c51ba9958648c6d1e0935b7e0ee446ee4abe22",
"sha256:f679d93dec7f7210575c85379a31322df4c46496f184ef650d3aba1484b38a2d",
"sha256:fd213bb5166e46974f113c8228daaef1732abc47cb561ce9c4c8eaed4bd3b09b",
"sha256:fdcb57b906dbc1f80666e6290e794ab8fb959a2e17aa5aee1758a85d1da4533f",
"sha256:ff424b01d090ffe1947ec7432b07f536912e0300458f9a7f48ea217dd8362b86"
],
"version": "==4.3.3"
},
"mysqlclient": {
"hashes": [
......@@ -137,10 +144,10 @@
},
"pkgconfig": {
"hashes": [
"sha256:048c3b457da7b6f686b647ab10bf09e2250e4c50acfe6f215398a8b5e6fcdb52",
"sha256:3eb03a6345d4916489d3433f60e6d044a21f50e1d86fb611a52fd28061582065"
"sha256:97bfe3d981bab675d5ea3ef259045d7919c93897db7d3b59d4e8593cba8d354f",
"sha256:cddf2d7ecadb272178a942eb852a9dee46bda2adcc36c3416b0fef47a4ed9f38"
],
"version": "==1.4.0"
"version": "==1.5.1"
},
"pyjwt": {
"hashes": [
......@@ -239,10 +246,10 @@
},
"isort": {
"hashes": [
"sha256:18c796c2cd35eb1a1d3f012a214a542790a1aed95e29768bdcb9f2197eccbd0b",
"sha256:96151fca2c6e736503981896495d344781b60d18bfda78dc11b290c6125ebdb6"
"sha256:01cb7e1ca5e6c5b3f235f0385057f70558b70d2f00320208825fa62887292f43",
"sha256:268067462aed7eb2a1e237fcb287852f22077de3fb07964e87e00f829eea2d1a"
],
"version": "==4.3.15"
"version": "==4.3.17"
},
"lazy-object-proxy": {
"hashes": [
......
This diff is collapsed.
This diff is collapsed.
......@@ -11,3 +11,15 @@ def lord_url():
base=reverse("social:begin", kwargs={"backend": "saml"}),
params=urllib.parse.urlencode({"next": "/", "idp": "lord"}),
)
@register.filter
def get_obj_attr(obj, attr):
"""Devuelve el valor del atributo `attr` del objeto `obj`"""
return getattr(obj, attr)
@register.filter
def get_attr_verbose_name(obj, attr):
"""Devuelve el nombre prolijo del atributo indicado"""
return obj._meta.get_field(attr).verbose_name
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
from django.urls import include, path
# from . import views
from .views import AyudaView, HomePageView, ProyectoCreateView, ProyectoDetailView
from .views import (
AyudaView,
HomePageView,
ProyectoCreateView,
ProyectoDetailView,
ProyectoUpdateFieldView,
)
urlpatterns = [
path("", HomePageView.as_view(), name="home"),
path("summernote/", include("django_summernote.urls")),
path("ayuda/", AyudaView.as_view(), name="ayuda"),
path("proyecto/new/", ProyectoCreateView.as_view(), name="proyecto_new"),
path("proyecto/<int:pk>/", ProyectoDetailView.as_view(), name="proyecto_detail"),
path(
"proyecto/<int:pk>/edit/<campo>",
ProyectoUpdateFieldView.as_view(),
name="proyecto_update_field",
),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
import json
from django.contrib.auth.mixins import LoginRequiredMixin
from django.forms.models import modelform_factory
from django.http.response import HttpResponse
from django.shortcuts import render, redirect
from django.urls import reverse_lazy
......@@ -12,6 +14,7 @@ from django.views.generic import (
FormView,
)
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django_summernote.widgets import SummernoteWidget
from .models import (
Convocatoria,
......@@ -34,6 +37,10 @@ class HomePageView(TemplateView):
class ProyectoCreateView(LoginRequiredMixin, CreateView):
"""Crea una nueva solicitud de proyecto"""
# TODO: Comprobar usuario para Proyectos de titulación y POU.
# TODO: Comprobar fecha
# TODO: Check programa/linea
model = Proyecto
template_name = "proyecto/new.html"
fields = ["titulo", "descripcion", "programa", "linea", "centro", "estudio"]
......@@ -72,6 +79,10 @@ class ProyectoCreateView(LoginRequiredMixin, CreateView):
class ProyectoDetailView(DetailView):
"""Muestra una solicitud de proyecto."""
# TODO: Comprobar permisos
# - Coordinadores, participantes/invitados, evaluadores. Gestores.
model = Proyecto
template_name = "proyecto/detail.html"
......@@ -86,4 +97,33 @@ class ProyectoDetailView(DetailView):
coordinador = self.object.get_participante_or_none("coordinador")
context["coordinador"] = coordinador
context["campos"] = json.loads(self.object.programa.campos)
return context
class ProyectoUpdateFieldView(LoginRequiredMixin, UpdateView):
# TODO: Comprobar permisos - coordinadores
# Modificar estado, sólo para gestores
# No permitir modificar convocatoria, etc
# TODO: Comprobar estado/fecha
model = Proyecto
template_name = "proyecto/update.html"
def get_form_class(self, **kwargs):
campo = self.kwargs["campo"]
if campo not in (
"centro",
"convocatoria",
"departamento",
"licencia",
"linea",
"programa",
"ayuda",
"estado",
):
return modelform_factory(
Proyecto, fields=(campo,), widgets={campo: SummernoteWidget()}
)
self.fields = (campo,)
return super().get_form_class()
{% extends 'base.html' %}
{% load custom_tags %}
{% block content %}
<div class="container-blanco">
<h1>{{ proyecto.titulo }}</h1> {# Our context object, proyecto, is made available by DetailView #}
<div class='alert alert-info'>
<i class="fas fa-info-circle"></i>
<div>Puede editar su solicitud tantas veces como desee.</br>
Cuando esté satisfecho, pulse el botón «Presentar».
Una vez haya presentado la solicitud, ya no podrá modificarla.
</div>
</div>
<h1>{{ proyecto.titulo }}</h1> {# DetailView proporciona el objeto de contexto `proyecto` #}
<hr><br>
<p><strong>Convocatoria</strong>: {{ proyecto.convocatoria_id }}</p>
......@@ -28,8 +37,23 @@
<p><strong>{{ coordinador.get_cargo }}</strong>: {{ coordinador.usuario.get_full_name }}</p>
{% endif %}
{# TODO: filtro para HTML procedente de procesador de textos #}
<h3>Descripción</h3>
<p>{{ proyecto.descripcion }}</p>
<p>{{ proyecto.descripcion|safe }}</p>
{% for campo in campos %}
<h3>{{ proyecto|get_attr_verbose_name:campo }}</h3>
<p>{{ proyecto|get_obj_attr:campo|default:""|safe }}</p>
<p><a href="edit/{{ campo }}" class="btn btn-info btn-sm">
<i class="fas fa-pencil-alt" aria-hidden="true"></i> &nbsp; Editar
</a></p>
{% endfor %}
<h3>{{ proyecto|get_attr_verbose_name:"financiacion"}}</h3>
<p>{{ proyecto.financiacion|default:""|safe }}</p>
<h3>{{ proyecto|get_attr_verbose_name:"ayuda"}}</h3>
<p>{{ proyecto.ayuda|default:"" }}</p>
</div>
{% endblock content %}
\ No newline at end of file
......@@ -7,8 +7,10 @@
<div class="container-blanco">
<div class='alert alert-info'>
<i class="fas fa-info-circle"></i>
<div>Introduzca los datos básicos de su solicitud.</br>
En la siguiente página se le solicitará más información.
<div>Introduzca los datos básicos de su proyecto.<br>
Se creará un <b>borrador</b> de solicitud, en el que posteriormente podrá añadir o modificar la
información.<br>
Finalmente, podrá presentarla pulsando el botón «Presentar».
</div>
</div>
......@@ -18,7 +20,7 @@
<form action="" method="post">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-success" type="submit">Guardar</button>
<button class="btn btn-success" type="submit">Crear</button>
</form>
</div>
{% endblock content %}
\ No newline at end of file
{% extends 'base.html' %}
{% block title %}Actualizar solicitud de proyecto{% endblock title %}
{% block description %}Actualizar solicitud de proyecto{% endblock description %}
{% block extracss %}<style>
label {
font-size: 1.75rem;
font-weight: 500;
line-height: 1.2;
margin-bottom: 0.5rem;
margin-top: 0;
}
.helptext {
color: #6c757d !important;
}
</style>{% endblock extracss %}
{% block content %}
<div class="container-blanco">
<h1>Actualizar solicitud de proyecto</h1>
<hr><br>
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<br style="clear: both;">
<button class="btn btn-success" type="submit">Actualizar</button>
</form>
</div>
{% endblock content %}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment