Skip to content

Commit

Permalink
fix(storeapi): Expiration date never found on a subscribed product (#327
Browse files Browse the repository at this point in the history
)

We observed during the attempt to integration testing with the WSL SAAS
backend that we could never find the current subscription expiration
date, even though we could clearly see that the user was subscribed to
the product under test.

It turns out that, when iterating over the product `SKU`s, we had the
broken assumption `IsSubscription() && IsInUserCollection()`.
In this particular example the only SKU under user's possession doesn't
show `IsSubscription` as true.


![image](https://github.com/canonical/ubuntu-pro-for-windows/assets/11138291/5fe710f6-b934-4116-962e-68af5ea1cd72)


Pre iteration loop (product is in user collection)

![image](https://github.com/canonical/ubuntu-pro-for-windows/assets/11138291/a37edeb8-9420-4ae4-a334-e3393dab7097)

First SKU ( is subscription but not owned by the current user)

![image](https://github.com/canonical/ubuntu-pro-for-windows/assets/11138291/6d29ab4a-8d29-4d2a-bb6e-15ff79ccd3ba)

Second SKU (is owned by this user, but it's not a subscription 🙃 )

![image](https://github.com/canonical/ubuntu-pro-for-windows/assets/11138291/58140d4b-a184-4d66-a030-3279f5f36b40)


So with this PR I'm relaxing on checking whether the SKU
`IsSubscription` when querying the expiration date.

Also, this test raised the concern that it might be possible that a user
may hold several SKUs of the same product (most likely one SKU will
still be valid while others will be expired). Thus, I also changed the
iteration to go over all SKUs found and return the greatest expiration
date (the one most towards the future) instead of stopping the iteration
on the first item found in user's collection.
  • Loading branch information
CarlosNihelton authored Oct 11, 2023
2 parents 4b63ebb + e57afb0 commit 589caa0
Showing 1 changed file with 19 additions and 11 deletions.
30 changes: 19 additions & 11 deletions storeapi/base/impl/StoreContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
#include <winrt/Windows.System.h>
#include <winrt/base.h>

#include <algorithm>
#include <format>
#include <functional>
#include <iterator>
#include <ranges>
#include <type_traits>

#include "../Exception.hpp"
Expand All @@ -38,19 +40,25 @@ winrt::hstring sha256(winrt::hstring input);

std::chrono::system_clock::time_point
StoreContext::Product::CurrentExpirationDate() const {
// A single product might have more than one SKU.
for (auto sku : self.Skus()) {
if (sku.IsInUserCollection() && sku.IsSubscription()) {
auto collected = sku.CollectionData();
return winrt::clock::to_sys(collected.EndDate());
}
// A single product might have more than one SKU and not all of them
// (maybe none) show both `IsSubscription` and `IsInUserCollection` properties
// simultaneously true.
auto expDates = self.Skus() |
std::views::filter(&StoreSku::IsInUserCollection) |
std::views::transform([](StoreSku const& s) {
return s.CollectionData().EndDate();
});
auto endWinDate = std::ranges::max_element(expDates);

// Should never be true if called from a product the user is subscribed to.
if (expDates.empty()) {
throw Exception{
ErrorCode::Unsubscribed,
std::format("product ID: {}", winrt::to_string(self.StoreId())),
};
}

// Should be unreachable if called from a product user is subscribed to.
throw Exception{
ErrorCode::Unsubscribed,
std::format("product ID: {}", winrt::to_string(self.StoreId())),
};
return winrt::clock::to_sys(*endWinDate);
}

void StoreContext::Product::PromptUserForPurchase(
Expand Down

0 comments on commit 589caa0

Please sign in to comment.