📖 Ajuda — Contests · Affiliates

← Voltar à tela

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.

Dados que a tela usa

  • Lista de contests: lida de 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).
  • Aba “Exercícios (índices)”:localstorage/problems_origin.json, problems_topics.json e problems_skills.json (gerados pelo botão de índices).
  • Links para problemas: usam a pasta do workspace (slug do repositório), não a API.

Botões no topo da página

Atualizar índices (origin, topics, skills)

Rota: POST /admin/contests/rebuild-origin-jsonadmin_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.

Atualizar lista de contests

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).

Abas: Eventos | Exercícios (índices)

  • Eventos: três colunas (lista de eventos → tópicos → exercícios). Apenas JavaScript no cliente; alterna visibilidade de #tab-eventos / #tab-exercises.
  • Exercícios (índices): três colunas “Por origin / Por topic / Por skill” com links para /project/<pasta>. Dados vêm dos JSON de índice; se vazios, a própria tela pede para clicar em “Atualizar índices”.

Aba Eventos — coluna “Eventos”

  • Todos / Contests / Disciplines: filtram linhas por data-discipline-type (CONTEST vs outros). Atualiza query string ?filter= e ?contest= via history.replaceState (updateContestsUrl).
  • Clique no nome do evento: 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.
  • ✏️ ao lado do evento: link GET /admin/contests/<id>/editadmin_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).

Aba Eventos — coluna “Tópicos”

  • Level / Ordem (módulo) / Alfabético: reordenam a lista em memória (sortTopics). Para disciplinas não-CONTEST com modo “Ordem (módulo)”, agrupam por item_order com rótulo “Módulo N”.
  • Clique no tópico: 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).
  • ✏️ no tópico: abre modal “Editar Tópico”. Ao salvar: 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, ... }

Modais na mesma página

  • Editar Contest (modal): formulário com id, nome, slug, descrição. Submit → 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.
  • Editar Tópico (modal): como acima; inclui level (BASIC/NORMAL/ADVANCED/REVISION) e módulo (item_order).
  • Log “Atualizar lista de contests”: stream no <pre id="contest-rebuild-log">. Botão fechar pode chamar window.location.reload().

Rotas relacionadas (fora da lista principal)

  • GET /admin/contests/<id>/edit-discipline-topicsadmin_contest_edit_discipline_topics: tela para editar pontuação (discipline topic) em tabela.
  • POST /admin/contests/<id>/save-discipline-topicsadmin_contest_save_discipline_topics: salva em lote na API e no Contest.json.
  • POST /admin/contests/rebuild-hierarchyadmin_contests_rebuild_hierarchy: apenas redireciona para /admin/contests; o sync real é o endpoint stream.