package controllers; import actions.User; import com.avaje.ebean.Ebean; import com.google.common.base.Predicate; import com.google.common.io.Files; import models.Difficulty; import models.Game; import models.Mode; import models.Platform; import models.Player; import models.Score; import models.Ship; import models.Stage; import org.joda.time.DateTime; import play.Logger; import play.data.Form; import play.mvc.Controller; import play.mvc.Http; import play.mvc.Result; import views.html.score_create; import views.html.score_import; import views.html.score_update; import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; import static com.avaje.ebean.Ebean.find; import static com.google.common.collect.Collections2.filter; import static java.lang.Integer.parseInt; import static java.lang.Long.parseLong; import static java.math.RoundingMode.HALF_UP; import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNumeric; import static play.data.Form.form; public class ScoreController extends Controller { public static Result selectGame() { return ok(views.html.select_game.render(Game.findAll())); } public static Result fillForm() { models.Game game = Game.finder.byId(Long.parseLong(request().body().asFormUrlEncoded().get("game")[0])); return ok(score_create.render(game, form(Score.class))); } public static Result fillFormWithGame(Game game) { return ok(score_create.render(game, form(Score.class))); } public static Result importScores(Game game) { return ok(score_import.render(game, form(Score.class))); } public static Result read(models.Score score) { if (score == null) { return notFound(); } return ok(score_update.render(score, form(Score.class))); } public static Result save() throws IOException { if (!User.current().isAuthenticated()) { return unauthorized(); } Form<models.Score> scoreForm = new Form<models.Score>(models.Score.class).bindFromRequest(); Map<String, String> data = scoreForm.data(); Logger.info("Nouveau score envoyé par " + User.current().name + ", " + data.toString()); models.Score score = createScore(data); if (score.value == null) { scoreForm.reject("Veuillez saisir une valeur de score."); return badRequest(views.html.score_create.render(score.game, scoreForm)); } List<Http.MultipartFormData.FilePart> files = request().body().asMultipartFormData().getFiles(); if (!files.isEmpty()) { if (files.get(0).getKey().equals("photo")) { storePhoto(score, files.get(0)); } else { storeInp(score, files.get(0)); } if (files.size() > 1) { storeInp(score, files.get(1)); } } Score bestScore = score.player.getBestScoreFor(score.game, score.mode, score.difficulty); Integer oldRank = null; if (bestScore != null) { oldRank = bestScore.rank; } score.save(); CacheController.getRankingCache().remove(score.game); CacheController.getSignatureCache().remove(score.player); CacheController.getMedalsCache().remove(score.player); score.game.recomputeRankings(); score.refresh(); if (oldRank != null && score.rank != null) { score.progression = oldRank - score.rank; score.update(); } return shmup(score); } private static void storePhoto(Score score, Http.MultipartFormData.FilePart filePart) throws IOException { File file = filePart.getFile(); String filename = filePart.getFilename().replaceAll("[^a-zA-Z0-9.]+", ""); String pathname = "/photos/" + new Date().getTime() + "-" + filename; Files.copy(file, new File(pathname)); score.photo = "http://hiscores.shmup.com" + pathname; } private static void storeInp(Score score, Http.MultipartFormData.FilePart filePart) throws IOException { File file = filePart.getFile(); String filename = filePart.getFilename().replaceAll("[^a-zA-Z0-9.]+", ""); String pathname = "/inp/" + new Date().getTime() + "-" + filename; Files.copy(file, new File(pathname)); score.inp = "http://hiscores.shmup.com" + pathname; } public static Result update() throws IOException { Form<models.Score> scoreForm = new Form<models.Score>(models.Score.class).bindFromRequest(); Map<String, String> data = scoreForm.data(); Logger.info("Mise a jour du score envoyé par " + User.current().name + ", " + data.toString()); models.Score score = Ebean.find(models.Score.class, Long.valueOf(data.get("scoreId"))); if (!score.isPlayedBy(User.current())) { return unauthorized(); } updateScore(score, data); if (score.value == null) { scoreForm.reject("Veuillez saisir une valeur de score."); return badRequest(views.html.score_update.render(score, scoreForm)); } List<Http.MultipartFormData.FilePart> files = request().body().asMultipartFormData().getFiles(); if (!files.isEmpty()) { if (files.get(0).getKey().equals("photo")) { storePhoto(score, files.get(0)); } else { storeInp(score, files.get(0)); } if (files.size() > 1) { storeInp(score, files.get(1)); } } else { score.photo = data.get("oldPhoto"); score.inp = data.get("oldInp"); } score.update(); CacheController.getRankingCache().remove(score.game); CacheController.getSignatureCache().remove(score.player); CacheController.getMedalsCache().remove(score.player); score.game.recomputeRankings(); return redirect("/"); } public static Result shmup(models.Score score) { return ok(views.html.post_to_shmup.render(score)); } private static models.Score createScore(Map<String, String> data) { String login = User.current().name; return createScore(data, login); } private static Score createScore(Map<String, String> data, String login) { Difficulty difficulty = difficulty(data); Stage stage = stage(data); Ship ship = ship(data); Mode mode = mode(data); Platform platform = find(Platform.class, parseLong(data.get("platform"))); Player player = Player.findOrCreatePlayer(login); Game game = find(Game.class, parseLong(data.get("gameId"))); BigDecimal value = value(data); String comment = data.get("comment"); String replay = data.get("replay"); String photo = data.get("photo"); return new Score(game, player, stage, ship, mode, difficulty, comment, platform, value, photo, replay); } private static Stage stage(Map<String, String> data) { String stage = data.get("stage"); if (stage == null) { return null; } return find(Stage.class, parseLong(stage)); } private static void updateScore(models.Score score, Map<String, String> data) { score.stage = stage(data); score.mode = mode(data); score.difficulty = difficulty(data); score.ship = ship(data); score.comment = data.get("comment"); score.platform = find(Platform.class, parseLong(data.get("platform"))); score.value = value(data); score.photo = data.get("photo"); score.replay = data.get("replay"); } private static Difficulty difficulty(Map<String, String> data) { Difficulty difficulty = null; if (data.get("difficulty") != null) { difficulty = find(Difficulty.class, parseLong(data.get("difficulty"))); } return difficulty; } public static BigDecimal value(Map<String, String> data) { String scoreValue = data.get("value"); String minutes = data.get("minutes"); String seconds = data.get("seconds"); String milliseconds = data.get("milliseconds"); if (isBlank(scoreValue) && isBlank(minutes) && isBlank(seconds) && isBlank(milliseconds)) { return null; } if (isNotBlank(scoreValue)) { StringBuilder strValue = new StringBuilder(); for (Character c : scoreValue.toCharArray()) { if (isNumeric(c.toString())) { strValue.append(c); } } return new BigDecimal(strValue.toString()); } else { minutes = minutes.trim().isEmpty() ? "0" : minutes.trim(); seconds = seconds.trim().isEmpty() ? "0" : seconds.trim(); milliseconds = milliseconds.trim().isEmpty() ? "0" : milliseconds.trim(); return BigDecimal.valueOf(new DateTime().withTimeAtStartOfDay().withDate(0, 1, 1). withMinuteOfHour(parseInt(minutes)). withSecondOfMinute(parseInt(seconds)). withMillisOfSecond(parseInt(milliseconds)). getMillis()); } } private static Mode mode(Map<String, String> data) { Mode mode = null; if (data.get("mode") != null) { mode = find(Mode.class, parseLong(data.get("mode"))); } return mode; } private static Ship ship(Map<String, String> data) { Ship ship = null; if (data.get("ship") != null) { ship = find(Ship.class, parseLong(data.get("ship"))); } return ship; } public static Collection<Score> findProgressionOf(final Score score) { List<Score> scores = score.player.allScores; scores = new ArrayList<Score>(filter(scores, new Predicate<Score>() { @Override public boolean apply(@Nullable Score _score) { return score.game.equals(_score.game) && score.mode == _score.mode && score.difficulty == _score.difficulty; } })); if (scores.size() > 1) { for (int i = 1; i < scores.size(); i++) { Score previous = scores.get(i - 1); Score current = scores.get(i); BigDecimal gap = current.value.subtract(previous.value); if (previous.value.equals(BigDecimal.ZERO)) { current.gapWithPreviousScore = 0L; } else { current.gapWithPreviousScore = Math.abs(gap.multiply(BigDecimal.valueOf(100)).divide(previous.value, HALF_UP).longValue()); } } } return scores; } public static Result importScore(Game game) throws IOException { if (!User.current().isAuthenticated()) { return unauthorized(); } Form<models.Score> scoreForm = new Form<models.Score>(models.Score.class).bindFromRequest(); Map<String, String> data = scoreForm.data(); models.Score score = createScore(data, playerName(game, data)); List<Http.MultipartFormData.FilePart> files = request().body().asMultipartFormData().getFiles(); if (!files.isEmpty()) { storePhoto(score, files.get(0)); } score.save(); CacheController.getRankingCache().remove(game); CacheController.getSignatureCache().remove(score.player); CacheController.getMedalsCache().remove(score.player); game.recomputeRankings(); return ok(score_import.render(game, form(Score.class))); } private static String playerName(Game game, Map<String, String> data) { if (game.event == null) { return data.get("player"); } return game.event.name + " - " + data.get("player"); } public static Result delete() { if (!User.current().isAuthenticated()) { return unauthorized(); } Form<models.Score> scoreForm = new Form<models.Score>(models.Score.class).bindFromRequest(); Map<String, String> data = scoreForm.data(); models.Score score = Score.finder.byId(Long.parseLong(data.get("score"))); score.delete(); Game game = score.game; CacheController.getRankingCache().remove(game); CacheController.getSignatureCache().remove(score.player); CacheController.getMedalsCache().remove(score.player); game.recomputeRankings(); return ok(score_import.render(game, form(Score.class))); } }