mirror of
https://github.com/quay/quay.git
synced 2025-07-28 20:22:05 +03:00
marketplace: add expiration check to org subscription operations (PROJQUAY-6716) (#2696)
add expiration check to org subscription operations
This commit is contained in:
@ -3,6 +3,7 @@ Billing information, subscriptions, and plan information.
|
|||||||
"""
|
"""
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import stripe
|
import stripe
|
||||||
@ -55,7 +56,15 @@ def check_internal_api_for_subscription(namespace_user):
|
|||||||
for subscription in org_subscriptions:
|
for subscription in org_subscriptions:
|
||||||
quantity = 1 if subscription.get("quantity") is None else subscription["quantity"]
|
quantity = 1 if subscription.get("quantity") is None else subscription["quantity"]
|
||||||
subscription_id = subscription["subscription_id"]
|
subscription_id = subscription["subscription_id"]
|
||||||
sku = marketplace_subscriptions.get_subscription_sku(subscription_id)
|
subscription_details = marketplace_subscriptions.get_subscription_details(
|
||||||
|
subscription_id
|
||||||
|
)
|
||||||
|
sku = subscription_details["sku"]
|
||||||
|
expiration = subscription_details["expiration_date"]
|
||||||
|
now_ms = time.time() * 1000
|
||||||
|
if expiration < now_ms:
|
||||||
|
organization_skus.remove_subscription_from_org(namespace_user.id, subscription_id)
|
||||||
|
continue
|
||||||
for x in range(quantity):
|
for x in range(quantity):
|
||||||
plans.append(get_plan_using_rh_sku(sku))
|
plans.append(get_plan_using_rh_sku(sku))
|
||||||
pass
|
pass
|
||||||
@ -957,11 +966,17 @@ class OrganizationRhSku(ApiResource):
|
|||||||
if query:
|
if query:
|
||||||
subscriptions = list(query.dicts())
|
subscriptions = list(query.dicts())
|
||||||
for subscription in subscriptions:
|
for subscription in subscriptions:
|
||||||
subscription_sku = marketplace_subscriptions.get_subscription_sku(
|
subscription_details = marketplace_subscriptions.get_subscription_details(
|
||||||
subscription["subscription_id"]
|
subscription["subscription_id"]
|
||||||
)
|
)
|
||||||
subscription["sku"] = subscription_sku
|
now_ms = time.time() * 1000
|
||||||
subscription["metadata"] = get_plan_using_rh_sku(subscription_sku)
|
if subscription_details["expiration_date"] < now_ms:
|
||||||
|
model.organization_skus.remove_subscription_from_org(
|
||||||
|
organization.id, subscription["subscription_id"]
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
subscription["sku"] = subscription_details["sku"]
|
||||||
|
subscription["metadata"] = get_plan_using_rh_sku(subscription_details["sku"])
|
||||||
if subscription.get("quantity") is None:
|
if subscription.get("quantity") is None:
|
||||||
subscription["quantity"] = 1
|
subscription["quantity"] = 1
|
||||||
return subscriptions
|
return subscriptions
|
||||||
|
@ -3,6 +3,7 @@ Manage organizations, members and OAuth applications.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
import recaptcha2
|
import recaptcha2
|
||||||
from flask import request
|
from flask import request
|
||||||
@ -378,11 +379,17 @@ class OrgPrivateRepositories(ApiResource):
|
|||||||
if features.RH_MARKETPLACE:
|
if features.RH_MARKETPLACE:
|
||||||
query = organization_skus.get_org_subscriptions(organization.id)
|
query = organization_skus.get_org_subscriptions(organization.id)
|
||||||
rh_subscriptions = list(query.dicts()) if query is not None else []
|
rh_subscriptions = list(query.dicts()) if query is not None else []
|
||||||
|
now_ms = time.time() * 1000
|
||||||
for subscription in rh_subscriptions:
|
for subscription in rh_subscriptions:
|
||||||
subscription_sku = marketplace_subscriptions.get_subscription_sku(
|
subscription_details = marketplace_subscriptions.get_subscription_details(
|
||||||
subscription["subscription_id"]
|
subscription["subscription_id"]
|
||||||
)
|
)
|
||||||
equivalent_stripe_plan = get_plan_using_rh_sku(subscription_sku)
|
if subscription_details["expiration_date"] < now_ms:
|
||||||
|
organization_skus.remove_subscription_from_org(
|
||||||
|
organization.id, subscription["subscription_id"]
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
equivalent_stripe_plan = get_plan_using_rh_sku(subscription_details["sku"])
|
||||||
if equivalent_stripe_plan:
|
if equivalent_stripe_plan:
|
||||||
if subscription.get("quantity") is None:
|
if subscription.get("quantity") is None:
|
||||||
quantity = 1
|
quantity = 1
|
||||||
|
@ -5183,6 +5183,14 @@ class TestOrganizationRhSku(ApiTestCase):
|
|||||||
plans = check_internal_api_for_subscription(org)
|
plans = check_internal_api_for_subscription(org)
|
||||||
assert len(plans) == 1
|
assert len(plans) == 1
|
||||||
|
|
||||||
|
def test_expired_attachment(self):
|
||||||
|
self.login(SUBSCRIPTION_USER)
|
||||||
|
user = model.user.get_user(SUBSCRIPTION_USER)
|
||||||
|
org = model.organization.get_organization(SUBSCRIPTION_ORG)
|
||||||
|
model.organization_skus.bind_subscription_to_org(80808080, org.id, user.id, 1)
|
||||||
|
json = self.getJsonResponse(OrgPrivateRepositories, params=dict(orgname=SUBSCRIPTION_ORG))
|
||||||
|
self.assertEqual(json["privateAllowed"], False)
|
||||||
|
|
||||||
|
|
||||||
class TestUserSku(ApiTestCase):
|
class TestUserSku(ApiTestCase):
|
||||||
def test_get_user_skus(self):
|
def test_get_user_skus(self):
|
||||||
|
@ -191,9 +191,9 @@ class RedHatSubscriptionApi(object):
|
|||||||
|
|
||||||
return r.status_code
|
return r.status_code
|
||||||
|
|
||||||
def get_subscription_sku(self, subscription_id):
|
def get_subscription_details(self, subscription_id):
|
||||||
"""
|
"""
|
||||||
Return the sku for a specific subscription
|
Return the sku and expiration date for a specific subscription
|
||||||
"""
|
"""
|
||||||
request_url = f"{self.marketplace_endpoint}/subscription/v5/products/subscription_id={subscription_id}"
|
request_url = f"{self.marketplace_endpoint}/subscription/v5/products/subscription_id={subscription_id}"
|
||||||
request_headers = {"Content-Type": "application/json"}
|
request_headers = {"Content-Type": "application/json"}
|
||||||
@ -210,8 +210,9 @@ class RedHatSubscriptionApi(object):
|
|||||||
|
|
||||||
info = json.loads(r.content)
|
info = json.loads(r.content)
|
||||||
|
|
||||||
SubscriptionSKU = info[0]["sku"]
|
subscription_sku = info[0]["sku"]
|
||||||
return SubscriptionSKU
|
expiration_date = info[1]["activeEndDate"]
|
||||||
|
return {"sku": subscription_sku, "expiration_date": expiration_date}
|
||||||
except requests.exceptions.SSLError:
|
except requests.exceptions.SSLError:
|
||||||
raise requests.exceptions.SSLError
|
raise requests.exceptions.SSLError
|
||||||
except requests.exceptions.ReadTimeout:
|
except requests.exceptions.ReadTimeout:
|
||||||
@ -267,7 +268,7 @@ TEST_USER = {
|
|||||||
"subscriptionNumber": "12399889",
|
"subscriptionNumber": "12399889",
|
||||||
"quantity": 2,
|
"quantity": 2,
|
||||||
"effectiveStartDate": 1707368400000,
|
"effectiveStartDate": 1707368400000,
|
||||||
"effectiveEndDate": 3813177600,
|
"effectiveEndDate": 3813177600000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 11223344,
|
"id": 11223344,
|
||||||
@ -282,7 +283,7 @@ TEST_USER = {
|
|||||||
"subscriptionNumber": "12399889",
|
"subscriptionNumber": "12399889",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
"effectiveStartDate": 1707368400000,
|
"effectiveStartDate": 1707368400000,
|
||||||
"effectiveEndDate": 3813177600,
|
"effectiveEndDate": 3813177600000,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@ -329,10 +330,12 @@ class FakeSubscriptionApi(RedHatSubscriptionApi):
|
|||||||
def extend_subscription(self, subscription_id, end_date):
|
def extend_subscription(self, subscription_id, end_date):
|
||||||
self.subscription_extended = True
|
self.subscription_extended = True
|
||||||
|
|
||||||
def get_subscription_sku(self, subscription_id):
|
def get_subscription_details(self, subscription_id):
|
||||||
valid_ids = [subscription["id"] for subscription in TEST_USER["subscriptions"]]
|
valid_ids = [subscription["id"] for subscription in TEST_USER["subscriptions"]]
|
||||||
if subscription_id in valid_ids:
|
if subscription_id in valid_ids:
|
||||||
return "MW02701"
|
return {"sku": "MW02701", "expiration_date": 3813177600000}
|
||||||
|
elif subscription_id == 80808080:
|
||||||
|
return {"sku": "MW02701", "expiration_date": 1645544830000}
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -140,6 +140,60 @@ mocked_subscription_response = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
mocked_expired_sub = [
|
||||||
|
{
|
||||||
|
"id": 41619474,
|
||||||
|
"masterEndSystemName": "SUBSCRIPTION",
|
||||||
|
"createdEndSystemName": "SUBSCRIPTION",
|
||||||
|
"createdByUserName": None,
|
||||||
|
"createdDate": 1708616554000,
|
||||||
|
"lastUpdateEndSystemName": "SUBSCRIPTION",
|
||||||
|
"lastUpdateUserName": None,
|
||||||
|
"lastUpdateDate": 1708616554000,
|
||||||
|
"externalCreatedDate": None,
|
||||||
|
"externalLastUpdateDate": None,
|
||||||
|
"activeStartDate": None,
|
||||||
|
"activeEndDate": None,
|
||||||
|
"inactiveDate": None,
|
||||||
|
"signedDate": None,
|
||||||
|
"terminatedDate": None,
|
||||||
|
"renewedDate": None,
|
||||||
|
"parentSubscriptionProductId": None,
|
||||||
|
"externalOrderSystemName": "SUBSCRIPTION",
|
||||||
|
"externalOrderNumber": None,
|
||||||
|
"status": None,
|
||||||
|
"sku": "MW02701",
|
||||||
|
"childrenIds": [41619475],
|
||||||
|
"serviceable": False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 41619475,
|
||||||
|
"masterEndSystemName": "SUBSCRIPTION",
|
||||||
|
"createdEndSystemName": "SUBSCRIPTION",
|
||||||
|
"createdByUserName": None,
|
||||||
|
"createdDate": 1645544830000,
|
||||||
|
"lastUpdateEndSystemName": "SUBSCRIPTION",
|
||||||
|
"lastUpdateUserName": None,
|
||||||
|
"lastUpdateDate": 1645544830000,
|
||||||
|
"externalCreatedDate": None,
|
||||||
|
"externalLastUpdateDate": None,
|
||||||
|
"activeStartDate": 1645544830000,
|
||||||
|
"activeEndDate": 1645544830000,
|
||||||
|
"inactiveDate": None,
|
||||||
|
"signedDate": None,
|
||||||
|
"terminatedDate": None,
|
||||||
|
"renewedDate": None,
|
||||||
|
"parentSubscriptionProductId": 41619474,
|
||||||
|
"externalOrderSystemName": "SUBSCRIPTION",
|
||||||
|
"externalOrderNumber": None,
|
||||||
|
"status": "active",
|
||||||
|
"oracleInventoryOrgId": None,
|
||||||
|
"sku": "SVCMW02701",
|
||||||
|
"childrenIds": None,
|
||||||
|
"serviceable": True,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class TestMarketplace(unittest.TestCase):
|
class TestMarketplace(unittest.TestCase):
|
||||||
@patch("requests.request")
|
@patch("requests.request")
|
||||||
@ -152,8 +206,8 @@ class TestMarketplace(unittest.TestCase):
|
|||||||
assert customer_id is None
|
assert customer_id is None
|
||||||
subscription_response = subscription_api.lookup_subscription(123456, "sku")
|
subscription_response = subscription_api.lookup_subscription(123456, "sku")
|
||||||
assert subscription_response is None
|
assert subscription_response is None
|
||||||
subscription_sku = subscription_api.get_subscription_sku(123456)
|
subscription_details = subscription_api.get_subscription_details(123456)
|
||||||
assert subscription_sku is None
|
assert subscription_details is None
|
||||||
extended_subscription = subscription_api.extend_subscription(12345, 102623)
|
extended_subscription = subscription_api.extend_subscription(12345, 102623)
|
||||||
assert extended_subscription is None
|
assert extended_subscription is None
|
||||||
create_subscription_response = subscription_api.create_entitlement(12345, "sku")
|
create_subscription_response = subscription_api.create_entitlement(12345, "sku")
|
||||||
@ -178,3 +232,12 @@ class TestMarketplace(unittest.TestCase):
|
|||||||
|
|
||||||
subscriptions = subscription_api.lookup_subscription(12345, "some_sku")
|
subscriptions = subscription_api.lookup_subscription(12345, "some_sku")
|
||||||
assert len(subscriptions) == 2
|
assert len(subscriptions) == 2
|
||||||
|
|
||||||
|
@patch("requests.request")
|
||||||
|
def test_subscription_details(self, requests_mock):
|
||||||
|
subscription_api = RedHatSubscriptionApi(app_config)
|
||||||
|
requests_mock.return_value.content = json.dumps(mocked_expired_sub)
|
||||||
|
|
||||||
|
subscription_details = subscription_api.get_subscription_details(12345)
|
||||||
|
assert subscription_details["sku"] == "MW02701"
|
||||||
|
assert subscription_details["expiration_date"] == 1645544830000
|
||||||
|
Reference in New Issue
Block a user