From 0212f8b6d0b226465fda6115028910778ce68f5c Mon Sep 17 00:00:00 2001 From: anibus Date: Sat, 24 Oct 2026 22:02:29 +0300 Subject: [PATCH] Decider admin --- KODA.md | 0 app/actors/LobbieActor.scala | 17 +- .../images/maps/4p_abandoned_jungle.jpg | Bin 0 -> 36805 bytes app/assets/images/maps/4p_ruined_greatway.jpg | Bin 0 -> 59285 bytes app/assets/images/maps/4p_sad_spires.jpg | Bin 0 -> 3831 bytes app/assets/images/maps/4p_summit.jpg | Bin 0 -> 5102 bytes app/controllers/AdminController.scala | 251 ++++++- app/controllers/HomeController.scala | 18 +- app/controllers/SecuredActions.scala | 59 ++ app/repository/DeciderRepository.scala | 179 +++++ app/repository/MapImageRepository.scala | 190 +++++ app/views/admin.scala.html | 654 +++++++++++++++++- app/views/index.scala.html | 2 +- build.sbt | 7 +- conf/application.conf | 27 +- conf/routes | 21 +- project/build.properties | 2 +- project/plugins.sbt | 6 +- 18 files changed, 1362 insertions(+), 71 deletions(-) create mode 100644 KODA.md create mode 100644 app/assets/images/maps/4p_abandoned_jungle.jpg create mode 100644 app/assets/images/maps/4p_ruined_greatway.jpg create mode 100644 app/assets/images/maps/4p_sad_spires.jpg create mode 100644 app/assets/images/maps/4p_summit.jpg create mode 100644 app/controllers/SecuredActions.scala create mode 100644 app/repository/DeciderRepository.scala create mode 100644 app/repository/MapImageRepository.scala diff --git a/KODA.md b/KODA.md new file mode 100644 index 0000000..e69de29 diff --git a/app/actors/LobbieActor.scala b/app/actors/LobbieActor.scala index ceac990..df97ec7 100644 --- a/app/actors/LobbieActor.scala +++ b/app/actors/LobbieActor.scala @@ -4,14 +4,11 @@ import actors.UserActor._ import akka.actor.{Actor, ActorRef} import akka.event.LoggingReceive import akka.util.Timeout -import com.typesafe.config.ConfigFactory import com.typesafe.scalalogging.LazyLogging +import repository.DeciderRepository -import java.util -import scala.collection.JavaConverters.iterableAsScalaIterableConverter import scala.collection.immutable.HashSet import scala.concurrent.duration._ -import scala.util.Try case class LobbyUser(name: String, actorRef: ActorRef) @@ -23,7 +20,6 @@ case class DeciderMap(map: String, description: Option[String] = None, var isBan */ class LobbieActor(hostUser: LobbyUser, deciderName: String) extends Actor with LazyLogging { - val config = ConfigFactory.load() logger.info(s"Create lobby... host: ${hostUser.actorRef.path.name}") @@ -49,11 +45,12 @@ class LobbieActor(hostUser: LobbyUser, deciderName: String) extends Actor with L private val mapsLobby: Set[DeciderMap] = { - val configMaps = config.getList(s"deciders.$deciderName.maps").asScala - configMaps.map(e => { - val mapConfig = e.unwrapped().asInstanceOf[util.ArrayList[String]].asScala - DeciderMap(mapConfig.head, mapConfig.tail.headOption) - }).toSet + DeciderRepository.get(deciderName) match { + case Some(d) => + d.maps.map(m => DeciderMap(m.map, m.description)).toSet + case None => + Set.empty[DeciderMap] + } } hostUser.actorRef.tell( diff --git a/app/assets/images/maps/4p_abandoned_jungle.jpg b/app/assets/images/maps/4p_abandoned_jungle.jpg new file mode 100644 index 0000000000000000000000000000000000000000..214e3defca12e701def1818099220f65f1b6311c GIT binary patch literal 36805 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 D5sZs~ literal 0 HcmV?d00001 diff --git a/app/assets/images/maps/4p_sad_spires.jpg b/app/assets/images/maps/4p_sad_spires.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aa675dfd6f6d000634b8674e04b1a37eac087a75 GIT binary patch literal 3831 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 - logger.info(s"Received request from: ${request.remoteAddress}") + // ---------- Public endpoints ---------- - val allUsers = userParentActor ? GetAllUsers - val res = Await.result(allUsers, Duration.Inf) - Ok(res.toString) + def login() = Action { implicit request => + val realm = request.headers.get("Host").map(h => s"http://$h/").getOrElse("http://localhost:1337/") + val returnTo = controllers.routes.AdminController.steamCallback().absoluteURL() + + val params = Map( + "openid.ns" -> "http://specs.openid.net/auth/2.0", + "openid.mode" -> "checkid_setup", + "openid.return_to" -> returnTo, + "openid.realm" -> realm, + "openid.identity" -> "http://specs.openid.net/auth/2.0/identifier_select", + "openid.claimed_id" -> "http://specs.openid.net/auth/2.0/identifier_select" + ) + + val query = params.map { case (k, v) => s"${java.net.URLEncoder.encode(k, "UTF-8")}=${java.net.URLEncoder.encode(v, "UTF-8")}" }.mkString("&") + Redirect(s"$SteamLoginUrl?$query") } + def steamCallback() = Action.async { implicit request => + // Steam присылает параметры в формате OpenID: openid.mode, openid.identity, + // openid.claimed_id. Play отдаёт ключи в queryString как есть, с точкой, + // поэтому нормализуем имена к виду openid_mode и т.д. + val openidParams = request.queryString.map { case (k, v) => k.replace('.', '_') -> v } - def reloadConfig()= Action { implicit request => - ConfigFactory.invalidateCaches() - logger.info("Config reloaded") + // Validate Steam OpenID response + val mode = openidParams.get("openid_mode").flatMap(_.headOption) + val identifier = openidParams.get("openid_identity").flatMap(_.headOption) + val assertion = openidParams.get("openid_claimed_id").flatMap(_.headOption) + + (mode, identifier orElse assertion) match { + case (Some("id_res"), Some(steamId)) if isSteamId(steamId) => + val steamId64 = parseSteamId64(steamId) + val config = ConfigFactory.load() + val allowed = Try(config.getStringList("admin.allowedSteamIds").asScala.toSet).getOrElse(Set.empty) + if (allowed.isEmpty || allowed.contains(steamId64)) { + Future.successful(Redirect("/decider/admin").withSession("steamId" -> steamId64)) + } else { + Future.successful(Redirect("/decider/admin").flashing("error" -> "You are not authorized")) + } + + case (Some("id_res"), _) => + Future.successful(Redirect("/decider/admin").flashing("error" -> "Steam authentication failed")) + + case _ => + Future.successful(Redirect("/decider/admin").flashing("error" -> "Invalid OpenID response")) + } + } + + private def isSteamId(id: String): Boolean = + id.startsWith("https://steamcommunity.com/openid/id/") || + id.startsWith("http://steamcommunity.com/openid/id/") + + private def parseSteamId64(id: String): String = + id.replaceAll("""(https?://steamcommunity\.com/openid/id/)""", "") + + // ---------- Admin page ---------- + + def index() = Secured { implicit request => + implicit val messages: Messages = messagesApi.preferred(request) + Ok(views.html.admin(DeciderRepository.all)) + } + + // ---------- API: list map images ---------- + + def mapImages() = Secured { implicit request => + val images = repository.MapImageRepository.all.map { image => + Json.obj( + "name" -> image.name, + "file" -> image.file, + "players" -> image.players + ) + } + Ok(Json.toJson(images)) + } + + // ---------- API: upload map image ---------- + + def mapImageUpload() = Secured(parse.multipartFormData) { implicit request => + request.body.file("file") match { + case Some(part) => + repository.MapImageRepository.saveUploaded(part.filename, part.ref.path.toFile) match { + case Right(image) => + logger.info(s"Admin ${SecuredActions.steamIdOrUnknown(request)} uploaded map image '${image.file}'") + Ok(Json.obj( + "ok" -> true, + "name" -> image.name, + "file" -> image.file, + "players" -> image.players + )) + case Left(error) => + BadRequest(Json.obj("error" -> error)) + } + case None => + BadRequest(Json.obj("error" -> "No file uploaded")) + } + } + + // ---------- API: list all deciders ---------- + + def decidersList() = Secured { implicit request => + val list = DeciderRepository.all.map(d => Json.obj( + "key" -> d.key, + "name" -> d.name, + "rules" -> d.rules, + "raceCount" -> d.raceCount, + "existAdditionalRaces" -> d.existAdditionalRaces, + "existTextFieldRaces" -> d.existTextFieldRaces, + "description" -> d.description, + "maps" -> d.maps.map(m => Json.obj("map" -> m.map, "description" -> m.description)) + )) + Ok(Json.toJson(list)) + } + + // ---------- API: get one decider ---------- + + def deciderGet(key: String) = Secured { implicit request => + DeciderRepository.get(key) match { + case Some(d) => + Ok(Json.obj( + "key" -> d.key, + "name" -> d.name, + "rules" -> d.rules, + "raceCount" -> d.raceCount, + "existAdditionalRaces" -> d.existAdditionalRaces, + "existTextFieldRaces" -> d.existTextFieldRaces, + "description" -> d.description, + "maps" -> d.maps.map(m => Json.obj("map" -> m.map, "description" -> m.description)) + )) + case None => + NotFound(Json.obj("error" -> s"Decider $key not found")) + } + } + + // ---------- API: save / update decider ---------- + + def deciderSave() = SecuredJson { implicit request => + val json = request.body + + (json \ "key").asOpt[String] match { + case None => + BadRequest(Json.obj("error" -> "Missing key")) + + case Some(key) => + Try { + val maps = (json \ "maps").as[List[JsValue]].map { m => + repository.DeciderMapConfig( + map = (m \ "map").as[String], + description = (m \ "description").asOpt[String] + ) + } + repository.Decider( + key = key, + name = (json \ "name").as[String], + rules = (json \ "rules").as[String], + raceCount = (json \ "raceCount").as[Int], + existAdditionalRaces = (json \ "existAdditionalRaces").as[Boolean], + existTextFieldRaces = (json \ "existTextFieldRaces").as[Boolean], + description = (json \ "description").as[Boolean], + maps = maps + ) + }.toEither match { + case Right(decider) => + val existed = DeciderRepository.get(decider.key).isDefined + DeciderRepository.save(decider) + DeciderRepository.reload() + if (existed) { + logger.info( + s"Admin ${SecuredActions.steamIdOrUnknown(request)} updated decider '${decider.key}' " + + s"(name='${decider.name}', maps=${decider.maps.size})" + ) + } else { + logger.info( + s"Admin ${SecuredActions.steamIdOrUnknown(request)} created decider '${decider.key}' " + + s"(name='${decider.name}', maps=${decider.maps.size})" + ) + } + Ok(Json.obj("ok" -> true)) + + case Left(error) => + BadRequest(Json.obj("error" -> s"$error")) + } + } + } + + // ---------- API: delete decider ---------- + + def deciderDelete(key: String) = SecuredApi { implicit request => + if (DeciderRepository.delete(key)) { + DeciderRepository.reload() + logger.info(s"Admin ${SecuredActions.steamIdOrUnknown(request)} deleted decider '$key'") + Ok(Json.obj("ok" -> true)) + } else { + NotFound(Json.obj("error" -> s"Decider $key not found")) + } + } + + // ---------- Legacy endpoints (deprecated) ---------- + + @deprecated("unused", "1.0") + def viewAllUsers() = Action { implicit request => + logger.info("viewAllUsers") + Ok("viewAllUsers") + } + + @deprecated("unused", "1.0") + def reloadConfig() = Action { implicit request => Ok("Config reloaded") } } diff --git a/app/controllers/HomeController.scala b/app/controllers/HomeController.scala index 24e955b..ce4b57d 100644 --- a/app/controllers/HomeController.scala +++ b/app/controllers/HomeController.scala @@ -13,6 +13,7 @@ import com.typesafe.config.ConfigFactory import org.reactivestreams.Publisher import play.api.libs.json._ import play.api.mvc._ +import repository.DeciderRepository import scala.concurrent.duration._ import scala.concurrent.{ExecutionContext, Future} @@ -41,14 +42,15 @@ class HomeController @Inject()(cc: ControllerComponents) extends AbstractControl // Home page that renders template def index(deciderName: String) = Action { implicit request => logger.info(s"Received request from: ${request.remoteAddress}") - val deciderHumanName = config.getString(s"deciders.$deciderName.name") - val deciderDescription = config.getString(s"deciders.$deciderName.rules") - val existAdditionalRaces = Try(config.getBoolean(s"deciders.$deciderName.existAdditionalRaces")).getOrElse(false) - val existTextFieldRaces = Try(config.getBoolean(s"deciders.$deciderName.existTextFieldRaces")).getOrElse(false) - val raceCount = Try(config.getInt(s"deciders.$deciderName.raceCount")).getOrElse(1) - val lastmapsSettings = LastMapsSelectConfig(true, true, true, true) - val raceSelect = RaceSelect(true, false) - Ok(views.html.index(deciderName, deciderHumanName, raceCount, deciderDescription, raceSelect, lastmapsSettings, existAdditionalRaces, existTextFieldRaces)) + val deciderOpt = DeciderRepository.get(deciderName) + if (deciderOpt.isEmpty) { + NotFound(s"Decider $deciderName not found") + } else { + val d = deciderOpt.get + val lastmapsSettings = LastMapsSelectConfig(true, true, true, true) + val raceSelect = RaceSelect(true, false) + Ok(views.html.index(deciderName, d.name, d.raceCount, d.rules, raceSelect, lastmapsSettings, d.existAdditionalRaces, d.existTextFieldRaces)) + } } /** diff --git a/app/controllers/SecuredActions.scala b/app/controllers/SecuredActions.scala new file mode 100644 index 0000000..9101840 --- /dev/null +++ b/app/controllers/SecuredActions.scala @@ -0,0 +1,59 @@ +package controllers + +import play.api.libs.json.{JsValue, Json} +import play.api.libs.typedmap.TypedKey +import play.api.mvc._ + +import scala.concurrent.{ExecutionContext, Future} + +object SecuredActions { + + private val SteamIdAttr: TypedKey[String] = TypedKey("steamId") + + /** Steam ID текущего авторизованного пользователя (если он есть в запросе). */ + def steamId[A](request: Request[A]): Option[String] = request.attrs.get(SteamIdAttr) + + /** Steam ID текущего пользователя или "unknown", если его нет в запросе. */ + def steamIdOrUnknown[A](request: Request[A]): String = steamId(request).getOrElse("unknown") +} + +/** + * Simple session-based authentication via Steam ID. + * Used to protect admin panel routes. + */ +trait SecuredActions { + + self: AbstractController => + + private val SteamIdAttr: TypedKey[String] = SecuredActions.SteamIdAttr + + /** Wrapper that requires the user to be logged in with Steam. */ + def Secured: ActionBuilder[Request, AnyContent] = + securedWith(controllerComponents.parsers.defaultBodyParser, apiStyle = false) + + /** Same as [[Secured]], but parses the request body as JSON. */ + def SecuredJson: ActionBuilder[Request, JsValue] = + securedWith(controllerComponents.parsers.json, apiStyle = true) + + /** Same as [[Secured]], but answers AJAX calls with 401 JSON instead of a redirect. */ + def SecuredApi: ActionBuilder[Request, AnyContent] = + securedWith(controllerComponents.parsers.defaultBodyParser, apiStyle = true) + + private def securedWith[A](bodyParser: BodyParser[A], apiStyle: Boolean): ActionBuilder[Request, A] = + new ActionBuilder[Request, A] { + + override def parser: BodyParser[A] = bodyParser + + override def executionContext: ExecutionContext = controllerComponents.executionContext + + override def invokeBlock[B](request: Request[B], block: Request[B] => Future[Result]): Future[Result] = + request.session.get("steamId") match { + case Some(steamId) => + block(request.addAttr(SteamIdAttr, steamId)) + case None if apiStyle => + Future.successful(Unauthorized(Json.obj("error" -> "Please log in with Steam"))) + case None => + Future.successful(Redirect("/decider/admin/login").flashing("error" -> "Please log in with Steam")) + } + } +} \ No newline at end of file diff --git a/app/repository/DeciderRepository.scala b/app/repository/DeciderRepository.scala new file mode 100644 index 0000000..edeabaf --- /dev/null +++ b/app/repository/DeciderRepository.scala @@ -0,0 +1,179 @@ +package repository + +import com.typesafe.config.{Config, ConfigFactory} + +import java.io.{File, PrintWriter} +import scala.collection.JavaConverters._ +import scala.util.Try + +/** Описание одной карты в маппуле десайдера. */ +case class DeciderMapConfig(map: String, description: Option[String] = None) + +/** Полное описание десайдера (турнира). */ +case class Decider( + key: String, + name: String, + rules: String, + raceCount: Int, + existAdditionalRaces: Boolean, + existTextFieldRaces: Boolean, + description: Boolean, + maps: List[DeciderMapConfig] +) + +/** + * Чтение и запись десайдеров. + * + * Десайдеры хранятся во внешнем HOCON-файле (admin.decidersFile, по умолчанию + * "conf/deciders.conf"). Пока этот файл не существует, десайдеры читаются из + * application.conf, поэтому приложение работает "из коробки". Как только админ + * что-то сохраняет через админку, внешний файл становится единственным источником + * правды. + */ +object DeciderRepository { + + private def appConfig: Config = ConfigFactory.load() + + /** Файл, в который админка пишет десайдеров. */ + def file: File = { + val path = Try(appConfig.getString("admin.decidersFile")).getOrElse("conf/deciders.conf") + new File(path) + } + + /** Десайдеры как объект Config (содержимое блока `deciders { ... }`). */ + def decidersConfig: Config = { + val f = file + if (f.isFile) { + Try(ConfigFactory.parseFile(f)).toOption + .filter(_.hasPath("deciders")) + .map(_.getConfig("deciders")) + .getOrElse(fallback) + } else { + fallback + } + } + + /** Переинициализировать кеш конфигуратора (вызывать после сохранения). */ + def reload(): Unit = { + ConfigFactory.invalidateCaches() + } + + private def fallback: Config = + if (appConfig.hasPath("deciders")) appConfig.getConfig("deciders") else ConfigFactory.empty() + + /** Ключи всех десайдеров (отсортированные). */ + def keys: Seq[String] = decidersConfig.root().keySet().asScala.toSeq.sorted + + /** Один десайдер по ключу. */ + def get(key: String): Option[Decider] = { + val c = decidersConfig + if (!c.hasPath(key)) None + else { + val d = c.getConfig(key) + val maps = d.getList("maps").asScala.toList.map { value => + value.unwrapped() match { + case list: java.util.List[_] => + val parts = list.asScala.map(_.toString).toList + DeciderMapConfig(parts.head, parts.lift(1).filter(_.nonEmpty)) + case other => + // Некоторые десайдеры заданы просто списком строк без описаний. + DeciderMapConfig(other.toString, None) + } + } + Some(Decider( + key = key, + name = Try(d.getString("name")).getOrElse(key), + rules = Try(d.getString("rules")).getOrElse(""), + raceCount = Try(d.getInt("raceCount")).getOrElse(1), + existAdditionalRaces = Try(d.getBoolean("existAdditionalRaces")).getOrElse(false), + existTextFieldRaces = Try(d.getBoolean("existTextFieldRaces")).getOrElse(false), + description = Try(d.getBoolean("description")).getOrElse(false), + maps = maps + )) + } + } + + /** Все десайдеры. */ + def all: Seq[Decider] = keys.flatMap(get) + + /** Создаёт или обновляет десайдера и перезаписывает весь файл десайдеров. */ + def save(decider: Decider): Unit = { + val updated = (all.filterNot(_.key == decider.key) :+ decider).sortBy(_.key) + write(updated) + } + + /** Удаляет десайдера. Возвращает true, если десайдер существовал. */ + def delete(key: String): Boolean = { + val current = all + if (current.exists(_.key == key)) { + write(current.filterNot(_.key == key)) + true + } else { + false + } + } + + private def write(deciders: Seq[Decider]): Unit = { + val sb = new StringBuilder + sb.append("# Конфигурация десайдеров.\n") + sb.append("# Файл управляется админкой (авторизация через Steam).\n") + sb.append("# Ручные правки могут быть перезаписаны при следующем сохранении.\n\n") + sb.append("deciders {\n") + deciders.foreach { d => + sb.append(" ").append(quoteKey(d.key)).append(" {\n") + sb.append(" name = ").append(quote(d.name)).append('\n') + sb.append(" raceCount = ").append(d.raceCount).append('\n') + if (d.existAdditionalRaces) sb.append(" existAdditionalRaces = true\n") + if (d.existTextFieldRaces) sb.append(" existTextFieldRaces = true\n") + if (d.description) sb.append(" description = true\n") + if (d.maps.isEmpty) { + sb.append(" maps = []\n") + } else { + sb.append(" maps = [\n") + d.maps.zipWithIndex.foreach { case (m, i) => + sb.append(" ").append(renderMap(m)) + if (i < d.maps.size - 1) sb.append(',') + sb.append('\n') + } + sb.append(" ]\n") + } + sb.append(" rules = ").append(quote(d.rules)).append('\n') + sb.append(" }\n") + } + sb.append("}\n") + + val f = file + Option(f.getParentFile).foreach(_.mkdirs()) + val writer = new PrintWriter(f, "UTF-8") + try writer.write(sb.toString) finally writer.close() + } + + private def renderMap(m: DeciderMapConfig): String = + m.description.filter(_.nonEmpty) match { + case Some(desc) => s"[${quote(m.map)}, ${quote(desc)}]" + case None => s"[${quote(m.map)}]" + } + + private def quoteKey(key: String): String = + if (key.matches("[A-Za-z0-9_-]+") && !key.forall(_.isDigit)) key else quote(key) + + /** Рендерит строку как строку в формате JSON/HOCON. */ + private def quote(value: String): String = { + val sb = new StringBuilder("\"") + value.foreach { + case '"' => sb.append("\\\"") + case '\\' => sb.append("\\\\") + case '\n' => sb.append("\\n") + case '\r' => sb.append("\\r") + case '\t' => sb.append("\\t") + // Литерал из обратного слэша и буквы u ломает компилятор Scala: + // такая последовательность обрабатывается как Unicode-escape ещё до лексера. + // Поэтому символы добавляем по отдельности, без escape-последовательности в исходнике. + case c if c < ' ' => + sb.append(0x5c.toChar).append('u').append("%04x".format(c.toInt)) + case c => sb.append(c) + } + sb.append('"') + sb.toString + } +} diff --git a/app/repository/MapImageRepository.scala b/app/repository/MapImageRepository.scala new file mode 100644 index 0000000..743991a --- /dev/null +++ b/app/repository/MapImageRepository.scala @@ -0,0 +1,190 @@ +package repository + +import java.io.File +import java.net.{JarURLConnection, URL} +import java.nio.file.StandardCopyOption +import scala.collection.JavaConverters._ +import scala.util.Try + +/** Изображение карты, доступное для выбора в админке. */ +case class MapImage(name: String, file: String, players: Int) + +/** + * Список картинок карт из app/assets/images/maps. + * + * Картинки читаются из исходников (при запуске через `sbt run`) либо из + * classpath (когда приложение собрано и assets упакованы в jar). + */ +object MapImageRepository { + + private val ImageExtensions = Set("jpg", "jpeg", "png", "webp") + + /** Служебные картинки, которые не являются картами. */ + private val IgnoredFiles = Set("default.jpg") + private val IgnoredPattern = """^img(_\d+)?\.(jpg|jpeg|png|webp)$""".r + + /** Каталоги с картинками: исходники и результат сборки assets. */ + private val MapDirectories = Seq( + "app/assets/images/maps", + "target/web/public/main/images/maps", + "public/images/maps" + ) + + private val ClasspathDirectory = "public/images/maps" + + /** Каталог, в который сохраняются загруженные картинки (исходники). */ + private val SourceUploadDirectory = "app/assets/images/maps" + + /** Каталоги, из которых Play раздаёт assets в dev-режиме. */ + private val RuntimeUploadDirectory = "target/web/public/main/images/maps" + + /** Максимальный размер загружаемого файла. */ + private val MaxUploadBytes = 10L * 1024 * 1024 + + /** Все карты, отсортированные по количеству игроков и имени. */ + def all: Seq[MapImage] = + loadFileNames() + .distinct + .map(toMapImage) + .sortBy(image => (groupOrder(image.players), image.name.toLowerCase)) + + /** + * Сохраняет загруженную картинку карты и возвращает её описание. + * + * Файл пишется и в исходники (app/assets), и в каталог, который раздаётся + * в dev-режиме (target/web/public/main), чтобы картинка сразу появилась + * в галерее без перезапуска приложения. + */ + def saveUploaded(rawFileName: String, source: File): Either[String, MapImage] = { + if (!source.isFile) Left("Uploaded file not found") + else if (source.length() <= 0) Left("Uploaded file is empty") + else if (source.length() > MaxUploadBytes) Left("File is too large (max 10 MB)") + else sanitizeFileName(rawFileName) match { + case None => Left("Unsupported file (allowed types: jpg, jpeg, png, webp)") + case Some(safeName) => + val directories = uploadDirectories() + if (directories.isEmpty) Left("Map images directory not found") + else { + val fileName = uniqueFileName(safeName, directories) + Try { + directories.foreach { dir => + java.nio.file.Files.copy( + source.toPath, + new File(dir, fileName).toPath, + StandardCopyOption.REPLACE_EXISTING + ) + } + }.toEither match { + case Right(_) => Right(toMapImage(fileName)) + case Left(error) => Left(s"Failed to save file: ${error.getMessage}") + } + } + } + } + + /** Каталоги для записи: исходники создаются при необходимости, остальные — только существующие. */ + private def uploadDirectories(): Seq[File] = { + val source = new File(SourceUploadDirectory) + if (!source.isDirectory) source.mkdirs() + (source +: Seq(new File(RuntimeUploadDirectory))) + .filter(_.isDirectory) + } + + /** Проверяет расширение и убирает из имени всё, что может сломать путь. */ + private def sanitizeFileName(rawFileName: String): Option[String] = { + val name = Option(rawFileName) + .map(_.trim) + .map(new File(_).getName) + .getOrElse("") + val safe = name.map { c => + if (c.isLetterOrDigit || c == '_' || c == '-' || c == '.' || c == ' ' || + c == '(' || c == ')' || c == '[' || c == ']') c + else '_' + }.mkString.trim + if (safe.nonEmpty && isMapImage(safe)) Some(safe) else None + } + + /** Подбирает свободное имя, добавляя суффикс -1, -2, ... при совпадении. */ + private def uniqueFileName(fileName: String, directories: Seq[File]): String = { + def taken(name: String): Boolean = directories.exists(dir => new File(dir, name).exists()) + + if (!taken(fileName)) fileName + else { + val dot = fileName.lastIndexOf('.') + val base = fileName.substring(0, dot) + val ext = fileName.substring(dot) + Iterator.from(1) + .map(i => s"$base-$i$ext") + .find(name => !taken(name)) + .getOrElse(fileName) + } + } + + private def loadFileNames(): Seq[String] = { + val fromDisk = MapDirectories + .map(new File(_)) + .find(_.isDirectory) + .map(dir => Option(dir.listFiles()).toSeq.flatten.filter(_.isFile).map(_.getName)) + .getOrElse(Seq.empty) + + val fileNames = if (fromDisk.nonEmpty) fromDisk else loadFromClasspath() + fileNames.filter(isMapImage) + } + + private def isMapImage(fileName: String): Boolean = { + val lower = fileName.toLowerCase + ImageExtensions.exists(ext => lower.endsWith("." + ext)) && + !IgnoredFiles.contains(lower) && + IgnoredPattern.findFirstIn(lower).isEmpty + } + + private def loadFromClasspath(): Seq[String] = { + val loader = Option(getClass.getClassLoader).getOrElse(ClassLoader.getSystemClassLoader) + loader.getResources(ClasspathDirectory).asScala.toSeq.flatMap(readResource) + } + + private def readResource(url: URL): Seq[String] = url.getProtocol match { + case "file" => + Try(new File(url.toURI)).toOption + .filter(_.isDirectory) + .flatMap(dir => Option(dir.listFiles())) + .toSeq + .flatten + .filter(_.isFile) + .map(_.getName) + + case "jar" => + Try { + val connection = url.openConnection().asInstanceOf[JarURLConnection] + connection.setUseCaches(false) + val jar = connection.getJarFile + try { + jar.entries().asScala + .map(_.getName) + .filter(_.startsWith(ClasspathDirectory + "/")) + .map(_.stripPrefix(ClasspathDirectory + "/")) + .filterNot(_.contains("/")) + .toSeq + } finally jar.close() + }.getOrElse(Seq.empty) + + case _ => Seq.empty + } + + private def toMapImage(fileName: String): MapImage = { + val baseName = fileName.substring(0, fileName.lastIndexOf('.')) + MapImage(baseName, fileName, playersFrom(fileName)) + } + + private val PlayersPattern = """(?i)(?:^|\])\s*(\d+)p""".r + + /** Количество игроков из префикса имени: 2p -> 2, 4p -> 4 и т.д. */ + private def playersFrom(fileName: String): Int = + PlayersPattern.findFirstMatchIn(fileName).map(_.group(1).toInt).getOrElse(0) + + /** Порядок групп: 1x1, 2x2, 3x3, 4x4, остальные. */ + private def groupOrder(players: Int): Int = players match { + case 2 | 4 | 6 | 8 => players + case _ => 99 + } +} diff --git a/app/views/admin.scala.html b/app/views/admin.scala.html index f681e07..7898572 100644 --- a/app/views/admin.scala.html +++ b/app/views/admin.scala.html @@ -1,6 +1,656 @@ -@()(implicit r: Request[_]) +@(deciders: Seq[repository.Decider])(implicit request: Request[_], messages: Messages) + + + + + + Admin — Decider + + + + + + +
+
+ +
+
+
+

+ Deciders (@deciders.size) + +

+
+
+ @for(d <- deciders) { + +

@d.name

+

@d.key • maps: @d.maps.size

+
+ } + @if(deciders.isEmpty) { +
No deciders
+ } +
+
+
+ + +
+ + +
+

Select a decider to edit

+

or create a new one

+
+
+
+
+ + + + + + + + + + + + diff --git a/app/views/index.scala.html b/app/views/index.scala.html index 0942bd8..4a9e2db 100644 --- a/app/views/index.scala.html +++ b/app/views/index.scala.html @@ -61,7 +61,7 @@
Правила турнира "@deciderHumanName"
-

@rules

+

@rules


diff --git a/build.sbt b/build.sbt index 26476e1..54c65e6 100644 --- a/build.sbt +++ b/build.sbt @@ -4,7 +4,7 @@ version := "1.0-SNAPSHOT" lazy val root = (project in file(".")).enablePlugins(PlayScala) -scalaVersion := "2.12.8" +scalaVersion := "2.12.20" cancelable in Global := true @@ -23,8 +23,9 @@ libraryDependencies += "org.webjars" % "backbonejs" % "1.3.3" libraryDependencies += guice libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.9.2" -libraryDependencies += "com.typesafe.play" %% "play" % "2.8.2" -libraryDependencies += "com.typesafe.play" %% "play-json" % "2.9.1" +// Версии play/play-json берутся из sbt-plugin (2.8.21). +// Раньше здесь были явные версии 2.8.2/2.9.1, из-за чего подтягивался Guice 4.2.3 +// с cglib, который не работает на Java 17+ (InaccessibleObjectException). lazy val akkaVersion = "2.4.18" libraryDependencies += "com.typesafe.akka" %% "akka-testkit" % akkaVersion % Test diff --git a/conf/application.conf b/conf/application.conf index 1dc7ef8..821395c 100644 --- a/conf/application.conf +++ b/conf/application.conf @@ -7,6 +7,13 @@ play.filters.hosts { play.http.secret.key="QCY?tAnfk?aZ?iwrNwnxIlR6CTf:123123Latabg@5241AB`R5W:1uDFN];Ik@n" play.server.http.port = 1337 +admin { + steamApiKey = "" + steamRedirectUrl = "http://localhost:1337/decider/admin/steam/callback" + allowedSteamIds = [] + decidersFile = "conf/deciders.conf" +} + deciders{ classic{ maps = [["2p_battle_marshes"], @@ -42,19 +49,19 @@ deciders{ } montanaz0r{ maps = [["2p_battle_marshes"], + ["2p_blood_river"], ["2p_fallen_city"], - ["2p_fata_morgana"], - ["2p_quests_triumph"], - ["2p_meeting_of_minds"], - ["2p_shrine_of_excellion"], - ["2p_titan_fall"], ["2p_tranquilitys_end"], - ["2p_emerald_river"], + ["2p_shrine_of_excellion"], + ["2p_quests_triumph"], ["2p_outer_reaches"], - ["2p_blood_river"]] - name = "VOX of War tournament" - raceCount = 1 - rules = """There are 11 maps in total, and each player will ban 3 maps. This means that at the end of the draft, 5 maps will remain.""" + ["2p_fata_morgana"], + ["2p_titan_fall"], + ["2p_meeting_of_minds"], + ["2p_deadly_fun_archeology"]] + name = "-" + raceCount = 2 + rules = """There are 11 maps in total. The veto process varies depending on the round: cross-pick continues until 1 map remains for Bo1, 3 maps remain for Bo3, or 5 maps remain for Bo5.""" } mistrzostwa{ maps = [["2p_battle_marshes"], diff --git a/conf/routes b/conf/routes index 4e335a4..76685fc 100644 --- a/conf/routes +++ b/conf/routes @@ -2,11 +2,24 @@ # This file defines all application routes (Higher priority routes first) # ~~~~ -GET /decider/:name controllers.HomeController.index(name) +GET /ws controllers.HomeController.ws -GET /ws controllers.HomeController.ws +# Admin panel +# ВАЖНО: админские маршруты должны идти ДО /decider/:name, +# иначе /decider/admin перехватывается как десайдер с именем "admin". +GET /decider/admin controllers.AdminController.index() +GET /decider/admin/login controllers.AdminController.login() +GET /decider/admin/steam/callback controllers.AdminController.steamCallback() -GET /admin/users controllers.AdminController.viewAllUsers() +# Admin API +GET /decider/admin/maps controllers.AdminController.mapImages() +POST /decider/admin/maps controllers.AdminController.mapImageUpload() +GET /decider/admin/deciders controllers.AdminController.decidersList() +GET /decider/admin/deciders/:key controllers.AdminController.deciderGet(key) +POST /decider/admin/deciders controllers.AdminController.deciderSave() +DELETE /decider/admin/deciders/:key controllers.AdminController.deciderDelete(key) + +GET /decider/:name controllers.HomeController.index(name) # Map static resources from the /public folder to the /assets URL path -GET /assets/*file controllers.Assets.at(path="/public", file) +GET /assets/*file controllers.Assets.at(path="/public", file) diff --git a/project/build.properties b/project/build.properties index c0bab04..abbbce5 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.2.8 +sbt.version=1.9.8 diff --git a/project/plugins.sbt b/project/plugins.sbt index 426577a..690b597 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,4 +1,8 @@ // Use the Play sbt plugin for Play projects -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.0") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.21") addSbtPlugin("com.typesafe.sbt" % "sbt-less" % "1.1.2") + +// Ignore scala-xml binary incompatibility between 1.x (sbt-native-packager, twirl) +// and 2.x (scala-compiler) – they are compatible enough for the build to work +libraryDependencySchemes += "org.scala-lang.modules" %% "scala-xml" % "always"