diff --git a/db/sql_changeset_schema b/db/sql_changeset_schema index 568e6dd68..4bdd2da9a 100644 --- a/db/sql_changeset_schema +++ b/db/sql_changeset_schema @@ -15,13 +15,14 @@ CREATE SEQUENCE supporters_seq START 1000; ALTER TABLE supporters ADD PRIMARY KEY (userid); --- Main primary key orderid + sku (alternative purchasetoken + sku but there could be multiple orderid for same purchaseToken) -CREATE TABLE supporters_device_sub(sku text, purchasetoken text, prevvalidpurchasetoken text, timestamp timestamp, +CREATE TABLE supporters_device_sub(userid int, sku text, purchasetoken text, prevvalidpurchasetoken text, timestamp timestamp, autorenewing boolean, starttime timestamp, expiretime timestamp, kind text, payload text, orderid text, price int, pricecurrency text, introprice int, intropricecurrency text, introcycles int, introcyclename text, paymentstate int, valid boolean, checktime timestamp); CREATE INDEX supporters_device_sub_starttime_idx on supporters_device_sub(starttime); CREATE INDEX supporters_device_sub_expiretime_idx on supporters_device_sub(expiretime); CREATE INDEX supporters_device_sub_orderid_idx on supporters_device_sub(orderid); +CREATE INDEX supporters_device_sub_userid_idx on supporters_device_sub(userid); ALTER TABLE supporters_device_sub add primary key (sku, orderid); ------ PREMIUM accounts ---- diff --git a/java-tools/OsmAndServer/src/main/java/net/osmand/server/api/repo/DeviceSubscriptionsRepository.java b/java-tools/OsmAndServer/src/main/java/net/osmand/server/api/repo/DeviceSubscriptionsRepository.java index 1bdc92453..e1bac704b 100644 --- a/java-tools/OsmAndServer/src/main/java/net/osmand/server/api/repo/DeviceSubscriptionsRepository.java +++ b/java-tools/OsmAndServer/src/main/java/net/osmand/server/api/repo/DeviceSubscriptionsRepository.java @@ -5,13 +5,7 @@ import java.util.Date; import java.util.List; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.IdClass; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import javax.persistence.*; import org.springframework.data.jpa.repository.JpaRepository; @@ -25,6 +19,8 @@ public interface DeviceSubscriptionsRepository extends JpaRepository findFirst5BySkuOrderByStarttimeDesc(String sku); + List findAllByUserid(int userId); + // PRIMARY KEY is (orderId + SKU) or (purchaseToken + SKU), orderId could be restored from purchaseToken and sku @Entity @Table(name = "supporters_device_sub") @@ -81,6 +77,9 @@ public class SupporterDeviceSubscription implements Serializable { @Column(name = "introcycles") public Integer introcycles ; + + @Column(name = "userid") + public Integer userid; } public class SupporterDeviceSubscriptionPrimaryKey implements Serializable { diff --git a/java-tools/OsmAndServer/src/main/java/net/osmand/server/api/services/UserdataService.java b/java-tools/OsmAndServer/src/main/java/net/osmand/server/api/services/UserdataService.java index fdd446ca5..2b959e5f6 100644 --- a/java-tools/OsmAndServer/src/main/java/net/osmand/server/api/services/UserdataService.java +++ b/java-tools/OsmAndServer/src/main/java/net/osmand/server/api/services/UserdataService.java @@ -26,6 +26,7 @@ import javax.transaction.Transactional; import net.osmand.server.WebSecurityConfiguration; +import net.osmand.server.api.repo.DeviceSubscriptionsRepository; import net.osmand.shared.gpx.GpxFile; import net.osmand.shared.gpx.GpxUtilities; import net.osmand.shared.io.KFile; @@ -102,6 +103,9 @@ public class UserdataService { @Autowired EmailSenderService emailSender; + @Autowired + DeviceSubscriptionsRepository subscriptionsRepository; + @Autowired protected PremiumUserDevicesRepository devicesRepository; @@ -1266,4 +1270,22 @@ private void processGpxFile(PremiumUserDevicesRepository.PremiumUserDevice dev, } } } + + public ResponseEntity addPurchase(String code, PremiumUserDevicesRepository.PremiumUserDevice dev) { + List purchases = subscriptionsRepository.findByOrderId(code); + if (purchases.isEmpty()) { + return ResponseEntity.ok("No purchase found"); + } + if (purchases.size() > 1) { + return ResponseEntity.ok("Multiple purchases found"); + } + DeviceSubscriptionsRepository.SupporterDeviceSubscription purchase = purchases.get(0); + if (purchase.userid != null) { + return ResponseEntity.ok("Purchase already added"); + } + purchase.userid = dev.userid; + subscriptionsRepository.saveAndFlush(purchase); + + return ResponseEntity.ok("Purchase added"); + } } diff --git a/java-tools/OsmAndServer/src/main/java/net/osmand/server/controllers/pub/UserdataController.java b/java-tools/OsmAndServer/src/main/java/net/osmand/server/controllers/pub/UserdataController.java index 4e8808344..ca7838ae0 100644 --- a/java-tools/OsmAndServer/src/main/java/net/osmand/server/controllers/pub/UserdataController.java +++ b/java-tools/OsmAndServer/src/main/java/net/osmand/server/controllers/pub/UserdataController.java @@ -23,6 +23,7 @@ import net.osmand.server.api.services.DownloadIndexesService.ServerCommonFile; import net.osmand.server.controllers.user.MapApiController; +import net.osmand.server.utils.MultiPlatform; import net.osmand.server.utils.exception.OsmAndPublicApiException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -81,6 +82,9 @@ public class UserdataController { @Autowired protected UserSubscriptionService userSubService; + @Autowired + OsmAndMapsService osmAndMapsService; + @Autowired EmailSenderService emailSender; @@ -441,4 +445,16 @@ public ResponseEntity confirmCode(@RequestBody MapApiController.UserPass } return ResponseEntity.badRequest().body("Please enter valid email"); } + + @MultiPlatform + @PostMapping(path = {"/add-purchase"}, produces = "application/json") + public ResponseEntity addPurchase(@RequestBody String code, + @RequestParam(name = "deviceid", required = false) Integer deviceId, + @RequestParam(required = false) String accessToken) { + PremiumUserDevice dev = (deviceId != null && accessToken != null) ? checkToken(deviceId, accessToken) : osmAndMapsService.checkUser(); + if (dev == null) { + return userdataService.tokenNotValidResponse(); + } + return ResponseEntity.ok(gson.toJson(userdataService.addPurchase(code, dev))); + } } diff --git a/java-tools/OsmAndServer/src/main/java/net/osmand/server/controllers/user/MapApiController.java b/java-tools/OsmAndServer/src/main/java/net/osmand/server/controllers/user/MapApiController.java index cc53b0535..6975ba696 100644 --- a/java-tools/OsmAndServer/src/main/java/net/osmand/server/controllers/user/MapApiController.java +++ b/java-tools/OsmAndServer/src/main/java/net/osmand/server/controllers/user/MapApiController.java @@ -592,6 +592,7 @@ public ResponseEntity getAccountInfo() { final String EXPIRE_TIME_KEY = "expireTime"; final String MAX_ACCOUNT_SIZE = "maxAccSize"; final String NICKNAME = "nickname"; + final String PURCHASES = "purchases"; PremiumUserDevice dev = osmAndMapsService.checkUser(); PremiumUsersRepository.PremiumUser pu = usersRepository.findById(dev.userid); @@ -618,6 +619,10 @@ public ResponseEntity getAccountInfo() { info.put(EXPIRE_TIME_KEY, prepareExpireTime.toString()); info.put(MAX_ACCOUNT_SIZE, String.valueOf((MAXIMUM_ACCOUNT_SIZE))); } + List purchases = subscriptionsRepo.findAllByUserid(dev.userid); + info.put(PURCHASES, gson.toJson(purchases.stream() + .map(s -> Map.of(TYPE_SUB, s.sku, START_TIME_KEY, s.starttime, EXPIRE_TIME_KEY, s.expiretime)) + .toList())); } return ResponseEntity.ok(gson.toJson(Collections.singletonMap(INFO_KEY, info))); }