mirror of https://github.com/interlegis/sigi.git
Sesostris Vieira
4 years ago
33 changed files with 143 additions and 7123 deletions
@ -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 |
@ -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, |
|||
), |
|||
] |
@ -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', |
|||
), |
|||
] |
@ -1,3 +0,0 @@ |
|||
from django.contrib import admin |
|||
|
|||
# Register your models here. |
File diff suppressed because it is too large
@ -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,), |
|||
), |
|||
] |
@ -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' |
@ -1,3 +0,0 @@ |
|||
from django.shortcuts import render |
|||
|
|||
# Create your views here. |
@ -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) |
@ -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) |
@ -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,), |
|||
), |
|||
] |
@ -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'] |
@ -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 %} |
@ -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 %} |
@ -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> |
@ -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), |
|||
) |
@ -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')) |
@ -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 |
Loading…
Reference in new issue