Commit Graph

91 Commits

Author SHA1 Message Date
4a8a10971c Refactor: bind content admin forms via @ModelAttribute DTOs 2026-09-27 22:06:09 +03:00
9a2a4023b5 Refactor: split loop/throws helpers; drop deprecated JSON accessors 2026-09-27 22:02:56 +03:00
511df7977e Refactor: extract helpers to satisfy detekt (throws, returns, loops) 2026-09-27 22:00:15 +03:00
b7d96d2ea4 Refactor: reduce detekt findings (unused params, throws, long methods, config) 2026-09-27 21:54:00 +03:00
f3e8b2668f Build: enable ktlint+detekt, format sources, add core unit tests 2026-09-27 21:46:05 +03:00
802616918f Admin: name submission archives as group-studentNo-name-attempt 2026-09-27 20:46:17 +03:00
a8785d48d9 Submissions: reject XML project files, show submitted file names to admin 2026-09-24 11:32:19 +03:00
0bb55e6e4b Fix mobile layout; scroll tables themselves, not cards 2026-09-17 22:13:56 +03:00
3c40ffb11d Bump LMS version to 0.2.0 2026-09-17 21:19:52 +03:00
51f0836894 Learn: remember expanded sections, open only in the last chapter by default 2026-09-17 20:41:54 +03:00
930e2fb580 Learn: remove link underlines 2026-09-17 20:35:29 +03:00
22b732633c Learn: section actions on the title row, scrollable tables, copy code 2026-09-17 20:16:35 +03:00
78b72267a8 Learn: drag handles on the left, chapters always expanded 2026-09-17 19:56:35 +03:00
cb4cfee05b Learn: drag & drop sections and articles on chapter and section pages 2026-09-17 19:15:56 +03:00
03c712fe2f Learn: fix navigate buttons 2026-09-17 19:01:52 +03:00
80f551745a Learn: fix alert notification 2026-09-17 18:55:57 +03:00
57052ed117 Learn: icon formatting toolbar; fix editor shown when hidden 2026-09-17 18:38:19 +03:00
c111dce6da Learn: inline markdown editor with formatting toolbar; drop edit modals 2026-09-17 18:31:43 +03:00
8753d3658e Learn: outline panel moved to the left of the article
- article layout: content column on the right, sticky outline (chapters, sections,
  articles) on the left; on narrow screens the article comes first and the
  outline follows it
2026-09-17 17:36:54 +03:00
df5020fea6 Learn UI: prev/next navigation, sidebar outline, editing on every page; merge import; defense date
- article page: ← / → navigation across the whole material tree (including
  between sections), sticky sidebar outline with the current article highlighted
- editing on chapter, section and article pages: rename, publish/hide, delete,
  create section/article, move articles while deleting a section; forms return
  to the page they were opened from (validated internal `back` parameter)
- article page opens the edit dialog directly via ?edit=1 (used by "Править"
  links on section/chapter pages)
- import: optional sync flag — with it stale sections/articles of archived
  chapters are deleted (previous behaviour), without it import only adds and
  updates, so material edited in the UI is not overwritten
- student area: lab page and lab cards now show the defense date next to the
  submission deadline
- fix SpEL crash on the student lab page (`and` with nullable strings)
2026-09-17 17:14:16 +03:00
6246d4c8d3 Materials: images with captions and video support
- markdown: new directives `:::figure assets/x.png | Подпись` and
  `:::video assets/x.mp4 | Подпись` rendered as figure/figcaption and a
  video player (works with HTML escaping on); sanitizer allows video/source/
  track/figure with safe attributes only
- assets: video extensions (mp4/webm/ogg) allowed, separate limits — images
  up to 10 MB, video up to 100 MB; correct content types
- upload limits raised: web/academic multipart 120 MB per file / 200 MB per
  request, nginx client_max_body_size 200m (covers media inside ZIP imports)
- docs: new docs/06-authoring.md (markdown, images, video, assets, limits,
  import semantics); import message now says "медиафайлов"
2026-09-17 15:44:16 +03:00
a1392a469e Content import: sync sections and articles (archive is the source of truth)
- importZip now updates titles/positions of existing chapters and sections and
  removes sections/articles of archived chapters that are missing in the archive
  (so restructured material no longer leaves stale sections behind); removed
  count is reported in ContentImportResult and in the admin flash message
- docs: note about import semantics in the class diagram and sequences
2026-09-16 22:00:22 +03:00
da464f882a Content sort: autosave without reload; keep page state across reloads
- drag & drop now saves in the background (700 ms debounce) without reloading:
  sections stay open, scroll position is kept; on failure it retries every 3 s,
  and navigator.sendBeacon flushes unsaved changes on page leave
- removed the explicit save button (autosave only), status indicator shows
  «Изменения не сохранены… / Сохранение… / Порядок сохранён»
- new global ui-state.js: restores open <details> and scroll position after any
  reload/redirect within the same page (applies to all pages, not just /learn)
- auto-expand a collapsed chapter/section while hovering during drag
2026-09-16 19:00:03 +03:00
5ffeaa0217 Content: drag & drop reordering and moving of chapters, sections and articles
- academic: POST /api/v1/content/reorder applies a full tree arrangement in one
  request — chapter order, section order and section->chapter moves, article
  order and article->section moves (positions and parent ids updated)
- web: POST /admin/content/reorder accepts the tree from JS (CSRF via query
  param), calls the gateway with the admin token
- /learn admin view: draggable handles (⠿) for chapters, sections and articles;
  drop before/after to reorder, drop into a chapter/section to move; visual
  indicators; structure is collected from DOM and saved, then page reloads
- docs: class diagram method + new sequence diagram for drag & drop
2026-09-16 18:51:21 +03:00
c379be7fba Content: publish/hide chapters, sections and articles
- migration V5 adds published flag (default true) to chapters/sections/articles
- ContentService: tree(includeHidden) filters, treeAll(), findArticle(includeHidden),
  set*Published; public tree/article expose only published items
- admin API: GET /tree/all, GET /all/{chapter}/{section}/{article}, PUT
  /{chapters|sections|articles}/{id}/published
- web: learn pages for admins load the full tree, show "скрыто" badges and
  publish/hide buttons for every chapter, section and article; hidden articles
  open in preview for admins, guests get "not found"; article view carries
  published flag
2026-09-16 18:29:44 +03:00
2a0e8ddf9f Table columns: dropdown/text filters per column
- tablekit builds a filter row under the headers for every th with data-filter;
  distinct cell values become a select (label from data-filter-label), or a
  text substring filter with data-filter="text"
- filters combine with the global table search; placeholder rows (colspan) are
  not filtered away; filter row follows the lab-focus column hiding
- enabled on: matrix lab columns (by variant), defense table (ЛР, status with
  readable values), students (Основа, Пароль), lab assignment lists (Уровень,
  Источник, Сдача), labs list (Статус)
2026-09-15 22:43:48 +03:00
a4f2c7db90 Tables: initial ФИО order, click-to-sort columns, substring search
- identity group detail (and thus every student list) is ordered by full name;
  defense rows on the group page sorted by name + lab number
- tablekit.js: click a header to sort (numeric-aware, ru locale), second click
  flips direction (▲/▼ indicator); search input with data-target filters rows
  by substring live
- tables wired: group matrix (with data-sort on variant cells), defense table
  (data-sort on status/date), students table, lab assignment lists per group,
  groups list and labs list; name/number columns pre-marked ascending
- non-sortable columns marked data-nosort (checkbox/actions)
2026-09-15 22:38:42 +03:00
cdf4fb0ee0 Phase 7: deployment, data import, UI hardening and security fixes
Docker/prod deployment:
- multi-stage Dockerfile (JDK21 build, JRE21 run), docker-compose.prod.yml,
  nginx config for lms.our-place.ru, deploy.sh; DEPLOY/IMPORT guides (UI flow)
- Fix Docker 401: LMS_JWT_JWK_SET_URI for academic/progress; forward-headers

Variant distribution (lab page only):
- round-robin by student level, shared random queue across selected groups,
  least-used variants, manual pins always preserved; occupied/dup labels
- setup page: single form + one «Сохранить всё», batch level/variant for
  selected students (checkboxes)

Grades, defense, materials:
- publication gate + comment lists; defense CSV import (2/3 cols, quotes)
- additional task after defense ("начать заново"); enroll/unenroll students
  from group page; temporary-password lock (no navigation until changed) and
  persistent "Смена пароля"; forced change once
- chapter page /learn/{c}; header: LMS home, Войти, user -> dashboard,
  compact theme toggle; responsive mobile header
- markdown: single newlines are soft breaks; highlight.js with light/dark themes
- lab/content imports ZIP-only (lab.yaml+README+variants/assets,
  chapters tree+assets); duplicate lab numbers rejected; variant ordering
  and date defaults honored

Fixes:
- 500 on student create (@MapsId set before persist); broken dialogs/JS refs in group page
2026-09-15 00:09:28 +03:00
5e60cc3819 Phase 6: accordion in /learn; README feature notes; tests green
- collapse chapters/sections via styled <details> with chevrons
- identity testcontainers smoke passes on JDK 21
- README: student UX, comments, JDK note (logback ThrowableProxy in
  fat-jars → restart recovery), data dirs
2026-09-12 02:00:45 +03:00
76a9a915c2 Phase 4: grade comments with frequency-ranked suggestions
- progress comment_templates (tone + use_count) and grade_comments tables;
  setGrade now accepts comments list; templates created/bumped automatically;
  GET /api/v1/comment-templates?q= returns suggestions ranked by frequency
- admin group page: per-grade ✎ dialog (score + editable comment rows with
  tone, datalist suggestions), chips under each score, data-comments JSON attr
- student lab page: score + colored tone chips
- fixed damaged button/attributes from earlier manual template surgery
2026-09-12 01:51:23 +03:00
d6fc47794e Phase 3: individual defense assignments with invite codes
- progress V5 defense_sessions: per student+lab individual task (md), status
  machine waiting -> started -> ready, one-time 6-digit codes
- 30-min timer with server-side lazy expiry (syncTimeouts: started->ready by
  timeout), countdown JS on student page
- admin: assign task dialog (+prefill existing via data-md), CSV import
  (studentNo;task, \n for newlines) resolved via identity students,
  issue/reset code buttons, defense status column
- student: code entry form (code hidden until start), assignment md,
  'Готов к сдаче', waiting-for-teacher note
- gateway: /api/v1/defenses,/api/v1/defenses/** routes
- web api client + admin/student controllers wired
2026-09-12 00:54:10 +03:00
e1da254599 Phase 2+5: lab submissions and student lab flow
- progress: submissions table+V4; SubmissionService (deadline-gated submit,
  unlimited resubmits, per-student history, zip download); files on disk
  data/submissions/{student}/{lab}/{seq}/
- student API: POST submit (multipart), GET me submissions, download; admin
  GET lab submissions + admin download (zip pack)
- progress enrich(): labId in MeAssignment; web DTO aligned
- web: /student dashboard (avg/best/worst cards), /student/labs cards,
  /student/labs/{id}: condition md, variant block, submit form, history;
  'Лабораторные' link in nav for students
- admin: submissions column on lab assignment table + download link
- fixed long-standing template bug: broken @{} expression (missing }) in
  admin/lab and student/lab
2026-09-12 00:20:46 +03:00
eb55f47f47 Phase 1 fixes: broken dialogs, score width, status badge, MSK date round-trip
- group/lab/labs: move dialogs/scripts INSIDE the #content fragment (they were
  outside — the layout fragment dropped them, which is why 'add student' did nothing)
- group.html toast had swallowed the dialog (th:if createdStudent) — split properly
- .input-score width no longer overridden by .inline-form .input-sm (10rem min)
- lab page: remove separate 'change status' button — status badge is now a toggle
  button itself (confirm dialog kept)
- DateUtils.localInput/toUtcIso: dates entered in datetime-local are Moscow-local,
  stored as UTC instant, shown back MSK — correct round-trip both ways
- academic parseInstant: naive local datetimes treated as Europe/Moscow
- README/module docs left as-is
2026-09-11 23:11:40 +03:00
8336c5a9b2 Moscow-time date display, CSRF error UX, session cookie hardening
- DateUtils: format ISO instants as dd.MM.yyyy HH:mm in Europe/Moscow
- admin/lab page and student dashboard show deadlines in MSK time
- CSRF failure redirects to /login with friendly message instead of 403
- session tracking-modes=cookie (no ;jsessionid in URLs) (previously set)
- web rebuild with all dialog/status-toggle fixes verified end-to-end
2026-09-11 21:55:08 +03:00
12383e7c39 Fix learn dialog rendering, add lab publish/draft toggle, bump to v0.1.2
- learn/index.html: restructured dialogs inside section divs to fix scope
- learn/index.html: edit-article dialogs via flat articles list in modal blocks
- LearnController: sectionChoices for select options; secure article fetching
- ContentService: createArticlePlaced: new section adjacent to anchor section
- lab status: published = student-visible, draft = hidden
- lab toggle: click badge in labs list or button in lab header to switch status
- added badge-btn CSS class, removed inline styles
- removed all th:onclick with expressions → data-modal attributes
- footer v0.1.2
2026-09-11 20:41:11 +03:00
08890875e5 UI rework: modal dialogs, inline lab editing, manual creation, content management
- Dashboard: real stats (groups, students, labs, average grade), labs/groups
  summary lists, no placeholder tile
- Lab page: view + edit combined — metadata form in modal, condition rendered
  as markdown, per-level variant tables with add/edit/delete dialogs,
  level rename/delete, student level/variant selectors with group filter
- Labs list: create-lab dialog with manual level entry (code; title lines)
- Groups: create-group dialog, add-student dialog (auto password, toast card)
- Content: public /learn reader is the single place; admin buttons (new
  article with chapter/section create-or-select, rename/delete chapters and
  sections, move articles between sections, import zip) appear for admins;
  removed separate 'Контент' admin section
- Buttons use btn classes instead of nav-link
- Favicon: generated SVG book icon
- Security: CSRF synchronizer token interceptor (replaced spring-security in
  web which broke logback under nested jars), session regenerated on login,
  hardened session cookie, gateway actuator limited to health,info
- Jackson 3: nullable-safe request DTOs for labs (FAIL_ON_NULL_FOR_PRIMITIVES)
- academic: POST /labs (manual create with levels), level add/rename/delete,
  content chapters/sections CRUD, article create/move/delete endpoints
2026-09-11 16:00:56 +03:00
cca20b5416 Lab editing and group grades
- academic-service: PUT /labs/{id} (title, deadline, defense, points, status,
  description), POST/PUT/DELETE variants endpoints
- progress-service: lab_grades table, POST/GET /api/v1/grades, GET /me/grades
- gateway: routes for /api/v1/assign and /api/v1/grades
- web: lab edit page (metadata + per-variant forms + add/delete variant)
- web: group page shows grades matrix per lab with editable score inputs
  and computed average column
- web: student dashboard renders statement via markdown, shows deadline
2026-09-11 00:03:24 +03:00
feed600d43 Lab assignment management UI and student variant view
- progress-service: POST /api/v1/assign (manual variant), GET /api/v1/assignments?labId=
  (enriched assignments), fixed enrich() to return real variant number/title/statement
- gateway: routes for /api/v1/assign and /api/v1/levels (exact paths)
- web: lab detail page shows students grouped with level and variant selects,
  group filter, distribute/redistribute buttons, source badge (auto/manual)
- web: student dashboard renders variant statement via libs/markdown (spoilers,
  code highlight, sanitized)
- academic-service: unquote YAML front-matter values (variant numbers were quoted)
- academic-service: LabLevelDetail.id for level references
2026-09-10 23:25:36 +03:00
0fdb9faab6 Complete distribution flow and student UI
- progress-service: Distribute variants (round-robin per lab per level),
  student level assignment, API for levels/assignments
- progress-service: Inter-service clients (academic, identity) via RestClient
- web: Admin lab detail page with distribute/level buttons
- web: Student dashboard shows assigned labs from progress-service
- web: ApiClient methods for labs detail, distribute, levels, me/assignments
- academic-service: Add id to LabLevelDetail DTO for progress-service
- Fix: CSS-only layout, footer at bottom via flex column
2026-09-10 22:18:47 +03:00
b48cf1d1e3 Refactor web UI: CSS classes only, no inline styles; fix footer; add full lab1.zip
- Replace all inline style= with reusable CSS classes
- Add layout classes: page, page-header, page-main, page-footer
- Fix footer at bottom via flex column + flex:1 on main
- Remove jsessionid from static resource URLs
- Create lab1-full.zip with 30 variants from PDF metodichka
- All templates use CSS var classes for light/dark theme
2026-09-10 21:29:10 +03:00
2cee104633 Initial commit: LMS microservices scaffold
- Gradle multi-module: libs/{common-http,security-jwt,markdown,test-support},
  services/{identity,academic,progress,gateway}, web (Thymeleaf+htmx)
- identity-service: JWT auth (RSA), accounts, students, groups, enrollment,
  import from XLSX/CSV, credentials export, password reset
- academic-service: lab import from JSON/zip (markdown + YAML + variants),
  levels, API
- progress-service: schema for student levels and variant assignments
- gateway: Spring Cloud Gateway, JWT validation, route propagation
- web: Server-side UI with flex/footer layout, light/dark theme toggle,
  admin dashboard, groups CRUD, student portal placeholder
- docker-compose: PostgreSQL 18
- Tests: identity smoke test with Testcontainers
2026-09-10 19:46:13 +03:00