Este documento descreve a API de integração do broker suap2local_suap:
o broker que recebe payloads no padrão Suap e os envia ao plugin Moodle local_suap.
Status: implementado e em produção.
Visão geral¶
| Item | Valor |
|---|---|
| Plugin Moodle | local_suap |
| Endpoint Moodle | /local/suap/api/index.php |
| Broker (classe) | Suap2LocalSuapBroker (src/integrador/brokers/suap2local_suap/) |
| Autenticação Moodle | Authentication: Token <token_do_ambiente> |
| Autenticação cliente | Authentication: Token <SUAP_INTEGRADOR_KEY> |
Endpoints do Integrador¶
POST /api/enviar_diarios/¶
Sincroniza matrículas, papéis e coortes no Moodle para um diário.
Headers obrigatórios¶
Payload (padrão Suap)¶
Todos os campos a seguir são obrigatórios.
{
"campus": {
"id": 1,
"sigla": "ZL",
"descricao":"Campus Zona Leste"
},
"curso": {
"id": 1,
"codigo": "15806",
"nome": "Sistemas Operacionais Abertos"
},
"turma": {
"id": 2,
"codigo": "20261.6.15806.1E"
},
"componente": {
"id": 1,
"sigla": "TEC.1023",
"descricao":"Bancos de Dados"
},
"diario": {
"id": 2,
"sigla": "TEC.1023",
"situacao": "Aberto"
}
}
Campos obrigatórios por objeto¶
| Objeto | Campos obrigatórios |
|---|---|
campus |
id, sigla, descricao |
curso |
id, codigo, nome |
turma |
id, codigo |
componente |
id, sigla, descricao |
diario |
id, sigla, situacao |
Payload enviado ao Moodle¶
O broker injeta a lista de coortes selecionadas (calculada pelo BaseBroker.get_cohort()
com base nas regras rule_diario e rule_coordenacao dos cohorts ativos) antes de enviar
ao Moodle:
{
"campus": { ... },
"curso": { ... },
"turma": { ... },
"componente": { ... },
"diario": { ... },
"coortes": [
{
"nome": "Professores ZL",
"role": "editingteacher",
"ativo": true,
"idnumber":"prof-zl",
"descricao":"Corpo docente do campus ZL",
"colaboradores": [
{
"nome": "João da Silva",
"email": "joao@ifrn.edu.br",
"login": "joao.silva",
"status": true
}
]
}
]
}
Resposta de sucesso (HTTP 200)¶
O Integrador adiciona ambiente à resposta do plugin:
{
"url": "https://ava.zl.ifrn.edu.br/course/view.php?id=42",
"url_sala_coordenacao": "https://ava.zl.ifrn.edu.br/course/view.php?id=43",
"roles_not_found": [],
"ambiente": "https://ava.zl.ifrn.edu.br"
}
Respostas de erro¶
| Código | Condição |
|---|---|
| 400 | Método não é POST |
| 401 | Header Authentication ausente ou token inválido |
| 404 | Nenhum Ambiente ativo corresponde ao payload |
| 422 | Payload com campos obrigatórios ausentes |
| 525 | Erro ao obter coortes (falha interna antes de chamar o Moodle) |
| 5xx | Erro do Moodle ou falha de comunicação |
Corpo do erro (exemplo 422):
{
"code": 422,
"error": "Campos obrigatórios ausentes no payload de sync_up_enrolments: campus.id, curso.nome.",
"event_id": "sentry-event-id"
}
GET /api/baixar_notas/¶
Baixa as notas de um diário do Moodle.
Headers obrigatórios¶
Query parameters¶
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
campus_sigla |
string | Sim | Sigla do campus (para seleção do ambiente) |
diario_id |
int | Sim | ID do diário no SUAP |
Exemplo:
Resposta de sucesso (HTTP 200)¶
Respostas de erro¶
| Código | Condição |
|---|---|
| 400 | Método não é GET |
| 401 | Header Authentication ausente ou token inválido |
| 404 | Nenhum Ambiente ativo corresponde ao campus_sigla |
| 5xx | Erro do Moodle ou falha de comunicação |
Stack de decorators¶
As views são compostas por decorators aplicados de fora para dentro:
sync_up_enrolments¶
@transaction.atomic
@json_response ← garante JsonResponse na saída
@exception_as_json ← captura exceções → JSON + Sentry
@check_is_post ← rejeita se não for POST (400)
@valid_token ← valida SUAP_INTEGRADOR_KEY (401)
@check_json(operacao) ← valida Content-Type e carrega JSON recebido
@detect_ambiente ← seleciona Ambiente via expressao_seletora
@try_solicitacao ← cria registro Solicitacao, atualiza status
sync_down_grades¶
@transaction.atomic
@json_response
@exception_as_json
@check_is_get ← rejeita se não for GET (400)
@valid_token
@detect_ambiente ← usa ?campus_sigla= para seleção
@try_solicitacao
Fluxo completo — sync_up_enrolments¶
SGA (SUAP)
│ POST /api/enviar_diarios/
│ Authentication: Token <SUAP_INTEGRADOR_KEY>
│ { campus, curso, turma, componente, diario }
▼
Integrador (Django)
├── valid_token → verifica SUAP_INTEGRADOR_KEY
├── check_json → carrega JSON recebido
├── detect_ambiente → seleciona Ambiente via expressao_seletora
├── try_solicitacao → cria Solicitacao(status=P)
├── _validate_sync_payload → verifica campos obrigatórios (422 se falhar)
├── get_cohort → calcula lista de coortes elegíveis
├── POST local_suap → { ...payload, coortes: [...] }
└── atualiza Solicitacao(status=S/F) + retorna ao SGA
▼
Plugin Moodle (local_suap)
Authentication: Token <token_do_ambiente>
→ cria curso, matricula usuários, atribui papéis
→ retorna { url, url_sala_coordenacao, roles_not_found }
Variáveis de ambiente¶
| Variável | Descrição |
|---|---|
SUAP_INTEGRADOR_KEY |
Token que o SGA deve enviar no header Authentication |
DJANGO_SECRET_KEY |
Chave secreta Django |
Configuradas em src/settings/securities.py e injetadas via .env ou Docker Compose.
Teste local sem Moodle real¶
Use LocalSuapHTTPMock para simular o endpoint /local/suap/api/index.php:
from integrador.moodle_mock import LocalSuapHTTPMock
mock = LocalSuapHTTPMock()
response = mock.post(
"https://moodle.test/local/suap/api/index.php?sync_up_enrolments",
jsonbody={
"campus": {"id": 1, "sigla": "ZL", "descricao": "Campus ZL"},
"curso": {"id": 1, "codigo": "15806", "nome": "Sistemas Operacionais Abertos"},
"turma": {"id": 2, "codigo": "20261.6.15806.1E"},
"componente": {"id": 1, "sigla": "TEC.1023", "descricao": "Bancos de Dados"},
"diario": {"id": 2, "sigla": "TEC.1023", "situacao": "Aberto"},
},
headers={"Authentication": f"Token {LocalSuapHTTPMock.TOKEN}"},
)
assert response.ok
Documentação completa do mock: docs/tests/moodle_mock.md
Referências de código¶
| Artefato | Caminho |
|---|---|
| Broker | src/integrador/brokers/suap2local_suap/__init__.py |
| Base do broker | src/integrador/brokers/base/__init__.py |
| Views | src/integrador/views.py |
| URLs | src/integrador/urls.py |
| Decorators | src/integrador/decorators.py |
| Mock HTTP | src/integrador/moodle_mock.py |
| Testes | src/integrador/tests.py → Suap2LocalSuapBrokerTestCase, LocalSuapHTTPMockTestCase |
| Exemplo de requisição | requests.http (raiz do projeto) |