Esta página resume o comportamento dos botões e fluxos da rota /admin/contests,
alinhada aos comentários e docstrings do código em
app/controllers/main.py, app/services/contest_sync_service.py e
app/integrations/local_store/contests_store.py.
localstorage/Contest.json (CONTESTS_JSON_PATH). Ao abrir a página, o backend só lê o JSON — não reexecuta SQL nem grava nada (admin_contests docstring).localstorage/problems_origin.json, problems_topics.json e problems_skills.json (gerados pelo botão de índices).
Rota: POST /admin/contests/rebuild-origin-json — admin_contests_rebuild_origin.
Docstring: “Varre metadatas do workspace e regera origin_problems, topic_problems e skill_problems.”
PARA cada pasta NNNN-slug em WORKSPACE_DIR (exceto . e problems-tools):
SE existe metadata.yaml:
LER YAML
SE campo origin: adicionar pasta ao mapa origin → [pastas]
PARA cada item em topics: adicionar pasta ao mapa topic_slug → [pastas]
PARA cada item em skills: adicionar pasta ao mapa skill_slug → [pastas]
GRAVAR localstorage/problems_origin.json
GRAVAR localstorage/problems_topics.json
GRAVAR localstorage/problems_skills.json
FLASH com contagens de chaves (origins, topics, skills)
REDIRECT de volta à tela (referrer ou /admin/contests)
Implementação: ContestsLocalStore.build_origin_problems(), build_topic_problems(), build_skill_problems() em contests_store.py.
Não chama API externa e não altera Contest.json.
UI: abre modal e faz fetch(GET /admin/contests/rebuild-hierarchy-stream) — streaming text/plain.
admin_contests_rebuild_hierarchy_stream docstring: atualiza Contest.json via API Mundo do Código.
sdk = MundoDoCodigoSDK()
sync_contests_from_api_stream(sdk, contests_json_path=CONTESTS_JSON_PATH)
// contest_sync_service.sync_contests_from_api — docstring:
// "Obtém disciplinas CONTEST e tópicos da API, monta o payload no formato Contest.json"
SE não houver bearer_token: sdk.authenticate()
disciplines = GET /api/admin/disciplines // get_admin_disciplines_all
PARA cada disciplina d:
topics_raw = GET .../disciplines/{slug}/topics/list
topics = normalizar (item_order, level, etc.) // _topics_to_list
PARA cada tópico: GET admin topic por slug (enriquecer description, event_url, event_fase)
PARA cada tópico: GET exercícios da disciplina no tópico → t["exercises"]
contest = _discipline_to_contest(d, topics, is_active_fallback do JSON antigo se existir)
acrescentar contest à lista
GRAVAR {"contests": [...]} em localstorage/Contest.json
// Cada linha de log é enviada ao navegador em streaming.
// Ao fechar o modal, a UI pode recarregar a página para ver a lista nova.
Detalhes e normalização de campos: app/services/contest_sync_service.py (comentários no topo do arquivo e em sync_contests_from_api).
#tab-eventos / #tab-exercises./project/<pasta>. Dados vêm dos JSON de índice; se vazios, a própria tela pede para clicar em “Atualizar índices”.data-discipline-type (CONTEST vs outros). Atualiza query string ?filter= e ?contest= via history.replaceState (updateContestsUrl).selectContest(id) — destaca o botão, preenche a coluna de tópicos (ou mensagem “Nenhum tópico”), limpa o painel de exercícios até escolher um tópico.GET /admin/contests/<id>/edit — admin_contest_edit docstring: “Página de edição avançada de um único curso/disciplina.” Abre em nova navegação (não é o modal de contest da mesma página).sortTopics). Para disciplinas não-CONTEST com modo “Ordem (módulo)”, agrupam por item_order com rótulo “Módulo N”.selectTopic — monta lista de exercícios a partir de exercisesByKey["<contestId>-<topicSlug>"] (calculado no backend por exercises_by_contest_topic: prefere topic.exercises da API/JSON; senão, nomes vindos de topic_problems).POST /admin/contests/update-topic (JSON). Docstring: atualiza tópico na API; opcionalmente PATCH em discipline-topic (level, item_order); em seguida tenta refletir alterações no Contest.json local.// admin_contests_update_topic (resumo)
PUT admin topic (campos name, slug, description, eventUrl, eventFase)
SE level ou item_order enviados:
PATCH /api/admin/disciplines/topics // patch_admin_discipline_topic
ATUALIZAR entrada do tópico correspondente em Contest.json (se encontrar por id)
RETORNAR { ok, local_updated, ... }
POST /admin/contests/update-discipline (JSON). Docstring: “Atualiza uma disciplina (contest) no banco via API Mundo do Código.” — sdk.put_admin_discipline. Nota: no template atual o modal existe e a função JS openEditContestModal está definida, mas a lista lateral usa o link ✏️ para a página avançada; o modal de contest pode não estar ligado a um botão visível na lista.item_order).<pre id="contest-rebuild-log">. Botão fechar pode chamar window.location.reload().GET /admin/contests/<id>/edit-discipline-topics — admin_contest_edit_discipline_topics: tela para editar pontuação (discipline topic) em tabela.POST /admin/contests/<id>/save-discipline-topics — admin_contest_save_discipline_topics: salva em lote na API e no Contest.json.POST /admin/contests/rebuild-hierarchy — admin_contests_rebuild_hierarchy: apenas redireciona para /admin/contests; o sync real é o endpoint stream.