feat(jwt): enhance JWT token generation with user address check
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 6m36s
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 6m36s
- Updated GenerateJwtTokenService to include IApplicationDbContext for accessing user addresses. - Added logic to check if a user has an address and included this information as a claim in the generated JWT token. - Improved overall token generation process by incorporating additional user data for better context.
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
One-time cleanup: ClubMemberships without a successful UserPackagePurchases row.
|
||||
|
||||
Goal after this script:
|
||||
every non-deleted ClubMembership user has >= 1 successful UPP
|
||||
(TransactionId IS NULL OR Transaction.PaymentStatus = 0 / Success)
|
||||
|
||||
Priority for missing rows:
|
||||
1) ManualPayments Approved + successful Transaction -> reuse same TransactionId
|
||||
PurchaseMethod = Manual (3)
|
||||
2) else ClubMembershipCycles / membership dates -> create synthetic Success Transaction + UPP
|
||||
PurchaseMethod priority:
|
||||
Cycle.PurchaseMethod (if not None)
|
||||
-> ClubMembership.PurchaseMethod (if not None)
|
||||
-> Users.PackagePurchaseMethod (if not None)
|
||||
-> Manual (3) as last resort
|
||||
|
||||
Safe to re-run (skips users who already have a successful UPP).
|
||||
|
||||
Run against CMS database once, then verify Orphans left = 0.
|
||||
*/
|
||||
|
||||
SET NOCOUNT ON;
|
||||
SET XACT_ABORT ON;
|
||||
|
||||
BEGIN TRAN;
|
||||
|
||||
------------------------------------------------------------
|
||||
-- 1) From ManualPayments (reuse existing Success transaction)
|
||||
------------------------------------------------------------
|
||||
;WITH OrphanClubUsers AS (
|
||||
SELECT m.UserId,
|
||||
COALESCE(NULLIF(m.LastPackageId, 0), NULLIF(m.FirstPackageId, 0)) AS PackageIdHint
|
||||
FROM CMS.ClubMemberships m
|
||||
WHERE m.IsDeleted = 0
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM CMS.UserPackagePurchases upp
|
||||
LEFT JOIN CMS.Transactions t ON t.Id = upp.TransactionId AND t.IsDeleted = 0
|
||||
WHERE upp.UserId = m.UserId
|
||||
AND upp.IsDeleted = 0
|
||||
AND (upp.TransactionId IS NULL OR t.PaymentStatus = 0)
|
||||
)
|
||||
),
|
||||
BestManual AS (
|
||||
SELECT mp.UserId,
|
||||
mp.Id AS ManualPaymentId,
|
||||
mp.Amount,
|
||||
mp.TransactionId,
|
||||
COALESCE(mp.ApprovedAt, mp.Created) AS PurchasedAt,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY mp.UserId
|
||||
ORDER BY COALESCE(mp.ApprovedAt, mp.Created) DESC, mp.Id DESC
|
||||
) AS rn
|
||||
FROM CMS.ManualPayments mp
|
||||
INNER JOIN CMS.Transactions t ON t.Id = mp.TransactionId AND t.IsDeleted = 0 AND t.PaymentStatus = 0
|
||||
WHERE mp.IsDeleted = 0
|
||||
AND mp.Status = 1 -- Approved
|
||||
AND mp.TransactionId IS NOT NULL
|
||||
),
|
||||
BasePkg AS (
|
||||
SELECT TOP (1) Id AS PackageId, Price
|
||||
FROM CMS.Packages
|
||||
WHERE IsDeleted = 0 AND IsBasePackage = 1
|
||||
ORDER BY Id
|
||||
)
|
||||
INSERT INTO CMS.UserPackagePurchases
|
||||
(
|
||||
UserId, PackageId, PurchaseMethod, PurchasedAt, Amount,
|
||||
OrderId, TransactionId, Created, CreatedBy, LastModified, LastModifiedBy, IsDeleted
|
||||
)
|
||||
SELECT
|
||||
o.UserId,
|
||||
COALESCE(o.PackageIdHint, b.PackageId),
|
||||
3, -- Manual
|
||||
bm.PurchasedAt,
|
||||
bm.Amount,
|
||||
NULL,
|
||||
bm.TransactionId,
|
||||
SYSUTCDATETIME(),
|
||||
NULL,
|
||||
SYSUTCDATETIME(),
|
||||
NULL,
|
||||
0
|
||||
FROM OrphanClubUsers o
|
||||
INNER JOIN BestManual bm ON bm.UserId = o.UserId AND bm.rn = 1
|
||||
CROSS JOIN BasePkg b
|
||||
WHERE COALESCE(o.PackageIdHint, b.PackageId) IS NOT NULL;
|
||||
|
||||
DECLARE @FromManual INT = @@ROWCOUNT;
|
||||
PRINT CONCAT('Inserted from ManualPayments: ', @FromManual);
|
||||
|
||||
------------------------------------------------------------
|
||||
-- 2) Remaining orphans from Cycle / membership dates
|
||||
------------------------------------------------------------
|
||||
;WITH OrphanClubUsers AS (
|
||||
SELECT
|
||||
m.UserId,
|
||||
m.PurchaseMethod,
|
||||
u.PackagePurchaseMethod AS UserPurchaseMethod,
|
||||
COALESCE(NULLIF(m.LastPackageId, 0), NULLIF(m.FirstPackageId, 0)) AS MembPackageId,
|
||||
COALESCE(m.FirstActivationDate, m.LastActivationDate, m.ActivatedAt, m.Created) AS MembPurchasedAt
|
||||
FROM CMS.ClubMemberships m
|
||||
INNER JOIN CMS.Users u ON u.Id = m.UserId AND u.IsDeleted = 0
|
||||
WHERE m.IsDeleted = 0
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM CMS.UserPackagePurchases upp
|
||||
LEFT JOIN CMS.Transactions t ON t.Id = upp.TransactionId AND t.IsDeleted = 0
|
||||
WHERE upp.UserId = m.UserId
|
||||
AND upp.IsDeleted = 0
|
||||
AND (upp.TransactionId IS NULL OR t.PaymentStatus = 0)
|
||||
)
|
||||
),
|
||||
BestCycle AS (
|
||||
SELECT
|
||||
c.UserId,
|
||||
c.PackageId,
|
||||
c.PackageAmount,
|
||||
c.PurchaseMethod,
|
||||
c.PackagePurchasedAt,
|
||||
ROW_NUMBER() OVER (PARTITION BY c.UserId ORDER BY c.CycleNumber ASC, c.Id ASC) AS rn
|
||||
FROM CMS.ClubMembershipCycles c
|
||||
WHERE c.IsDeleted = 0
|
||||
),
|
||||
BasePkg AS (
|
||||
SELECT TOP (1) Id AS PackageId, Price
|
||||
FROM CMS.Packages
|
||||
WHERE IsDeleted = 0 AND IsBasePackage = 1
|
||||
ORDER BY Id
|
||||
),
|
||||
ToInsert AS (
|
||||
SELECT
|
||||
o.UserId,
|
||||
COALESCE(NULLIF(bc.PackageId, 0), o.MembPackageId, b.PackageId) AS PackageId,
|
||||
CASE
|
||||
WHEN bc.PurchaseMethod IS NOT NULL AND bc.PurchaseMethod <> 0 THEN bc.PurchaseMethod
|
||||
WHEN o.PurchaseMethod IS NOT NULL AND o.PurchaseMethod <> 0 THEN o.PurchaseMethod
|
||||
WHEN o.UserPurchaseMethod IS NOT NULL AND o.UserPurchaseMethod <> 0 THEN o.UserPurchaseMethod
|
||||
ELSE 3 -- Manual (last resort)
|
||||
END AS PurchaseMethod,
|
||||
COALESCE(bc.PackagePurchasedAt, o.MembPurchasedAt, SYSUTCDATETIME()) AS PurchasedAt,
|
||||
CASE
|
||||
WHEN bc.PackageAmount IS NOT NULL AND bc.PackageAmount > 0 THEN bc.PackageAmount
|
||||
ELSE COALESCE(p.Price, b.Price, 0)
|
||||
END AS Amount
|
||||
FROM OrphanClubUsers o
|
||||
LEFT JOIN BestCycle bc ON bc.UserId = o.UserId AND bc.rn = 1
|
||||
CROSS JOIN BasePkg b
|
||||
LEFT JOIN CMS.Packages p ON p.Id = COALESCE(NULLIF(bc.PackageId, 0), o.MembPackageId, b.PackageId) AND p.IsDeleted = 0
|
||||
)
|
||||
SELECT *
|
||||
INTO #BackfillCandidates
|
||||
FROM ToInsert
|
||||
WHERE PackageId IS NOT NULL AND Amount > 0;
|
||||
|
||||
DECLARE @Remaining INT = (SELECT COUNT(*) FROM #BackfillCandidates);
|
||||
PRINT CONCAT('Remaining orphans to synthetic backfill: ', @Remaining);
|
||||
|
||||
DECLARE @UserId BIGINT, @PackageId BIGINT, @PurchaseMethod INT, @PurchasedAt DATETIME2, @Amount BIGINT;
|
||||
DECLARE @TxId BIGINT;
|
||||
|
||||
DECLARE cur CURSOR LOCAL FAST_FORWARD FOR
|
||||
SELECT UserId, PackageId, PurchaseMethod, PurchasedAt, Amount
|
||||
FROM #BackfillCandidates;
|
||||
|
||||
OPEN cur;
|
||||
FETCH NEXT FROM cur INTO @UserId, @PackageId, @PurchaseMethod, @PurchasedAt, @Amount;
|
||||
|
||||
DECLARE @Synthetic INT = 0;
|
||||
|
||||
WHILE @@FETCH_STATUS = 0
|
||||
BEGIN
|
||||
INSERT INTO CMS.Transactions
|
||||
(
|
||||
Amount, Description, PaymentStatus, PaymentDate, RefId, Type,
|
||||
Created, CreatedBy, LastModified, LastModifiedBy, IsDeleted
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@Amount,
|
||||
CONCAT(N'بکفیل عضویت باشگاه — UserId ', @UserId),
|
||||
0, -- Success
|
||||
@PurchasedAt,
|
||||
CONCAT('UPP-BACKFILL-', @UserId, '-', @PackageId),
|
||||
2, -- DepositExternal1
|
||||
SYSUTCDATETIME(), NULL, SYSUTCDATETIME(), NULL, 0
|
||||
);
|
||||
|
||||
SET @TxId = SCOPE_IDENTITY();
|
||||
|
||||
INSERT INTO CMS.UserPackagePurchases
|
||||
(
|
||||
UserId, PackageId, PurchaseMethod, PurchasedAt, Amount,
|
||||
OrderId, TransactionId, Created, CreatedBy, LastModified, LastModifiedBy, IsDeleted
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@UserId, @PackageId, @PurchaseMethod, @PurchasedAt, @Amount,
|
||||
NULL, @TxId, SYSUTCDATETIME(), NULL, SYSUTCDATETIME(), NULL, 0
|
||||
);
|
||||
|
||||
SET @Synthetic += 1;
|
||||
FETCH NEXT FROM cur INTO @UserId, @PackageId, @PurchaseMethod, @PurchasedAt, @Amount;
|
||||
END
|
||||
|
||||
CLOSE cur;
|
||||
DEALLOCATE cur;
|
||||
|
||||
PRINT CONCAT('Inserted synthetic UPP rows: ', @Synthetic);
|
||||
|
||||
DROP TABLE #BackfillCandidates;
|
||||
|
||||
------------------------------------------------------------
|
||||
-- Verify invariant
|
||||
------------------------------------------------------------
|
||||
DECLARE @ClubCount INT =
|
||||
(
|
||||
SELECT COUNT(*) FROM CMS.ClubMemberships WHERE IsDeleted = 0
|
||||
);
|
||||
|
||||
DECLARE @OrphansLeft INT =
|
||||
(
|
||||
SELECT COUNT(*)
|
||||
FROM CMS.ClubMemberships m
|
||||
WHERE m.IsDeleted = 0
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM CMS.UserPackagePurchases upp
|
||||
LEFT JOIN CMS.Transactions t ON t.Id = upp.TransactionId AND t.IsDeleted = 0
|
||||
WHERE upp.UserId = m.UserId
|
||||
AND upp.IsDeleted = 0
|
||||
AND (upp.TransactionId IS NULL OR t.PaymentStatus = 0)
|
||||
)
|
||||
);
|
||||
|
||||
DECLARE @SuccessfulBuyers INT =
|
||||
(
|
||||
SELECT COUNT(DISTINCT upp.UserId)
|
||||
FROM CMS.UserPackagePurchases upp
|
||||
LEFT JOIN CMS.Transactions t ON t.Id = upp.TransactionId AND t.IsDeleted = 0
|
||||
WHERE upp.IsDeleted = 0
|
||||
AND (upp.TransactionId IS NULL OR t.PaymentStatus = 0)
|
||||
);
|
||||
|
||||
PRINT CONCAT('ClubMemberships: ', @ClubCount);
|
||||
PRINT CONCAT('Distinct successful UPP users: ', @SuccessfulBuyers);
|
||||
PRINT CONCAT('Orphans left (must be 0): ', @OrphansLeft);
|
||||
|
||||
IF @OrphansLeft > 0
|
||||
BEGIN
|
||||
ROLLBACK;
|
||||
THROW 50001, 'Backfill incomplete — orphans remain; transaction rolled back.', 1;
|
||||
END
|
||||
|
||||
COMMIT;
|
||||
PRINT 'Backfill committed successfully.';
|
||||
Reference in New Issue
Block a user