diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts index d35ec7fb..b2d3b1ec 100644 --- a/backend/build.gradle.kts +++ b/backend/build.gradle.kts @@ -3,12 +3,12 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - id("org.springframework.boot") version "4.0.6" + id("org.springframework.boot") version "4.1.1" id("io.spring.dependency-management") version "1.1.7" - id("org.owasp.dependencycheck") version "12.2.2" - kotlin("jvm") version "2.3.21" - kotlin("plugin.spring") version "2.3.21" - id("org.sonarqube") version "7.3.0.8198" + id("org.owasp.dependencycheck") version "13.0.0" + kotlin("jvm") version "2.4.10" + kotlin("plugin.spring") version "2.4.10" + id("org.sonarqube") version "7.5.0.8588" } group = "hu.bme.sch" @@ -54,18 +54,18 @@ dependencies { implementation("com.github.spullara.mustache.java:compiler:0.9.14") implementation("com.google.zxing:core:3.5.4") implementation("com.google.zxing:javase:3.5.4") - implementation("com.itextpdf:itext-core:9.6.0") - implementation("com.squareup.okhttp3:okhttp:5.3.2") + implementation("com.itextpdf:itext-core:9.7.1") + implementation("com.squareup.okhttp3:okhttp:5.5.0") implementation(platform("io.jsonwebtoken:jjwt-bom:0.13.0")) runtimeOnly("io.jsonwebtoken:jjwt-impl") runtimeOnly("io.jsonwebtoken:jjwt-jackson") implementation("io.jsonwebtoken:jjwt-api") - implementation(platform("io.micrometer:micrometer-bom:1.16.5")) + implementation(platform("io.micrometer:micrometer-bom:1.17.1")) runtimeOnly("io.micrometer:micrometer-core") runtimeOnly("io.micrometer:micrometer-observation") runtimeOnly("io.micrometer:micrometer-registry-prometheus") - implementation("org.commonmark:commonmark-ext-gfm-tables:0.28.0") - implementation("org.commonmark:commonmark:0.28.0") + implementation("org.commonmark:commonmark-ext-gfm-tables:0.30.0") + implementation("org.commonmark:commonmark:0.30.0") implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlin:kotlin-scripting-common") implementation("org.jetbrains.kotlin:kotlin-scripting-dependencies") @@ -75,7 +75,7 @@ dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.11.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0") - implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:3.0.3") + implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:3.1.0") implementation("org.springframework.boot:spring-boot-starter-actuator") implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.boot:spring-boot-starter-oauth2-client") @@ -85,7 +85,7 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-webclient") implementation("org.springframework.session:spring-session-jdbc") - implementation("software.amazon.awssdk:s3:2.44.12") + implementation("software.amazon.awssdk:s3:2.54.13") runtimeOnly("com.h2database:h2") runtimeOnly("org.postgresql:postgresql") testImplementation("org.springframework.boot:spring-boot-starter-test") @@ -99,7 +99,7 @@ dependencyCheck { tasks.withType { compilerOptions { freeCompilerArgs.add("-Xjsr305=strict") - apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_3) + apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_4) jvmTarget.set(JvmTarget.JVM_25) } } diff --git a/backend/gradle/wrapper/gradle-wrapper.jar b/backend/gradle/wrapper/gradle-wrapper.jar index b1b8ef56..eddabd2e 100644 Binary files a/backend/gradle/wrapper/gradle-wrapper.jar and b/backend/gradle/wrapper/gradle-wrapper.jar differ diff --git a/backend/gradle/wrapper/gradle-wrapper.properties b/backend/gradle/wrapper/gradle-wrapper.properties index df6a6ad7..ad7845be 100644 --- a/backend/gradle/wrapper/gradle-wrapper.properties +++ b/backend/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip networkTimeout=10000 retries=0 retryBackOffMs=500 diff --git a/backend/gradlew b/backend/gradlew index b9bb139f..249efbb0 100755 --- a/backend/gradlew +++ b/backend/gradlew @@ -20,7 +20,7 @@ ############################################################################## # -# Gradle start up script for POSIX generated by Gradle. +# gradlew start up script for POSIX generated by Gradle. # # Important for running: # @@ -29,7 +29,7 @@ # bash, then to run this script, type that shell name before the whole # command line, like: # -# ksh Gradle +# ksh gradlew # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: diff --git a/backend/gradlew.bat b/backend/gradlew.bat index 24c62d56..a51ec4f5 100644 --- a/backend/gradlew.bat +++ b/backend/gradlew.bat @@ -19,7 +19,7 @@ @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem -@rem Gradle startup script for Windows +@rem gradlew startup script for Windows @rem @rem ########################################################################## @@ -72,7 +72,7 @@ echo location of your Java installation. 1>&2 -@rem Execute Gradle +@rem Execute gradlew @rem endlocal doesn't take effect until after the line is parsed and variables are expanded @rem which allows us to clear the local environment before executing the java command endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/admission/AdmissionComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/admission/AdmissionComponentController.kt index a7ea11ff..b3de194c 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/admission/AdmissionComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/admission/AdmissionComponentController.kt @@ -27,23 +27,40 @@ class AdmissionComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ - A **Beléptetés** (Admission) komponens a rendezvényre való bejutást és a helyszíni jegyellenőrzést kezeli. Lehetővé teszi a hozzáférési szintek finomhangolását csoportok, felhasználók és szerepkörök alapján. - - ## Beállítások - - A **Komponens beállításai** menüpontban konfigurálhatod a beléptetési szabályokat: - - - **Beléptetés működése** – szabályozható a belépési naplózás és az űrlapalapú beléptetés (csak elfogadott jelentkezéssel engedjen be). - - **Csoportok hozzáférése** – csoportonként (pl. VIP, Szervezők, Fellépők) definiálható a hozzáférési szint. - - **Felhasználók hozzáférése** – egyedi CMSCH ID alapján adható kiemelt hozzáférés. - - **Szerepkörök hozzáférése** – globális szabályok a felhasználói szerepkörök (pl. STAFF, ADMIN) szerinti beléptetéshez. - - **Tiltólista** – csoportok vagy egyének kizárása a beléptetésből. - - **Jegyek** – BME Jegy integráció és a korábbi belépések számának megjelenítése a beolvasónál. - - ## Funkciók - - - **Hozzáférési szintek** – támogatott szintek: USER, VIP, PERFORMER, ORGANIZER, LEAD_ORGANIZER. A rendszer mindig a felhasználó számára elérhető legmagasabb szintet veszi alapul. - - **Naplózás** – minden sikeres és sikertelen belépési kísérlet rögzíthető az utólagos ellenőrzéshez. + A **Beléptetés** komponens a helyszíni beengedést végzi: a rendező beolvassa a belépő kódját, a rendszer pedig a beállított szabályok alapján dönt. Nyilvános (résztvevői) menüpontja nincs, minden funkció a rendezői menü **Beléptetés** kategóriájában érhető el. + + ## Beengedés menete + + 1. A **Jogosultságok** menüpontban állítsd be, kiket engedj be (lásd lent). + 2. A beolvasókhoz a **Beléptetés kezelése**, a naplóhoz a **Beléptetés logok megtekintése** jogosultságot add meg a kijelölt rendezőknek. + 3. A **Beléptetés** menüpontban nyílik a kamerás beolvasó (mobilon érdemes használni). Az eredmény ablakban a **Név**, a **Belépés** (csoport) és a **JOGKÖR** látszik: KITILTVA, NEM JOGOSULT, BELÉPHET, VIP, RENDEZŐ, FELLÉPŐ, FŐRENDEZŐ. + 4. Űrlapos beengedéshez az **Űrlapos beléptetés**, jegyekhez a **Jegyellenőrzés** menüpontot használd. + + ## Jogosultsági szabályok + + A rendszer minden forrásból összegyűjti a jogosultságokat, és a **legmagasabb** elért szintet adja. Ha egyik lista sem tartalmazza a belépőt, a válasz **NEM JOGOSULT** – üres listákkal senki sem jut be. + + - **Csoportok hozzáférése** – a **USER / VIP / PERFORMER / ORGANIZER / LEAD_ORGANIZER hozzáférésű csoportok** mezőkben a csoportnevek pontos, vesszővel elválasztott felsorolása. + - **Felhasználók hozzáférése** – ugyanezek a szintek CMSCH ID-k alapján. + - **Szerepek hozzáférése** – a **USER hozzáférés** és az **ORGANIZER hozzáférés** a kiválasztott szerepkörtől felfelé mindenkire vonatkozik. + - **Tiltó lista** – a **Kitiltott csoportok** és a **Kitiltott felhasználók** minden más szabályt felülírnak, az érintett belépő KITILTVA jelzést kap. + + ## Beállítások (Jogosultságok menüpont) + + | Beállítás | Mit tesz | + | --- | --- | + | **Beléptetések mentése** | Minden beolvasás a **Belépés logok** közé és az audit naplóba kerül. Kikapcsolva nem működik az ismételt beolvasás számlálása, és az űrlapos CSV export sem jelöli, ki lépett már be. | + | **Csak az elfogadott űrlapok számítanak** | Űrlapos beléptetésnél csak az elfogadott és nem elutasított beadás enged be. Csak az űrlapok komponenssel együtt működik. | + | **BME Jegyesek beengedése** | BME Jegy utalványkódokat is elfogad (csak bekapcsolt bmejegy komponens mellett). | + | **Belépések számának mutatása** | A **Jegyellenőrzés** beolvasónál kiírja, hányszor olvasták be ugyanazt a kódot; ismétlésnél **NEM ELSŐ!!!** figyelmeztetést ad. | + + ## Beolvasók és oldalak + + - **Beléptetés** – CMSCH profil QR kódot (a beállított előtaggal kezdődik) és BME Jegy utalványkódot ismer fel. A **Jegyek** listát nem használja. + - **Jegyellenőrzés** – a **Jegyek** listából dolgozik. **A jegy megléte önmagában beenged**, a jegy **Belépési jogosultság** mezője csak a kijelzett jogkört adja meg. + - **Űrlapos beléptetés** – csak a felhasználók által létrehozott (nem csoport-tulajdonú) űrlapokat listázza, űrlapok komponens nélkül csak figyelmeztetést mutat. A **Beengedés** művelet az adott űrlap beolvasóját nyitja, a **CSV Export** a beadásokat és a belépéseket adja egy táblában (**Beléptetés kimentése** jogosultság kell hozzá). Az elfogadott beadás önmagában BELÉPHET szintet ad, amit a csoport/felhasználó/szerep szabályok emelhetnek; névtelen beadásnál az űrlap token mezőjének kódja is beolvasható. + - **Jegyek** – egy sor egy jegy, a listában **Tulajdonos**, **Email** és **QR** látszik; szerkesztve adható meg a **Belépési jogosultság**, a **Megjegyzés** és a **Profil QR kód használata** (bekapcsolva a jegy a **QR** mezőben tárolt kóddal, kikapcsolva a belépő profiljához tartozó **Email** címmel azonosítható). Import és export is elérhető. + - **Belépés logok** – a listában a **Felhasználó**, az **Engedélyezve** és a **Frissült** látszik; a sorok szerkeszthetők és törölhetők, de a törlés az ismételt beolvasás számlálóját is módosítja. """ ) { diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/app/FooterComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/app/FooterComponentController.kt index f1dd0e36..2b128cfe 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/app/FooterComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/app/FooterComponentController.kt @@ -31,53 +31,38 @@ class FooterComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -# Stílus +A **Lábléc** a felhasználói oldalak alján minden oldalon megjelenő sáv. A beállításai a **Stílus** kategória **Lábléc** menüpontjában találhatók, a színei (**Footer színe**, **Footer alsó sáv színe**, **A footerre alkalmazott filter**) viszont a **Stílus beállítások** menüpontban állíthatók, világos és sötét témához külön. -A **Stílus** komponens segítségével testre szabhatod a weboldal megjelenését CSS-ismeretek nélkül. +## Felépítés -## Beállítások +- Bal oldalon a **Footer szöveg**, mellette a szervező logója a linkjeivel és a Kir-Dev logó. +- Felette a támogatói és partneri logósáv, legalul pedig egy fix, nem állítható sáv (Made with ♥ by Kir-Dev / Minden jog fenntartva, az aktuális évszámmal). -A **Komponens beállításai** menüpontban konfigurálhatod a témákat: +## Lábléc -- **Világos téma (Light Mode)** – színek (háttér, szöveg, brand), háttérképek és logók beállítása nappali módhoz. -- **Sötét téma (Dark Mode)** – színek és képek éjszakai módhoz. Szabályozható, hogy a rendszer automatikusan kövesse-e az eszköz beállításait, vagy kényszerítve legyen valamelyik mód. -- **Tipográfia** – az oldalon használt betűtípusok (fontok) és azok forrásának (CDN) megadása. +- **Minimalisztikus lábléc** – elrejti a támogatói és partneri logósávot, valamint a szervező linkjeit (Weboldal, Facebook, Instagram); csak a logók, a **Footer szöveg** és az alsó sáv maradnak. +- **Esemény szervezőjének a logója** – feltölthető kép vagy URL; ha üres, nem jelenik meg kép. **Esemény szervezőjének alt szövege** – ha a kép nem tölt be, ez látszik. +- **Esemény szervezőjének oldala** – a logó melletti Weboldal link. **Facebook url**, **Instagram url** – üresen hagyva az adott ikon nem jelenik meg. +- **Footer szöveg** – a lábléc szöveges tartalma, Markdown formázással, több sorban is írható. +- **A kir-dev oldala**, **A kir-dev kapcsolat linkje** – a Kir-Dev logó melletti linkek, csak **Fejlesztő** (SUPERUSER) szerepkörrel szerkeszthetők. -## Funkciók +## Támogatók -- **Brand-szín** – egyetlen szín megadásával az egész oldal arculatát a rendezvényhez igazíthatod (gombok, linkek, kiemelések). -- **Reszponzív hátterek** – külön háttérképet állíthatsz be asztali és mobil nézethez. +- **Sponsorok láthatóak** – enélkül a támogatói blokk egyáltalán nem jelenik meg. +- **Szponzorok fejléc** – a blokk fölé kerülő cím (alapértéke: Támogatóink). +- **Sponsor logók**, **Sponsor alt üzenetek**, **Sponsor weblapok** – vesszővel elválasztott listák, amelyek pozíció szerint párosulnak: az első logóhoz az első alt szöveg és az első weblap tartozik. Ha egy weblap üres, az adott logó nem lesz kattintható. -# Manifest +## Partnerek -A **Manifest** komponens a webalkalmazás (PWA - Progressive Web App) telepítési tulajdonságait szabályozza. Ez határozza meg, hogyan jelenik meg az oldal, ha a felhasználó hozzáadja a kezdőképernyőjéhez. +- **BME VIK logó**, **BME logó**, **Schönherz logó**, **schdesign logó** – beépített logók, világos és sötét témához külön változatban. +- **Szponzorok fejléc** – a partneri blokk címe (a felirat tévesen ugyanaz, mint a támogatóknál, alapértéke: Partnereink), továbbá **Partner logók**, **Partner alt üzenetek**, **Partner weblapok** – a támogatókéhoz hasonló vesszős listák. +- A partneri blokk akkor jelenik meg, ha bármelyik beépített logó be van kapcsolva, vagy a **Partner logók** mező nem üres. -## Beállítások +## Figyelmeztetések -A **Komponens beállításai** menüpontban konfigurálhatod a manifest fájlt: - -- **A manifest.json tartalma** – az alkalmazás neve, rövid neve, leírása, színei és megjelenítési módja (pl. `standalone`, `browser`). -- **Ikonok** – a különböző eszközökhöz és felbontásokhoz szükséges ikonok feltöltése. - -## Funkciók - -- **PWA támogatás** – a helyesen beállított manifest lehetővé teszi, hogy az oldal alkalmazásként viselkedjen (ikon a főképernyőn, nincs böngésző keret). - -# Lábléc - -A **Lábléc** (Footer) komponens az oldal alján megjelenő információkat kezeli. - -## Beállítások - -A **Komponens beállításai** menüpontban konfigurálhatod a láblécet: - -- **Lábléc** – alapvető adatok: szervező logója, linkje, közösségi média elérhetőségek és a copyright szöveg. -- **Támogatók** – a rendezvény szponzorainak logói és weboldalai. -- **Partnerek** – együttműködő partnerek (pl. BME, VIK, SCH) logóinak megjelenítése. - -## Funkciók - -- **Minimalisztikus lábléc** – ha be van kapcsolva, a lábléc kevesebb helyet foglal, és csak a legszükségesebb információkat mutatja. -- **Dinamikus partnerek** – a szponzorok és partnerek listája vesszővel elválasztott URL-ek megadásával egyszerűen bővíthető. +- A **Sponsor logók** és **Partner logók** alapértéke `url1,url2`: írd felül valódi URL-ekkel vagy töröld, különben törött képek jelennek meg. +- A három lista mindig ugyanannyi és ugyanolyan sorrendű elemet tartalmazzon, különben elcsúsznak az alt szövegek és a linkek. +- A támogatói és partneri sáv a **Minimalisztikus lábléc** bekapcsolása esetén nem jelenik meg, hiába állítod be a többi beállítást. +- A Kir-Dev logó és linkjei az admin felületről nem kapcsolhatók ki, csak a frontend `VITE_HIDE_KIR_DEV_IN_FOOTER` beállításával. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/bmejegy/BmejegyComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/bmejegy/BmejegyComponentController.kt index 6de85887..b1f48c26 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/bmejegy/BmejegyComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/bmejegy/BmejegyComponentController.kt @@ -35,19 +35,43 @@ class BmejegyComponentController( menuService = menuService, storageService = storageService, documentationMarkdown = """ - A **BME Jegy** komponens a bmejegy.hu rendszerével való integrációt valósítja meg. Lehetővé teszi a kifizetett jegyek automatikus szinkronizálását és a sikeres vásárlás utáni jogosultságkiosztást. - + A **BME JEGY** komponens a bmejegy.hu-s jegyvásárlásokat szinkronizálja a CMSch-ba: a megvásárolt jegyek a **Jegyek** menüben jelennek meg, a vásárló pedig automatikusan szerepkört vagy csoportot kaphat. + ## Beállítások - - A **Komponens beállításai** menüpontban konfigurálhatod a szinkronizációt: - - - **Működés** – engedélyezhető az automatikus szinkronizáció és beállítható annak gyakorisága. - - **Fizetés utáni műveletek** – meghatározható, hogy egy adott termék (pl. "Gólyatábor jegy") megvásárlása után a felhasználó milyen jogosultságot (ATTENDEE, PRIVILEGED) kapjon, vagy melyik belső csoportba kerüljön át. - - ## Funkciók - - - **Automatikus szinkronizáció** – a rendszer rendszeres időközönként lekéri a bmejegy.hu-ról a friss vásárlásokat. - - **Voucher-kezelés** – a szinkronizált jegyek adatai (voucher-kód, típus) tárolódnak a rendszerben, és felhasználhatók beléptetésnél. + + A **Jegyek testreszabása** menüpont **Működés** csoportjában: + + - **Szinkronizáció** – a bmejegy.hu-s automatikus letöltés főkapcsolója. Ha a jegyeket a Cheers rendszer küldi be API-n keresztül, ez a kapcsoló nem befolyásolja a beérkezést. + - **Frissítési idő** – hány percenként nézze meg a bmejegy.hu-t (alapból 10). + - **Buffer méret** – [ADVANCED] a letöltött válasz maximális mérete; csak akkor növeld, ha a szinkronizálás mérethirdő hibát ír a naplóba. + - A **NEM TÁMOGATOTT** jelölésű mezőket csak indokolt esetben módosítsd: a **Keresés NEPTUN alapján** nincs implementálva, a **Szig. szám mező neve** viszont az egyeztetéshez kell. + + ## Fizetés utáni műveletek + + A **Fizetés utáni művelet #1**, **#2** és **#3** csoportokban három termékszabály adható meg: + + - **Termék neve** – a megvásárolt termék nevének részlete; üresen hagyva a szabály nem él. + - **Adjon-e ATTENDEE ROLE-t**, **Adjon-e PRIVILEGED ROLE-t** – a vevő szerepkörét állítja. Ha mindkettő be van kapcsolva, a PRIVILEGED marad. + - **Csoportba helyezés** – a vevő átkerül az itt megadott nevű csoportba (pontos csoportnév kell, üresen nem állít). + + ## Jegy és felhasználó összekapcsolása + + Szerepkör és csoport csak akkor jár, ha a jegyhez tartozik beazonosított felhasználó – ez a **Jegyek** táblában a **Beazonosított user ID-ja** mező. Az egyeztetés csak az **Űrlapok** menüben a **BME jegy integráció** kapcsolóval megjelölt űrlapok beküldéseiből dolgozik, és csak azokra a jegyekre fut le, ahol a mező még 0: + + | Jegyek honnan | Kapcsoló | Az űrlapmező neve | + | --- | --- | --- | + | bmejegy.hu letöltés | **Keresés SZIGSZÁM alapján** | **Szig. szám mező neve** | + | Cheers feltöltés | **Keresés EMAIL alapján** | **Email mező neve** | + + ## Jegyek menü + + Itt láthatók és szerkeszthetők a szinkronizált sorok (a listában **Termék**, **Vásárló**, **Email**, **Státusz**, **QR**), a sorok importálhatók és exportálhatók. A szinkronizáló **csak új jegyet vesz fel** – a **Rendelés termék azonosító** alapján dönti el, hogy egy jegyet ismer-e már –, a meglévő sorokat nem írja felül, így a kézi javításaid megmaradnak. + + ## Figyelmeztetések + + - A szerepkör-állítás csak **STAFF** alatti felhasználókra hat. Ha csak az **Adjon-e ATTENDEE ROLE-t** van bekapcsolva, a magasabb jogú (PRIVILEGED) vevő is **ATTENDEE**-re csökken. + - A **Beazonosított user ID-ja** kézi átírása maradandó: az automatikus egyeztetés csak a 0 értékű sorokat nézi. + - A jegy **QR** mezője a voucher-kód. Bmejegy.hu-s letöltésnél a **Jegyellenőrzés** menü ezzel lépteti be a jegyest (ha a beléptetésnél a **BME Jegyesek beengedése** be van kapcsolva); Cheers-es feltöltésnél a kód a **Profil beállítások** menü **BMEJEGY kód küldése** kapcsolójával kerül a felhasználó QR-kódjába. """ ) { diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/challenge/ChallengeComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/challenge/ChallengeComponentController.kt index 16b63e21..86f24de2 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/challenge/ChallengeComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/challenge/ChallengeComponentController.kt @@ -30,24 +30,46 @@ class ChallengeComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -A **Beadások** (Challenge) komponens egyszerű, pontozható beadások kezelésére szolgál. +A **Beadások** komponens kézzel felvitt pontbejegyzések adminisztrációja. Nincs résztvevői oldala: a pontokat nem a résztvevők küldik be, hanem a szervezők rögzítik (helyszínen értékelt feladatok, külső rendszerből átvett pontok, korrekció, levonás). A bejegyzések a **Toplista** pontszámításába folynak be. -## Beállítások +## Hol találod -A komponensnek nincsenek bonyolult globális beállításai: +Az admin menü **Beadások** kategóriájában: **Beadások** (a bejegyzések listája), **Beadások testreszabása** (a komponens beállításai) és **Beadások Dokumentáció** (ez az oldal). -- **Jogosultságok** – mely szerepkörökkel érhető el a beadások modul. +A listához **Beadások megtekintése**, új bejegyzéshez **Beadások létrehozása**, módosításhoz **Beadások szerkesztése**, törléshez **Beadások törlése** jogosultság kell. A beállítások és a dokumentáció a **Beadások komponens testreszabása** jogosultság mögött van. -## Beadások kezelése +## Egy bejegyzés mezői -A **Beadások** menüpont alatt: +| Mező | Jelentése | +| --- | --- | +| **Kategória** | szabad szöveg; a **Toplista kategória szerint aktív** nézetben ez lesz a pont sora, ezért érdemes mindig ugyanazt a szöveget írni | +| **Felhasználó** | a pontot kapó felhasználó (csak USER üzemmódban számít) | +| **Csoport** | a pontot kapó csoport (csak GROUP üzemmódban számít) | +| **Adott pont** | negatív érték is adható, így levonásra és korrekcióra is használható | +| **Cimke** | szabad szöveges címke, a listában nem látszik | -- **Beadások megtekintése** – láthatod a felhasználók által beküldött megoldásokat. -- **Pontozás** – az adminisztrátorok pontot adhatnak a beküldött munkákra. +A soroknál **Megtekintés**, **Szerkesztés**, **Másolat készítése** és **Törlés**, felül **Új Beadás**, **Import / Export** és **Összes törlése** érhető el; a kereső a Kategória, Felhasználó, Csoport és Pont oszlopokon működik. -## Használati tippek +## Felhasználó vagy csoport kapja a pontot? -- Ezt a komponenst akkor használd, ha egyszerűbb, nem kategóriákba sorolt feladatokat akarsz beadatni a résztvevőkkel. -- Ha komplexebb feladatkezelésre van szükséged (határidőkkel, kategóriákkal), használd a **Feladatok** komponenst. +Ezt nem a Beadások beállításaiban, hanem a backend induló konfigurációjában lehet megadni (OWNER_CHALLENGE, azaz hu.bme.sch.cmsch.startup.challenge-ownership-mode), módosítása újraindítást igényel: + +- **USER**: a **Felhasználó** mezőt kell kitölteni, a csoportot a rendszer a felhasználó csoportjából írja be. +- **GROUP**: a **Csoport** mezőt kell kitölteni, ilyenkor a bejegyzésben megadott felhasználó törlődik. + +Ha egyik mező sincs kitöltve (marad a "-"), a bejegyzés elmentődik, de senkihez nem tartozik, így a toplistán sem jelenik meg. + +## Hogyan lesz ebből toplista pont? + +- A pontok a **Toplista** komponens **Beadások szorzó (%)** beállításával skálázódnak (100 = 1x). +- USER üzemmódban a felhasználói toplistán jelennek meg; a csoportos pontszámba csak a **Felhasználói pontok felhasználása pontszámításnál** bekapcsolásával számítanak bele. +- GROUP üzemmódban csak azok a csoportok kapnak belőle pontot, amelyeknél a csoport adatlapján be van jelölve a **Játszik a csoport a versenyben?**. + +## Figyelmeztetések + +- **CSV importnál nem fut le a hivatkozás feloldása**: a **userId** és **groupId** oszlopot is ki kell tölteni, különben a pont nem a megfelelő résztvevőhöz kerül. A programból exportált CSV ezeket tartalmazza, kézzel írt fájlban pótolni kell. +- A **Felhasználó**/**Csoport** mezőt mindig a legördülő listából válaszd, mert mentéskor a rendszer a kiválasztott rekord belső azonosítóját tárolja. +- A csoportos pontszámítás a csoportot név szerint keresi, ezért egy csoport átnevezése után a korábbi bejegyzései kiesnek a csoportos toplistából. +- A **Jogosultságok** beállítás jelenleg nem nyit meg semmit, mert a komponensnek nincs résztvevői oldala; az admin oldalakat a fenti jogosultságok szabályozzák. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/CommunitiesComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/CommunitiesComponentController.kt index 4ac6e760..0fd34aaa 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/CommunitiesComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/CommunitiesComponentController.kt @@ -30,32 +30,55 @@ class CommunitiesComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -A **Körök** (közösségek) komponens a különböző öntevékeny körök, szakosztályok és reszortok bemutatását és kezelését teszi lehetővé. +A **Körök** komponens a kollégiumi öntevékeny köröket és az őket összefogó reszortokat mutatja be a nyilvános oldalon, és egy Tinder nevű párosító játékot is tartalmaz. + +- **Körök** (`/community`) – kereshető körlista, a kör adatlapja a `/community/{id}` címen. +- **Reszortok** (`/organization`) – ugyanez reszortokra, adatlap a `/organization/{id}` címen. +- **Tinder** (`/tinder`) – bejelentkezett felhasználók a kérdésekre adott válaszaik alapján húzogatják a köröket, a kedveltek a `/tinder/liked` oldalon gyűlnek. ## Beállítások -A **Komponens beállításai** menüpontban konfigurálhatod a közösségi oldalakat: +A **Beállítások** oldalon három csoport van: **Körök**, **Reszortok** és **Tinder**. A **Körök** és a **Reszortok** csoport ugyanazokat a mezőket tartalmazza a saját listájára (a reszortok leírás mezőjének neve is **Körök leírása**, és a reszortlista fölé kerül). + +- **Körök lap címe** / **Reszortok lap címe** – böngésző címsor és a lista fejléce. +- **Körök menü neve** / **Reszortok menü neve** – a menüpont neve. +- **Jogosultságok** – mely szerepkörök érhetik el az oldalt. Ha egy szerepkör kimarad, az oldal helyett a „komponens nem elérhető” üzenet jön, ezért csak megfontoltan szűkítsd. +- **Körök leírása** – Markdown bevezető a lista tetején. +- **Keresés engedélyezése** – egyelőre nincs hatása, a keresőmező mindig megjelenik, és a kör neve, **Kulcsszavak** és **Érdeklődési körök** alapján szűr. + +**Tinder** csoport: + +- **Tinder engedélyezése** – enélkül a `/tinder` oldalak használhatatlanok, és a Tinder menüpont sem jelenik meg. +- **Jogosultságok** – csak azt dönti el, kinek látszik a Tinder menüpont, és alapból üres, azaz csak adminnak. A játék eléréséhez a felső **Jogosultságok** mezőben is szerepelnie kell a szerepkörnek. + +## Admin oldalak + +A **Körök** kategória menüpontjai: + +| Menüpont | Mire való | +| --- | --- | +| **Körök** | Körök felvétele, szerkesztése, törlése, duplikálása, CSV import/export. Soronként innen nyílik a **Válaszok megtekintése** és a **Válaszok szerkesztése** (a kör Tinder válaszai) | +| **Reszortok** | Reszortok kezelése, duplikálás, import/export | +| **Tinder kérdések** | A párosítás kérdései, a **Válaszlehetőségek** vesszővel elválasztva | +| **Tinder válaszok** | A felhasználók válaszai. A körök saját válaszait ne itt keresd, az a **Körök** listáról érhető el | +| **Interakciók** | A húzások körönként csoportosítva, **Jobbra húzva** / **Balra húzva** darabszámmal | -- **Jogosultságok** – mely szerepkörökkel érhető el az oldal. -- **Körök** – az egyes körök (pl. Kir-Dev, HA5KTT) listázása, leírása és keresési lehetősége. -- **Reszortok** – a köröket összefogó nagyobb szervezetek (pl. Simonyi Károly Szakkollégium) bemutatása. -- **Tinder** – egy speciális, játékos funkció, amivel a felhasználók "matchelhetnek" a hozzájuk illő körökkel. +## Tinder beállítási sorrend -## Közösségek kezelése +1. **Tinder kérdések**: vedd fel a kérdéseket, mindegyikhez a **Válaszlehetőségek** vesszővel elválasztva. +2. A **Körök** listáról, a **Válaszok szerkesztése** művelettel add meg minden kör válaszait – csak a kérdéseknél felsorolt lehetőségeket fogadja el. Új kör mentésekor a rendszer üres válaszrekordot hoz létre, ezért a kör felvétele után térj vissza ide. +3. Kapcsold be a **Tinder engedélyezése** beállítást, és add meg a **Jogosultságok** mezőkben az érintett szerepköröket. +4. A felhasználók a **Tinder kérdések** oldalon válaszolnak, majd a Tinder oldalon húzogatnak; a döntés végleges, de a **Tinder kérdések** oldalon az **Interakciók törlése** gombbal a saját lista nullázható. -Két fő entitást kezelhetsz: +## A kör adatlapja -1. **Körök** – az egyes közösségek adatai (név, leírás, logó, reszorttagság, elérhetőségek). -2. **Reszortok** – a felsőbb szintű szervezeti egységek. +A **Kör neve**, a **Rövid leírás** (a listában és a Tinder kártyán látszik) és a **Teljes leírás** (Markdown, az adatlap törzsében) adja a szöveges tartalmat, a **Logó url** / **Sötét logó url** párból a témához illő jelenik meg. Az **Alapítva**, **E-mail cím**, **Tagok száma** és **Érdeklődési körök** az adatlap adatsávjába kerül, a **Website url**, **Facebook URL**, **Instagram URL** és **Jelentkezés URL-je** gombokat ad (az üres mezők egyszerűen kimaradnak). A **Képek URL-jei** és a **Videók URL-jei** vesszővel elválasztott lista, utóbbiba YouTube videó ID kerül, nem teljes URL. -## Kör létrehozása / szerkesztése +## Mire figyelj -- **Név** – a kör teljes neve. -- **Rövid név** – a kör beceneve (pl. Kir-Dev). -- **URL** – a kör adatlapjának címe (pl. `kir-dev`). -- **Reszort** – melyik reszorthoz tartozik. -- **Leírás** – részletes bemutatkozó szöveg Markdown-formátumban. -- **Logó / Kép** – a kör vizuális megjelenése. -- **Kulcsszavak** – a Tinder funkcióhoz és kereséshez használt címkék. +- **Reszort előbb**: a kör **Reszort ID-je** mezőjébe a reszort numerikus azonosítója kell. Ha nem létező ID szerepel benne (a 0 is ilyen), a mentés hibaüzenet nélkül elmarad, ezért előbb vedd fel a reszortot. +- **Látható**: csak a bekapcsolt körök és reszortok jelennek meg a nyilvános oldalakon. A Tinder ezt nem nézi, minden kört listáz. +- **Név rejtett**: csak az adatlapról tünteti el a nevet, a listában és a Tinder kártyán továbbra is látszik. +- Néhány mező egyelőre nem hat semmire: **Szín**, **SVG térképek id-je**, **Keresés engedélyezése**, valamint a Tinder kérdés **Látható** kapcsolója. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/conference/ConferenceComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/conference/ConferenceComponentController.kt index 0f4595b8..b1c4d474 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/conference/ConferenceComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/conference/ConferenceComponentController.kt @@ -30,28 +30,53 @@ class ConferenceComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -A **Konferencia** komponens egy komplex eseménykezelő modul, amely kifejezetten tudományos vagy szakmai konferenciák igényeire lett szabva. Kezeli az előadókat, előadásokat, támogatókat és a regisztrációt. +A **Konferencia** komponens szolgálja ki a konferencia nyilvános oldalát: a korábbi konferenciák, regisztráció, mobilapp, nyereményjáték, promó videó, támogatók, rendezők, kiemelt előadások és előadáslista szekciók tartalma az admin listákból, a feliratok és linkek a **Konferencia testreszabása** oldal beállításaiból jönnek. Ütemezett feladat nincs: minden szöveg és lista kézzel szerkesztett, a **Látható** kapcsolók döntenek a megjelenésről. -## Beállítások +## Admin oldalak + +A **Konferencia** adminmenüben öt lista és a beállítások oldala (**Konferencia testreszabása**) található. A listákban felvétel, szerkesztés, törlés, duplikálás, keresés, valamint CSV import és export van. + +| Menü | Mezők | +| --- | --- | +| **Korábbi konferenciák** | **Név**, **Prioritás**, **Képek URL-jei** (vesszővel elválasztva) | +| **Cégek** | **Név**, **Logó URL**, **URL**, **Kategória** (MAIN_SPONSOR / FEATURED_SPONSOR / SPONSOR / NO_ASSOCIATION), **Selector**, **Látható** | +| **Előadók** | **Név**, **Beosztás**, **Fotó URL**, **Cégének a seletora**, **Selector**, **Látható** | +| **Előadások** | **Cím**, **Slug**, **Kezdet ideje**, **Eddig tart**, **Terem** (IB028 / IB025 / OTHERS), **Nyelv** (HU / EN), **Leírás**, **Kérdések URL**, **Előadó a seletora**, **Selector**, **Látható**, **Szünet-e?** | +| **Rendezők** | **Név**, **Beosztás**, **Email cím**, **Profilkép url**, **Prioritás**, **Látható** | + +## A listák a Selector mezőkkel kapcsolódnak össze -A **Komponens beállításai** menüpontban konfigurálhatod a konferencia felületét: +Az összetartozó sorokat nem legördülő listával, hanem szöveges **Selector** mezőkkel kell összekötni: -- **Korábbi konferenciák** – szekció címe az archívumhoz. -- **Regisztráció** – Cooltix-integráció és a jelentkezési gomb szövege. -- **Mobil App** – az esemény saját alkalmazásának promóciója és letöltési linkjei. -- **Nyereményjáték** – a konferenciához kapcsolódó játék leírása, képe és szabályai. -- **Promó videó** – beágyazott YouTube-videó és leírása. -- **Támogatók** – a szponzorációs szekció címe. -- **Kiemelt előadás** – egy kiválasztott előadás hangsúlyos megjelenítése a főoldalon. +- **Előadók** → **Cégének a seletora** a **Cégek** egy sorának **Selector**ja. +- **Előadások** → **Előadó a seletora** az **Előadók** egy **Selector**ja. +- A **Kiemelt előadások selectorjai, vesszővel elválasztva** beállítás az **Előadások** **Selector**jait sorolja fel. + +A **Selector** legyen egyedi, és pontosan egyezzen a rá hivatkozó mezővel: üres vagy elgépelt selectornál az adott előadó/cég helyén egyszerűen nem jelenik meg semmi, hibaüzenet nincs. + +## Beállítások -## Konferencia kezelése +| Beállítás | Szerepe | +| --- | --- | +| **previousConferences.sectionTitle mező**, **giveaway.sectionTitle mező**, **promoVideo.sectionTitle mező**, **sponsors.sectionTitle mező**, **featuredPresentation.sectionTitle mező** | Az egyes szekciók címei. | +| **registration.buttonText mező** | A regisztrációs gomb felirata. | +| **registration.cooltixEventId mező** | A gomb linkje, azaz a Cooltix esemény URL-je. Alapértéke `https://url.com/`, mindenképp írd át. | +| **mobileApp.description mező** | A mobilapp szekció szövege. | +| **mobileApp.androidUrl mező**, **mobileApp.iosUrl mező** | Az app letöltési linkjei. | +| **giveaway.description mező** | A nyereményjáték leírása. | +| **giveaway.pictureUrl mező** | A nyereményjáték képe (URL vagy feltöltött kép). | +| **giveaway.rules mező** | A játék szabályai, Markdown formázással. | +| **promoVideo.youtubeUrl mező** | Beágyazható YouTube URL (a megosztás iframe kódjából), nem sima videólink. | +| **promoVideo.description mező** | A videó alatti leírás. | +| **featuredPresentation.description mező** | A kiemelt előadás szekció leírása. | +| **Kiemelt előadások selectorjai, vesszővel elválasztva** | A kiemeltként megjelenő előadások **Selector**ja, vesszővel elválasztva. | -A komponens számos entitást foglal magában: +## Amire figyelni kell -1. **Konferenciák** – az egyes események (évek/alkalmak) adatai. -2. **Cégek (Companies)** – a támogató partnerek listája. -3. **Szervezők (Organizers)** – a konferencia lebonyolításáért felelős személyek. -4. **Előadások (Presentations)** – a programpontok részletei (időpont, helyszín, téma). -5. **Előadók (Presenters)** – a szakmai előadók bemutatása. +- A **Korábbi konferenciáknál** nincs **Látható** kapcsoló, minden sor megjelenik – egy régi konferencia csak törléssel tüntethető el. +- A szekciók csak a **Látható** sorokat listázzák, kivéve a selectorral behivatkozottakat: a kiemelt előadás és az előadóhoz rendelt cég **Látható** nélkül is megjelenik. +- **Kezdet ideje** és **Eddig tart** szabad szöveges mező (nincs dátumválasztó és formátumellenőrzés), ezért írd egységes formátumban, pl. `2026-05-10 14:00:00`. +- A **featuredPresentation.sectionTitle mező** és a **featuredPresentation.description mező** alapértéke a promó videó szövege; ha nem írod át, az jelenik meg a kiemelt szekcióban. +- **Szünet-e?** bekapcsolva a sor szünetként kerül a programba, ilyenkor is a **Cím** jelenik meg. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/debt/DebtComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/debt/DebtComponentController.kt index 436a9521..ff2752f5 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/debt/DebtComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/debt/DebtComponentController.kt @@ -30,29 +30,49 @@ class DebtComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -A **Tartozások** (vagy Fogyasztás) komponens a rendezvény alatt vásárolt termékek és az értük fizetendő összegek nyilvántartására szolgál. +A **Tartozások** komponens a rendezvény alatti vásárlások nyilvántartása: ki mit vett, mennyiért (JMF), fizetett-e már, és melyik csoport felel érte. A vásárlók a **Fogyasztás** menüpontban látják a saját tételeiket. ## Beállítások -A **Komponens beállításai** menüpontban konfigurálhatod a modult: +- **Oldal tetején megjelenő szöveg** – markdown szöveg a vásárlói oldal tetején (fizetés módja, határidő). Ha üres, nem jelenik meg. +- **Lap címe** és **Menü neve** alapértéke „Fogyasztás", miközben az admin menüben minden **Tartozások** néven szerepel. -- **Lap címe** – a böngésző címsorában megjelenő szöveg. -- **Menü neve** – a menüben látható név. -- **Jogosultságok** – mely szerepkörökkel érhető el a saját fogyasztás oldala. -- **Oldal tetején megjelenő szöveg** – egyedi tájékoztató a fizetés módjáról vagy a határidőkről. Ha üres, nem jelenik meg. +## Beüzemelés sorrendje -## Tartozások kezelése +1. A **Termékek** oldalon vedd fel a terméket, és állítsd **Elérhető**-re, amit árulni fogtok. +2. Árusításkor a sor végén az **Árusít** gomb nyitja a QR-fizetés oldalt: a vevő profil-QR kódját olvassa be (kézzel a **Neptun-kód** is megadható), és megerősítés után azonnal létrejön a tranzakció. +3. A vevő a **Fogyasztás** oldalon és a **Saját tartozásaim** oldalon követi, mi tartozik hozzá. A tartozás mindig a vevő csoportjához kerül. +4. A csoport bármely tagja a **Csoportom tartozásai** oldalon a **Fizetve** gombbal jelölheti, hogy átvette a pénzt – onnantól a **Felelős neve** ő lesz, és neki kell elszámolnia a gazdaságissal. +5. A **Tranzakciók** oldalon (és a csoportosított listák szerkesztésénél) az **Átadva**, **Fizetve**, **Lezárva** jelölők kézzel is átállíthatók; a **Napló** mező naplózza a változtatásokat. -Két fő részből áll a rendszer: +## Termék mezői -1. **Termékek** – itt veheted fel a megvásárolható tételeket (pl. "Póló", "Ételjegy", "Sör"). Megadható a név és az ár. -2. **Eladott termékek** – a konkrét vásárlások listája. Itt látszik, hogy ki mit vett, és hogy kifizette-e már (fizetve státusz). +| Mező | Mit jelent | +| --- | --- | +| **Név**, **Ár** | A termék neve és egységára JMF-ben. | +| **Típus** | MERCH / FOOD / OTHER. Csak ennek alapján kerül fel a termék az **Étel árusítás** vagy **Merch árusítás** listára; az OTHER típus csak a **Termék árusítás** listán jelenik meg. | +| **Elérhető** | Csak az elérhető terméket lehet eladni, ezt ellenőrzi az árusítás. | +| **Látható** | Jelenleg semmilyen felületet nem szabályoz. | +| **Termék leírása**, **Kép a termékről**, **Material Ikon** | Megjelenítéshez használt adatok. | -## Termék létrehozása / szerkesztése +## Admin oldalak -- **Név** – a termék megnevezése. -- **Ár** – a termék egységára. -- **Típus** – kategória (opcionális). -- **Látható** – elérhető-e a termék az eladáshoz. +| Oldal | Mit tudsz itt | +| --- | --- | +| **Termékek** | A vásárolható termékek kezelése, importtal és exporttal. | +| **Termék árusítás**, **Étel árusítás**, **Merch árusítás** | Árusító listák (mind / FOOD / MERCH típus), innen nyílik a QR-fizetés. | +| **Tranzakciók** | Az összes eladás. Új tranzakció nem hozható létre, a vevő/eladó/termék adatai nem szerkeszthetők, csak a jelölők. | +| **Eladott termékek** | Eladott darabszám termékenként. | +| **Saját tartozásaim** | Mindenki a saját tételeit látja. | +| **Csoportom tartozásai** | A saját csoportod tételei; csak csoporttagoknak jelenik meg. | +| **Csoportok tartozásai** | Csoportonkénti összesítés: **Forgalom [JMF]**, **Fizetetlen [JMF]**, **Lezáratlan [JMF]**. | +| **Felhasználó tartozásai** | Felhasználónkénti összesítés ugyanígy. | + +## Jogosultságok és buktatók + +- Árusításhoz **Bármilyen típusú termék eladása**, **Étel típusú termék eladása** vagy **Merch típusú termék eladása** jogosultság kell; az összesítésekhez **Összes tartozás megtekintése**, **Tartozások szerkesztése**, **Eladott termékek statisztikájának megtekintése**. Jogosultságot a **Felhasználó kezelés** alatt, a **Jogkörök** vagy a **Felhasználók** oldalon adhatsz. +- A vevőnek csoportban kell lennie, különben nem jön létre a vásárlás. +- A tranzakció a vásárlás pillanatában rögzíti a termék nevét és árát, az utólagos árváltozás a már eladott tételeket nem érinti. +- A **Fizetve** gomb a **Csoportom tartozásai** oldalon nem vonható vissza (már fizetett tételre nem csinál semmit), a **Tranzakciók** oldalon viszont a jelölő átállítható. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/errorlog/ErrorLogService.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/errorlog/ErrorLogService.kt index 9849fd0f..213e55e8 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/errorlog/ErrorLogService.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/errorlog/ErrorLogService.kt @@ -39,6 +39,7 @@ class ErrorLogService( userAgent = userAgent, href = href, role = role, + lastReportedAt = clock.getTimeInSeconds(), ) errorLogRepository.save(newLog) } diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/event/EventComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/event/EventComponentController.kt index f0312303..70f22e6c 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/event/EventComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/event/EventComponentController.kt @@ -32,47 +32,51 @@ class EventComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ - Az **Események** komponens segítségével a rendezvény/program összes eseményét rögzítheted és megjelenítheted a felhasználók számára. - Az adminfelületen keresztül kezelheted az eseményeket és testre szabhatod a megjelenést. - + Az **Események** komponens a rendezvény programlistája: a programokat az adminfelületen veszed fel, + a látogatók pedig a nyilvános oldalon (alapértelmezésben **Programok**) böngészik napokra bontva vagy naptárnézetben. + + ## Első beállítás + + 1. Az **Események testreszabása** oldalon a **Jogosultságok** mezőben jelöld ki, kik nyithatják meg az oldalt. + Üresen hagyva csak ADMIN és SUPERUSER látja, a kijelentkezett látogatók nem, ezért ha mindenkinek látszania kell, + a GUEST szerepkört is vedd fel a listára. + 2. Az **Események** menüpontban vidd fel a programokat. + 3. Ha az eseményre kattintva külön oldal nyíljon meg, kapcsold be az **Elérhető a részletes nézet (külön lapon)** opciót. + Enélkül a listaelemek nem kattinthatók, és a megosztott linkek sem nyílnak meg. + ## Beállítások - - A **Komponens beállításai** menüpontban konfigurálhatod az események oldalát: - - - **Lap címe** – ez jelenik meg a böngésző címsorában. - - **Menü neve** – a menüben látható név. - - **Jogosultságok** – minimum szerepkör, amellyel az oldal megtekinthető (pl. mindenki, belépett felhasználók, szervezők). - - **Tekerjen oda a jelenlegi programhoz** – bekapcsolva az oldal betöltésekor az éppen zajló programhoz ugrik. - - **Részletes nézet** – ha be van kapcsolva, az események külön oldalon részletesen is megnyithatók. - - **Keresés elérhető** – bekapcsolva megjelenik egy kereső az események oldalának tetején. - - **Csoportosítás naponként** – a programok napokra bontva jelennek meg. - - **Kategória / helyszín / nap szerinti szűrés** – beállítható, hogy a felhasználók tudjanak szűrni ezen mezők alapján. - - **Oldal tetején megjelenő szöveg** – általános leírás a programokról, Markdown formátumban. - - ## Események kezelése - - Az **Események** menüpont alatt a rendezvény teljes programlistáját kezelheted: - - - **Új esemény létrehozása** – új program rögzítése. - - **Szerkesztés** – meglévő esemény adatainak módosítása. - - **Törlés** – felesleges események eltávolítása. - - **Importálás / Exportálás** – események tömeges betöltése vagy mentése. - - A lista tartalmazza az összes rögzített eseményt a státuszukkal együtt (látható / időpont / helyszín). - - ## Esemény létrehozása / szerkesztése - - Új esemény felvételekor vagy szerkesztésekor a következő főbb mezőket kell megadnod: - - - **Cím** – az esemény neve. - - **URL** – rövid azonosító az esemény webcíméhez (csak kisbetűk és kötőjelek). - Példa: `nyitoceremonia` - - **Leírás** – részletes szöveg az eseményről (Markdown formátumban). - - **Helyszín** – ahol az esemény zajlik. - - **Időpont (kezdés és befejezés)** – az esemény pontos időtartama. - - **Látható** – ha be van kapcsolva, megjelenik a felhasználói oldalon. - - **Minimum szerepkör a megtekintéshez** – korlátozhatod, hogy kik lássák (pl. csak résztvevők, csak szervezők). - - **Kategória** – opcionális besorolás, amely a szűréshez is használható. - - **Kép / illusztráció** – vizuális elem az eseményhez. - - **OG:Title, OG:Image, OG:Description** – közösségi megosztásokhoz tartozó metaadatok. + + | Beállítás | Hatás | + | --- | --- | + | **Lap címe** | az oldal címe, ami a kezdőlap esemény-szekciójának fejléce is | + | **Menü neve** | a menüben látható név | + | **Oldal tetején megjelenő szöveg** | Markdown szöveg a lista és a naptár tetején (üresen nem jelenik meg) | + | **Keresés elérhető** | keresőmező a lista tetején; csak a **Cím** mezőben keres, és ilyenkor a már lejárt események kikerülnek a listából | + | **Elérhető a részletes nézet (külön lapon)** | kattintható listaelemek és külön eseményoldal a **Hosszú leírással**, **Teljes képpel** és az extra gombbal | + | **Ha be van kapcsolva, kategória / helyszín / nap alapján is lehet szűrni** | három külön kapcsoló; mindegyik szűrőfület tesz a lista tetejére, a fül értékei pedig a **Kategória**, illetve a **Helyszín** mezők tartalmából épülnek fel | + | **Tekerjen oda a jelenlegi programhoz**, **Külön csoportosítva naponként** | jelenleg nincs hatásuk: a lista mindig napokra bontva jelenik meg | + + ## Esemény mezői + + - **Cím**, **Kategória**, **Helyszín** – rövid adatok; a kategóriát és a helyszínt írd következetesen, mert ezekből épülnek a szűrők. + - **Url** – az esemény azonosítója; a megosztható link a `share/event/` útvonalból és ebből az értékből áll. + - **Mikor lesz a program?** / **Meddig tart a program?** – a befejezés után az esemény lejártnak számít: eltűnik a kezdőlapról és a keresőből. + - **Rövid leírás** – sima szöveg a listakártyán; **Hosszú leírás** – Markdown, csak a részletes nézetben látszik. + - **Előnézeti kép** – a listakártya háttere; **Teljes kép** – a részletes nézet nagy képe. + - **Extra gomb szöveg** / **Extra gomb URL** – a gomb az URL kitöltésekor jelenik meg a részletes nézetben, felirata a szöveg mező. + - **OG:Title / OG:Image / OG:Description** – a megosztott link előnézetéhez; üresen hagyva a megosztás címe, képe és leírása is üres lesz. + - **Látható** – kikapcsolva az esemény nem kerül ki a nyilvános oldalra. + - **Minimum rang a megtekintéshez** – a látható esemény is csak az ennél legalább ilyen rangú felhasználóknak jelenik meg (GUEST = kijelentkezett, BASIC = belépett, STAFF = rendező). + + ## Admin oldalak + + - **Események** – a programok listája **Cím**, **Időpont**, **Helyszín** és **Látható** oszloppal; gombok: **Új Esemény**, **Import / Export**, + soronként pedig **Megtekintés**, **Szerkesztés**, **Másolat készítése** és **Törlés**. + - Az import CSV-fájlból dolgozik, ami nem tartalmaz azonosítót, ezért egy korábban exportált lista visszatöltése minden sort új eseményként vesz fel. + + ## Amit érdemes tudni + + - A lejárt események nem tűnnek el maguktól, a listán maradnak; csak a naptárnézet és a nap szerinti szűrő **Korábbi** csoportja választja le őket. + - Minden esemény kézzel kerül be és módosul, a komponens magától semmit nem tesz. + - A kezdőlapon az események csak akkor jelennek meg, ha a Kezdőlap beállításai között az **Események láthatóak** is be van kapcsolva. """) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/form/FormComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/form/FormComponentController.kt index a5bae6a4..42a00d8c 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/form/FormComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/form/FormComponentController.kt @@ -30,29 +30,58 @@ class FormComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -Az **Űrlapok** (jelentkezések) komponens segítségével egyedi adatbekérő íveket, regisztrációs űrlapokat vagy jelentkezési felületeket hozhatsz létre. +Az **Űrlapok** komponenssel adatbekérő íveket és jelentkezési felületeket készíthetsz. Egy űrlap a `/form/` címen érhető el, a válaszokat pedig a rendezői felületen dolgozod fel. Egy felhasználó – illetve **Csoport a birtokos** esetén egy csoport – egyszer küldhet be kitöltést, utána ugyanaz a sor szerkeszthető, nem jön létre új rekord. + +## Rendezői menük + +| Menü | Mire való | +| --- | --- | +| **Űrlapok** | űrlapok felvétele és szerkesztése; soronként **Kitöltés** (kézi kitöltés bárki nevében), és ha a Sheets komponens be van kapcsolva, **Sheets integráció** / **Sheets frissítése** | +| **Kitöltések** | a beérkezett kitöltések űrlaponként, itt történik az elfogadás és az elutasítás; soronként **Json Export** és **CSV Export** | +| **Szavazások** | a VOTE és SELECT mezők szavazatainak összesítése űrlaponként | +| **Űrlapok testreszabása** | a komponens beállításai | ## Beállítások -A **Komponens beállításai** menüpontban konfigurálhatod az általános üzeneteket: +- **Jogosultságok** – ezekkel a rangokkal kerül be a komponens a frontend konfigurációjába (innen jönnek a státusz szövegek), ezért vedd fel mindenkit, aki űrlapot tölthet. +- **Nyelvi beállítások** – a felhasználónak megjelenő szövegek: **'Túl korán' szöveg**, **'Túl késő' szöveg**, **'Nem elérhető' szöveg**, **'Betelt' szöveg**, **'Nem található' szöveg**, **'Nincs leadott jelentkezés' szöveg**, **'Beadva' szöveg**, **'Elfogadva' szöveg**, **'Elutasítva' szöveg**, **'Csoport nem jó' szöveg**, valamint a visszadobott kitöltésnél megjelenő **Visszadobás üzenet fejléce**. + +## Új űrlap létrehozása + +1. **Űrlapok** menü, új elem. **Url**: nem ékezetes kisbetűk és kötőjel, ez lesz a cím. **Űrlap címe**: ez jelenik meg a lap tetején. **Menüben megjelenő neve**: csak akkor kell, ha menüből is nyitható lesz, és a **Menü beállítások** oldalon is engedélyezni kell a menüpontot – enélkül csak közvetlen linkkel érhető el. +2. **Kitöltendő űrlap**: a mezők szerkesztője (**Új mező**, illetve **Export**/**Import** JSON-hoz). Mezőnként: **Mező neve** (ez lesz az adat kulcsa és az export oszlopfeje), **Típus**, **Cimke**, **Kötelező kitölteni**, **Nem módosítható beadás után**, **Alapértelmezett érték**, **Értékek** (SELECT és választós rácsok), **Leírás**, **RegEx minta**, **Hibás tartalom üzenete**. Az `INJECT_` kezdetű típusok automatikusan a profilból töltődnek (név, Neptun, e-mail, csoport, profilkép stb.). +3. **Kitölthető-e** – fő kapcsoló, kikapcsolva mindenki a **'Nem elérhető' szöveg**-et kapja. +4. **Kitölthető innentől** / **Kitölthető eddig** – a kitöltési időszak; ha az **eddig** 0 marad, az űrlap azonnal lejárt. +5. **Maximum kitöltés**: ennyi nem elutasított kitöltés után **Betelt**. `-1` a korlátlan, a `0` viszont azonnal beteltet jelent. + +## Ki töltheti ki + +- **Minimum rang a megtekintéshez** / **Maximum rang a megtekintéshez**: ki nyithatja meg az űrlapot (adminok mindig). +- **Csapatra korlátozás**: pontos csoportnevek vesszővel elválasztva; üresen mindenki tölthet. Aki nem tartozik ezekbe a csoportokba, a **Csoport tagság miatt eltiltva üzenet**-et kapja. +- **Csoport a birtokos**: a kitöltés a csoporthoz tartozik, csoportonként egy kitöltéssel. +- **ATTENDEE jog automatikusan** / **PRIVILEGED jog automatikusan**: sikeres kitöltésért rangot ad, de csak felfelé (magasabb rangút nem ront le), és a felhasználónak újra be kell jelentkeznie. +- **Hírdetett**: a csapat oldalán megjelenik kitöltendő formként, jelezve, hogy kitöltötték-e. + +## A kitöltések feldolgozása -- **Jogosultságok** – mely szerepkörökkel érhető el az űrlapok modul. -- **Nyelvi beállítások** – testreszabhatók az űrlapok különböző állapotaihoz (túl korán, lejárt, betelt, elfogadva, elutasítva stb.) tartozó visszajelzések. +A **Kitöltések** menüben űrlaponként látod a darabszámokat (**Limit**, **Beküldött**, **Fizetve**, **Visszautasított**, **Elfogadva**), az egyes sorokban pedig: -## Űrlapok kezelése +- **Fizetve** – elfogadott kitöltés, a felhasználó az **Elfogadás utáni üzenet**-et látja. +- **Elutasítva** + **Elutasítás indoka** – elutasítás. Ha az **Elutasítva** nincs bekapcsolva, csak visszadobás történik: a felhasználó látja az indokot a **Visszadobás üzenet fejléce** szöveggel, és javíthatja a kitöltést. +- **Adatok elfogadva** – lezárja a kitöltést, utána a felhasználó nem módosíthatja (a **Nem módosítható beadás után** mezők egyébként sem javíthatók). +- **Kitöltés** – a beküldött értékek JSON-ban; **Sorszám** – exportokhoz és a Google Sheets sorokhoz; **Beadás történet** – a beadások naplója; **Email** és **Beléptető token** – a kapcsolódó adatok. -A **Űrlapok** menüpont alatt: +## Automatikus működés -1. **Űrlapok** – itt hozhatod létre magukat a kérdőíveket. Megadhatod a kitöltési időszakot, a férőhelyek számát és az űrlap felépítését (JSON-formátumban). -2. **Beadott űrlapok** – a felhasználók által beküldött válaszok listája. Itt tudod elfogadni, elutasítani vagy módosítani a jelentkezéseket. +- **E-mail küldése a kitöltés után** + **E-mail sablon hivatkozása** (az E-mail komponensben felvett sablon **Hivatkozási név**-e): a levél az **E-mail mező neve** mező értékére megy, ha az üres, a felhasználó e-mail címére. Az **E-mail küldése csak egyszer** miatt szerkesztéskor nem megy ki új levél. +- **Beléptető token mező neve**: a megadott `INJECT_RANDOM_TOKEN` típusú mező értéke kerül a kitöltés **Beléptető token** mezőjébe – belépés nélküli, tokenes kitöltéshez. Ez a mező legyen **Nem módosítható beadás után**. +- **BME jegy integráció**: ezzel jelölöd ki, melyik űrlapot dolgozza fel a BME Jegy / Nova integráció (e-mail cím alapján, fizetés és adategyeztetés). +- Ha a Sheets komponens be van kapcsolva, minden új vagy módosított kitöltés bekerül a csatolt táblázatba, törléskor pedig kikerül onnan; a **Sheets frissítése** a teljes újraszinkronizáláshoz való. -## Űrlap létrehozása / szerkesztése +## Figyelmeztetések -- **URL** – az űrlap egyedi címe (pl. `regisztracio`). A frontenden a `/form/{url}` címen érhető el. -- **Név** – az űrlap belső megnevezése. -- **Időintervallum** – mikortól meddig tölthető ki. -- **Férőhely** – hányan jelentkezhetnek összesen. -- **Csoportos jelentkezés** – ha be van kapcsolva, a csapatkapitány az egész csapat nevében töltheti ki. -- **Struktúra** – a kérdések és beviteli mezők definíciója. +- A **Kitöltés** (kézi kitöltés) oldalon nem futnak le az ellenőrzések: sem a **Maximum kitöltés**, sem a meglévő kitöltés ellenőrzése, minden mentés új sort hoz létre. +- A **Szavazások** lista csak a **Kitölthető-e** szerint bekapcsolt, aktuális időablakban lévő űrlapokat mutatja, lezárt űrlap eredményét ott nem találod. +- Ha kézzel írsz JSON-t a **Kitöltendő űrlap** mezőbe, minden mezőhöz adj **RegEx minta**-t (a szerkesztő `.*`-ot ír), különben a beküldés "Érvénytelen kitöltés" hibát ad. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/gallery/GalleryComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/gallery/GalleryComponentController.kt index 4686c8a6..810dcc19 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/gallery/GalleryComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/gallery/GalleryComponentController.kt @@ -30,37 +30,32 @@ class GalleryComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -A **Galéria** komponens a rendezvényen készült fotók és képek feltöltését és megjelenítését teszi lehetővé. +A **Galéria** komponens a rendezvényen készült fotók gyűjteménye. A képeket az adminfelületen töltitek fel, a látogatók a galéria oldalán böngészik (kattintásra nagyban is megnyílnak), a kezdőlapra jelölt képek pedig a kezdőlapi carouselben jelennek meg. ## Beállítások -A **Komponens beállításai** menüpontban konfigurálhatod a galéria alapvető adatait: +A **Galéria** menü **Galéria testreszabása** pontjában: -- **Lap címe** – a böngésző címsorában megjelenő szöveg. -- **Menü neve** – a menüben látható név. -- **Jogosultságok** – mely szerepkörökkel érhető el a galéria oldala. +- **Jogosultságok** – mely szerepkörök nyithatják meg a galéria oldalát. Alapból üres, ilyenkor csak adminok látják, ezért élesítés előtt mindenképp állítsd be. +- **Oldal tetején megjelenő szöveg** / **Oldal alján megjelenő szöveg** – Markdown szöveg a galériaoldal tetején, illetve alján; üresen nem jelenik meg. -## Képoptimalizálás +## Képek feltöltése -A feltöltött képek automatikusan optimalizálásra kerülnek a jobb betöltési idő és kisebb tárolási igény érdekében: +A **Képfeltöltés** menüpontban egyszerre több fájlt is kijelölhetsz, és mindegyikhez külön **Cím**, **Leírás**, valamint **Kiemelt** és **Kezdőlapra** kapcsoló tartozik. Feltölteni **GALLERY_CREATE** („Galéria képek létrehozása”) jogosultsággal lehet; a feltöltés végén a felület visszajelzi a hozzáadott képek nevét. -- **Thumbnail generálás** – minden képhez automatikusan létrejön egy 800×800 pixeles thumbnail. -- **Progressive JPEG** – a JPEG képek progresszív kódolással kerülnek mentésre, így a kép már a teljes betöltés előtt látható. -- **Tömörítés** – a képek 85%-os minőségen kerülnek mentésre. -- **Átlátszóság kezelése** – ha az eredeti kép rendelkezik alpha csatornával (PNG), az átalakítás során fehér háttér kerül a kép mögé. +Feltöltéskor minden képhez készül egy legfeljebb 800×800 pixeles JPEG előnézet (**Thumbnail Url**), a galéria rácsában ez látszik, nagy nézetben viszont az eredeti fájl. Az eredeti feltöltött kép nem kerül átméretezésre vagy tömörítésre, ezért érdemes előre optimalizált képet feltölteni – a kezdőlapi carousel is az eredetit tölti. A szerver a teljes feltöltési kérést 30 MB-ra korlátozza, ennél nagyobb kép (vagy egyszerre túl sok kép) esetén a feltöltés hibára fut. -## Galéria kezelése +## Képek listája -A [Képfeltöltés](/admin/control/gallery-upload) menüpont alatt töltheted fel a képeket. A feltöltéshez `PERMISSION_CREATE_GALLERY` jogosultság szükséges. +A **Galéria** menüpont listázza az összes képet: innen tudsz egyesével új képet felvenni (ekkor az **Url** és **Thumbnail Url** mezőt neked kell kitöltened), szerkeszteni, törölni, illetve CSV-ben importálni és exportálni. A lista keresője a **Cím** és **Leírás** mezőben keres. -- **Új kép feltöltése** – új fotó rögzítése. -- **Szerkesztés / Törlés** – képek adatainak módosítása vagy eltávolítása. - -## Kép feltöltése / szerkesztése - -- **Cím** – a kép neve vagy rövid leírása. -- **Kép** – a fájl feltöltése. -- **Látható** – ha be van kapcsolva, megjelenik a galériában. -- **Kezdőlapra mehet** – ha be van kapcsolva, a kép megjelenhet a kezdőlapi carouselben is (ha a kezdőlap komponensnél ez engedélyezve van). +| Mező | Jelentés | +| --- | --- | +| **Cím** | A kép neve. | +| **Leírás** | Rövid leírás, a galéria rácsában a kép alatt jelenik meg. | +| **Url** | A kép linkje (a feltöltő automatikusan kitölti). | +| **Thumbnail Url** | Az előnézet linkje (a feltöltő automatikusan kitölti; ha üres, a rács az eredeti képet használja). | +| **Ezek a képek szerepelnek először** | A feltöltőn **Kiemelt**; jelenleg a galéria sorrendjét nem befolyásolja. | +| **Megjelenhet a kezdőlapon** | A feltöltőn **Kezdőlapra**; a képet beveszi a kezdőlapi carouselbe, de csak ha a **Kezdőlap** komponensnél a **Galéria képek láthatóak** be van kapcsolva. | """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/key/AccessKeyComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/key/AccessKeyComponentController.kt index 3f9cffa0..f93669c9 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/key/AccessKeyComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/key/AccessKeyComponentController.kt @@ -31,31 +31,32 @@ class AccessKeyComponentController( storageService = storageService, documentationMarkdown = """ -A **Hozzáférési kulcsok** komponens segítségével egyedi kódokat generálhatsz, amelyeket a felhasználók beválthatnak bizonyos előnyökért (pl. csoportba kerülés, jogosultság szerzés). +A **Hozzáférési kulcsok** komponenssel egyszer beváltható kódokat adhatsz ki: a kódot beváltó felhasználó csoportot és/vagy szerepkört kap. Minden kód egy sor a kulcsok listájában, és a beváltás ténye rákerül a sorra. -## Beállítások +## Beüzemelés -A **Komponens beállításai** menüpontban konfigurálhatod a kódbeváltás folyamatát: +1. A **Hozzáférések testreszabása** oldalon kapcsold be a **Lehet beváltani** opciót, és a **Jogosultságok** listában pipáld be azokat a szerepköröket, akik beválthatnak (pl. `ATTENDEE`). Ha egyet sem pipálsz be, a menüpontot és az oldalt az adminokon kívül senki nem látja. +2. A **Hozzáférési kulcsok** oldalon az **Új Hozzáférési kulcs** gombbal vedd fel a kódokat. Kódgenerátor nincs: a **Kulcs** mezőbe kézzel írt szöveget kell beírni, a **Cimke** pedig csak emlékeztető (kit vagy mit jelöl). +3. A **Menü neve** és a **Lap címe** adja a menüpont és az oldal nevét. A **Lapon megjelenő szöveg** (markdown) az oldal tetején jelenik meg, de csak akkor, ha a beváltás be van kapcsolva. -- **Lap címe** – a böngésző címsorában megjelenő szöveg. -- **Menü neve** – a menüben látható név. -- **Hibaüzenetek** – testre szabható üzenetek különböző esetekre (hibás kód, már felhasznált kód, nincs bejelentkezve stb.). -- **Működés** – engedélyezhető vagy tiltható a beváltás, illetve beállítható, hogy egy felhasználó több kódot is felhasználhat-e. -- **Megjelenés** – egyedi leírás és mezőnév a beváltó oldalon. +## Mit ad a kulcs? -## Kulcsok kezelése +A beváltás önmagában csak felhasználttá teszi a kulcsot; csoportot és szerepkört a soron lévő kapcsolók adnak: -A **Hozzáférési kulcsok** menüpont alatt: +| Mező a kulcs sorában | Hatás beváltáskor | +| --- | --- | +| **Csoport átállítása** + **Csoport neve** | a felhasználó csoportja erre a névre áll be. A névnek pontosan egyeznie kell egy létező csoporttal (a **Csoportok** menüben láthatók), különben a csoport nem változik, viszont a kód elhasználódik. | +| **Szerep átállítása** + **Szerepkör** | a felhasználó szerepe erre áll be (`BASIC`-tól `SUPERUSER`-ig). | -- **Új kulcs létrehozása** – egyedi kód generálása. -- **Szerkesztés / Törlés** – kulcsok módosítása. +Beváltáskor a **Felhasználó ID-je**, a **Felhasználó neve** és a **Mikor használta fel** mezők kitöltődnek; a név és az idő csak napló, a **Felhasználó ID-je** dönti el, hogy a kód fel van-e használva. Ha ezt visszaírod 0-ra, a kód újra beváltható. -## Kulcs létrehozása / szerkesztése +## Amire figyelni kell -- **Név** – a kulcs belső neve. -- **Kulcs** – maga a beváltandó kód (pl. `SECRET123`). -- **Csoport** – melyik belső csoportba kerüljön a felhasználó beváltás után. -- **Gárda** – melyik gárdába kerüljön a felhasználó. -- **Szerepkör** – milyen jogosultságot kapjon (pl. ATTENDEE). +- Egy **Kulcs** csak egyszer érvényes, és pontos egyezéssel keresődik: a beírt szöveg elejéről és végéről a szóköz levágódik, de a kis- és nagybetű számít. +- Ha az **Egy felhasználó többet is beválthat** ki van kapcsolva, aki már beváltott egy kódot, az semmilyen további kódot nem tud beváltani (ilyenkor a **Te már használtál fel hibaüzenet** jön). +- A **Szerepkör** valódi jogosultságot ad, akár `SUPERUSER`-ig, ezért a kulcs gyakorlatilag jelszó: csak annak add oda, akit fel akarsz jogosítani. +- A hibaüzenetek külön beállításokként átírhatók: **Hibás kód hibaüzenet**, **Kód be lett váltva hibaüzenet**, **Nem lett bejelentkezve hibaüzenet** (bejelentkezés nélkül nem lehet beváltani), **Te már használtál fel hibaüzenet**, **Kikapcsolt hibaüzenet**. +- A **Lehet beváltani** kikapcsolásakor a beváltó oldal figyelmeztetést mutat, beküldésre pedig a **Kikapcsolt hibaüzenet** szövege jön vissza. +- A kulcsok listája CSV-ben importálható és exportálható, egy sorról pedig a **Másolat készítése** gombbal készíthető új kulcs. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/leaderboard/LeaderBoardComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/leaderboard/LeaderBoardComponentController.kt index 7310f41b..5ee3099a 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/leaderboard/LeaderBoardComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/leaderboard/LeaderBoardComponentController.kt @@ -30,23 +30,43 @@ class LeaderBoardComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -A **Toplista** komponens összesíti a felhasználók és csapatok pontszámait különböző forrásokból (feladatok, riddle-ök, tokenek, beadások), és rangsort állít fel belőlük. +A **Toplista** a **Feladatok**, **Riddle-ök**, **Beadások** és **QR Kódok** komponensekben szerzett pontokat összesíti, és rangsorba állítja a résztvevőket és a csoportokat. A pontok nem élőben számolódnak, hanem egy gyorsítótárból jönnek, amit újra kell számoltatni. -## Beállítások +## Beállítások (Toplista testreszabása) -A **Komponens beállításai** menüpontban konfigurálhatod a toplista működését: +- **Toplista aktív** – kikapcsolva a résztvevők üres toplistát kapnak. +- **Toplista részletek aktív** – a listában a sorok kinyithatók, és forrásonként bontva is látszanak a pontok (a forrás neve a Feladatok / Riddle-ök / Tokenek komponens **Menü neve**, a beadásoknál a beadás kategóriája). +- **Toplista kategória szerint aktív** + **Kategória megnevezése** – külön fül kategóriánkénti bontással; a fül felirata a **Kategória megnevezése** (alapból: Kategóriánként). +- **Toplista befagyasztott** – alapból be van kapcsolva. Ilyenkor az automatikus újraszámolás nem fut le, a résztvevők a legutóbb kiszámolt állást látják. Nem rejti el a toplistát, csak lefagyasztja az értékeket. +- **Pontok mutatása** – kikapcsolva a listákban csak a sorrend látszik; a **Saját pont** és a saját csoport pontját mutató csempe ettől függetlenül mutatja a pontot. -- **Lap címe** – a böngésző címsorában megjelenő szöveg. -- **Menü neve** – a menüben látható név. -- **Jogosultságok** – mely szerepkörökkel érhető el a toplista. -- **Működés** – bekapcsolható a részletes (kategóriánkénti) toplista, illetve befagyasztható az állás a verseny végén. -- **Pontszámítás** – beállítható, hogy melyik forrás (feladatok, riddle-ök, tokenek, beadások) hány százalékos súllyal számítson bele a végeredménybe. -- **Kijelzés** – szabályozható a megjelenített sorok száma, a keresési lehetőség, és hogy a felhasználói vagy a csoportos toplista (vagy mindkettő) látható legyen-e. +## Pont számítás -## Funkciók +A szorzók a forrásokban szerzett pontokat szorozzák (100 = 1x, 0 = nem számít bele): **Feladatok szorzó (%)**, **Riddle szorzó (%)**, **Beadások szorzó (%)**, **QR Kódok szorzó (%)**. A **Felhasználói pontok felhasználása pontszámításnál** opció a felhasználói elszámolású források pontjait is beszámítja a csoportos toplistába. -- **Befagyasztás** – a `Toplista befagyasztott` opcióval megállíthatod a pontok frissülését a felhasználók felé, így az utolsó pillanatig titokban tartható a végeredmény. -- **Szűrés** – a `Legalább ennyi ponttal` opcióval elrejtheted az inaktív résztvevőket a listáról. -- **Ritkaság szerinti tokenek** – külön kijelezhető, hogy a különböző ritkaságú tokenekből mennyit gyűjtöttek össze a résztvevők. +## Kijelzés + +- **Felhasználói toplista mutatása** és **Csoport toplista mutatása** – melyik lista (vagy mindkettő) látszódjon; **Keresés elérhető** – kereső az oldal tetején; **Felhasználó csoportjának kijelzése** – a felhasználói listán látszik-e a csoport. +- **Toplista sorainak száma** – kétszer szerepel, külön a felhasználói és a csoportos listához; -1 = az összes sor. +- **Legalább ennyi ponttal** – az ennél kevesebb pontot szerzők lekerülnek a listáról; alapértéke 1, ezért a 0 pontos résztvevők eleve nem látszanak. +- **Csoport toplista neve** – a csoportos lista fül felirata; **Saját csoport neve** – a saját csoport pontját mutató csempe felirata; **Felső szöveg** – az oldal tetején megjelenő markdown szöveg. +- **Begyűjtött tokenek száma ritkaság szerint** – a részletes listában a QR kódok sora alatt ritkaságonkénti darabszám, módosítás után újraszámolás szükséges. Az **Összes token szám ritkaság szerint** beállítás létezik, de a felület jelenleg nem használja. + +## Admin oldalak (Toplista menü) + +| Oldal | Oszlopok | +| --- | --- | +| **Felhasználói toplista** | Felhasználó, Csoport, Feladatok, Riddleök, Beadások, QR Kódok, Totál | +| **Csoport toplista** | Csoport, Feladatok, Riddleök, Beadások, QR Kódok, Totál | + +Mindkét oldal alján **Újraszámol** (azonnali újraszámolás, a befagyasztást is felülírja) és **Mentés** (CSV export) gomb van. + +## Automatizmus és buktatók + +- A gyorsítótár induláskor, majd 10 óránként számolódik újra, de csak ha a **Toplista befagyasztott** ki van kapcsolva. A beállítások mentése önmagában nem indít újraszámolást. +- A csoportos toplistán csak azok a csoportok szerepelnek, amelyeknél a **Csoportok** adminon a **Játszik a csoport a versenyben?** be van kapcsolva. +- Egy forrás csak abban a nézetben ad pontot, amilyen elszámolásra telepítéskor be van állítva (felhasználói vagy csoportos), a másik listán üresen marad. +- A ritkaság szerinti bontás csak akkor jelenik meg, ha a Tokenek komponens **Menü neve** pontosan "QR kódok". +- A csapat oldal **Helyezés** / **Pontszám** csempéi is ebből a gyorsítótárból dolgoznak, ezért az elavult állás ott is látszik. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/location/LocationComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/location/LocationComponentController.kt index f4dde06e..4c47dbd2 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/location/LocationComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/location/LocationComponentController.kt @@ -30,22 +30,31 @@ class LocationComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -A **Helymeghatározás** (Térkép) komponens lehetővé teszi a felhasználók és csoportok valós idejű követését egy térképen. Ehhez egy külső tracker alkalmazás (pl. OwnTracks) használata szükséges. +A helymegosztás a **CMSch Bacon** tracker alkalmazással működik: az app a telefon pozícióját küldi a CMSch-nek, a szerver pedig a résztvevők **Térkép** oldalán és az admin követő oldalakon jeleníti meg a jelölőket. -## Beállítások +## Beállítás menete -A **Komponens beállításai** menüpontban konfigurálhatod a térképet: +1. **Telepítési útmutató** – ez a szöveg jelenik meg a **Helymeghatározás** admin oldalon, ide írd a telepítés lépéseit. Az **Android App URL-je** és az **iOS App URL-je** a letöltési gombok célja, a **Megnyitás a CMSch Bacon-ben** gomb pedig egy kattintással beállítja az appot. +2. **Csoport színek** – minden színhez külön beállítás tartozik (**Kék csoport neve**, **Narancs csoport neve**, **Fekete csoport színe**, …). A mezőkbe a csoport **nevét** írd (pl. SENIOR), nem a színt; a felsoroltakon kívüli csoportok az **Alapértelmezett csoport színe** színt kapják. +3. **Megjelenítés** – **Felhasználó nevének kiírása**, **Becenév nevének kiírása**, **Csoport nevének kiírása**: mi látszódjon a jelölő alatt. A **Láthatóság ideje** (másodperc) letelte után a jelölő eltűnik, ha nem érkezik új pozíció; alapból 600. +4. **Megjelenés** – **Oldal tetején megjelenő szöveg** és **Oldal alján megjelenő szöveg** (markdown) a Térkép oldalon. -- **Térkép menü neve** – a menüben látható név. -- **Jogosultságok** – mely szerepkörökkel érhető el a térkép. -- **Megjelenés** – egyedi üzenetek a térkép oldalán. -- **Csoportszínek** – beállítható, hogy melyik csoport (pl. SENIOR, KIRDEV, LEAD) milyen színnel jelenjen meg a térképen. -- **Tracker alkalmazás** – a felhasználók számára megjelenő telepítési útmutató és az appok letöltési linkjei. -- **Megjelenítés** – szabályozható, hogy mi szerepeljen a térképen lévő jelölők (markerek) alatt (név, becenév, csoportnév), és mennyi ideig maradjanak láthatóak a markerek frissítés nélkül. +## Admin oldalak -## Funkciók +| Menüpont | Leírás | +| --- | --- | +| **Követés (térkép)** | Élő térkép az összes csoport jelölőjével, 5 másodpercenként frissül. | +| **Csoport követése** | Azok a csoportok, amelyektől van pozíció; a **Térkép** gombbal csak az adott csoport jelölői látszanak. | +| **Pozíciók** | A beérkező nyers pozíciók listája. Új pozíció itt nem vehető fel, de szerkeszthető, törölhető és exportálható; a **Frissítés** gomb a felhasználói adatokat (név, becenév, csoport) tölti újra. | +| **Jelzők** | Fix pontok a térképen (pl. büfé, elsősegély): **Kijelzett szöveg**, **Latitude**, **Longitude**, **Forma**, **Szín**, **Leírás**. A jelzők a résztvevők Térkép oldalán mindenkinek látszanak (a követő admin térképen nem), és nem tűnnek el. | +| **Helymeghatározás** | A helymegosztók oldala: token, útmutató, app-letöltés. | -- **Valós idejű követés** – a rendszer fogadja a tracker-alkalmazásokból érkező GPS-koordinátákat és megjeleníti azokat egy interaktív térképen. -- **Csoportosítás** – a különböző színek segítenek gyorsan megkülönböztetni a szervezői egységeket. +## Fontos + +- Pozíciót **kizárólag Rendező (STAFF) vagy magasabb szerepkörű** felhasználó küldhet, a többiek appja hibát kap. A token a **Helymeghatározás** oldalon látható, és nem szabad kiadni. +- A résztvevők a **Térkép** menüben a jelzők mellett csak a **saját csoportjuk** jelölőit látják, és csak akkor, ha a Profil komponensben be van kapcsolva a **Vezetők helyzetének mutatása**. +- Aki megkapta a `Közvetítés funkció (mindenki láthassa)` jogot, az az appban bekapcsolhatja, hogy a pozíciója mindenkinél megjelenjen. A **Pozíciók** listában ezt a **Publikus helyzet** kapcsoló mutatja, de a következő beérkező pozíció felülírja. +- A pozíciók **csak memóriában** élnek: újraindítás után üres a **Pozíciók** lista (az appok néhány percen belül újraküldik). +- A **Térkép** oldal 15, az admin **Követés (térkép)** 5 másodpercenként frissül. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/login/LoginComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/login/LoginComponentController.kt index b89b9a66..a861dcbb 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/login/LoginComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/login/LoginComponentController.kt @@ -58,23 +58,40 @@ class UnitScopeComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -A **Jogviszonyok** komponens lehetővé teszi a felhasználók automatikus besorolását és jogosultságkiosztását az egyetemi jogviszonyuk alapján (AuthSCH BME_UNIT_SCOPE adatok segítségével). +A **Jogviszony beállítások** oldalon az AuthSCH-tól kapott BME jogviszony adatok alapján a belépés pillanatában automatikusan ROLE-t adhatsz és csoportba sorolhatod a felhasználókat. A szabályok kizárólag AuthSCH-s belépésnél futnak le, Google / Keycloak / emailes belépésnél nem. -## Beállítások +## Előkészítés -A **Komponens beállításai** menüpontban különböző szabályokat definiálhatsz: +1. **Auth beállítások** oldal, **AuthSCH** csoport, **Oauth scopeok**: szerepeljen benne a `BME_UNIT_SCOPE`. Ha nincs benne, az AuthSCH nem küld jogviszony adatot, és itt semmi nem fog történni. +2. **Jogviszony beállítások** oldal, **Jogviszonyok** csoport: kapcsold be a **Jogok adása** opciót. Amíg ez ki van kapcsolva, az összes többi beállítás hatástalan. +3. A **Csoportba áthelyezés** mezőkben megadott csoportok létezzenek a **Csoportok** menüpontban, pontos névvel – ha nincs ilyen nevű csoport, a belépéskor csendben nem történik semmi. -- **BME-s felhasználók** – mindenki, aki rendelkezik érvényes BME-s jogviszonnyal. -- **Aktív hallgatók** – azok, akiknek jelenleg aktív hallgatói státuszuk van. -- **Elsőévesek** – a frissen felvett hallgatók. -- **Kar szerinti szűrés** – külön szabályok a VIK-es vagy VBK-s hallgatókra, illetve ezek elsőéveseire. +## Kategóriák és érvényesülési sorrendjük -## Funkciók +Egy felhasználó több kategóriába is beletartozhat, ezért a szabályok mindig ebben a sorrendben futnak le, és a későbbi felülírja a korábbi döntését: -Minden kategóriánál (BME, Aktív, Elsőéves, Karok) háromféle művelet állítható be: +| # | Csoport a beállításokban | Kire vonatkozik | +|---|---|---| +| 1 | **BME-s felhasználók** | bármilyen érvényes BME jogviszony | +| 2 | **Aktív hallgató felhasználók** | aktív hallgatói státusz | +| 3 | **Első éves felhasználók** | elsőéves hallgató | +| 4 | **VIK-es felhasználók** | VIK-es jogviszony | +| 5 | **VIK-es elsőéves felhasználók** | VIK-es elsőéves | +| 6 | **VBK-s felhasználók** | VBK-s jogviszony | +| 7 | **VBK-s elsőéves felhasználók** | VBK-s elsőéves | -1. **ATTENDEE szerepkör adása** – a felhasználó alapszintű résztvevői jogot kap. -2. **PRIVILEGED szerepkör adása** – a felhasználó emelt szintű résztvevői jogot kap. -3. **Csoportba áthelyezés** – a felhasználó automatikusan bekerül egy megadott belső csoportba (pl. "Gólyák"). +Mind a hét kategóriában ugyanez a három beállítás érhető el: + +- **ATTENDEE role adása** – ATTENDEE ("Résztvevő") ROLE-t ad. +- **PRIVILEGED role adása** – PRIVILEGED ("Kiemelt") ROLE-t ad. +- **Csoportba áthelyezés** – a felhasználó ebbe a csoportba kerül; üresen hagyva nem nyúl a csoporthoz. + +## Jó tudni + +- A szabály a belépéskor **felülírja** a ROLE-t (a meglévőt is), nem csak emeli: ha egy későbbi kategóriában csak az **ATTENDEE role adása** van bekapcsolva, az egy korábban adott PRIVILEGED-et is ATTENDEE-re vihet vissza. Csak azt a kategóriát állítsd be, amelynek a ROLE-ját mindenképp adni akarod. +- Rendező (STAFF) és annál magasabb ROLE-t a rendszer nem módosít. +- Csoportba áthelyezés csak akkor történik meg, ha a felhasználónak még nincs csoportja, vagy a jelenlegi csoportja **Elhagyható** (Csoportok menüpont). +- A módosítások a következő belépésnél érvényesülnek: a már belépett felhasználók megtartják a jelenlegi ROLE-jukat és csoportjukat. +- Ha a jogviszony szabályai nem sorolták be a felhasználót, utána az **Auth beállítások** oldal **Automatikus GROUP** csoportjában beállított **Fallback csoport neve** érvényesül. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/news/NewsComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/news/NewsComponentController.kt index b6c1859d..ce3e4c15 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/news/NewsComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/news/NewsComponentController.kt @@ -32,45 +32,37 @@ class NewsComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -A **Hírek** komponens segítségével híreket és közleményeket tudsz létrehozni és megjeleníteni a felhasználók számára. -Az adminfelületen keresztül minden fontos beállítást elérsz. +A **Hírek** komponens hírek és közlemények közzétételére való: a híreket az adminfelületen veszed fel, a látogatók pedig a nyilvános **Hírek** oldalon olvassák. Egy hír csak akkor kerül ki, ha a **Látható a hír** be van kapcsolva, a **Publikálás időpontja** már elmúlt, és a néző rangja eléri a **Minimum rang a megtekintéshez** értékét. -## Beállítások +## Hírek felvétele -A **Komponens beállításai** menüpontban konfigurálhatod a hírek megjelenését: +A **Hírek** menüpontban (**Új Hír** gomb) veszed fel a híreket. A lista oszlopai **ID**, **Cím**, **Látható** és **Kiemelt**, a kereső pedig csak a **Cím** mezőben keres. Soronként **Megtekintés**, **Szerkesztés**, **Másolat készítése** és **Törlés**, a lap tetején **Import / Export** és **Összes törlése** gomb van. -- **Lap címe** – ez jelenik meg a böngésző címsorában. -- **Menü neve** – a menüben látható név. -- **Jogosultságok** – mely szerepkörökkel érhető el a hírek oldala. -- **Részletes nézet** – ha be van kapcsolva, akkor a hírek külön oldalon is megnyithatók, nem csak listában. +| Mező | Jelentés | +| --- | --- | +| **Cím** | a hír címe, ez látszik a listában és a részletes oldalon is. | +| **Url** | a hír azonosítója, ez szerepel a részletes oldal és a megosztott link címében. Csak nem ékezetes kisbetűt és kötőjelet használj, és minden hírnél legyen egyedi. | +| **Rövid tartalom** | Markdown szöveg, a listában a cím alatt jelenik meg. | +| **Tartalom** | Markdown szöveg, csak a részletes nézetben látszik. | +| **Kép a hír mellé** | kép linkje vagy feltöltött fájl; a listában kis négyzetben, a részletes nézetben nagyban jelenik meg. | +| **Látható a hír** | kikapcsolva a hír sehol nem jelenik meg, akkor sem, ha az időpontja már elmúlt. | +| **Kiemelt hír** | a lista tetejére kerül, nagyobb címmel és kiemelt színű kerettel. | +| **Publikálás időpontja** | eddig az időpontig a hír nem jelenik meg; egyben a lista sorrendje is ez, csökkenően. | +| **Minimum rang a megtekintéshez** | a látható hírt is csak az ennél legalább ilyen rangú felhasználók látják (GUEST = kijelentkezett, BASIC = belépett, STAFF = rendező). | +| **OG:Title**, **OG:Image**, **OG:Description** | a megosztott link előnézetéhez; üresen hagyva az előnézet címe, képe és leírása is üres lesz. | -## Hírek kezelése +## Megjelenés a látogatóknál -A hírek listájában láthatod az összes eddig létrehozott hírt. Innen tudsz: +- A **Hírek** oldalon a **Kiemelt hír** bejegyzések jönnek elöl, utána a többi hír **Publikálás időpontja** szerint csökkenő sorrendben. A lista tetején a kereső a **Cím** mezőben szűr. +- A listaelem címe csak akkor kattintható, ha a **Hírek testreszabása** oldalon a **Részletes nézet** be van kapcsolva: ekkor nyílik meg a külön hír oldal a **Tartalom** mezővel. Kikapcsolva a részletes oldal nem érhető el. +- A kezdőlapon is megjelennek a hírek, de csak ha a Kezdőlap beállításai között a **Hírek láthatóak** be van kapcsolva, és legfeljebb a **Max megjelenő hír** értéknek megfelelő darabszámban. +- A `share/news/{Url}` cím közösségi megosztásra való előnézetet ad, és a hír oldalára visz tovább. -- **Új hír létrehozása** gombbal új hírt rögzíteni. -- Meglévő hírt **szerkeszteni** vagy **törölni**. -- Állapotukról információt szerezni (látható / kiemelt / publikálás ideje). +## Amit érdemes tudni -## Hír létrehozása / szerkesztése - -Új hír felvételekor vagy szerkesztéskor a következő mezőket tudod beállítani: - -- **URL** – rövid azonosító, ami a hír webcímében szerepel. Csak kisbetűk és kötőjelek használhatók. -- **Cím** – a hír fő címe. -- **Rövid tartalom** – rövid leírás, ami a hírek listájában jelenik meg. -- **Tartalom** – a hír teljes szövege, Markdown-formázással. -- **Kép** – illusztráció a hírhez (feltöltés szükséges). -- **Látható** – ha be van kapcsolva, a hír megjelenik a felhasználók számára. -- **Kiemelt** – ha be van jelölve, a hír külön kiemeltként jelenhet meg a felületen. -- **Publikálás időpontja** – időzítésre használható. Az itt beállított időpont előtt nem látszik a hír. -- **Minimum szerepkör a megtekintéshez** – korlátozhatod, hogy csak bizonyos szerepkörrel rendelkező felhasználók lássák. -- **OG:Title, OG:Image, OG:Description** – a közösségi megosztásokhoz tartozó metaadatok. - -## Használati tippek - -- Ha **előre be szeretnéd időzíteni** a hírt, állítsd be a publikálás időpontját, és jelöld be a **Látható** kapcsolót. A hír csak az időpont után fog megjelenni. -- A **Kiemelt hírek** előtérbe kerülnek a felhasználói oldalon, ezért fontos közleményeknél használd. -- A **Jogosultságok** mezővel egyszerűen korlátozhatod, hogy egy hír csak a szervezőknek, vagy csak a bejelentkezett résztvevőknek látszódjon. +- Ha nem adsz meg **Publikálás időpontját**, a hír azonnal látható, de a lista végére kerül, mert a sorrend időpont szerint csökkenő. +- A **Másolat készítése** minden mezőt átmásol, az **Url**-t is: mentés előtt írd át, különben két hír kerül ki ugyanazzal az azonosítóval, és a részletes nézet hibára fut. +- A CSV import és export nem tartalmazza a **Kép a hír mellé** és az OG mezőket, ezeket import után kézzel kell kitölteni. +- Az **Összes törlése** az összes hírt véglegesen törli. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/proto/ProtoComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/proto/ProtoComponentController.kt index c5f60b6a..77105d32 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/proto/ProtoComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/proto/ProtoComponentController.kt @@ -30,12 +30,28 @@ class ProtoComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -A **Prototípusok** (Proto) komponens fejlesztési és tesztelési célokat szolgál. +A **Prototípusok** (Proto) komponens egy „dummy” végpontgyűjtemény: a benne felvett sorokra az oldal egy előre megadott HTTP-választ ad vissza, bejelentkezés nélkül. A rendezvény lebonyolításában nincs szerepe, jellemzően külső rendszerek (olvasó, mobilapp, integráció) kipróbálásához és hibakereséséhez használjuk. Minden élesített oldalon alapértelmezés szerint be van kapcsolva, és nincs olyan beállítása, amivel a viselkedését érdemben szabályozni lehetne. -## Beállítások +## Végpont létrehozása -Ez a komponens általában csak fejlesztői környezetben aktív, és a rendszer belső működésének tesztelésére használható. +1. **Prototípusok** menü → **Válaszok** → **Új Válasz**. +2. Töltsd ki a mezőket (lásd a táblázatot), kapcsold be az **Aktív** kapcsolót, és mentsd el. +3. A végpont máris működik, újraindítás nem kell: `GET /api/proto/<Útvonal>`, például **Útvonal** = `/health` esetén `GET /api/proto/health`. -*Éles rendszeren történő használata nem ajánlott, hacsak nem specifikus okból van rá szükség.* +| Mező | Jelentése | +| --- | --- | +| **Útvonal** | A végpont útvonala, kötelezően `/` jellel kezdődik. Pontos egyezéssel keresődik, regex és minta nem használható. | +| **Válasz** | A visszaadott válasz törzse, szó szerint, változóhelyettesítés nélkül. | +| **Mime type** | A válasz `Content-Type` fejléce, például `application/json`. | +| **HTTP code** | A válasz státuszkódja, például `200`. | +| **Aktív** | Kikapcsolt sor nem érhető el: a kérés 404-gyel tér vissza. | + +## Fontos tudnivalók + +- A végpont **bejelentkezés nélkül, bárki számára elérhető**, ezért soha ne kerüljön ide titok, jelszó vagy belső adat. +- Csak **GET** kérést szolgál ki; nem létező vagy kikapcsolt útvonalra 404-et ad. +- Ha több sor ugyanazzal az **Útvonal**-lal szerepel, nem meghatározott, melyik válaszol – ne hozz létre duplikátumot. +- A **Válaszok** tábla CSV importot/exportot és **Másolat készítése** műveletet is kínál. +- A komponens egyetlen beállítása a **Jogosultságok**, de mivel a komponensnek nincs nyilvános oldala és menüpontja, ez a végpontok elérését nem befolyásolja. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/qrfight/QrFightComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/qrfight/QrFightComponentController.kt index 305748cf..1f321b5b 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/qrfight/QrFightComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/qrfight/QrFightComponentController.kt @@ -34,37 +34,56 @@ class QrFightComponentController( menuService = menuService, storageService = storageService, documentationMarkdown = """ - A **QR Fight** komponens egy interaktív, területfoglalós játékot valósít meg. A csapatok QR-kódok ("tornyok") beolvasásával szerezhetnek területeket és pontokat. - - ## Beállítások - - A **Komponens beállításai** menüpontban konfigurálhatod a játékot: - - - **Lap címe** – a böngésző címsorában megjelenő szöveg. - - **Menü neve** – a menüben látható név. - - **Jogosultságok** – mely szerepkörökkel érhető el a játék oldala. - - **QR Fight engedélyezve** – a játék aktív állapotának kapcsolója. - - **Napi limit** – szabályozható, hogy egy játékos hányszor olvashat be egy tornyot egy nap (visszaélések elkerülésére). - - **InduláSch integráció** – speciális összeköttetés az InduláSch rendszerrel, ahol a toronyfoglalások állása külső kijelzőkön is megjeleníthető. - - ## QR Fight kezelése - - Két fő entitással dolgozhatsz: - - 1. **Szintek (Levels)** – a játék különböző fázisai vagy területei. - 2. **Tornyok (Towers)** – a konkrét beolvasandó pontok. Megadható a nevük, a selectoruk és az értékük. - - ## Torony létrehozása / szerkesztése - - - **Név** – a torony megnevezése. - - **Selector** – egyedi azonosító a toronyhoz. - - **Pontszám** – mennyit ér a torony elfoglalása vagy megtartása. - - **Látható** – megjelenjen-e a térképen/listában. - - ## Használati tippek - - - A **Napi torony beolvasás limit** (-1-re állítva kikapcsolható) segít abban, hogy a csapatok ne tudják folyamatos "spammeléssel" uralni a tornyokat. - - Az **InduláSch integráció** segítségével valós időben mutathatod a rendezvény helyszínén, hogy éppen melyik csapat vezeti a harcot. + A **QR Fight** egy területfoglalós játék: a résztvevők QR kódokat olvasnak be, amivel szinteket teljesítenek, és tornyokat foglalnak el egymástól. A játék oldala a `/qr-fight` címen érhető el, a menüben a **Menü neve** szerinti néven. + + A játékhoz háromféle adat tartozik: + + | Hol | Mi | + | --- | --- | + | **Szintek** menü | a játék fázisai (kategóriák); ide tartoznak a tornyok és a hozzájuk beolvasandó tokenek | + | **Tornyok** menü | a konkrét, QR-kóddal foglalható pontok | + | **Tokenek** komponens | a kinyomtatható QR kódok; ezek beolvasásakor történik a foglalás | + + ## Beüzemelés menete + + 1. A **QR Fight beállítások** oldalon kapcsold be a **QR Fight engedélyezve** kapcsolót, és állítsd át a **Napi torony beolvasás limit**-et (0-val nem lehet tornyot foglalni). + 2. **Szintek:** vegyél fel egy szintet. A **Kategória** legyen egyedi, erre hivatkoznak a tornyok és a tokenek is. A szint csak akkor jelenik meg a játékosoknak, ha a **Szint látható** és a **Szint elérhető** is be van kapcsolva. + 3. **Tornyok:** vedd fel a tornyokat. A **Kategória** egyezzen a szint kategóriájával, a **Selector név** pedig az legyen, amit a token akciója hivatkozik. + 4. **Tokenek:** készíts tokent a toronyhoz. A **Kategória** a szint kategóriája legyen, a **Kiváltott esemény** pedig `capture:` (foglalás, a torony elvehető), `history:` (csak naplózza a beolvasást) vagy `enslave:` (csak akkor sikerül, ha a torony még senkié). Az **Aktív cél** kell ahhoz, hogy a token beleszámítson a szint teljesítésébe. + 5. Nyomtasd ki és helyezd ki a tokenek QR kódjait; a játékosok a játék oldal **QR kód beolvasása** gombjáról érik el őket. + + ## Szintek + + - **Elérhető ekkortól / eddig** – időablak, azon kívül a szint nem elérhető. + - **Min. token a teljesítéshez** – ennyi aktív célú token kell a teljesítéshez; 0 esetén a szint azonnal teljesítettnek számít. + - **Előfeltétel** – egy másik szint kategóriája; amíg az nincs teljesítve, ez a szint „Zárt”, és a tokenjei sem olvashatók be. + - **Leírás amég nem elérhető / ha elérhető / miután teljesítve lett** – a játékosoknak mutatott szöveg az adott állapotban (markdown). + - **Extra szint** – külön fülön jelenik meg a játékosoknak. A **Treasure hunt szint** kincskereső szint, ahol a már megszerzett tokenek adják a következőkhöz a hintet; ez csak egyéni (nem csapatos) birtoklási módban működik, és a felületen jelenleg nincs rá fül. + + ## Tornyok + + - **Selector név** – ez az azonosító szerepel a token `capture:` / `history:` / `enslave:` akciójában; ha nem létezik ilyen torony, a beolvasás hibát ad. + - **Lezárva**, **Foglalható ekkortól / eddig** – zárt vagy lejárt tornyot sem foglalni, sem naplózni nem lehet. + - **Publikus leírás** mindenkinek látszik, a **Leírás a tulajdonosoknak** csak az éppen birtokló csapatnak. + - **Idő logolása** – ha be van kapcsolva, a torony számolja a birtoklási időt; enélkül nem lesz helytartója. + - **Totem** – csapatos módban az első foglalás után véglegesen az adott csapaté: sem a `capture:`, sem az `enslave:` nem veszi el többé, és az időzítő sem számol rá birtoklási időt. + - **Tulajdonos ...**, **Helytartó**, **Birtoklás állása**, **Beolvasás log** – a rendszer tartja karban, kézzel ne írd. + + ## Automatikus működés + + - 10 percenként lefut a torony időzítő: minden **Idő logolása** kapcsolós, nem **Lezárva** és időben nyitott toronynál növeli az aktuális birtokos számlálóját. A **Helytartó** a legtöbb időt birtokló csapat lesz, a **Helytartás ennyi időegysége (perc)** pedig a birtoklás hossza percben – ezt a játékosok a torony „Helytartó” felirata alatt látják. + - Ugyanekkor frissül az InduláSch kijelző is. Kézi futtatás: `/admin/control/component/qrFight/execute-towers` (csak sysadmin érheti el, a felületen nincs hozzá gomb). + - A **Napi torony beolvasás limit** egy játékos egy tornyot 24 órán belül ennyiszer foglalhat el, **-1 = korlátlan**. Alapértéke 0, ami minden foglalást letilt. Csak a `capture:` akcióra érvényes, és csak csapatos birtoklási módban. + + ## InduláSch integráció + + Az **Indulásch torony** bekapcsolásával a szerver a **Torony selector**-ral kiválasztott torony állását kiírja a **Kioszk azonosító**-val megadott InduláSch kioszk szöveges widgetjére (fő szöveg: a helytartó neve, alszöveg: „Birtokos: ...”). Az **API Kulcs** is kell hozzá; ha bármelyik üres, a frissítés elmarad. Külső kijelzős lekérdezéshez nem ez, hanem az **API tokenek** beállítás való (`selector:token` párok vesszővel elválasztva): a `GET /api/qrfight/tower/?token=` végpont adja vissza a torony nevét, birtokosát, helytartóját és a birtoklás hosszát. + + ## Amire figyelni kell + + - A tornyok beolvasása a szint állapotán is múlik: ha a token kategóriájához tartozó szint le van tiltva, lejárt vagy nincs megnyitva, a foglalás elutasításra kerül. + - A játékosok oldalán a szintek „Fő szintek” és „Extra szintek” fülön, állapotjelvényzővel (Elérhető, Teljesítve, Zárt, Nem elérhető), a kategória legjobb csapataival, valamint a tornyokkal és totemekkel jelennek meg. Az **Oldal tetején megjelenő szöveg** markdown szöveget tesz az oldal tetejére. + - Csapatos vagy egyéni birtoklás: ezt a szerver indulási beállítása dönti el (`hu.bme.sch.cmsch.startup.token-ownership-mode`, env: `OWNER_TOKEN`), a beállítási felületen nem állítható. Egyéni módban nincs napi limit, és a játékosok nem csapatként versenyeznek. """ ) { diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/race/RaceComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/race/RaceComponentController.kt index 43502863..d6a2c8d9 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/race/RaceComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/race/RaceComponentController.kt @@ -30,31 +30,50 @@ class RaceComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -A **Verseny** komponens időalapú vagy pontalapú mérések eredményeinek rögzítésére és rangsorolására szolgál. +A **Verseny** komponens (jellemzően „Sörmérés”) időeredmények rögzítésére és toplistázására szolgál. Minden eredményt **Mért idő** formában, másodpercben adsz meg, és egy kategóriához tartozik: az üres kategóriájú sorok az alap toplistára kerülnek (`/race`), a többi kategória a saját oldalát kapja (`/race/SLUG`). A toplista csapatonként vagy felhasználónként összesít – ezt telepítési beállítás dönti el, az admin felületen nem váltható. ## Beállítások -A **Komponens beállításai** menüpontban konfigurálhatod a méréseket: +A **Verseny testreszabása** oldalon: -- **Lap címe** – a böngésző címsorában megjelenő szöveg. -- **Menü neve** – a menüben látható név. -- **Jogosultságok** – mely szerepkörökkel érhető el az oldal. -- **Kijelzés** – szabályozható a toplista láthatósága, a rendezési elv (növekvő/csökkenő) és a keresési lehetőség. -- **Szabad kategória** – egyedi, kötetlenebb mérési kategória (pl. "Funky mérés") beállítása. +| Beállítás | Hatás | +| --- | --- | +| **Látható** | főkapcsoló; kikapcsolva a felhasználók a toplista helyett hibaoldalt kapnak | +| **Extra kategóriák láthatóak** | enélkül a nem alap kategóriák oldalai nem érhetők el | +| **Növekvő sorrend** | bekapcsolva a kisebb, kikapcsolva a nagyobb idő a jobb; a lista sorrendjét és a résztvevőnként beszámított értéket (minimum/maximum) is ez dönti el | +| **Alapértelmezett kategória leírása** | markdown szöveg az alap toplista tetején; üresen nem jelenik meg | +| **Keresés elérhető** | keresőmező a toplista fölött | +| **Szabad kategória neve** | a szabad kategóriás oldal és menüpontjának neve (alapértéke: Funky mérés) | +| **Szabad kategória leírása** | markdown szöveg a szabad kategóriás toplista tetején | -## Verseny kezelése +## Beállítás menete -Három szinten kezelheted az adatokat: +1. Kapcsold be a **Látható**, extra kategóriákhoz az **Extra kategóriák láthatóak** beállítást. +2. A **Mérés kategóriák** menüpontban vedd fel a méréseket (**Név**, **Slug (url)**, **Leírás**, **Látható-e a kategória**); az alap toplistához nem kell kategóriát létrehozni. +3. A **Mérések** menüpontban rögzítsd az eredményeket kézzel vagy importtal. +4. A **Menü beállítások** oldalon engedélyezd szerepkörönként a menüpontokat: a **Menü neve** szerinti fő menüt, valamint a kategóriák és a szabad kategória külön menüpontját (utóbbiak csak **Látható-e a kategória** bekapcsolása után választhatók). -1. **Versenykategóriák** – hozz létre csoportokat a különböző méréseknek (pl. "Alap mérés", "Profi mérés"). -2. **Mérési eredmények** – itt rögzítheted a konkrét eredményeket (idő, név, csapat). -3. **Szabad kategóriás eredmények** – a kötetlenebb mérések eredményeinek helyszíne. +## Eredmény rögzítése -## Eredmény rögzítése / szerkesztése +- **Kategória** – a legördülő a kategóriák **Slug (url)** értékét kínálja; az üres az alap kategória. +- **Felhasználó** / **Csoport** – az üzemmód dönti el, melyiket kell kitölteni; a **Felhasználó** formátuma `Teljes Név | id | [a/g] email`, és ilyenkor a **Csoport** a felhasználó csapatából töltődik. +- **Mért idő** – másodpercben, ponttal elválasztva, legfeljebb 3 tizedesjegyig (pl. 12.345). +- **Címke** és **Szín** – a név melletti színes jelvény a toplistán. +- **Időbélyeg** – mentéskor automatikusan kitöltődik, kézzel nem szerkeszthető. -- **Név** – a résztvevő neve. -- **Csapat** – a résztvevő csapata. -- **Idő / Pont** – a mért eredmény. -- **Kategória** – melyik méréshez tartozik. +## Amire figyelni kell + +- Ha nem választasz csoportot vagy felhasználót, a sor névtelenül, egyetlen összevont toplistaelemként jelenik meg; a mentés akkor is elutasításra kerül, ha a megadott név nem létezik. +- A toplista résztvevőnként egy sort mutat, de a **Címke**/**Szín** nem feltétlenül a legjobb időhöz tartozó sorból származik, ezért egy résztvevőnél érdemes mindig ugyanazt használni. +- A szabad kategóriás lista minden beadást külön sorol fel (**Beadás módja** szöveggel), nincs résztvevőnkénti összevonás. +- A profiloldali mérési statisztika a **Profil beállítások** oldal **Mérés eredmény látható** kapcsolójától függ, minden kategóriát összevon, és mindig a kisebb időt tekinti jobbnak. + +## Admin oldalak + +- **Mérések** – a nyers eredmények felvétele, szerkesztése, importja és exportja. +- **Mérés kategóriák** – a mérések kategóriái. +- **Extra mérések** – kategóriánkénti, résztvevőnként összevont toplista e-mail címmel; a soronkénti **Json Export** gomb valójában CSV-t tölt le. +- **Mérés toplista** – az alap kategória toplistája (amit a felhasználók is látnak), exportálható. +- **Funky mérések** – a szabad kategória beadásai; a menü neve fix, a **Szabad kategória neve** beállítást nem követi. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/riddle/RiddleComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/riddle/RiddleComponentController.kt index e62a12fe..3959c943 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/riddle/RiddleComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/riddle/RiddleComponentController.kt @@ -30,38 +30,49 @@ class RiddleComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -A **Riddle-ök** komponens logikai feladványok kezelését teszi lehetővé. A felhasználók képeket vagy szöveges nyomokat kapnak, amikre meg kell találniuk a helyes választ. +A **Riddleök** komponens képrejtvény-játék: a játékosok kategóriánként egyszerre néhány feladványt látnak (kép, leírás), beírják a megoldást, a helyes válaszért **Pont** jár. A pontok a leaderboardon (a Leaderboard komponens **Riddle szorzó (%)**-ával súlyozva) jelennek meg, a riddle oldal maga nem mutat pontszámot. A játékos a **Riddleök** menüpont alatt játszik, a **Megoldott riddleök** gombon pedig a megoldott feladványokat nézheti vissza, megoldással és hinttel együtt. -## Beállítások +## Felépítés sorrendje -A **Komponens beállításai** menüpontban konfigurálhatod a játékmenetet: +1. **Riddle Kategóriák** – vedd fel a kategóriákat: **Cím**, **Kategória id-je**, **Látható-e a riddle kategória**, **Minimum rang**. +2. **Riddleök** – a feladványok felvétele. A **Kategória id-je** mezőbe a kategória **Kategória id-je** értéke kerül, nem a sor ID-ja. +3. **Riddleök testreszabása** – a játékmenet beállításai. -- **Lap címe** – a böngésző címsorában megjelenő szöveg. -- **Menü neve** – a menüben látható név. -- **Jogosultságok** – mely szerepkörökkel érhető el a riddle-ök oldala. -- **Válaszok ellenőrzése** – beállítható a kis- és nagybetűk, ékezetek és szóközök figyelmen kívül hagyása a megoldásoknál. -- **Pontozás** – a hinttel megoldott riddle-ök pontértékének (%) szabályozása. -- **Átugrás funkció** – bizonyos számú megoldó után elérhetővé tehető a feladvány átugrása. -- **Moderálás** – egyedi tiltólisták (Ban / Shadow Ban) kezelése játékosokra vagy csoportokra. +## Egy feladvány mezői -## Riddle-ök kezelése +- **Cím**, **A képrejtvény** (kép URL), **Pont**, **Sorrend** (a kategórián belüli sorrend), **Kategória id-je**. +- **Megoldás** – több elfogadott válasz pontosvesszővel elválasztva; maga a válasz nem tartalmazhat pontosvesszőt. +- **Hint** – a segítség szövege, csak hint kérés után látszik a játékosnak. +- **Leírás** (Markdown) és **Riddle készítője** – a játékos is látja; az **Első megoldó** mezőt a rendszer tölti ki az első nem átugrott megoldásnál. -A feladványokat kategóriákba rendezve kezelheted: +## Beállítások, amik a játékmenetet alakítják -1. **Riddle kategóriák** – hozz létre csoportokat (pl. "Kezdő", "Haladó", "Extra"). -2. **Riddle-ök** – itt töltheted fel a képeket és adhatod meg a megoldásokat. +| Beállítás | Hatás | +| --- | --- | +| **Egyidőben mutatott riddle-ök száma** | kategóriánként ennyi megoldatlan riddle látszik **Sorrend** szerint; egy megoldása után kerül elő a következő (alapértéke 1). | +| **Hint engedélyezve** | megjelenik a **Hintet kérek** gomb a játékos oldalán. | +| **Hint pont érték (%)** | a hintet kért riddle ennyi százalékot ér a leaderboardon (100 = nincs levonás). A hint kérésével a feladvány véglegesen hintezettnek számít, akkor is, ha a játékos a szöveg nélkül is megoldotta volna. | +| **Átugrás engedélyezve** / **Átugrás ennyi megoldó után** | az átugrás gomb akkor engedett, ha a feladványt már ennyien (átugrás nélkül) megoldották; az átugrott riddle 0 pontot ér, de megoldottnak számít. | +| **Kis- és nagybetű / Szóközök és elválasztók / Ékezetek figyelmen kívül hagyása** | a beküldött válasz és a tárolt megoldás összehasonlítása; a szóközök elhagyásakor a szóköz, a kötőjel, a `&`, a `+` és a vessző tűnik el. | +| **Hibás válaszok számának mentése** | gyűjti a hibás próbálkozásokat (erőforrásigényes); a próbálkozás-számok legfeljebb 5 percenként íródnak ki az adatbázisba. | +| **Userek szerinti csoportosítás** | csapatos játéknál a megoldásokat felhasználónként is rögzíti. | -## Riddle létrehozása / szerkesztése +Az egyéni vagy csapatos játékmód telepítési beállítás (`OWNER_RIDDLE`, azaz `hu.bme.sch.cmsch.startup.riddle-ownership-mode`), az admin felületen nem kapcsolható. -- **Cím** – a feladvány neve (az admin felületen). -- **Megoldás** – a helyes válasz. -- **Hint** – segítség, ha a felhasználó elakad (opcionális pontlevonással). -- **Kép** – a feladvány képe. -- **Pontszám** – a helyes megoldásért járó pontszám. -- **Sorszám** – a kategórián belüli sorrend meghatározásához. +## Moderálás (Ban / Shadow Ban) -## Használati tippek +A **Riddle beadások moderálása – Ban** és a **– Shadow Ban** csoportba írt játékosok és csoportok beadása nem kerül rögzítésre, de a feladványokat továbbra is látják. Bannál a játékos a „Ki vagy tiltva a riddleökből!” üzenetet kapja; shadow bannál minden ugyanígy történik, csak ő „Helytelen válasz!”-t lát, így nem szerez tudomást a tiltásról. Az azonosítók soronként vagy vesszővel elválasztva adhatók meg: játékosnál a **PéK internal id** (a Felhasználók oldalon a felhasználó szerkesztésénél), csoportnál a csoport numerikus ID-ja (a **Csoportok** oldal ID oszlopa) – a beállítás leírása itt tévesen csoportnevet ír. A listák mentéskor lépnek életbe, és a korábbi eredményeket nem törlik. -- A **Shadow Ban** funkcióval anélkül zárhatsz ki gyanúsan gyors megoldókat, hogy tudnának róla (a válaszaikat a felület elfogadja, de automatikusan rossz válaszként kezeli). +## Admin oldalak + +- **Riddleök** és **Riddle Kategóriák** – a két lista, CSV import/exporttal. +- **Riddle felhasználónként** / **Riddle csoportonként** – beadások megoldónként: **Beadó**, **Elfogadott**, **Hintek felhasználva**, megnyitva pedig **Riddle**, **Hint**, **Megoldva**, **Átugorva**, **Próbálkozás**, **Beadva**. A csoportos oldalon **Riddle statisztika export** (CSV) gomb is van; a sorok törlésével beadás törölhető. +- **Riddle MS dashboard** – csak microservice-es telepítésnél látszik a menüben: ping, cache újratöltés, minden adat mentése és a zárolások felengedése a riddle node felé. A **Beállítások szinkronizálása** beállítás nincs implementálva, a node cache-e nem frissül magától. + +## Figyelmeztetések + +- A feladvány és a kategória a **Kategória id-je** értékkel kapcsolódik: ha nincs ilyen azonosítójú **Látható** kategória, vagy a játékos rangja a kategória **Minimum rang**ja alatt van, a feladvány soha nem jelenik meg. Ha több kategóriának ugyanaz a **Kategória id-je**, a besorolás nem egyértelmű. +- Ha az **Egyidőben mutatott riddle-ök száma** kevés, és a soron következő feladvány megoldhatatlan, átugrás nélkül elakad a játék. +- A feladványok és a beadások memóriában élnek: a feladvány vagy a kategória mentése azonnal érvényesül, a törlésük viszont csak újraindításkor; a törölt beadás is csak az adatbázisból tűnik el, a játékos a szerver újraindításáig (microservice-es telepítésnél a **Teljes cache ürítése** gombig) megoldottként látja. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/staticpage/StaticPageComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/staticpage/StaticPageComponentController.kt index aefd8720..76b98ab4 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/staticpage/StaticPageComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/staticpage/StaticPageComponentController.kt @@ -30,30 +30,41 @@ class StaticPageComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -A **Statikus oldalak** komponens segítségével tetszőleges tartalmú oldalakat hozhatsz létre, amelyek Markdown formátumban szerkeszthetők. +A **Statikus oldalak** komponenssel a látogatóknak szánt, egyszerű tartalmi oldalakat hozhattok létre (GYIK, szabályzat, kapcsolat, program). A tartalom Markdown, az oldal a `/page/{url}` címen nyílik meg (pl. `/page/gyik`). A komponensnek nincs saját látogatói menüpontja: az oldalakat egyenként tehetitek be a menübe. ## Beállítások -A komponensnek nincsenek globális beállításai, az oldalakat egyenként kell konfigurálni. +Az **Oldalak testreszabása** oldalon egyetlen beállítás van: -## Oldalak kezelése +- **Jogosultságok** – mely szerepkörök nyithatnak meg bármelyik statikus oldalt. Alapból mindenki benne van; ha szűkíted, a kimaradó szerepkörök minden statikus oldalra hibát kapnak. -A **Statikus oldalak** menüpont alatt: +## Oldal létrehozása -- **Új oldal létrehozása** – új tartalom rögzítése. -- **Szerkesztés / Törlés** – meglévő oldalak módosítása. +1. **Statikus oldalak** menüpont → **Új Statikus Oldal**. +2. Add meg az **Url**-t (ékezet nélküli kisbetű, pl. `gyik`), a **Cím**-et és **Az oldal tartalma** mezőt Markdown szöveggel. +3. Kapcsold be a **Látható**-t, különben az oldal senkinek sem nyílik meg. +4. Menübe tételhez a **Látható a menüben** be, majd a **Tartalom → Menü beállítások** oldalon szerepkörönként pipáld be és sorold be; a menüben a **Menü cím** szövege jelenik meg. -## Oldal létrehozása / szerkesztése +## Mezők -- **URL** – az oldal címe a böngészőben (pl. `info`). A frontenden a `/page/{url}` címen lesz elérhető. -- **Cím** – az oldal neve. -- **Tartalom** – a megjelenített szöveg Markdown formátumban. -- **Látható** – ha be van kapcsolva, az oldal elérhető a felhasználók számára. -- **Minimum szerepkör a megtekintéshez** – korlátozhatod az oldal láthatóságát. +| Mező | Mit jelent | +| --- | --- | +| **Url** | Az oldal azonosítója: ebből lesz a `/page/{url}` cím, a megosztható link pedig a `/share/page/{url}`. | +| **Cím** | Az oldal neve, ez látszik a böngésző címsorában és az oldal tetején. | +| **Az oldal tartalma** | Markdown: címsorok, felsorolások, kiemelés, linkek, képek, táblázatok, kódblokkok, idézetek. A nyers HTML-t nem jeleníti meg. | +| **Látható** | Csak bekapcsolva nyitható meg az oldal; kikapcsolva a látogató hibát kap. | +| **Elérhető** | Megjelenik a listában, de a működésre jelenleg nincs hatása. | +| **Jog a szerkesztéshez** | Üresen hagyva mindenki szerkesztheti, aki a listát látja. Kitöltve (pl. `STATICPAGE_EDIT_GYIK`) csak azok, akiknek ezt a jogot a **Felhasználók** vagy a **Jogkörök** oldalon megadtad – ilyenkor az oldal a többiek listájából el is tűnik. A mezőt csak adminok látják. | +| **Látható a menüben** | Bekapcsolva az oldal kiválasztható a **Menü beállítások**ban. | +| **Menü cím** | A menüben megjelenő szöveg a **Cím** helyett. | +| **Minimum jogkör** | Az ennél alacsonyabb szerepkörű látogató nem nyithatja meg az oldalt, és a **Menü beállítások**ban sem választható ki. | +| **OG:Title / OG:Image / OG:Description** | A `/share/page/{url}` link megosztásakor megjelenő előnézet. | -## Használati tippek +## Jó tudni -- Használd a statikus oldalakat szabályzatok, általános tájékoztatók vagy GYIK megjelenítésére. -- A Markdown formázással képeket, táblázatokat és linkeket is elhelyezhetsz a szövegben. +- A **Statikus oldalak** lista a **Cím**, **Látható** és **Elérhető** oszlopokat mutatja, a kereső a **Cím**-ben keres. A soroknál szerkesztés, **Másolat készítése** és törlés érhető el, valamint CSV import és export; másolásnál az **Url**-t mindenképp írd át. +- Az admin oldalakhoz **Statikus oldalak megtekintése** (`STATIC_PAGE_SHOW`), új oldal felvételéhez **Statikus oldalak létrehozása** (`STATIC_PAGE_CREATE`) jog kell; a szerkesztés és törlés jogát a **Felhasználók**/**Jogkörök** oldalon adhatod meg. +- A látogatói menü a menü- vagy komponensbeállítások mentésekor frissül: ha egy már menüben lévő oldal **Menü cím**-ét módosítod vagy kiveszed a menüből, a **Menü beállítások** újramentése kell hozzá. +- Két oldalnak ne legyen ugyanaz az **Url**-je, és a menübe tett oldalon a **Látható** is legyen bekapcsolva, különben a menüpont hibára visz. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/task/TaskComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/task/TaskComponentController.kt index 2278b898..4233876f 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/task/TaskComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/task/TaskComponentController.kt @@ -30,33 +30,47 @@ class TaskComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -A **Feladatok** komponens segítségével különböző típusú feladványokat (szöveges, kép- vagy fájlfeltöltős) írhatsz ki a felhasználók vagy csapatok számára, amiket az adminisztrátorok értékelhetnek. +A **Feladatok** komponens feladványok kiírására és online beadatására szolgál: a résztvevők (az indulási `task-ownership-mode` beállítástól függően felhasználónként vagy csapatonként) szöveget, képet, PDF-et vagy ZIP-et küldhetnek be, amit a rendezők értékelnek és pontoznak. -## Beállítások +## Első lépések -A **Komponens beállításai** menüpontban konfigurálhatod a feladatok működését: +1. **Feladat kategóriák** menü: itt hozd létre a kategóriát (**Kategória neve**, **Kategória id-je**, **Beadhatóak ekkortól**, **Beadhatóak eddig**, **Típus**). +2. **Feladatok** menü: a feladat **Kategória id-je** mezőjébe pontosan a kategória **Kategória id-je** számát írd – ez a két szám köti össze őket, nem a sorok azonosítója. A **Kategória id-je** értékének egyedinek kell lennie, különben összeakad a rendszer. +3. **Látható** bekapcsolása nélkül a feladat senkinek sem jelenik meg. +4. **Értékelések** menü: a beérkező beadások elbírálása. -- **Lap címe** – a böngésző címsorában megjelenő szöveg. -- **Menü neve** – a menüben látható név. -- **Jogosultságok** – mely szerepkörökkel érhető el a feladatok oldala. -- **Nyelvi beállítások** – a kötelező (pl. profil kitöltéséhez szükséges) és a normál feladatok csoportosítása és leírása. -- **Működés** – beállítható az újraküldés lehetősége, a pontszámok láthatósága és a megnyitások naplózása. -- **Beadások exportálása** – konfigurálható egy PDF-export, amely a beadott feladatokat összesíti. +## Kategória beállításai -## Feladatok kezelése +- **Típus** – REGULAR: a feladatok listáján szerepel. PROFILE_REQUIRED: külön blokkban, a lista tetején, és a profil csak akkor számít kitöltöttnek, ha ezekre a feladatokra van elfogadott beadás. +- **Hírdetett** – a csapat komponens is kiemelten listázza. +- **Minimum/Maximum rang a megtekintéshez** – a kategória csak az adott rangtartományba tartozóknak látszik. +- A **Beadhatóak ekkortól / eddig** ablakon kívül a kategória a listában sem jelenik meg. -A feladatok kezelése több szinten történik: +## Feladat beállításai -1. **Feladat kategóriák** – csoportosítsd a feladatokat (pl. "Kreatív", "Sport", "Beugró"). -2. **Feladatok** – itt hozhatod létre magukat a feladványokat. -3. **Beadások** – a beküldött megoldások listája, ahol az adminisztrátorok pontozhatnak és visszajelzést adhatnak. +- **Típus** – mit fogadjon el a szerver: TEXT (szöveg), IMAGE (kép: png/jpg/jpeg/gif/webp), BOTH (szöveg és kép), ONLY_PDF (csak .pdf), ONLY_ZIP (csak .zip). A kiterjesztést a szerver ellenőrzi. +- **Formátum** – hogyan lehet beadni: NONE (nincs online beadás, személyesen kell leadni), TEXT (szövegmező vagy fájltallózó), CODE (kódszerkesztő), FORM (saját űrlap). +- **Formátum leírása** – FORM formátumnál ide kerül a mezők leírása: [{"title":"","type":"number|text|textarea","suffix":""}]. +- **Max pont**, **Beadható ekkortól**, **Beadható eddig** – ezen az ablakon kívül beadás nem lehetséges. +- **Beadandó formátum** – rövid útmutató a beadó mező mellett; **Leírás** – a feladat szövege Markdownban. +- **Mintamegoldás** – Markdown szöveg, ami csak a határidő lejárta után jelenik meg a résztvevőknek. +- **Kiemelt** – „hamarosan lejár” jelzés; **Sorrend** – kategórián belüli sorrend; **Minimum/Maximum rang a megtekintéshez** – a feladat láthatósága rang szerint. -## Feladat létrehozása / szerkesztése +## Értékelés -- **Típus** – Szöveges (TEXT), Kép (IMAGE), Fájl (FILE) vagy csak leírás (ONLY_DESCRIPTION). -- **Kategória** – melyik csoportba tartozik. -- **Pontszám** – a feladatért járó maximális pontszám. -- **Határidők** – mikortól és meddig adható be a megoldás. -- **Megjelenés** – leírás Markdown formátumban, kép vagy fájl melléklet. +- **Értékelések** – feladatonként összesítve (elfogadva / elutasítva / nincs értékelve). Az **Értékel** gomb a még el nem bírált beadásokat listázza, a **Kijavít** gomb nyitja az értékelő űrlapot: **Elfogadva**, **Elutasítva**, **Adott pont**, **Értékelés** (ez a szöveg a beadónak is megjelenik). Ha mindkettőt bejelölöd, az **Elfogadva** nyer; a döntéseket a **Beadás történet** naplózza. +- **Nyers beadások** – minden beadás egy listában, kézzel is javítható, CSV exporttal. +- **Személyes beadás értékelése** – felhasználó/csoport és feladat kiválasztásával egy lépésben rögzíthetsz értékelést; ha még nincs beadás, létrehozza, így személyes leadás pótlására is jó. +- **Pontok ellenőrzése** – az elfogadott beadások közül azok, amelyek pontszáma nem 0 és nem a **Max pont** (elgépelt pontszámok kiszűrésére). + +## Működés + +- **Újraküldés lehetséges** – kikapcsolva az elfogadott vagy el nem bírált beadás nem módosítható (az elutasított viszont újra beadható); bekapcsolva a határidőig bármelyik beadás újraküldhető, ilyenkor az addigi döntés törlődik, és a beadás újra értékelésre vár. +- **Pontok látszódnak közben** – kikapcsolva a pontszám csak elfogadott beadásnál, a határidő lejárta után látszik; **Pontok látszódnak egyáltalán** – kikapcsolva egyénileg soha, csak az összesítésekben. +- **Feladatok megnyitásának logolása** – naplózza, ki nyitott meg egy feladatot. +- **Kötelező feladatok fejléc szövege / alatti szöveg** és **Feladatok fejléc szövege / alatti szöveg** – a feladatok oldal két blokkjának címe, illetve a cím alatti Markdown szöveg. +- **Endpoint elérhető** – bekapcsolva a `/export-tasks` oldal a bejelentkezett résztvevő saját csapata beadásairól ad nyomtatható összesítőt (Ctrl+P → PDF), a **Főrendezők üzenetével** és a **Logó URL-je** képpel. Menüből nem érhető el, a linket neked kell megosztanod. +- A pontszámok a ranglista összesítésébe is bekerülnek, a Leaderboard komponens **tasksPercent** arányában. +- **Jogosultságok** alapból üres, ilyenkor a Feladatok oldalt csak adminok látják, ezért élesítés előtt mindenképp vedd fel a résztvevői szerepköröket. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/task/TasksService.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/task/TasksService.kt index 2c4c5922..c451d2bc 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/task/TasksService.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/task/TasksService.kt @@ -10,16 +10,18 @@ import hu.bme.sch.cmsch.service.StorageService import hu.bme.sch.cmsch.service.TimeService import org.slf4j.LoggerFactory import org.springframework.boot.autoconfigure.condition.ConditionalOnBean -import org.springframework.resilience.annotation.Retryable +import org.springframework.dao.CannotAcquireLockException import org.springframework.stereotype.Service -import org.springframework.transaction.annotation.Isolation +import org.springframework.transaction.PlatformTransactionManager +import org.springframework.transaction.TransactionDefinition import org.springframework.transaction.annotation.Transactional +import org.springframework.transaction.support.TransactionTemplate import org.springframework.web.multipart.MultipartFile -import java.sql.SQLException import java.util.* import kotlin.jvm.optionals.getOrNull private const val target = "task" +private const val MAX_SERIALIZABLE_ATTEMPTS = 5 @Service @ConditionalOnBean(TaskComponent::class) @@ -32,11 +34,31 @@ class TasksService( private val listeners: List, private val userRepository: UserRepository, private val groupRepository: GroupRepository, - private val storageService: StorageService + private val storageService: StorageService, + private val transactionManager: PlatformTransactionManager ) { private val log = LoggerFactory.getLogger(javaClass) + private val serializableTransaction = TransactionTemplate(transactionManager).apply { + isolationLevel = TransactionDefinition.ISOLATION_SERIALIZABLE + } + + private fun withSerializableRetry(action: String, block: () -> T): T { + var attempt = 0 + while (true) { + try { + return serializableTransaction.execute { block() }!! + } catch (e: CannotAcquireLockException) { + // Postgres aborts one of the concurrent SERIALIZABLE transactions at commit time; + // retrying in a fresh transaction succeeds once the competing one is done. + if (++attempt >= MAX_SERIALIZABLE_ATTEMPTS) throw e + log.warn("Serializable transaction conflict during $action, retrying ($attempt/$MAX_SERIALIZABLE_ATTEMPTS)") + Thread.sleep(100L shl (attempt - 1)) + } + } + } + @Transactional(readOnly = true) fun getById(id: Int): Optional { @@ -116,8 +138,6 @@ class TasksService( } } - @Retryable(value = [ SQLException::class ], maxRetries = 5, delay = 500L, multiplier = 1.5) - @Transactional(readOnly = false, isolation = Isolation.SERIALIZABLE) fun submitTaskReview( taskId: Int, userId: Int?, @@ -126,6 +146,20 @@ class TasksService( isApproved: Boolean, score: Int, adminUserName: String + ): Boolean { + return withSerializableRetry("task review") { + doSubmitTaskReview(taskId, userId, groupId, reviewMessage, isApproved, score, adminUserName) + } + } + + private fun doSubmitTaskReview( + taskId: Int, + userId: Int?, + groupId: Int?, + reviewMessage: String, + isApproved: Boolean, + score: Int, + adminUserName: String ): Boolean { if (userId == null && groupId == null) { return false @@ -172,9 +206,11 @@ class TasksService( return true } - @Retryable(value = [ SQLException::class ], maxRetries = 5, delay = 500L, multiplier = 1.5) - @Transactional(readOnly = false, isolation = Isolation.SERIALIZABLE) fun submitTaskForGroup(answer: TaskSubmissionDto, file: MultipartFile?, user: CmschUser): TaskSubmissionStatus { + return withSerializableRetry("task submission") { doSubmitTaskForGroup(answer, file, user) } + } + + private fun doSubmitTaskForGroup(answer: TaskSubmissionDto, file: MultipartFile?, user: CmschUser): TaskSubmissionStatus { val groupId = user.groupId ?: return TaskSubmissionStatus.NO_ASSOCIATE_GROUP val task = taskRepository.findById(answer.taskId).orElse(null) @@ -203,8 +239,11 @@ class TasksService( } } - @Transactional(readOnly = false, isolation = Isolation.SERIALIZABLE) fun submitTaskForUser(answer: TaskSubmissionDto, file: MultipartFile?, user: CmschUser): TaskSubmissionStatus { + return withSerializableRetry("task submission") { doSubmitTaskForUser(answer, file, user) } + } + + private fun doSubmitTaskForUser(answer: TaskSubmissionDto, file: MultipartFile?, user: CmschUser): TaskSubmissionStatus { val task = taskRepository.findById(answer.taskId).orElse(null) ?: return TaskSubmissionStatus.INVALID_TASK_ID diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/team/TeamComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/team/TeamComponentController.kt index 665542b2..4e297cc9 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/team/TeamComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/team/TeamComponentController.kt @@ -30,27 +30,44 @@ class TeamComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -A **Csapatok** komponens a felhasználók közösségbe szerveződését és a csapatok közötti versengést kezeli. Lehetővé teszi csapatok létrehozását, csatlakozást, csapatmenedzsmentet és a csapatok adatlapjának megtekintését. +A **Csapatok** komponens a résztvevőket csapatokba szervezi. A csapatok valójában a **Csoportok** adminon kezelt csoportok, ezért a **Toplista** csoportos listája és több más komponens is ezekre épül. A résztvevők csapatot hozhatnak létre, jelentkezhetnek mások csapatába, a kapitány pedig a saját csapatát kezeli. -## Beállítások +Fontos: a kapcsolók nagy része alapból ki van kapcsolva, ezért friss telepítésnél még a csapatlista sem látszik, és sem létrehozni, sem jelentkezni nem lehet. -A komponens rendkívül részletesen testre szabható: +## Beüzemelés -- **Csapatom** – a felhasználó saját csapatának információs oldala. -- **Csapatlista** – az összes regisztrált csapat felsorolása, rendezési és keresési lehetőségekkel. -- **Csapat létrehozása** – ki és hogyan hozhat létre új csapatot, név-ellenőrzési szabályok (regex, tiltólista). -- **Csapat admin felület** – a csapatvezetők eszköztára: tagok kezelése (eltávolítás, jogosultság átadása), feladatok és űrlapok követése. -- **Csapat adatlap** – mi látszódjon egy csapatról (tagok, pontszám, statisztikák). -- **Csapat statisztika** – integráció más komponensekkel (Leaderboard, QR Fight, Riddle, Race), hogy a csapat eredményei egy helyen látszódjanak. +1. A **Csapatok beállítások** oldalon kapcsold be: **Csapatlista megjelenítése**, **Részletek megjelenítése**, **Csapatkészítés engedélyezve**, **Csatlakozás engedélyezve**, **Kilépés engedélyezve**. **Részletek megjelenítése** nélkül a csapat adatlapja hibát ad, **Csapatlista megjelenítése** nélkül üres a lista. +2. Névszabályok: **Csapatnév szabály (Regex)** és **Tiltott nevek** (vesszővel elválasztva). Egy csapatnév ezen kívül nem egyezhet meg kis-nagybetűre sem egy már létező csapat nevével. +3. Jogosultságok: **Csapatok menü jogosultságok** (a listát, az adatlapot és a jelentkezést is ez engedi), **Csapatom menü jogosultságai**, **Csapatkészítés menü jogosultságai**, **Admin oldal jogosultságai** (a kapitányi felület, alapból PRIVILEGED-től). Ezek pontos szerepkör-listák: a **Csapatkészítés** alapból csak a BASIC szerepkört tartalmazza, így adminisztrátor sem tud csapatot létrehozni. +4. Szerepkörök: **PRIVILEGED jog a csapatkészítőnek** – aki csapatot hoz létre, azonnal kapitány lesz; **ATTENDEE jog a csapattagoknak** – az elfogadott jelentkező ATTENDEE szerepkört kap. +5. **Alapból versenyzik** és **Alapból lehet jelentkezni** az új csapatok kezdőértéke a **Csoportok** admin **Játszik a csoport a versenyben?** és **Kiválasztható** kapcsolójához. Nem versenyző csapat csak a **Nem versenyző csapatok megjelenítése** bekapcsolásával látszik, kikapcsolt **Kiválasztható** csapatnál "Nem lehet csatlakozni", az adminon felvett csapatok pedig az **Admin által nevezett csapatok megjelenítése** kapcsolóval kerülnek a listába. +6. A csapatlista keresője a **Keresés engedélyezése**; **Rendezés név alapján** bekapcsolva névsorban, kikapcsolva meghatározatlan sorrendben jelenik meg a lista. -## Csapatok kezelése +## A résztvevők útja -Az admin felületen kezelheted az összes csapatot, módosíthatod az adataikat vagy a tagságokat. +1. **Csapat létrehozása** – csak egy nevet kell megadni (a **Csapatkészítés felső szöveg** markdown szöveg jelenik meg felette). A létrehozó lesz a **Csapatkapitány**, és automatikusan kap egy "Csapatkapitány: ..." bemutatkozást. +2. **Bemutatkozás és logó** – a kapitány a **Csapatszerkesztés** oldalon írja le a csapatot (**Csapatszerkesztés engedélyezése**), és tölthet fel logót (**Csapatlogó feltöltés engedélyezése**; csak png/jpg/jpeg/gif). Az új bemutatkozás csak a **Bemutatkozások** adminon adott **Elfogadva** után látszik, addig a régi marad; **Elutasítva** és **Elutasítás oka** esetén a saját csapata látja az indoklást. +3. **Jelentkezés** – a csapat adatlapján a "Jelentkezés a csapatba" gomb kérést készít, amit a kapitány a **Csapatom** oldal "Jelentkezők" szakaszában fogad el vagy utasít el. A kérelmek a **Kérelmek** adminon is megjelennek. +4. **Tagság** – egy résztvevő egyszerre csak egy csapat tagja lehet. A kapitány a **Vezetőség átadása**, **Tagok eltávolítása** és **Jogosultságok kezelése** kapcsolókkal rúghat ki tagot vagy adhat neki kapitányi jogot, a saját oldalát pedig a **Feladatok megjelenítése**, **Űrlapok megjelenítése** és **Üzenet a vezetőknek** beállításokkal alakítja. +5. **Kilépés** – **Kilépés engedélyezve** esetén a tag kiléphet; a kapitány csak akkor, ha előbb átadta a vezetőséget. -## Funkciók felhasználóknak +## Admin oldalak (Csapatok menü) -- **Csapat készítése** – névválasztással, leírással és logóval indíthatnak új közösséget. -- **Csatlakozás** – a felhasználók jelentkezhetnek meglévő csapatokba (ha a csapat nyitott). -- **Vezetői felület** – a saját csapatukon belül követhetik a verseny állását és a teendőket a vezetők. +| Oldal | Fontos mezők | +| --- | --- | +| **Kérelmek** | Felhasználó, Felhasználó ID-je, Csapat, Csapat ID-je – a beérkezett jelentkezések; elfogadni a kapitányi felületen lehet. | +| **Bemutatkozások** | Csapat, Bemutatkozás, Logó url, Elfogadva, Elutasítva, Elutasítás oka – itt hagyod jóvá a bemutatkozásokat (az **Elfogadva** felülírja az elutasítást). | +| **Címkék** | Csapatonkénti címkék (**Csoport**, **A címke ami megjelenik**, **Szín**, **Leírás**, **Listába megjelenik**) a csapatlista jelöléseihez. | + +A csapat adatai – név, **Csoport borítóképe**, versenyző státusz, **Csoport létszáma** – a **Csoportok** adminon szerkeszthetők, a tagok hozzárendelése a felhasználók menüben történik. + +A csapat adatlapján és a saját csapat oldalán megjelenő csempéket a **Csapat statisztika** csoport kapcsolói adják: **Tagok számának megjelenítése**, **Helyezés megjelenítése**, **Pontszám megjelenítése**, **QR Fight megjelenítése**, **Versenyeredmény megjelenítése**, **Riddle eredmény megjelenítése** (ezek a Toplista / QR Fight / Verseny / Riddle komponenst igénylik, a fejlécek külön állíthatók). A **Mérés gomb megjelenítése** a csapat versenyeredményeihez tesz gombot az adatlapra. A csapattagok listája a **Tagok publikussá tétele** nélkül csak a saját csapatnál látszik. + +## Buktatók + +- A csapat egyben csoport: a **Csoportok** adminon átnevezve a tagoknál tárolt csapatnév nem frissül, ezért a csapattagok listája eltűnik. +- A **Csapat adatlap** csoport **Pontszám megjelenítése** és **Részletes pontszám gomb** beállításait a felület nem használja; a pontszám csempét a **Csapat statisztika** **Pontszám megjelenítése** kapcsolója vezérli. +- A statisztikák a **Toplista** gyorsítótárából dolgoznak, ezért elavult állást mutathatnak. +- A **Csapatom**, **Csapatkészítés** és **Csapatom kezelése** oldalak rejtett menüpontok: a menüben nem jelennek meg, a csapatlistából és a csapat adatlapjáról nyithatók. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/token/TokenComponentController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/token/TokenComponentController.kt index 1dfaf58e..93fa43d6 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/token/TokenComponentController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/token/TokenComponentController.kt @@ -30,35 +30,48 @@ class TokenComponentController( auditLogService = auditLogService, storageService = storageService, documentationMarkdown = """ -A **Tokenek** (vagy QR kódok) komponens segítségével QR kódokat generálhatsz, amiket a felhasználók beolvashatnak. Ez használható pecsétgyűjtésre, jelenléti ívek készítésére vagy egyszerűen pontgyűjtésre. +A **Tokenek** (QR kódok) komponenssel QR kódokat generálhatsz, amiket a résztvevők beolvasnak: pecsétet gyűjtenek vele, pontot szereznek, és egy megadott darabszám elérését is kijelezheted. A szervezők a kódokat létrehozzák és kinyomtatják, a felhasználók a **QR kódok** oldalon (és a profiljukon) látják a haladásukat. -## Beállítások +## Beüzemelés -A **Komponens beállításai** menüpontban konfigurálhatod a tokenek működését: +1. **Jogosultságok**: pipáld be azokat a szerepköröket, akik megnyithatják a QR kódok oldalát – üresen csak adminok látják. Itt állítható a **Lap címe** és a **Menü neve** is. +2. **QR frontend url**: az oldal saját címe a `token=` paraméterrel a végén (pl. `.../token/scan?token=`). Ez kerül a QR kódokba, ezért mindenképp a saját instance címére írd át. +3. **Pecsét gyűjtés aktív** – ha a beolvasásokból teljesítést is akarsz számolni: **Szükséges pecsét**, valamint **Pecsét token típusa** (a token **Kategória** mezőjére szűr, `*` = bármelyik). A **'Nincs elég' üzenet**ben a `{}` helyére a hiányzó darabszám kerül, a **'Már van elég' üzenet** a teljesítéskor jelenik meg; a sáv a QR kódok oldal és a profil tetején látszik. +4. Tokenek felvétele: a **Tokenek** oldalon egyenként, vagy a **Token generálás** menüben sok egyszerre (**Nevek** soronként, **Kódok hossza**, **Típus**, **Ikon**, **Pont érték**, **Hány napig érhető el** – a kódokat a rendszer generálja). +5. Nyomtatás a **QR export** menüben: az összes tokenből zip készül. Az **Oldal URL-jének csatolása** teszi a QR kódot sima kamerával is olvashatóvá, mellette a hibajavító szint, a fájlformátum (png/jpg), a **Képek mérete** és az **Extra szöveg** (a QR alján) állítható. -- **Lap címe** – a böngésző címsorában megjelenő szöveg. -- **Menü neve** – a menüben látható név. -- **Jogosultságok** – mely szerepkörökkel érhető el a kódok oldala. -- **QR frontend URL** – a generált QR kódok alapja. -- **Pecsét gyűjtés** – beállítható, hogy egy bizonyos mennyiségű token összegyűjtése után egyedi üzenet jelenjen meg (pl. tanköri jelenlét igazolása). -- **Stílus** – a megjelenítés testreszabása (ikonok, nevek láthatósága). -- **Jelenléti ív** – a generálható PDF-alapú jelenléti ív (riport) testreszabása. +## Egy token mezői -## Tokenek kezelése +| Mező | Mit jelent | +| --- | --- | +| **Token neve** | a token megjelenő neve | +| **Token** | a QR kódba kerülő egyedi kód. A szerkesztő két QR-t mutat: a sűrűbb (benne az oldal URL-je) sima kamerával is olvasható, a másik csak az oldalon belüli olvasóval | +| **Beolvasható-e a token** | kikapcsolva a beolvasás "Rossz QR" hibát ad | +| **Kategória** | szöveges típus; a pecsétgyűjtés és a jelenléti ív erre szűr | +| **Pont** | a beolvasásért járó pont, a ranglista összesítésébe is beszámít | +| **Scannelhető innentől / eddig** | ezen az időablakon kívül "Ez a QR jelenleg nem aktív" | +| **Kijelzett szöveg**, **Kijelzett kép URL-je** | sikeres beolvasás után megjelenő markdown szöveg és kép | +| **Rarity** | besorolás; a ranglista e szerint tudja bontani a begyűjtött tokeneket | -A **Tokenek** menüpont alatt kezelheted a kódokat: +A **Kiváltott esemény** (`capture:`, `history:`, `enslave:`, `treasure:`) és az **Aktív cél** csak a QR Fight komponensnél számít; ilyenkor a **Kategória** a QR Fight szintjét is kijelöli. -- **Új token létrehozása** – új beolvasható kód rögzítése. -- **Szerkesztés / Törlés** – meglévő kódok módosítása. -- **Exportálás** – a tokenek listájának kimentése. +## Beolvasás -## Token létrehozása / szerkesztése +- A felhasználó a QR kódok oldalon a kamerás olvasóval vagy a QR-ben lévő URL megnyitásával olvas be; kijelentkezve előbb be kell jelentkeznie, a kód beküldése utána magától megtörténik. +- Egy token felhasználónként (az instance beállításától függően csoportonként) csak egyszer szerezhető meg; a második próbálkozás "Már beolvasott QR", pont nélkül. A kód csak akkor talál, ha a **Token** mezővel pontosan egyezik, a **Beolvasható-e a token** be van kapcsolva, és az időablakban vagyunk. -- **Cím** – a token neve (pl. "Kir-Dev stand"). -- **Token** – az egyedi azonosító, ami a QR kódban szerepel. -- **Típus** – a token kategóriája (szűréshez és pecsétgyűjtéshez). -- **Pont** – mennyit ér a beolvasás. -- **Ikon** – egyedi ikon a tokenhez. -- **Látható** – megjelenjen-e a felhasználónak, ha már megszerezte. +## Admin oldalak + +- **Tokenek** – a tokenek listája, innen nyílik a **Generálás** és a **QR export** is; a lista CSV-ben importálható és exportálható. +- **Nyers beolvasás** – minden beolvasás (**Felhasználó név**, **Csoport név**, **Pont**, **Token**, **Beolvasva**). A sor törlésével a pecsét és a pont eltűnik (a felhasználó újra beolvashatja). +- **Token statisztika** – tokenenként a beolvasások száma, lenyitva a **Tulajdonos** és a **Beolvasva** időpont. +- **Felhasználói tokenek**, illetve a két **Csoportos tokenek** oldal („Tokenek csoportonként csoportosítva”, illetve „Felhasználói tokenek csoportonként” – utóbbi a csoportlétszámmal korrigált pontokat mutatja). +- **Pecsét statisztika** – csak a `default` kategóriájú tokeneket és csak a szervezői csoporton kívüli beolvasásokat számolja. A szervezői csoport nevét a Login komponens **Szervező csoport neve** beállítása adja; az oldalt a szervezői csoport tagjai is látják, nem csak adminok. +- **Jelenléti export** – tankörönként egy sor, a **Mentés** gombbal PDF jelenléti ív tölt le. A PDF a **Jelenléti ív címe**, **Jelenléti ív leírás**, **Jelenléti ív logója**, **Jelenléti footer szöveg** és a **Riport összefoglaló táblázat oszlopai** (stamp, attendance, riddle, achievement, time-between-scans) beállításokat használja, a jelenlétet pedig a **Szükséges pecsét** és a **Pecsét token típusa** alapján számolja. + +## Figyelmeztetések + +- A **Pecsét gyűjtés** beállításait csak akkor írd át, ha tudod, mit csinálsz: egy elrontott küszöb vagy típus miatt a résztvevők nem kapják meg a jelenlétet. +- A **Megszerző neve látszik**, az **Alapértelmezett ikon** és az **Alapértelmezett teszt ikon** beállításoknak jelenleg nincs hatásuk a felületre. """ ) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/config/AppConfig.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/config/AppConfig.kt index a1818ebb..4416d4a8 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/config/AppConfig.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/config/AppConfig.kt @@ -5,6 +5,7 @@ import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.core.convert.TypeDescriptor import org.springframework.core.convert.converter.GenericConverter +import org.springframework.resilience.annotation.EnableResilientMethods import org.springframework.scheduling.annotation.EnableAsync import org.springframework.scheduling.annotation.EnableScheduling import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator @@ -21,6 +22,7 @@ import java.util.* @Configuration @EnableScheduling @EnableAsync +@EnableResilientMethods class AppConfig { @Bean diff --git a/frontend/index.html b/frontend/index.html index e675fcc7..281641b6 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -5,6 +5,9 @@ %VITE_NAME% + + +