From 6c02cc88959401b8e1560afea41413c214589be6 Mon Sep 17 00:00:00 2001 From: gsd Date: Sat, 30 Mar 2024 10:25:52 +0300 Subject: [PATCH] promocode v2 --- .../other/ExternalVIPController.java | 1 + .../other/PromoCodeController.java | 93 +++++++++++++++++++ .../java/app/entities/PromoCodeStatus.java | 5 + src/main/java/app/entities/db/PromoCode.java | 65 +++++++++++++ .../app/services/db/PromoCodeService.java | 69 ++++++++++++++ src/main/java/app/utils/SteamIDConverter.java | 1 + 6 files changed, 234 insertions(+) create mode 100644 src/main/java/app/controllers/other/PromoCodeController.java create mode 100644 src/main/java/app/entities/PromoCodeStatus.java create mode 100644 src/main/java/app/entities/db/PromoCode.java create mode 100644 src/main/java/app/services/db/PromoCodeService.java diff --git a/src/main/java/app/controllers/other/ExternalVIPController.java b/src/main/java/app/controllers/other/ExternalVIPController.java index 7553e8b..b77f6ec 100644 --- a/src/main/java/app/controllers/other/ExternalVIPController.java +++ b/src/main/java/app/controllers/other/ExternalVIPController.java @@ -42,6 +42,7 @@ public class ExternalVIPController { prices.add(new VipPrice("1 Неделя", 100, "40 рефов", "site_content/images/vip/VIP_7_DAYS.jpg", "week", true, true, true, 10)); prices.add(new VipPrice("1 День", 35, "10 рефов", "site_content/images/vip/VIP_1_DAY.jpg", "day", true, true, true, 10)); prices.add(new VipPrice("1 День", 0, "бесплатно", "site_content/images/vip/freevip.jpg", "free", true, true, true, 10)); + prices.add(new VipPrice("Промокод", 0, "бесплатно", "site_content/images/vip/freevip.jpg", "promocode", true, true, true, 10)); } @PostMapping diff --git a/src/main/java/app/controllers/other/PromoCodeController.java b/src/main/java/app/controllers/other/PromoCodeController.java new file mode 100644 index 0000000..9a43c7d --- /dev/null +++ b/src/main/java/app/controllers/other/PromoCodeController.java @@ -0,0 +1,93 @@ +package app.controllers.other; + +import app.annotations.enums.AuthMethod; +import app.annotations.enums.CollectStages; +import app.annotations.interfaces.CheckPermitionFlag; +import app.annotations.interfaces.CheckWebAccess; +import app.annotations.interfaces.CollectStatistic; +import app.annotations.interfaces.WaitAfterNext; +import app.entities.PromoCodeStatus; +import app.entities.VipGiveMethod; +import app.entities.db.PromoCode; +import app.entities.other.SteamID; +import app.services.db.PromoCodeService; +import app.services.db.VIPService; +import app.utils.SteamIDConverter; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("api/promocode") +public class PromoCodeController { + private VIPService vipService; + private PromoCodeService promoCodeService; + + @Autowired + PromoCodeController(VIPService vipService, PromoCodeService promoCodeService) { + this.vipService = vipService; + this.promoCodeService = promoCodeService; + } + + @GetMapping + @CheckWebAccess(auth_method = AuthMethod.STEAM64) + @CheckPermitionFlag(flag = "z") + public ResponseEntity> getCodes() { + return new ResponseEntity<>(promoCodeService.getActualPromocodes().stream().collect(Collectors.toMap(PromoCode::getCode, PromoCode::getAction)), HttpStatus.OK); + } + + @PostMapping + @CheckWebAccess(auth_method = AuthMethod.STEAM64) + @CheckPermitionFlag(flag = "z") + @CollectStatistic(stage = CollectStages.COMBINED) + public ResponseEntity generateCode(HttpServletRequest request, + @CookieValue(value = "steam64") String admin_steam64, + @RequestParam(value = "action") String action, + @RequestParam(value = "append") String append) { + return new ResponseEntity<>(promoCodeService + .generatePromoCode(SteamIDConverter.getSteamID(admin_steam64), action, append), HttpStatus.CREATED); + } + + @PutMapping + @CheckWebAccess(auth_method = AuthMethod.STEAM64) + @CollectStatistic(stage = CollectStages.COMBINED) + @WaitAfterNext(order = "promocode") + public ResponseEntity acceptCode(HttpServletRequest request, + @CookieValue(value = "steam64") String steam64, + @RequestParam(value = "code") String code) { + SteamID steamID = SteamIDConverter.getSteamID(steam64); + + int status = promoCodeService.acceptPromoCode(steamID, code); + PromoCode promoCode = promoCodeService.getPromoCode(code); + + if (status > 0) { + String[] action = promoCode.getAction().toLowerCase().split(":"); + if ("vip".equals(action[0])) { + int result = vipService.addVIP(steamID, Integer.parseInt(action[1]), VipGiveMethod.PROMOCODE, code); + if (result == 0) return new ResponseEntity<>(HttpStatus.NO_CONTENT); + else if (result > 0) { + return new ResponseEntity<>(HttpStatus.CREATED); + } else { + return new ResponseEntity<>(HttpStatus.OK); + } + } + return new ResponseEntity<>(HttpStatus.ALREADY_REPORTED); + } else if (status == 0) { + if (promoCode == null) return new ResponseEntity<>(HttpStatus.NOT_FOUND); + if (PromoCodeStatus.DISABLED.equals(promoCode.getStatus())) return new ResponseEntity(HttpStatus.LOCKED); + if (PromoCodeStatus.ACCEPTED.equals(promoCode.getStatus())) return new ResponseEntity( + Map.of("steam", promoCode.getAccept(), "utime", promoCode.getAccepted_timestamp().getTime()/1000), + HttpStatus.GONE + ); + return new ResponseEntity<>(HttpStatus.I_AM_A_TEAPOT); + } else { + return new ResponseEntity(Map.of("cd", status * -1), HttpStatus.CONFLICT); + } + } +} diff --git a/src/main/java/app/entities/PromoCodeStatus.java b/src/main/java/app/entities/PromoCodeStatus.java new file mode 100644 index 0000000..d73efba --- /dev/null +++ b/src/main/java/app/entities/PromoCodeStatus.java @@ -0,0 +1,5 @@ +package app.entities; + +public enum PromoCodeStatus { + CREATED, ACCEPTED, DISABLED +} diff --git a/src/main/java/app/entities/db/PromoCode.java b/src/main/java/app/entities/db/PromoCode.java new file mode 100644 index 0000000..eeeb98c --- /dev/null +++ b/src/main/java/app/entities/db/PromoCode.java @@ -0,0 +1,65 @@ +package app.entities.db; + +import app.entities.PromoCodeStatus; +import app.entities.other.SteamID; +import app.utils.SteamIDConverter; +import com.fasterxml.jackson.annotation.JsonIgnore; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; + +public class PromoCode { + @JsonIgnore + int id; + Timestamp created_timestamp; + String code; + SteamID creator; + SteamID accept; + Timestamp accepted_timestamp; + PromoCodeStatus status; + String action; + + public PromoCode(ResultSet resultSet) throws SQLException { + id = resultSet.getInt("id"); + created_timestamp = resultSet.getTimestamp("created_timestamp"); + code = resultSet.getString("code"); + creator = SteamIDConverter.getSteamID(resultSet.getString("creator_steam64")); + accept = SteamIDConverter.getSteamID(resultSet.getString("accepted_steam64")); + accepted_timestamp = resultSet.getTimestamp("accepted_timestamp"); + status = PromoCodeStatus.values()[resultSet.getInt("status")]; + action = resultSet.getString("action"); + } + + public int getId() { + return id; + } + + public Timestamp getCreated_timestamp() { + return created_timestamp; + } + + public String getCode() { + return code; + } + + public SteamID getCreator() { + return creator; + } + + public SteamID getAccept() { + return accept; + } + + public Timestamp getAccepted_timestamp() { + return accepted_timestamp; + } + + public PromoCodeStatus getStatus() { + return status; + } + + public String getAction() { + return action; + } +} diff --git a/src/main/java/app/services/db/PromoCodeService.java b/src/main/java/app/services/db/PromoCodeService.java new file mode 100644 index 0000000..42256fd --- /dev/null +++ b/src/main/java/app/services/db/PromoCodeService.java @@ -0,0 +1,69 @@ +package app.services.db; + +import app.entities.PromoCodeStatus; +import app.entities.db.PromoCode; +import app.entities.other.SteamID; +import org.apache.commons.lang3.RandomStringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Service; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.List; + +@Service +public class PromoCodeService { + + @Autowired + @Qualifier("jt_rw") + private JdbcTemplate jdbcTemplate; + + private static int cd = 60 * 60 * 24; + + public String generatePromoCode(SteamID steamID, String action, String append) { + String code = generatePromoCode(append); + while (null != getPromoCode(code)) { + code = generatePromoCode(append); + } + return jdbcTemplate.update("INSERT INTO `gived_promocode` (`code`, `creator_steam64`, `action`) VALUES (?, ?, ?)", + code, String.valueOf(steamID.steam64), action) > 0 ? code : ""; + } + + public int acceptPromoCode(SteamID steamID, String code) { + PromoCode promoCode = getPromoCode(code); + Timestamp lastAccept = getLastedAcceptFromUser(steamID); + if (promoCode == null) return 0; + if (!PromoCodeStatus.CREATED.equals(promoCode.getStatus())) return 0; + if (lastAccept != null) { + if (Instant.now().getEpochSecond() - lastAccept.getTime()/1000 < cd) return (int) (lastAccept.getTime() / 1000 - Instant.now().getEpochSecond()); + } + return jdbcTemplate.update("UPDATE `gived_promocode` SET accepted_steam64 = ?, accepted_timestamp = ?, status = ? WHERE id = ?", + String.valueOf(steamID.steam64), Timestamp.from(Instant.now()), PromoCodeStatus.ACCEPTED.ordinal(), promoCode.getId()); + } + + public List getActualPromocodes() { + return jdbcTemplate.query("SELECT * FROM `gived_promocode` WHERE `status` = ?", + new Object[]{PromoCodeStatus.CREATED.ordinal()}, + (rs, n) -> new PromoCode(rs)); + } + + public PromoCode getPromoCode(String code) { + return jdbcTemplate.query("SELECT * FROM `gived_promocode` WHERE `code` LIKE ?", + new Object[]{code}, + (rs, n) -> new PromoCode(rs)).stream().findFirst().orElse(null); + } + + private String generatePromoCode(String append) { + return (RandomStringUtils + .randomAlphabetic(48) + .replaceAll("(.{12})", "$1-") + append).toUpperCase(); + } + + private Timestamp getLastedAcceptFromUser(SteamID steamID) { + return jdbcTemplate.query("SELECT `accepted_timestamp` FROM `gived_promocode` WHERE accepted_steam64 LIKE ? ORDER BY `gived_promocode`.`id` DESC LIMIT 1", + new Object[]{ String.valueOf(steamID.steam64) }, + (rs, n) -> rs.getTimestamp("accepted_timestamp")).stream().findFirst().orElse(null); + } +} diff --git a/src/main/java/app/utils/SteamIDConverter.java b/src/main/java/app/utils/SteamIDConverter.java index 4e6b51a..0ffc210 100644 --- a/src/main/java/app/utils/SteamIDConverter.java +++ b/src/main/java/app/utils/SteamIDConverter.java @@ -23,6 +23,7 @@ public class SteamIDConverter { } public static SteamID getSteamID(String text){ + if (text == null) return null; boolean isSteamID = false; String steam3;