Browse Source

Alterações para o gabinete do ILB

pull/11/head
Sesostris Vieira 4 years ago
parent
commit
4d1b2df4ef
  1. 24
      moodlerouter.py
  2. 96
      sigi/apps/casas/admin.py
  3. 45
      sigi/apps/casas/migrations/0008_auto_20210218_1007.py
  4. 30
      sigi/apps/casas/models.py
  5. 2
      sigi/apps/diagnosticos/models.py
  6. 3
      sigi/apps/eventos/admin.py
  7. 18
      sigi/apps/eventos/migrations/0004_remove_evento_curso_moodle_id.py
  8. 42
      sigi/apps/eventos/models.py
  9. 11
      sigi/apps/home/templatetags/menu_conf.yaml
  10. 0
      sigi/apps/mdl/__init__.py
  11. 3
      sigi/apps/mdl/admin.py
  12. 6007
      sigi/apps/mdl/base_models.py
  13. 116
      sigi/apps/mdl/migrations/0001_initial.py
  14. 0
      sigi/apps/mdl/migrations/__init__.py
  15. 360
      sigi/apps/mdl/models.py
  16. 3
      sigi/apps/mdl/views.py
  17. 0
      sigi/apps/saberes/__init__.py
  18. 13
      sigi/apps/saberes/admin.py
  19. 0
      sigi/apps/saberes/management/__init__.py
  20. 0
      sigi/apps/saberes/management/commands/__init__.py
  21. 102
      sigi/apps/saberes/management/commands/get_moodle_stats.py
  22. 44
      sigi/apps/saberes/migrations/0001_initial.py
  23. 0
      sigi/apps/saberes/migrations/__init__.py
  24. 74
      sigi/apps/saberes/models.py
  25. 13
      sigi/apps/saberes/templates/saberes/dashboard.html
  26. 50
      sigi/apps/saberes/templates/saberes/detail.html
  27. 33
      sigi/apps/saberes/templates/saberes/snippets.html
  28. 14
      sigi/apps/saberes/urls.py
  29. 50
      sigi/apps/saberes/views.py
  30. 87
      sigi/apps/utils/moodle_ws_api.py
  31. 8
      sigi/settings/base.py
  32. 13
      sigi/settings/dev.py
  33. 5
      sigi/urls.py

24
moodlerouter.py

@ -1,24 +0,0 @@
# -*- coding: utf-8 -*-
class MoodleRouter(object):
def db_for_read(self, model, **hints):
if model._meta.app_label == 'mdl':
return 'moodle'
return None
def db_for_write(self, model, **hints):
if model._meta.app_label == 'mdl':
return 'moodle'
return None
def allow_relation(self, obj1, obj2, **hints):
if obj1._meta.app_label == 'mdl' and obj2._meta.app_label == 'mdl':
return True
return None
def allow_migrate(self, db, model):
if model._meta.app_label == 'mdl':
return False
return None

96
sigi/apps/casas/admin.py

@ -34,31 +34,43 @@ class TelefonesInline(generic.GenericTabularInline):
class PresidenteInline(admin.StackedInline):
model = Presidente
fieldsets = ((None, {
'fields': (
('nome', 'sexo', 'data_nascimento'),
('nota', 'email', 'tempo_de_servico'),
('ult_alteracao',),
)
}),)
fields = ('nome', 'sexo', 'data_nascimento', 'nota', 'email',
'tempo_de_servico', 'ult_alteracao', 'endereco', 'municipio',
'bairro', 'cep', 'redes_sociais',)
raw_id_fields = ('municipio',)
# fieldsets = ((None, {
# 'fields': (
# ('nome', 'sexo', 'data_nascimento'),
# ('nota', 'email', 'tempo_de_servico'),
# ('ult_alteracao',),
# )
# }),)
# exclude = ['setor', 'cargo', 'funcao']
readonly_fields = ('ult_alteracao',)
extra = 1
max_num = 1
inlines = (TelefonesInline)
verbose_name_plural = _(u'Presidente')
class FuncionariosInline(admin.StackedInline):
model = Funcionario
fieldsets = ((None, {
'fields': (
('nome', 'sexo', 'data_nascimento'),
('nota', 'email'),
('cargo', 'funcao', 'setor'),
('tempo_de_servico', 'ult_alteracao'),
('desativado', 'observacoes'),
)
}),)
fields = ('nome', 'sexo', 'data_nascimento', 'nota', 'email', 'cargo',
'funcao', 'setor', 'tempo_de_servico', 'ult_alteracao',
'endereco', 'municipio', 'bairro', 'cep', 'redes_sociais',
'desativado', 'observacoes')
raw_id_fields = ('municipio',)
# fieldsets = ((None, {
# 'fields': (
# ('nome', 'sexo', 'data_nascimento'),
# ('nota', 'email'),
# ('cargo', 'funcao', 'setor'),
# ('tempo_de_servico', 'ult_alteracao'),
# ('endereco', 'municipio'),
# ('bairro', 'cep'),
# ('redes_sociais'),
# ('desativado', 'observacoes'),
# )
# }),)
readonly_fields = ('ult_alteracao',)
extra = 1
inlines = (TelefonesInline,)
@ -73,7 +85,7 @@ class ConveniosInline(admin.TabularInline):
model = Convenio
fieldsets = (
(None, {'fields': (
('link_sigad', 'status_convenio', 'num_convenio',
('link_sigad', 'status_convenio', 'num_convenio',
'projeto', 'observacao'),
('data_adesao', 'data_retorno_assinatura', 'data_termo_aceite',
'data_pub_diario', 'data_devolucao_via', 'data_postagem_correio'),
@ -89,25 +101,25 @@ class ConveniosInline(admin.TabularInline):
'data_retorno_sem_assinatura',]
extra = 0
can_delete = False
def has_add_permission(self, request):
return False
# def get_tramitacoes(self, obj):
# return '<br/>'.join([t.__unicode__() for t in obj.tramitacao_set.all()])
#
#
# get_tramitacoes.short_description = _(u'Tramitações')
# get_tramitacoes.allow_tags = True
#
#
# def get_anexos(self, obj):
# return '<br/>'.join(['<a href="%s" target="_blank">%s</a>' % (a.arquivo.url, a.__unicode__()) for a in obj.anexo_set.all()])
#
#
# get_anexos.short_description = _(u'Anexos')
# get_anexos.allow_tags = True
#
#
# def get_equipamentos(self, obj):
# return '<br/>'.join([e.__unicode__() for e in obj.equipamentoprevisto_set.all()])
#
#
# get_equipamentos.short_description = _(u'Equipamentos previstos')
# get_equipamentos.allow_tags = True
@ -115,7 +127,7 @@ class ConveniosInline(admin.TabularInline):
if obj.pk is None:
return ""
status = obj.get_status()
if status in [u"Vencido", u"Desistência"]:
label = r"danger"
elif status == u"Vigente":
@ -124,11 +136,11 @@ class ConveniosInline(admin.TabularInline):
label = r"warning"
else:
label = r"info"
return u'<p class="label label-{label}">{status}</p>'.format(label=label, status=status)
status_convenio.short_description = _(u"Status do convênio")
status_convenio.allow_tags = True
def link_convenio(self, obj):
if obj.pk is None:
@ -142,12 +154,12 @@ class ConveniosInline(admin.TabularInline):
link_convenio.short_description = _(u'Editar convenio')
link_convenio.allow_tags = True
def link_sigad(self, obj):
if obj.pk is None:
return ""
return obj.get_sigad_url()
link_sigad.short_description = _("Processo no Senado")
link_sigad.allow_tags = True
@ -218,7 +230,7 @@ class OcorrenciaInline(admin.TabularInline):
max_num = 0
can_delete = False
template = 'casas/ocorrencia_inline.html'
def link_editar(self, obj):
if obj.pk is None:
return ""
@ -242,29 +254,29 @@ class GerentesInterlegisFilter(admin.filters.RelatedFieldListFilter):
class ConvenioFilter(admin.SimpleListFilter):
title = _(u"Tipo de convênio")
parameter_name = 'convenio'
def lookups(self, request, model_admin):
return (
('SC', _(u"Sem nenhum convênio")),
('CC', _(u"Com algum convênio"))
) + tuple([(p.pk, p.sigla) for p in Projeto.objects.all()])
def queryset(self, request, queryset):
if self.value() is not None:
if self.value() == 'SC':
queryset = queryset.filter(convenio=None)
queryset = queryset.filter(convenio=None)
elif self.value() == 'CC':
queryset = queryset.exclude(convenio=None)
else:
queryset = queryset.filter(convenio__projeto_id=self.value())
return queryset.distinct('municipio__uf__nome', 'nome')
class ServicoFilter(admin.SimpleListFilter):
title = _(u"Serviço")
parameter_name = 'servico'
def lookups(self, request, model_admin):
return (
('SS', _(u"Sem nenhum serviço")),
@ -272,7 +284,7 @@ class ServicoFilter(admin.SimpleListFilter):
('CH', _(u"Com algum serviço de hospedagem")),
('CR', _(u"Apenas serviço de registro")),
) + tuple([(p.pk, p.nome) for p in TipoServico.objects.all()])
def queryset(self, request, queryset):
if self.value() is not None:
if self.value() == 'SS':
@ -299,7 +311,7 @@ class ServicoFilter(admin.SimpleListFilter):
class CasaLegislativaAdmin(ImageCroppingMixin, BaseModelAdmin):
form = CasaLegislativaForm
actions = ['adicionar_casas', ]
inlines = (TelefonesInline, PresidenteInline, FuncionariosInline,
inlines = (TelefonesInline, PresidenteInline, FuncionariosInline,
ConveniosInline, LegislaturaInline, DiagnosticoInline, BemInline,
ServicoInline, PlanoDiretorInline, OcorrenciaInline,)
list_display = ('nome', 'get_uf', 'get_gerentes', 'get_convenios',
@ -321,7 +333,7 @@ class CasaLegislativaAdmin(ImageCroppingMixin, BaseModelAdmin):
}),
(_(u'Presença na Internet'), {
'fields': ('inclusao_digital', 'data_levantamento', 'pesquisador',
'pagina_web', 'email', 'obs_pesquisa',)
'pagina_web', 'email', 'obs_pesquisa',)
}),
(_(u'Outras informações'), {
'fields': ('observacoes', 'horario_funcionamento', 'foto',
@ -334,24 +346,24 @@ class CasaLegislativaAdmin(ImageCroppingMixin, BaseModelAdmin):
'cep', 'municipio__nome', 'municipio__uf__nome',
'municipio__codigo_ibge', 'pagina_web', 'observacoes')
filter_horizontal = ('gerentes_interlegis',)
def get_uf(self, obj):
return obj.municipio.uf.nome
get_uf.short_description = _(u'Unidade da Federação')
get_uf.admin_order_field = 'municipio__uf__nome'
def get_gerentes(self, obj):
return obj.lista_gerentes
get_gerentes.short_description = _(u'Gerente Interlegis')
get_gerentes.allow_tags = True
def get_convenios(self, obj):
return '<ul>' + ''.join(['<li>%s</li>' % c.__unicode__() for c in obj.convenio_set.all()]) + '</ul>'
get_convenios.short_description = _(u'Convênios')
get_convenios.allow_tags = True
def get_servicos(self, obj):
return '<ul>' + ''.join(['<li>%s</li>' % s.__unicode__()
for s in obj.servico_set.filter(

45
sigi/apps/casas/migrations/0008_auto_20210218_1007.py

@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('contatos', '0002_auto_20151104_0810'),
('casas', '0007_auto_20201016_1632'),
]
operations = [
migrations.AddField(
model_name='funcionario',
name='bairro',
field=models.CharField(max_length=100, verbose_name='Bairro', blank=True),
preserve_default=True,
),
migrations.AddField(
model_name='funcionario',
name='cep',
field=models.CharField(max_length=10, verbose_name='CEP', blank=True),
preserve_default=True,
),
migrations.AddField(
model_name='funcionario',
name='endereco',
field=models.CharField(max_length=100, verbose_name='Endere\xe7o', blank=True),
preserve_default=True,
),
migrations.AddField(
model_name='funcionario',
name='municipio',
field=models.ForeignKey(verbose_name='Municipio', to='contatos.Municipio', null=True),
preserve_default=True,
),
migrations.AddField(
model_name='funcionario',
name='redes_sociais',
field=models.TextField(help_text='Colocar um por linha', verbose_name='Redes sociais', blank=True),
preserve_default=True,
),
]

30
sigi/apps/casas/models.py

@ -8,6 +8,7 @@ from django.contrib.contenttypes import generic
from django.db import models
from image_cropping import ImageRatioField
from sigi.apps.contatos.models import Municipio
from sigi.apps.servidores.models import Servidor
from sigi.apps.utils import SearchField
@ -31,14 +32,14 @@ class CasaLegislativa(models.Model):
""" Modelo para representar uma Casa Legislativa
"""
INCLUSAO_DIGITAL_CHOICES = (
('NAO PESQUISADO', _(u'Não pesquisado')),
('NAO POSSUI PORTAL', _(u'Não possui portal')),
('PORTAL MODELO', _(u'Possui Portal Modelo')),
('OUTRO PORTAL', _(u'Possui outro portal')),
)
nome = models.CharField(
_(u"Nome"),
max_length=60,
@ -63,7 +64,7 @@ class CasaLegislativa(models.Model):
blank=True
)
# codigo_interlegis.ts_filter = True
gerentes_interlegis = models.ManyToManyField(
Servidor,
verbose_name=_(u"Gerentes Interlegis"),
@ -72,7 +73,7 @@ class CasaLegislativa(models.Model):
# Informações de contato
logradouro = models.CharField(
_(u"Logradouro"),
_(u"Logradouro"),
max_length=100,
help_text=_(u'Avenida, rua, praça, jardim, parque...')
)
@ -92,7 +93,7 @@ class CasaLegislativa(models.Model):
blank=True,
)
inclusao_digital = models.CharField(
_(u"Inclusão digital"),
_(u"Inclusão digital"),
max_length=30,
choices=INCLUSAO_DIGITAL_CHOICES,
default=INCLUSAO_DIGITAL_CHOICES[0][0]
@ -150,9 +151,9 @@ class CasaLegislativa(models.Model):
[g.nome_completo for g in self.gerentes_interlegis.all()])+\
u"</li></ul>"
else:
return u", ".join([g.nome_completo for g in
return u", ".join([g.nome_completo for g in
self.gerentes_interlegis.all()])
@property
def num_parlamentares(self):
if not self.legislatura_set.exists():
@ -359,7 +360,20 @@ class Funcionario(models.Model):
blank=True
)
email = models.CharField(_(u'e-mail'), max_length=75, blank=True)
endereco = generic.GenericRelation('contatos.Endereco')
# endereco = generic.GenericRelation('contatos.Endereco')
endereco = models.CharField(_(u'Endereço'), max_length=100, blank=True)
municipio = models.ForeignKey(
Municipio,
verbose_name=_(u'Municipio'),
null=True
)
bairro = models.CharField(_(u'Bairro'), max_length=100, blank=True)
cep = models.CharField(_(u'CEP'), max_length=10, blank=True)
redes_sociais = models.TextField(
_(u'Redes sociais'),
help_text=_(u'Colocar um por linha'),
blank=True
)
cargo = models.CharField(_(u"Cargo"), max_length=100, null=True, blank=True)
funcao = models.CharField(
_(u'função'),

2
sigi/apps/diagnosticos/models.py

@ -198,7 +198,7 @@ class Escolha(BaseChoice):
"""
schema = models.ForeignKey(Pergunta,
related_name='choices', verbose_name=_(u'pergunta'))
schema_to_open = models.ForeignKey(Pergunta, related_name='',
schema_to_open = models.ForeignKey(Pergunta, related_name='abre_por',
verbose_name=_(u'pergunta para abrir'), blank=True, null=True)
ordem = models.PositiveIntegerField(blank=True, null=True)

3
sigi/apps/eventos/admin.py

@ -28,8 +28,7 @@ class EventoAdminForm(forms.ModelForm):
model = Evento
fields = ('tipo_evento', 'nome', 'descricao', 'solicitante', 'data_inicio', 'data_termino',
'casa_anfitria', 'municipio', 'local', 'publico_alvo', 'status',
'data_cancelamento', 'motivo_cancelamento', 'curso_moodle_id',
)
'data_cancelamento', 'motivo_cancelamento', )
def clean(self):
cleaned_data = super(EventoAdminForm, self).clean()

18
sigi/apps/eventos/migrations/0004_remove_evento_curso_moodle_id.py

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('eventos', '0003_auto_20151104_0810'),
]
operations = [
migrations.RemoveField(
model_name='evento',
name='curso_moodle_id',
),
]

42
sigi/apps/eventos/models.py

@ -1,22 +1,4 @@
# -*- coding: utf-8 -*-
#
# sigi.apps.eventos.models
#
# Copyright (C) 2015 Interlegis
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from django.db import models
from django.utils.functional import lazy
@ -24,9 +6,7 @@ from django.utils.translation import ugettext as _
from sigi.apps.casas.models import CasaLegislativa
from sigi.apps.contatos.models import Municipio
from sigi.apps.servidores.models import Servidor
from sigi.apps.utils.moodle_ws_api import get_courses
from django.core.exceptions import ValidationError
from sigi.apps.mdl.models import Course
class TipoEvento(models.Model):
nome = models.CharField(_(u"Nome"), max_length=100)
@ -46,26 +26,6 @@ class Evento(models.Model):
('R', _(u"Realizado")),
('C', _(u"Cancelado"))
)
# def get_course_choices():
# result = [(None, u'---------')]
#
# try:
# courses = get_courses(sort_order='categorysortorder', idnumber__startswith='evento')
# result = result + [(c['id'], c['fullname']) for c in courses]
# except Exception as e:
# result.append((None, _(u"Erro ao acessar o saberes: '%s'" % (e.message,))))
#
# return result
def get_course_choices():
from django.apps import apps
if apps.models_ready:
courses = Course.objects.filter(idnumber__startswith='evento')
else:
courses = []
result = [(None, u'---------')] + [(c.id, c.fullname) for c in courses]
return result
tipo_evento = models.ForeignKey(TipoEvento)
nome = models.CharField(_(u"Nome do evento"), max_length=100)
@ -81,8 +41,6 @@ class Evento(models.Model):
status = models.CharField(_(u"Status"), max_length=1, choices=STATUS_CHOICES)
data_cancelamento = models.DateField(_(u"Data de cancelamento"), blank=True, null=True)
motivo_cancelamento = models.TextField(_(u"Motivo do cancelamento"), blank=True)
curso_moodle_id = models.IntegerField(_(u"Curso saberes"), blank=True, null=True,
choices=lazy(get_course_choices, list)())
class Meta:
ordering = ("-data_inicio",)

11
sigi/apps/home/templatetags/menu_conf.yaml

@ -113,13 +113,4 @@ main_menu:
url: financeiro/desembolso/
children:
- title: Desembolsos
url: financeiro/desembolso/
- title: Saberes
url: '/'
children:
- title: Dashboard
url: saberes/dashboard/
- title: Cursos sem Tutoria
url: saberes/dashboard/cursos-sem-turoria/
- title: Cursos com Tutoria
url: saberes/dashboard/cursos-com-turoria/
url: financeiro/desembolso/

0
sigi/apps/mdl/__init__.py

3
sigi/apps/mdl/admin.py

@ -1,3 +0,0 @@
from django.contrib import admin
# Register your models here.

6007
sigi/apps/mdl/base_models.py

File diff suppressed because it is too large

116
sigi/apps/mdl/migrations/0001_initial.py

@ -1,116 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
]
operations = [
migrations.CreateModel(
name='Cohort',
fields=[
],
options={
'db_table': 'mdl_cohort',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='CohortMembers',
fields=[
],
options={
'db_table': 'mdl_cohort_members',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='Context',
fields=[
],
options={
'db_table': 'mdl_context',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='Course',
fields=[
],
options={
'ordering': ['sortorder'],
'db_table': 'mdl_course',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='CourseCategories',
fields=[
],
options={
'ordering': ['sortorder'],
'db_table': 'mdl_course_categories',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='CourseCompletions',
fields=[
],
options={
'db_table': 'mdl_course_completions',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='CourseStats',
fields=[
],
options={
'db_table': 'sigi_course_stats',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='Enrol',
fields=[
],
options={
'ordering': ['sortorder'],
'db_table': 'mdl_enrol',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='User',
fields=[
],
options={
'db_table': 'mdl_user',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='UserEnrolments',
fields=[
],
options={
'db_table': 'mdl_user_enrolments',
'managed': False,
},
bases=(models.Model,),
),
]

0
sigi/apps/mdl/migrations/__init__.py

360
sigi/apps/mdl/models.py

@ -1,360 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
class CourseStats(models.Model):
# databaseview: (postgresql dialect):
# -- View: sigi_course_stats
#
# DROP VIEW sigi_course_stats;
#
# CREATE OR REPLACE VIEW sigi_course_stats AS
# SELECT cc.id AS categoryid, c.id AS courseid,
# CASE
# WHEN e.enrol = 'ilbeadtutorado' AND ue.status = 1 THEN 'N' -- Rejeitada
# WHEN e.enrol = 'ilbead' AND ue.timeend > date_part('epoch', now()) THEN 'C' -- Em curso
# WHEN e.enrol = 'ilbead' and ue.timeend < date_part('epoch', now()) and co.timecompleted is null and gg.finalgrade is null then 'L' -- Abandono
# WHEN (co.timestarted = 0 OR co.timestarted IS NULL) AND gg.finalgrade IS NOT NULL THEN 'R' -- Reprovada
# WHEN co.timestarted = 0 OR co.timestarted IS NULL THEN 'L' -- Abandono
# WHEN co.timestarted > 0 AND co.timecompleted IS NULL THEN 'R' -- Reprovado
# WHEN co.timecompleted IS NOT NULL THEN 'A' -- Aprovado
# ELSE 'I' -- Indeterminado
# END AS completionstatus, count(ue.id) AS usercount, avg(gg.finalgrade) as gradeaverage
# FROM mdl_course_categories cc
# JOIN mdl_course c ON c.category = cc.id
# JOIN mdl_enrol e ON e.courseid = c.id
# JOIN mdl_user_enrolments ue ON ue.enrolid = e.id
# JOIN mdl_grade_items gi ON gi.courseid = c.id AND gi.itemtype = 'course'
# LEFT JOIN mdl_grade_grades gg ON gg.itemid = gi.id AND gg.userid = ue.userid
# LEFT JOIN mdl_course_completions co ON co.userid = ue.userid AND co.course = c.id
# GROUP BY cc.id, c.id, completionstatus;
COMPLETIONSTATUS_CHOICES = (
('N', u'Matrículas rejeitadas'),
('C', u'Em curso'),
('R', u'Reprovação'),
('L', u'Abandono'),
('A', u'Aprovação'),
('I', u'Indeterminado'),)
category = models.ForeignKey('CourseCategories', db_column='categoryid', primary_key=True)
course = models.ForeignKey('Course', db_column='courseid')
completionstatus = models.CharField(max_length=1, choices=COMPLETIONSTATUS_CHOICES)
usercount = models.IntegerField()
gradeaverage = models.FloatField()
class Meta:
managed = False
db_table = 'sigi_course_stats'
def __unicode__(self):
return '%s - %s: %s' % (self.category.name, self.course.fullname, self.usercount)
class Cohort(models.Model):
id = models.BigIntegerField(primary_key=True)
context = models.ForeignKey('Context', db_column='contextid')
name = models.CharField(max_length=254)
idnumber = models.CharField(max_length=100, blank=True)
description = models.TextField(blank=True)
descriptionformat = models.SmallIntegerField()
component = models.CharField(max_length=100)
timecreated = models.BigIntegerField()
timemodified = models.BigIntegerField()
visible = models.SmallIntegerField()
# Manytomany
members = models.ManyToManyField('User', through='CohortMembers')
class Meta:
managed = False
db_table = 'mdl_cohort'
def __unicode__(self):
return self.name
class CohortMembers(models.Model):
id = models.BigIntegerField(primary_key=True)
cohort = models.ForeignKey('Cohort', db_column='cohortid')
user = models.ForeignKey('User', db_column='userid')
timeadded = models.BigIntegerField()
class Meta:
managed = False
db_table = 'mdl_cohort_members'
class Context(models.Model):
CONTEXT_SYSTEM = 10 # System context level - only one instance in every system
CONTEXT_USER = 30 # User context level - one instance for each user describing what others can do to user
CONTEXT_COURSECAT = 40 # Course category context level - one instance for each category
CONTEXT_COURSE = 50 # Course context level - one instances for each course
CONTEXT_MODULE = 70 # Course module context level - one instance for each course module
CONTEXT_BLOCK = 80 # Block context level - one instance for each block, sticky blocks are tricky
# because ppl think they should be able to override them at lower contexts.
# Any other context level instance can be parent of block context.
id = models.BigIntegerField(primary_key=True)
contextlevel = models.BigIntegerField()
instanceid = models.BigIntegerField()
path = models.CharField(max_length=255, blank=True)
depth = models.SmallIntegerField()
class Meta:
managed = False
db_table = 'mdl_context'
def __unicode__(self):
return self.path
class Course(models.Model):
id = models.BigIntegerField(primary_key=True)
category = models.ForeignKey('CourseCategories', db_column='category', related_name='courses')
sortorder = models.BigIntegerField()
fullname = models.CharField(max_length=254)
shortname = models.CharField(max_length=255)
idnumber = models.CharField(max_length=100)
summary = models.TextField(blank=True)
format = models.CharField(max_length=21)
showgrades = models.SmallIntegerField()
newsitems = models.IntegerField()
startdate = models.BigIntegerField()
marker = models.BigIntegerField()
maxbytes = models.BigIntegerField()
showreports = models.SmallIntegerField()
visible = models.SmallIntegerField()
groupmode = models.SmallIntegerField()
groupmodeforce = models.SmallIntegerField()
lang = models.CharField(max_length=30)
theme = models.CharField(max_length=50)
timecreated = models.BigIntegerField()
timemodified = models.BigIntegerField()
requested = models.SmallIntegerField()
defaultgroupingid = models.BigIntegerField()
enrolmax = models.BigIntegerField()
enablecompletion = models.SmallIntegerField()
legacyfiles = models.SmallIntegerField()
summaryformat = models.SmallIntegerField()
completionnotify = models.SmallIntegerField()
visibleold = models.SmallIntegerField()
calendartype = models.CharField(max_length=30)
cacherev = models.BigIntegerField()
class Meta:
managed = False
db_table = 'mdl_course'
ordering = ['sortorder', ]
def __unicode__(self):
return self.fullname
def total_alunos(self):
return sum(e.user_enrolments.count() for e in self.enrols.all())
def total_ativos(self):
return sum(e.user_enrolments.filter(status=0).count() for e in self.enrols.all())
def get_matriculas(self):
q = UserEnrolments.objects.none()
for e in self.enrols.all():
q = q | e.user_enrolments.all()
return q
class CourseCategories(models.Model):
id = models.BigIntegerField(primary_key=True)
name = models.CharField(max_length=255)
description = models.TextField(blank=True)
parent = models.ForeignKey('CourseCategories', db_column='parent', related_name='children')
sortorder = models.BigIntegerField()
coursecount = models.BigIntegerField()
visible = models.SmallIntegerField()
timemodified = models.BigIntegerField()
depth = models.BigIntegerField()
path = models.CharField(max_length=255)
theme = models.CharField(max_length=50, blank=True)
descriptionformat = models.SmallIntegerField()
visibleold = models.SmallIntegerField()
idnumber = models.CharField(max_length=100, blank=True)
class Meta:
managed = False
db_table = 'mdl_course_categories'
ordering = ['sortorder', ]
def __unicode__(self):
return self.name
def context(self):
return Context.objects.get(instanceid=self.id, contextlevel=Context.CONTEXT_COURSECAT)
def total_turmas(self):
return self.coursecount + sum([c.coursecount for c in self.children.all()])
def total_alunos(self):
total = 0
total = total + sum(c.total_alunos() for c in self.courses.all())
total = total + sum(c.total_alunos() for c in self.children.all())
return total
def cohortids(self):
cids = [c.pk for c in self.context().cohort_set.all()]
for c in self.children.all():
cids = cids + c.cohortids()
return cids
def total_alunos_cohort(self):
return sum([c.members.distinct().count() for c in Cohort.objects.filter(pk__in=self.cohortids())])
def get_all_courses(self, only_visible=False):
if only_visible:
q = self.courses.filter(visible=1)
else:
q = self.courses.all()
for c in self.children.all():
q = q | c.get_all_courses(only_visible=only_visible)
return q
class CourseCompletions(models.Model):
id = models.BigIntegerField(primary_key=True)
user = models.ForeignKey('User', db_column='userid')
course = models.ForeignKey('Course', db_column='course')
timeenrolled = models.BigIntegerField()
timestarted = models.BigIntegerField()
timecompleted = models.BigIntegerField(blank=True, null=True)
reaggregate = models.BigIntegerField()
class Meta:
managed = False
db_table = 'mdl_course_completions'
class Enrol(models.Model):
id = models.BigIntegerField(primary_key=True)
enrol = models.CharField(max_length=20)
status = models.BigIntegerField()
course = models.ForeignKey('Course', db_column='courseid', related_name='enrols')
sortorder = models.BigIntegerField()
name = models.CharField(max_length=255, blank=True)
enrolperiod = models.BigIntegerField(blank=True, null=True)
enrolstartdate = models.BigIntegerField(blank=True, null=True)
enrolenddate = models.BigIntegerField(blank=True, null=True)
expirynotify = models.SmallIntegerField(blank=True, null=True)
expirythreshold = models.BigIntegerField(blank=True, null=True)
notifyall = models.SmallIntegerField(blank=True, null=True)
password = models.CharField(max_length=50, blank=True)
cost = models.CharField(max_length=20, blank=True)
currency = models.CharField(max_length=3, blank=True)
roleid = models.BigIntegerField(blank=True, null=True)
customint1 = models.BigIntegerField(blank=True, null=True)
customint2 = models.BigIntegerField(blank=True, null=True)
customint3 = models.BigIntegerField(blank=True, null=True)
customint4 = models.BigIntegerField(blank=True, null=True)
customchar1 = models.CharField(max_length=255, blank=True)
customchar2 = models.CharField(max_length=255, blank=True)
customdec1 = models.DecimalField(max_digits=12, decimal_places=7, blank=True, null=True)
customdec2 = models.DecimalField(max_digits=12, decimal_places=7, blank=True, null=True)
customtext1 = models.TextField(blank=True)
customtext2 = models.TextField(blank=True)
timecreated = models.BigIntegerField()
timemodified = models.BigIntegerField()
customint5 = models.BigIntegerField(blank=True, null=True)
customint6 = models.BigIntegerField(blank=True, null=True)
customint7 = models.BigIntegerField(blank=True, null=True)
customint8 = models.BigIntegerField(blank=True, null=True)
customchar3 = models.CharField(max_length=1333, blank=True)
customtext3 = models.TextField(blank=True)
customtext4 = models.TextField(blank=True)
class Meta:
managed = False
db_table = 'mdl_enrol'
ordering = ['sortorder', ]
def __unicode__(self):
if not self.name:
return self.enrol
return self.name
class User(models.Model):
id = models.BigIntegerField(primary_key=True)
auth = models.CharField(max_length=20)
confirmed = models.SmallIntegerField()
policyagreed = models.SmallIntegerField()
deleted = models.SmallIntegerField()
mnethostid = models.BigIntegerField()
username = models.CharField(max_length=100)
password = models.CharField(max_length=255)
firstname = models.CharField(max_length=100)
lastname = models.CharField(max_length=100)
email = models.CharField(max_length=100)
emailstop = models.SmallIntegerField()
icq = models.CharField(max_length=15)
skype = models.CharField(max_length=50)
yahoo = models.CharField(max_length=50)
aim = models.CharField(max_length=50)
msn = models.CharField(max_length=50)
phone1 = models.CharField(max_length=20)
phone2 = models.CharField(max_length=20)
institution = models.CharField(max_length=255)
department = models.CharField(max_length=255)
address = models.CharField(max_length=255)
city = models.CharField(max_length=120)
country = models.CharField(max_length=2)
lang = models.CharField(max_length=30)
theme = models.CharField(max_length=50)
timezone = models.CharField(max_length=100)
firstaccess = models.BigIntegerField()
lastaccess = models.BigIntegerField()
lastlogin = models.BigIntegerField()
currentlogin = models.BigIntegerField()
lastip = models.CharField(max_length=45)
secret = models.CharField(max_length=15)
picture = models.BigIntegerField()
url = models.CharField(max_length=255)
description = models.TextField(blank=True)
mailformat = models.SmallIntegerField()
maildigest = models.SmallIntegerField()
maildisplay = models.SmallIntegerField()
autosubscribe = models.SmallIntegerField()
trackforums = models.SmallIntegerField()
timemodified = models.BigIntegerField()
trustbitmask = models.BigIntegerField()
imagealt = models.CharField(max_length=255, blank=True)
idnumber = models.CharField(max_length=255)
descriptionformat = models.SmallIntegerField()
timecreated = models.BigIntegerField()
suspended = models.SmallIntegerField()
lastnamephonetic = models.CharField(max_length=255, blank=True)
firstnamephonetic = models.CharField(max_length=255, blank=True)
middlename = models.CharField(max_length=255, blank=True)
alternatename = models.CharField(max_length=255, blank=True)
calendartype = models.CharField(max_length=30)
class Meta:
managed = False
db_table = 'mdl_user'
def __unicode__(self):
return u'%s %s' % (self.firstname, self.lastname)
class UserEnrolments(models.Model):
id = models.BigIntegerField(primary_key=True)
status = models.BigIntegerField()
enrol = models.ForeignKey('Enrol', db_column='enrolid', related_name='user_enrolments')
user = models.ForeignKey('User', db_column='userid', related_name='Enrolments')
timestart = models.BigIntegerField()
timeend = models.BigIntegerField()
modifierid = models.BigIntegerField()
timecreated = models.BigIntegerField()
timemodified = models.BigIntegerField()
class Meta:
managed = False
db_table = 'mdl_user_enrolments'

3
sigi/apps/mdl/views.py

@ -1,3 +0,0 @@
from django.shortcuts import render
# Create your views here.

0
sigi/apps/saberes/__init__.py

13
sigi/apps/saberes/admin.py

@ -1,13 +0,0 @@
# -*- coding: utf-8 -*-
from django.utils.translation import ugettext as _
from django.contrib import admin
from sigi.apps.saberes.models import CategoriasInteresse
class CategoriasInteresseAdmin(admin.ModelAdmin):
list_display = ('prefixo', 'descricao', 'count_categorias',)
def count_categorias(self, obj):
return obj.categorias().count()
count_categorias.short_description = _("Categorias que casam")
admin.site.register(CategoriasInteresse, CategoriasInteresseAdmin)

0
sigi/apps/saberes/management/__init__.py

0
sigi/apps/saberes/management/commands/__init__.py

102
sigi/apps/saberes/management/commands/get_moodle_stats.py

@ -1,102 +0,0 @@
# -*- coding: utf-8 -*-
#
# sigi.apps.servicos.management.commands.get_moodle_stats
#
# Copyright (c) 2014 by Interlegis
#
# GNU General Public License (GPL)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#
from django.utils.translation import ugettext as _
from django.core.management.base import BaseCommand
from django.db.models import Sum, Avg
from sigi.apps.metas.views import gera_map_data_file
from sigi.apps.saberes.models import CategoriasInteresse, PainelItem
from sigi.apps.mdl.models import User, CourseStats
class Command(BaseCommand):
help = u'Get Moodle data and generate statistical panels.'
def handle(self, *args, **options):
areas = []
numeros = [
{'descricao': _(u'Total de usuários cadastrados'), 'valor': User.objects.count()},
{'descricao': _(u'Novos usuários cadastrados'), 'valor': User.objects.filter(firstaccess__gte=1392326052).count()}
]
for ci in CategoriasInteresse.objects.all():
if ci.coorte:
total_matriculas = ci.total_alunos_coorte()
elif ci.apurar_conclusao:
data = {x['completionstatus']: x for x in CourseStats.objects.filter(category__in=ci.categorias(subcategorias=True)).
values('completionstatus').annotate(total_users=Sum('usercount'), grade_average=Avg('gradeaverage'))}
total_matriculas = sum(x['total_users'] for k, x in data.items())
else:
total_matriculas = CourseStats.objects.filter(category__in=ci.categorias(subcategorias=True)). \
aggregate(total_users=Sum('usercount'))['total_users']
dados = [{'descricao': _(u'Total de matrículas'), 'valor': total_matriculas}]
if ci.coorte:
for c in ci.categorias(subcategorias=True):
dados.append({'descricao': c.name, 'valor': c.total_alunos_cohort()})
if ci.apurar_conclusao:
if 'N' in data:
dados.append({'descricao': _(u'Matrículas rejeitadas'), 'help_text': _(u'demanda reprimida'),
'valor': data['N']['total_users'], 'percentual': 100.0 * data['N']['total_users'] / total_matriculas})
total_alunos = total_matriculas - data['N']['total_users']
dados.append({'descricao': _(u'Alunos efetivos'), 'help_text': _(u'os percentuais seguintes se referem a este indicador'),
'valor': total_alunos})
else:
total_alunos = total_matriculas
if 'C' in data:
dados.append({'descricao': _(u'Alunos em curso'), 'valor': data['C']['total_users'],
'percentual': 100.0 * data['C']['total_users'] / total_alunos})
if 'L' in data:
dados.append({'descricao': _(u'Alunos que abandonaram o curso'), 'valor': data['L']['total_users'],
'percentual': 100.0 * data['L']['total_users'] / total_alunos})
if 'R' in data:
dados.append({'descricao': _(u'Alunos reprovados'), 'valor': data['R']['total_users'],
'percentual': 100.0 * data['R']['total_users'] / total_alunos})
if 'A' in data:
dados.append({'descricao': _(u'Alunos aprovados'), 'valor': data['A']['total_users'],
'percentual': 100.0 * data['A']['total_users'] / total_alunos})
if 'I' in data:
dados.append({'descricao': _(u'Situação indefinida'), 'valor': data['I']['total_users'],
'help_text': _(u'Situação do aluno não pode ser determinada pelo sistema'),
'percentual': 100.0 * data['I']['total_users'] / total_alunos})
if 'A' in data:
dados.append({'descricao': _(u'Média das notas dos alunos aprovados (%)'), 'valor': int(data['A']['grade_average'])})
if 'R' in data:
dados.append({'descricao': _(u'Média das notas dos alunos reprovados (%)'), 'valor': int(data['R']['grade_average'])})
areas.append({'titulo': ci.descricao, 'dados': dados})
paineis = [{'titulo': _(u'Saberes em números'), 'dados': numeros}] + areas
PainelItem.objects.all().delete() # Clear dashboard
for p in paineis:
for d in p['dados']:
PainelItem.objects.create(painel=p['titulo'], descricao=d['descricao'], help_text=d['help_text'] if 'help_text' in
d else '', valor=d['valor'], percentual=d['percentual'] if 'percentual' in d else None)

44
sigi/apps/saberes/migrations/0001_initial.py

@ -1,44 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
]
operations = [
migrations.CreateModel(
name='CategoriasInteresse',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('prefixo', models.CharField(help_text='Identifica as categorias no Moodle (campo idnumber) relacionadas a este interesse', max_length=100, verbose_name='Prefixo das categorias no Moodle')),
('descricao', models.CharField(max_length=100, verbose_name='Descri\xe7\xe3o')),
('sigla', models.CharField(max_length=20, verbose_name='Sigla')),
('coorte', models.BooleanField(default=False, help_text='Usa cohorte para calcular o n\xfamero de matr\xedculas/alunos', verbose_name='Usa Cohorte')),
('apurar_alunos', models.BooleanField(default=False, help_text='Indica que deve-se verificar o perfil da inscri\xe7\xe3o para saber se \xe9 um aluno ou se a matr\xedcula foi rejeitada', verbose_name='Apurar alunos')),
('apurar_conclusao', models.BooleanField(default=False, help_text='Indica se o dashboard mostrar\xe1 o n\xfamero de alunos aprovados, reprovados e desistentes', verbose_name='Apurar conclus\xe3o')),
],
options={
'verbose_name': 'Categorias de interesse',
},
bases=(models.Model,),
),
migrations.CreateModel(
name='PainelItem',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('painel', models.CharField(max_length=255)),
('descricao', models.CharField(max_length=255)),
('help_text', models.CharField(max_length=255)),
('valor', models.IntegerField()),
('percentual', models.FloatField(null=True)),
],
options={
'ordering': ['pk'],
},
bases=(models.Model,),
),
]

0
sigi/apps/saberes/migrations/__init__.py

74
sigi/apps/saberes/models.py

@ -1,74 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.utils.translation import ugettext as _
from django.db import models
from django.db.models import Q
from sigi.apps.mdl.models import Course, CourseCategories, CourseCompletions, UserEnrolments
class CategoriasInteresse(models.Model):
prefixo = models.CharField(_(u"Prefixo das categorias no Moodle"), max_length=100,
help_text=_(u"Identifica as categorias no Moodle (campo idnumber) relacionadas a este interesse"))
descricao = models.CharField(_(u"Descrição"), max_length=100)
sigla = models.CharField(_(u"Sigla"), max_length=20)
coorte = models.BooleanField(_(u"Usa Cohorte"), default=False, help_text=_(u"Usa cohorte para calcular o número de matrículas/alunos"))
apurar_alunos = models.BooleanField(_(u"Apurar alunos"), default=False, help_text=_(u"Indica que deve-se verificar o perfil da"
+ " inscrição para saber se é um aluno ou se a matrícula foi rejeitada"))
apurar_conclusao = models.BooleanField(_(u"Apurar conclusão"), default=False, help_text=_(u"Indica se o dashboard mostrará o "
+ "número de alunos aprovados, reprovados e desistentes"))
class Meta:
verbose_name = _(u'Categorias de interesse')
def __unicode__(self):
return self.descricao
def categorias(self, subcategorias=False):
def get_sub_categorias(categorias):
result = CourseCategories.objects.none()
for c in categorias:
c_children = CourseCategories.objects.filter(parent=c)
result = result | c_children | get_sub_categorias(c_children)
return result
q = CourseCategories.objects.filter(idnumber__startswith=self.prefixo)
if subcategorias:
q = q | get_sub_categorias(q)
return q
def get_all_courses(self, only_visible=False):
q = Course.objects.none()
for categoria in self.categorias():
q = q | categoria.get_all_courses(only_visible=only_visible)
return q
def get_all_completions(self):
q = CourseCompletions.objects.none()
for c in self.get_all_courses():
q = q | c.coursecompletions_set.all()
return q
def get_all_enrolments(self):
q = UserEnrolments.objects.none()
for c in self.get_all_courses():
q = q | c.get_matriculas()
return q
def total_alunos_coorte(self):
return sum(c.total_alunos_cohort() for c in self.categorias())
# A temporary model to store Moodle processed data by management command (called from CRON)
class PainelItem(models.Model):
painel = models.CharField(max_length=255)
descricao = models.CharField(max_length=255)
help_text = models.CharField(max_length=255)
valor = models.IntegerField()
percentual = models.FloatField(null=True)
class Meta:
ordering = ['pk']

13
sigi/apps/saberes/templates/saberes/dashboard.html

@ -1,13 +0,0 @@
{% extends "admin/base_site.html" %}
{# turned off to avoid bootstrap version conflict #}
{% block default_javascript %}{% endblock %}
{% block extrahead %}
{{ block.super }}
{{ headers|safe }}
{% endblock %}
{% block content %}
{{ content|safe }}
{% endblock %}

50
sigi/apps/saberes/templates/saberes/detail.html

@ -1,50 +0,0 @@
{% extends "admin/base_site.html" %}
{% block extrastyle %}
{{ block.super }}
<style>
td.number {
text-align: right;
}
.panel-body {
max-height: 400px;
overflow: auto;
}
</style>
{% endblock %}
{% block content %}
<div id="content-main">
<div class="page-header"><h1>Detalhes para {{ area.descricao }}</h1></div>
<div class="results">
<table class="table table-striped table-bordered" id="result_list">
<thead>
<tr>
{% for col_title in table_head %}
<th>{{ col_title }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for k, row in table_data.items %}
<tr class="row1">
<th>{{ row.course_name }}</th>
<td class='number'>{{ row.total_matriculas }}</td>
{% if 'N' in flags %}
<td class='number'>{{ row.N }}</td>
<td class='number'>{{ row.efetivos }}</td>
{% endif %}
{% if 'C' in flags %}<td class='number'>{{ row.C }}</td>{% endif %}
{% if 'L' in flags %}<td class='number'>{{ row.L }}</td>{% endif %}
{% if 'R' in flags %}<td class='number'>{{ row.R }}</td>{% endif %}
{% if 'A' in flags %}<td class='number'>{{ row.A }}</td>{% endif %}
{% if 'MA' in flags %}<td class='number'>{{ row.media_aprovados|floatformat:2 }}</td>{% endif %}
{% if 'MR' in flags %}<td class='number'>{{ row.media_reprovados|floatformat:2 }}</td>{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}

33
sigi/apps/saberes/templates/saberes/snippets.html

@ -1,33 +0,0 @@
<div class="row row-flex row-flex-wrap">
{% for k, painel in paineis.items %}
<div class="col-md-4">
<div class="panel panel-primary flex-col">
<div class="panel-heading">
{{ painel.titulo }}
{% if painel.area %}
<span class="badge"><a href="{% url "saberes-dashboard-detail" painel.area.id %}">Detalhes</a></span>
{% endif %}
</div>
<div class="panel-body">
<table class='table'>
{% for linha in painel.dados %}
<tr>
<th>
{{ linha.descricao }}
{% if linha.help_text %}
<span class="help-block">{{ linha.help_text }}</span>
{% endif %}
</th>
<td class='number' {% if not linha.percentual %}colspan="2"{% endif %}>{{ linha.valor }}</td>
{% if linha.percentual %}
<td class='number'>{{ linha.percentual|floatformat:2 }}%</td>
{% endif %}
</tr>
{% endfor %}
</table>
</div>
</div>
</div>
{% cycle '' '' '</div><div class="row">' %}
{% endfor %}
</div>

14
sigi/apps/saberes/urls.py

@ -1,14 +0,0 @@
# coding: utf-8
from django.conf.urls import patterns, url
from .views import cursos_sem_tutoria, cursos_com_tutoria, dashboard, pentaho_proxy
urlpatterns = patterns(
'sigi.apps.saberes.views',
url(r'^dashboard/cursos-sem-turoria/?$', cursos_sem_tutoria, name="saberes-cursos-sem-tutoria"),
url(r'^dashboard/cursos-com-turoria/?$', cursos_com_tutoria, name="saberes-cursos-com-tutoria"),
url(r'^dashboard/?$', dashboard, name="saberes-dashboard-view"),
url(r'^(?P<path>(plugin|api)/.*)$', pentaho_proxy),
)

50
sigi/apps/saberes/views.py

@ -1,50 +0,0 @@
# -*- coding: utf-8 -*-
import requests
from django.http import HttpResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from requests.auth import HTTPBasicAuth
from sigi.settings import PENTAHO_SERVER, PENTAHO_DASHBOARDS, PENTAHO_USERNAME_PASSWORD
PENTAHO_CDF_URL = 'http://%s/pentaho/plugin/pentaho-cdf-dd/api/renderer/' % PENTAHO_SERVER
def get_dashboard_parts(dashboard_id, this_host):
params = PENTAHO_DASHBOARDS[dashboard_id]
params['root'] = this_host
return [requests.get(PENTAHO_CDF_URL + method,
params=params, auth=HTTPBasicAuth(*PENTAHO_USERNAME_PASSWORD)).content
for method in ('getHeaders', 'getContent')]
def make_dashboard(dashboard_id, adjust_content=lambda x: x):
def view(request):
headers, content = get_dashboard_parts(dashboard_id, request.META['HTTP_HOST'])
if request.is_secure:
headers = headers.replace('http://', 'https://')
content = adjust_content(content)
return render(request, 'saberes/dashboard.html',
dict(headers=headers, content=content))
return view
def use_to_container_fluid(content):
return content.replace("class='container'", "class='container-fluid'")
dashboard = make_dashboard('saberes-geral')
cursos_sem_tutoria = make_dashboard('saberes-cursos-sem-tutoria', use_to_container_fluid)
cursos_com_tutoria = make_dashboard('saberes-cursos-com-tutoria', use_to_container_fluid)
@csrf_exempt
def pentaho_proxy(request, path):
url = 'http://%s/pentaho/%s' % (PENTAHO_SERVER, path)
params = request.GET or request.POST
auth = HTTPBasicAuth(*PENTAHO_USERNAME_PASSWORD)
response = requests.get(url, params=params, auth=auth)
return HttpResponse(response.content,
status=response.status_code,
content_type=response.headers.get('Content-Type'))

87
sigi/apps/utils/moodle_ws_api.py

@ -1,87 +0,0 @@
# -*- coding: utf-8 -*-
#
# sigi.apps.utils.moodle_ws_api
#
# Copyright (C) 2015 Interlegis
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import json
import urllib2
from django.conf import settings
def get_courses(ids=[], sort_order='', *args, **kwargs):
''' Implements core_courses_get_courses function
@param ids: list of course ids to retrieve, blank for all courses
@param sort_order: String field to sort the course list.
Prefix wuth - char to indicate reverse order
@param [field_name[__function]: Filters to apply, in django-style filters. Examples:
- idnumber__startswith='evento'
- format='topics'
- visible.__ge=1
@return: list of courses that matches with criteria
'''
extra_filters = []
for k, v in kwargs.items():
k = k.split('__')
field = k[0]
if len(k) == 1:
k[1] == 'eq'
filter = {'field': k[0]}
if k[1] == 'eq':
filter['function'] = '__eq__'
elif k[1] == 'ge':
filter['function'] = '__ge__'
elif k[1] == 'gt':
filter['function'] = '__gt__'
elif k[1] == 'le':
filter['function'] = '__le__'
elif k[1] == 'lt':
filter['function'] = '__lt__'
elif k[1] == 'ne':
filter['function'] = '__ne__'
else:
filter['function'] = k[1]
filter['value'] = v
extra_filters.append(filter)
params = []
for i, id in enumerate(ids):
params.append('options[ids][%s]=%s' % (i, id))
params = '&'.join(params)
url = '%s/%s?wstoken=%s&wsfunction=core_course_get_courses&moodlewsrestformat=json' % (
settings.SABERES_URL, settings.SABERES_REST_PATH, settings.SABERES_TOKEN)
courses = json.loads(urllib2.urlopen(url, params).read())
if 'errorcode' in courses:
raise Exception(u"%(errorcode)s (%(exception)s): %(message)s" % courses)
for filter in extra_filters:
courses = [c for c in courses
if getattr(c[filter['field']], filter['function'])(filter['value'])]
if sort_order:
if sort_order[0] == '-': # Reverse order
sort_order = sort_order[1:]
courses.sort(key=lambda x: x[sort_order])
courses.reverse()
else:
courses.sort(key=lambda x: x[sort_order])
return courses

8
sigi/settings/base.py

@ -38,9 +38,6 @@ TEMPLATE_LOADERS = ('django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
# Database routers
DATABASE_ROUTERS = ['moodlerouter.MoodleRouter', ]
# Application definition
INSTALLED_APPS = (
@ -70,10 +67,6 @@ INSTALLED_APPS = (
'sigi.apps.eventos',
'sigi.apps.whois',
# Integração com Saberes (moodle)
'sigi.apps.mdl',
'sigi.apps.saberes',
# Third-party apps
'localflavor',
'reporting',
@ -181,7 +174,6 @@ LOGGING = {
},
}
SABERES_REST_PATH = 'webservice/rest/server.php'
OSTICKET_URL = 'https://suporte.interlegis.leg.br/scp/tickets.php?a=search&query=%s'
REST_FRAMEWORK = {

13
sigi/settings/dev.py

@ -12,10 +12,6 @@ DATABASES = {
'PASSWORD': '123456',
'HOST': 'localhost',
},
'moodle': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'moodle.db'),
}
}
# SECURITY WARNING: don't run with debug turned on in production!
@ -33,11 +29,4 @@ CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
}
}
PENTAHO_SERVER = 'http://localhost.com/pentaho/'
PENTAHO_DASHBOARDS = ('saberes',)
PENTAHO_USERNAME_PASSWORD = 'root@root'
SABERES_URL = 'http://your-moodle-url.com'
SABERES_TOKEN = 'token-generated-by-moodle-to-access-webservice-api'
}

5
sigi/urls.py

@ -5,9 +5,6 @@ from django.conf.urls.static import static
from django.contrib import admin
from django.views.generic.base import TemplateView
from sigi.apps.saberes.views import pentaho_proxy
admin.site.index_template = 'index.html'
admin.autodiscover()
@ -20,12 +17,10 @@ urlpatterns = patterns(
url(r'^diagnosticos/', include('sigi.apps.diagnosticos.urls')),
url(r'^servidores/', include('sigi.apps.servidores.urls')),
url(r'^servicos/', include('sigi.apps.servicos.urls')),
url(r'^saberes/', include('sigi.apps.saberes.urls')),
url(r'^dashboard/', include('sigi.apps.metas.urls')),
url(r'^ocorrencias/', include('sigi.apps.ocorrencias.urls')),
url(r'^eventos/', include('sigi.apps.eventos.urls')),
url(r'^whois/', include('sigi.apps.whois.urls')),
url(r'^pentaho/(?P<path>(plugin|api)/.*)$', pentaho_proxy),
url(r'^', include('sigi.apps.home.urls')),
url(r'^', include(admin.site.urls)),

Loading…
Cancel
Save