Browse Source

Integração SIGI x Saberes

pull/163/head
Sesostris Vieira 2 years ago
parent
commit
41fe440e5b
  1. 2
      docker/Dockerfile
  2. 1
      requirements/requirements.txt
  3. 209
      sigi/apps/eventos/admin.py
  4. 5
      sigi/apps/eventos/admin_urls.py
  5. 2
      sigi/apps/eventos/forms.py
  6. 22
      sigi/apps/eventos/migrations/0031_evento_moodle_courseid.py
  7. 33
      sigi/apps/eventos/migrations/0032_set_moodle_courseid.py
  8. 16
      sigi/apps/eventos/migrations/0033_remove_evento_link_inscricao.py
  9. 42
      sigi/apps/eventos/migrations/0034_funcao_moodle_roleid_tipoevento_moodle_categoryid_and_more.py
  10. 23
      sigi/apps/eventos/migrations/0035_alter_evento_options.py
  11. 47
      sigi/apps/eventos/models.py
  12. 21
      sigi/apps/eventos/templates/admin/eventos/evento/change_form.html
  13. 52
      sigi/apps/eventos/templates/admin/eventos/evento/createcourse.html
  14. 5
      sigi/apps/eventos/templates/admin/eventos/evento/seleciona_modelo.html
  15. 59
      sigi/apps/eventos/views.py
  16. 1
      sigi/apps/servidores/admin.py
  17. 22
      sigi/apps/servidores/migrations/0013_servidor_moodle_userid.py
  18. 7
      sigi/apps/servidores/models.py
  19. 6
      sigi/apps/utils/__init__.py
  20. 5
      sigi/settings.py

2
docker/Dockerfile

@ -39,6 +39,8 @@ ENV AUTH_LDAP_MIRROR_GROUPS=''
ENV AUTH_LDAP_CACHE_GROUPS='' ENV AUTH_LDAP_CACHE_GROUPS=''
ENV AUTH_LDAP_GROUP_CACHE_TIMEOUT='' ENV AUTH_LDAP_GROUP_CACHE_TIMEOUT=''
ENV AUTH_PROFILE_MODULE='' ENV AUTH_PROFILE_MODULE=''
ENV MOODLE_BASE_URL=''
ENV MOODLE_API_TOKEN=''
# Install env # Install env
ENV RUN_PACKAGES gcc locales build-essential python3-dev graphviz \ ENV RUN_PACKAGES gcc locales build-essential python3-dev graphviz \

1
requirements/requirements.txt

@ -3,6 +3,7 @@ docutils==0.19
gunicorn==20.1.0 gunicorn==20.1.0
ibge==0.0.5 ibge==0.0.5
ipython==8.11.0 ipython==8.11.0
moodlepy==0.23.10
pandas==1.5.3 pandas==1.5.3
Pillow==9.4.0 Pillow==9.4.0
psycopg2-binary==2.9.5 psycopg2-binary==2.9.5

209
sigi/apps/eventos/admin.py

@ -1,14 +1,20 @@
import datetime import datetime
from django.contrib import admin import time
from django.http import HttpResponseRedirect from moodle import Moodle
from django.shortcuts import get_object_or_404, render from django.conf import settings
from django.urls import path from django.contrib import admin, messages
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, render, redirect
from django.template import Template, Context
from django.urls import path, reverse
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from django_weasyprint.utils import django_url_fetcher
from django_weasyprint.views import WeasyTemplateResponse from django_weasyprint.views import WeasyTemplateResponse
from import_export.fields import Field from import_export.fields import Field
from tinymce.models import HTMLField from tinymce.models import HTMLField
from tinymce.widgets import AdminTinyMCE from tinymce.widgets import AdminTinyMCE
from weasyprint import HTML
from sigi.apps.eventos.models import ( from sigi.apps.eventos.models import (
Checklist, Checklist,
Cronograma, Cronograma,
@ -21,7 +27,8 @@ from sigi.apps.eventos.models import (
Convite, Convite,
Anexo, Anexo,
) )
from sigi.apps.eventos.forms import EventoAdminForm from sigi.apps.eventos.forms import EventoAdminForm, SelecionaModeloForm
from sigi.apps.utils import abreviatura
from sigi.apps.utils.filters import EmptyFilter, DateRangeFilter from sigi.apps.utils.filters import EmptyFilter, DateRangeFilter
from sigi.apps.utils.mixins import CartExportMixin, ValueLabeledResource from sigi.apps.utils.mixins import CartExportMixin, ValueLabeledResource
@ -205,6 +212,21 @@ class EventoAdmin(CartExportMixin, admin.ModelAdmin):
else: else:
return "" return ""
def render_change_form(self, request, context, add, change, form_url, obj):
context.update(
{
"can_createcourse": request.user.has_perm(
"eventos.createcourse_evento"
)
and obj.moodle_courseid is None
and obj.tipo_evento.moodle_template_courseid is not None
and obj.tipo_evento.moodle_categoryid is not None
}
)
return super().render_change_form(
request, context, add, change, form_url, obj
)
def lookup_allowed(self, lookup, value): def lookup_allowed(self, lookup, value):
return super(EventoAdmin, self).lookup_allowed( return super(EventoAdmin, self).lookup_allowed(
lookup, value lookup, value
@ -216,6 +238,11 @@ class EventoAdmin(CartExportMixin, admin.ModelAdmin):
def get_urls(self): def get_urls(self):
urls = super().get_urls() urls = super().get_urls()
my_urls = [ my_urls = [
path(
"<path:object_id>/declaracao/",
self.admin_site.admin_view(self.declaracao_report),
name="%s_%s_declaracaoreport" % self.get_model_info(),
),
path( path(
"<path:object_id>/gant/", "<path:object_id>/gant/",
self.admin_site.admin_view(self.gant_report), self.admin_site.admin_view(self.gant_report),
@ -231,9 +258,75 @@ class EventoAdmin(CartExportMixin, admin.ModelAdmin):
self.admin_site.admin_view(self.plano_comunicacao), self.admin_site.admin_view(self.plano_comunicacao),
name="%s_%s_comunicacaoreport" % self.get_model_info(), name="%s_%s_comunicacaoreport" % self.get_model_info(),
), ),
path(
"<path:object_id>/createcourse/",
self.admin_site.admin_view(self.create_course),
name="%s_%s_createcourse" % self.get_model_info(),
),
] ]
return my_urls + urls return my_urls + urls
def declaracao_report(self, request, object_id):
if request.method == "POST":
form = SelecionaModeloForm(request.POST)
if form.is_valid():
evento = get_object_or_404(Evento, id=object_id)
modelo = form.cleaned_data["modelo"]
membro = (
evento.equipe_set.filter(assina_oficio=True).first()
or evento.equipe_set.first()
)
if membro:
servidor = membro.membro
else:
servidor = None
template_string = (
"""
{% extends "eventos/declaracao_pdf.html" %}
{% block text_body %}"""
+ modelo.texto
+ """
{% endblock %}
"""
)
context = Context(
{
"pagesize": modelo.formato,
"pagemargin": modelo.margem,
"evento": evento,
"servidor": servidor,
"data": evento.data_inicio.date(),
}
)
string = Template(template_string).render(context)
# return HttpResponse(string)
response = HttpResponse(
headers={
"Content-Type": "application/pdf",
"Content-Disposition": 'attachment; filename="declaração.pdf"',
}
)
pdf = HTML(
string=string,
url_fetcher=django_url_fetcher,
encoding="utf-8",
base_url=request.build_absolute_uri("/"),
)
pdf.write_pdf(target=response)
return response
else:
form = SelecionaModeloForm()
context = {
"form": form,
"evento_id": object_id,
"opts": self.model._meta,
"preserved_filters": self.get_preserved_filters(request),
}
return render(
request, "admin/eventos/evento/seleciona_modelo.html", context
)
def gant_report(self, request, object_id): def gant_report(self, request, object_id):
evento = get_object_or_404(Evento, id=object_id) evento = get_object_or_404(Evento, id=object_id)
cronograma = list( cronograma = list(
@ -324,3 +417,109 @@ class EventoAdmin(CartExportMixin, admin.ModelAdmin):
context=context, context=context,
content_type="application/pdf", content_type="application/pdf",
) )
def create_course(self, request, object_id):
evento = get_object_or_404(Evento, id=object_id)
change_url = (
reverse(
"admin:%s_%s_change" % self.get_model_info(), args=[object_id]
)
+ "?"
+ self.get_preserved_filters(request)
)
if evento.moodle_courseid is not None:
self.message_user(
request,
_("Este evento já tem curso associado no Saberes"),
level=messages.ERROR,
)
return redirect(change_url)
if (
evento.tipo_evento.moodle_template_courseid is None
or evento.tipo_evento.moodle_categoryid is None
):
self.message_user(
request,
_("Este tipo de evento não possui template no Saberes"),
level=messages.ERROR,
)
return redirect(change_url)
if evento.data_inicio is None or evento.data_termino is None:
self.message_user(
request,
_(
"O evento precisa ter datas de início e término para criar "
"curso no Saberes."
),
level=messages.ERROR,
)
return redirect(change_url)
if evento.turma == "":
self.message_user(
request,
_(
"Preencha (e salve!) o campo Turma para poder criar o "
"curso no Saberes"
),
level=messages.ERROR,
)
return redirect(change_url)
api_url = f"{settings.MOODLE_BASE_URL}/webservice/rest/server.php"
mws = Moodle(api_url, settings.MOODLE_API_TOKEN)
fullname = f"{evento.nome} - {evento.turma}"
shortname = f"{evento.tipo_evento.nome} - {evento.turma}"
inicio = int(time.mktime(evento.data_inicio.astimezone().timetuple()))
fim = int(time.mktime(evento.data_termino.astimezone().timetuple()))
try:
novo_curso = mws.core.course.duplicate_course(
evento.tipo_evento.moodle_template_courseid,
fullname=fullname,
shortname=shortname,
categoryid=evento.tipo_evento.moodle_categoryid,
visible=0,
)
evento.moodle_courseid = novo_curso.id
evento.save()
changes = {
"id": novo_curso.id,
"summary": evento.descricao,
"startdate": inicio,
"enddate": fim,
}
res = mws.core.course.update_courses([changes])
membros = evento.equipe_set.exclude(
membro__moodle_userid=None
).exclude(funcao__moodle_roleid=None)
equipe = []
for membro in membros:
equipe.append(
{
"roleid": membro.funcao.moodle_roleid,
"userid": membro.membro.moodle_userid,
"courseid": evento.moodle_courseid,
}
)
mws.enrol.manual.enrol_users(equipe)
context = {
"evento": evento,
"fullname": fullname,
"shortname": shortname,
"membros": membros,
"opts": self.model._meta,
"preserved_filters": self.get_preserved_filters(request),
}
return render(
request, "admin/eventos/evento/createcourse.html", context
)
except Exception as e:
self.message_user(
request,
_(
"Ocorreu um erro ao criar o curso no Saberes com "
f"a mensagem {e.message}"
),
level=messages.ERROR,
)
return redirect(change_url)

5
sigi/apps/eventos/admin_urls.py

@ -6,9 +6,4 @@ urlpatterns = [
path( path(
"alocacaoequipe/", views.alocacao_equipe, name="eventos_alocacaoequipe" "alocacaoequipe/", views.alocacao_equipe, name="eventos_alocacaoequipe"
), ),
path(
"evento/<int:id>/declaracao/",
views.declaracao,
name="evento-declaracao",
),
] ]

2
sigi/apps/eventos/forms.py

@ -30,7 +30,7 @@ class EventoAdminForm(forms.ModelForm):
"total_participantes", "total_participantes",
"status", "status",
"publicar", "publicar",
"link_inscricao", "moodle_courseid",
"contato", "contato",
"telefone", "telefone",
"banner", "banner",

22
sigi/apps/eventos/migrations/0031_evento_moodle_courseid.py

@ -0,0 +1,22 @@
# Generated by Django 4.1.7 on 2023-04-14 15:02
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("eventos", "0030_alter_evento_descricao_alter_tipoevento_categoria"),
]
operations = [
migrations.AddField(
model_name="evento",
name="moodle_courseid",
field=models.PositiveBigIntegerField(
blank=True,
help_text="ID do curso no Saberes. Este campo é preenchido automaticamente quando o curso é criado no Saberes.",
null=True,
verbose_name="ID do curso",
),
),
]

33
sigi/apps/eventos/migrations/0032_set_moodle_courseid.py

@ -0,0 +1,33 @@
# Generated by Django 4.1.7 on 2023-04-14 15:02
from django.db import migrations
def set_courseid(apps, schema_editor):
Evento = apps.get_model("eventos", "Evento")
for evento in Evento.objects.exclude(link_inscricao=""):
if "=" in evento.link_inscricao:
evento.moodle_courseid = int(evento.link_inscricao.split("=")[1])
evento.save()
def reset_courseid(apps, schema_editor):
from django.conf import settings
Evento = apps.get_model("eventos", "Evento")
for evento in Evento.objects.exclude(moodle_courseid=None):
evento.link_inscricao = (
settings.MOODLE_BASE_URL
+ f"/course/view.php?id={evento.moodle_courseid}"
)
evento.save()
class Migration(migrations.Migration):
dependencies = [
("eventos", "0031_evento_moodle_courseid"),
]
operations = [
migrations.RunPython(set_courseid, reset_courseid),
]

16
sigi/apps/eventos/migrations/0033_remove_evento_link_inscricao.py

@ -0,0 +1,16 @@
# Generated by Django 4.1.7 on 2023-04-14 15:06
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("eventos", "0032_set_moodle_courseid"),
]
operations = [
migrations.RemoveField(
model_name="evento",
name="link_inscricao",
),
]

42
sigi/apps/eventos/migrations/0034_funcao_moodle_roleid_tipoevento_moodle_categoryid_and_more.py

@ -0,0 +1,42 @@
# Generated by Django 4.1.7 on 2023-04-14 17:14
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("eventos", "0033_remove_evento_link_inscricao"),
]
operations = [
migrations.AddField(
model_name="funcao",
name="moodle_roleid",
field=models.PositiveBigIntegerField(
blank=True,
help_text="Código do papel do membro da equipe no Saberes",
null=True,
verbose_name="Papel Saberes",
),
),
migrations.AddField(
model_name="tipoevento",
name="moodle_categoryid",
field=models.PositiveBigIntegerField(
blank=True,
help_text="Código da categoria no Saberes onde o curso deve ser criado.",
null=True,
verbose_name="Categoria do curso",
),
),
migrations.AddField(
model_name="tipoevento",
name="moodle_template_courseid",
field=models.PositiveBigIntegerField(
blank=True,
help_text="Código do curso que serve de protótipo no Saberes para criação de novos eventos desse tipo.",
null=True,
verbose_name="Curso protótipo",
),
),
]

23
sigi/apps/eventos/migrations/0035_alter_evento_options.py

@ -0,0 +1,23 @@
# Generated by Django 4.1.7 on 2023-04-18 19:57
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("eventos", "0034_funcao_moodle_roleid_tipoevento_moodle_categoryid_and_more"),
]
operations = [
migrations.AlterModelOptions(
name="evento",
options={
"ordering": ("-data_inicio",),
"permissions": [
("createcourse_evento", "Can create courses in Saberes platform")
],
"verbose_name": "Evento",
"verbose_name_plural": "Eventos",
},
),
]

47
sigi/apps/eventos/models.py

@ -32,6 +32,23 @@ class TipoEvento(models.Model):
_("Categoria"), max_length=1, choices=CATEGORIA_CHOICES _("Categoria"), max_length=1, choices=CATEGORIA_CHOICES
) )
casa_solicita = models.BooleanField(_("casa pode solicitar"), default=False) casa_solicita = models.BooleanField(_("casa pode solicitar"), default=False)
moodle_template_courseid = models.PositiveBigIntegerField(
_("Curso protótipo"),
blank=True,
null=True,
help_text=_(
"Código do curso que serve de protótipo no Saberes para criação de "
"novos eventos desse tipo."
),
)
moodle_categoryid = models.PositiveBigIntegerField(
_("Categoria do curso"),
blank=True,
null=True,
help_text=_(
"Código da categoria no Saberes onde o curso deve ser criado."
),
)
class Meta: class Meta:
ordering = ("nome",) ordering = ("nome",)
@ -129,7 +146,15 @@ class Evento(models.Model):
) )
status = models.CharField(_("Status"), max_length=1, choices=STATUS_CHOICES) status = models.CharField(_("Status"), max_length=1, choices=STATUS_CHOICES)
publicar = models.BooleanField(_("publicar no site"), default=False) publicar = models.BooleanField(_("publicar no site"), default=False)
link_inscricao = models.URLField(_("link de inscrição"), blank=True) moodle_courseid = models.PositiveBigIntegerField(
_("ID do curso"),
blank=True,
null=True,
help_text=_(
"ID do curso no Saberes. Este campo é preenchido automaticamente "
"quando o curso é criado no Saberes."
),
)
contato = models.CharField(_("contato"), max_length=100, blank=True) contato = models.CharField(_("contato"), max_length=100, blank=True)
telefone = models.CharField( telefone = models.CharField(
_("tefone de contato"), max_length=30, blank=True _("tefone de contato"), max_length=30, blank=True
@ -145,6 +170,9 @@ class Evento(models.Model):
class Meta: class Meta:
ordering = ("-data_inicio",) ordering = ("-data_inicio",)
verbose_name, verbose_name_plural = _("Evento"), _("Eventos") verbose_name, verbose_name_plural = _("Evento"), _("Eventos")
permissions = [
("createcourse_evento", "Can create courses in Saberes platform"),
]
def __str__(self): def __str__(self):
return _( return _(
@ -172,6 +200,17 @@ class Evento(models.Model):
).format(processo=self.num_processo, **m.groupdict()) ).format(processo=self.num_processo, **m.groupdict())
return self.num_processo return self.num_processo
@property
def link_inscricao(self):
if self.moodle_courseid is None:
return ""
from django.conf import settings
return (
settings.MOODLE_BASE_URL
+ f"/course/view.php?id={self.moodle_courseid}"
)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if self.status != Evento.STATUS_CANCELADO: if self.status != Evento.STATUS_CANCELADO:
self.data_cancelamento = None self.data_cancelamento = None
@ -262,6 +301,12 @@ class Evento(models.Model):
class Funcao(models.Model): class Funcao(models.Model):
nome = models.CharField(_("Função na equipe de evento"), max_length=100) nome = models.CharField(_("Função na equipe de evento"), max_length=100)
descricao = models.TextField(_("Descrição da função")) descricao = models.TextField(_("Descrição da função"))
moodle_roleid = models.PositiveBigIntegerField(
_("Papel Saberes"),
blank=True,
null=True,
help_text=_("Código do papel do membro da equipe no Saberes"),
)
class Meta: class Meta:
ordering = ("nome",) ordering = ("nome",)

21
sigi/apps/eventos/templates/admin/eventos/evento/change_form.html

@ -3,26 +3,39 @@
{% block object-tools-items %} {% block object-tools-items %}
{% if object_id %} {% if object_id %}
{% if can_createcourse %}
<li> <li>
<a href="{% url 'evento-declaracao' object_id %}"> {% url opts|admin_urlname:'createcourse' object_id|admin_urlquote as tool_url %}
<a href="{% add_preserved_filters tool_url %}">
<i class="left material-icons" aria-hidden="true">create_new_folder</i>
{% trans "Criar curso no Saberes" %}
</a>
</li>
{% endif %}
<li>
{% url opts|admin_urlname:'declaracaoreport' object_id|admin_urlquote as tool_url %}
<a href="{% add_preserved_filters tool_url %}">
<i class="left material-icons" aria-hidden="true">picture_as_pdf</i> <i class="left material-icons" aria-hidden="true">picture_as_pdf</i>
{% trans "Declaração" %} {% trans "Declaração" %}
</a> </a>
</li> </li>
<li> <li>
<a href="{% url opts|admin_urlname:'gantreport' object_id %}"> {% url opts|admin_urlname:'gantreport' object_id|admin_urlquote as tool_url %}
<a href="{% add_preserved_filters tool_url %}">
<i class="left material-icons" aria-hidden="true">insert_chart</i> <i class="left material-icons" aria-hidden="true">insert_chart</i>
{% trans "Gráfico de Gant" %} {% trans "Gráfico de Gant" %}
</a> </a>
</li> </li>
<li> <li>
<a href="{% url opts|admin_urlname:'checklistreport' object_id %}"> {% url opts|admin_urlname:'checklistreport' object_id|admin_urlquote as tool_url %}
<a href="{% add_preserved_filters tool_url %}">
<i class="left material-icons" aria-hidden="true">picture_as_pdf</i> <i class="left material-icons" aria-hidden="true">picture_as_pdf</i>
{% trans "Checklist" %} {% trans "Checklist" %}
</a> </a>
</li> </li>
<li> <li>
<a href="{% url opts|admin_urlname:'comunicacaoreport' object_id %}"> {% url opts|admin_urlname:'comunicacaoreport' object_id|admin_urlquote as tool_url %}
<a href="{% add_preserved_filters tool_url %}">
<i class="left material-icons" aria-hidden="true">picture_as_pdf</i> <i class="left material-icons" aria-hidden="true">picture_as_pdf</i>
{% trans "Plano de comunicação" %} {% trans "Plano de comunicação" %}
</a> </a>

52
sigi/apps/eventos/templates/admin/eventos/evento/createcourse.html

@ -0,0 +1,52 @@
{% extends "admin/base_site.html" %}
{% load i18n static admin_urls %}
{% block extrastyle %}
{{ block.super }}
<link rel="stylesheet" href="{% static 'material/admin/css/submit_line.min.css' %}">
{% endblock %}
{% block breadcrumbs %}{% endblock %}
{% block messages %}
{% if error %}
<ul class="messagelist">
<li class="error">{{ error|capfirst }}</li>
</ul>
{% endif %}
{% endblock messages %}
{% block content %}
<div class="container">
<div class="card">
<div class="card-content">
<span class="card-title">{% trans 'Integração SIGI x Saberes: Criação de curso' %}</span>
<p>
{% blocktrans with courseid=evento.moodle_courseid courseurl=evento.link_inscricao|urlize trimmed %}
Criado curso no ambiente Saberes com ID {{ courseid }}, que pode ser
acessado em {{ courseurl }}. O nome completo do curso é "{{ fullname }}"
e o nome breve é "{{ shortname }}".
{% endblocktrans %}
</p>
<span class="card-title">{% trans "Os seguintes servidores foram inscritos no curso:" %}</span>
<ul>
{% for membro in membros %}
<li>{{ membro }}</li>
{% endfor %}
</ul>
</div>
<div class="card-action">
<div class="submit-row">
<div class="open-actions">
{% url opts|admin_urlname:'change' evento_id|admin_urlquote as change_url %}
<a class="default waves-effect waves-light btn" role="button" href="{% add_preserved_filters change_url %}">
<i class="material-icons">undo</i>
{% trans "Voltar" %}
</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

5
sigi/apps/eventos/templates/eventos/seleciona_modelo.html → sigi/apps/eventos/templates/admin/eventos/evento/seleciona_modelo.html

@ -1,5 +1,5 @@
{% extends "admin/base_site.html" %} {% extends "admin/base_site.html" %}
{% load i18n static %} {% load i18n static admin_urls %}
{% block extrastyle %} {% block extrastyle %}
{{ block.super }} {{ block.super }}
@ -35,7 +35,8 @@
<i class="material-icons">picture_as_pdf</i> <i class="material-icons">picture_as_pdf</i>
{% trans "Imprimir" %} {% trans "Imprimir" %}
</button> </button>
<a class="default waves-effect waves-light btn" role="button" href="{% url 'admin:eventos_evento_change' evento_id %}"> {% url opts|admin_urlname:'change' evento_id|admin_urlquote as change_url %}
<a class="default waves-effect waves-light btn" role="button" href="{% add_preserved_filters change_url %}">
<i class="material-icons">undo</i> <i class="material-icons">undo</i>
{% trans "Voltar" %} {% trans "Voltar" %}
</a> </a>

59
sigi/apps/eventos/views.py

@ -114,64 +114,7 @@ def calendario(request):
return render(request, "eventos/calendario.html", context) return render(request, "eventos/calendario.html", context)
@login_required class EventoListView(ListView):
@staff_member_required
def declaracao(request, id):
if request.method == "POST":
form = SelecionaModeloForm(request.POST)
if form.is_valid():
evento = get_object_or_404(Evento, id=id)
modelo = form.cleaned_data["modelo"]
membro = (
evento.equipe_set.filter(assina_oficio=True).first()
or evento.equipe_set.first()
)
if membro:
servidor = membro.membro
else:
servidor = None
template_string = (
"""
{% extends "eventos/declaracao_pdf.html" %}
{% block text_body %}"""
+ modelo.texto
+ """
{% endblock %}
"""
)
context = Context(
{
"pagesize": modelo.formato,
"pagemargin": modelo.margem,
"evento": evento,
"servidor": servidor,
"data": timezone.localdate(),
}
)
string = Template(template_string).render(context)
# return HttpResponse(string)
response = HttpResponse(
headers={
"Content-Type": "application/pdf",
"Content-Disposition": 'attachment; filename="declaração.pdf"',
}
)
pdf = HTML(
string=string,
url_fetcher=django_url_fetcher,
encoding="utf-8",
base_url=request.build_absolute_uri("/"),
)
pdf.write_pdf(target=response)
return response
else:
form = SelecionaModeloForm()
context = {"form": form, "evento_id": id}
return render(request, "eventos/seleciona_modelo.html", context)
class eventoListView(ListView):
model = Evento model = Evento
paginate_by = 100 paginate_by = 100
template_name = "eventos/lista.html" template_name = "eventos/lista.html"

1
sigi/apps/servidores/admin.py

@ -121,6 +121,7 @@ class ServidorAdmin(admin.ModelAdmin):
"foto", "foto",
"servico", "servico",
"cargo", "cargo",
"moodle_userid",
) )
}, },
), ),

22
sigi/apps/servidores/migrations/0013_servidor_moodle_userid.py

@ -0,0 +1,22 @@
# Generated by Django 4.1.7 on 2023-04-14 17:00
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("servidores", "0012_add_user_interlegis"),
]
operations = [
migrations.AddField(
model_name="servidor",
name="moodle_userid",
field=models.PositiveBigIntegerField(
blank=True,
help_text="Código do usuário no Saberes",
null=True,
verbose_name="ID usuário Saberes",
),
),
]

7
sigi/apps/servidores/models.py

@ -55,6 +55,12 @@ class Servidor(models.Model):
Servico, on_delete=models.SET_NULL, blank=True, null=True Servico, on_delete=models.SET_NULL, blank=True, null=True
) )
cargo = models.CharField(max_length=100, blank=True) cargo = models.CharField(max_length=100, blank=True)
moodle_userid = models.PositiveBigIntegerField(
_("ID usuário Saberes"),
blank=True,
null=True,
help_text=_("Código do usuário no Saberes"),
)
externo = models.BooleanField(_("colaborador externo"), default=False) externo = models.BooleanField(_("colaborador externo"), default=False)
orgao_origem = models.CharField( orgao_origem = models.CharField(
_("órgão de origem, "), max_length=100, blank=True _("órgão de origem, "), max_length=100, blank=True
@ -93,6 +99,7 @@ User.servidor = property(
else None else None
) )
# Sinal para ao criar um usuário criar um servidor # Sinal para ao criar um usuário criar um servidor
# baseado no nome contido no LDAP # baseado no nome contido no LDAP
@receiver(post_save, sender=User) @receiver(post_save, sender=User)

6
sigi/apps/utils/__init__.py

@ -94,3 +94,9 @@ def editor_help(field_name, Field_list):
"home/editor_help_snippet.html", "home/editor_help_snippet.html",
{"field_name": field_name, "placeholders": placeholders}, {"field_name": field_name, "placeholders": placeholders},
) )
def abreviatura(name):
for conector in [" da ", " de ", " do ", " das ", " dos ", " e "]:
name = name.replace(conector, " ")
return ("".join([w[0] for w in name.split()])).upper()

5
sigi/settings.py

@ -261,3 +261,8 @@ TINYMCE_DEFAULT_CONFIG = {
MENU_FILE = BASE_DIR / "menu_conf.yaml" MENU_FILE = BASE_DIR / "menu_conf.yaml"
HOSPEDAGEM_PATH = Path(env("HOSPEDAGEM_PATH", default="/tmp/HOSP/")) HOSPEDAGEM_PATH = Path(env("HOSPEDAGEM_PATH", default="/tmp/HOSP/"))
REGISTRO_PATH = Path(env("REGISTRO_PATH", default="/tmp/DNS/")) REGISTRO_PATH = Path(env("REGISTRO_PATH", default="/tmp/DNS/"))
# Integração com Moodle
MOODLE_BASE_URL = env("MOODLE_BASE_URL", default=None)
MOODLE_API_TOKEN = env("MOODLE_API_TOKEN", default=None)

Loading…
Cancel
Save