Skip to content

Commit 302f2a5

Browse files
Merge pull request #16 from Moesif/add-subscriptions-support
add subscriptions support and move from Nose to pytest
2 parents 77e74d5 + e7bfb68 commit 302f2a5

File tree

6 files changed

+322
-13
lines changed

6 files changed

+322
-13
lines changed

README.md

+79-1
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,84 @@ companies = [{
309309
update_company = api_client.update_companies(companies)
310310
```
311311

312+
## Update a Single Subscription
313+
314+
Create or update a subscription profile in Moesif. The metadata field can store any subscription-related information you wish to keep. The `subscription_id`, `company_id`, and `status` fields are all required. This method is a convenient helper that calls the Moesif API library. For details, visit the [Python API Reference](https://www.moesif.com/docs/api?python#update-a-subscription).
315+
316+
```python
317+
from moesifapi.moesif_api_client import *
318+
from moesifapi.models import *
319+
from datetime import datetime, timedelta
320+
321+
api_client = MoesifAPIClient("YOUR_COLLECTOR_APPLICATION_ID").api
322+
323+
# Required fields for a subscription update
324+
subscription = {
325+
'subscription_id': 'sub_3456',
326+
'company_id': '67890',
327+
'current_period_start': datetime.utcnow(),
328+
'current_period_end': datetime.utcnow() + timedelta(days=30),
329+
'status': 'active',
330+
# Optional metadata can be any custom object
331+
'metadata': {
332+
'string_field': 'value_1',
333+
'number_field': 0,
334+
'object_field': {
335+
'field_1': 'value_1',
336+
'field_2': 'value_2'
337+
}
338+
}
339+
}
340+
341+
update_subscription = api_client.update_subscription(subscription)
342+
```
343+
344+
## Update Subscriptions in Batch
345+
346+
Similar to `updateSubscription`, but used to update a list of subscriptions in one batch. The `subscription_id`, `company_id`, and `status` fields are required for each subscription in the list. This method is a convenient helper that calls the Moesif API library. For details, visit the [Python API Reference](https://www.moesif.com/docs/api?python#update-subscriptions-in-batch).
347+
348+
```python
349+
from moesifapi.moesif_api_client import *
350+
from moesifapi.models import *
351+
from datetime import datetime, timedelta
352+
353+
api_client = MoesifAPIClient("YOUR_COLLECTOR_APPLICATION_ID").api
354+
355+
# Required fields for subscription updates in a batch
356+
subscriptions = [{
357+
'subscription_id': 'sub_3456',
358+
'company_id': '67890',
359+
'current_period_start': datetime.utcnow(),
360+
'current_period_end': datetime.utcnow() + timedelta(days=30),
361+
'status': 'active',
362+
# Optional metadata can be any custom object
363+
'metadata': {
364+
'string_field': 'value_1',
365+
'number_field': 0,
366+
'object_field': {
367+
'field_1': 'value_1',
368+
'field_2': 'value_2'
369+
}
370+
}
371+
}, {
372+
'subscription_id': 'sub_34567',
373+
'company_id': '6789',
374+
'current_period_start': datetime.utcnow(),
375+
'current_period_end': datetime.utcnow() + timedelta(days=30),
376+
'status': 'active',
377+
'metadata': {
378+
'string_field': 'value_1',
379+
'number_field': 0,
380+
'object_field': {
381+
'field_1': 'value_1',
382+
'field_2': 'value_2'
383+
}
384+
}
385+
}]
386+
387+
update_subscriptions = api_client.update_subscriptions_batch(subscriptions)
388+
```
389+
312390
## How to test:
313391

314392
You can test the SDK with automatically generated test
@@ -319,7 +397,7 @@ runner. You can run the tests as follows:
319397
2. From terminal/cmd navigate to the root directory of the SDK.
320398
3. Invoke 'pip install -r requirements.txt'
321399
4. Add your own application id to 'test/controllers/controller_test_base'
322-
5. Invoke 'nosetests tests/controllers/test_api_controller.py'
400+
5. Invoke 'pytest tests/controllers/test_api_controller.py'
323401

324402
[ico-built-for]: https://img.shields.io/badge/built%20for-python-blue.svg
325403
[ico-version]: https://img.shields.io/pypi/v/moesifapi.svg

moesifapi/controllers/api_controller.py

+113
Original file line numberDiff line numberDiff line change
@@ -458,3 +458,116 @@ def update_companies_batch(self,
458458

459459
# Global error handling using HTTP status codes.
460460
self.validate_response(_context)
461+
462+
def update_subscription(self,
463+
body):
464+
"""Does a POST request to /v1/subscriptions.
465+
466+
Update a single subscription
467+
468+
Args:
469+
body (SubscriptionModel): TODO: type description here. Example:
470+
471+
Returns:
472+
void: Response from the API. success
473+
474+
Raises:
475+
APIException: When an error occurs while fetching the data from
476+
the remote API. This exception includes the HTTP Response
477+
code, an error message, and the HTTP body that was received in
478+
the request.
479+
480+
"""
481+
482+
# The base uri for api requests
483+
_query_builder = Configuration.BASE_URI
484+
485+
# Prepare query string for API call
486+
_query_builder += '/v1/subscriptions'
487+
488+
# Validate and preprocess url
489+
_query_url = APIHelper.clean_url(_query_builder)
490+
491+
# Prepare headers
492+
_headers = {
493+
'content-type': 'application/json; charset=utf-8',
494+
'X-Moesif-Application-Id': Configuration.application_id,
495+
'User-Agent': Configuration.version,
496+
}
497+
498+
# Prepare the API call.
499+
_request = self.http_client.post(_query_url, headers=_headers, parameters=APIHelper.json_serialize(body))
500+
501+
# Invoke the on before request HttpCallBack if specified
502+
if self.http_call_back is not None:
503+
self.http_call_back.on_before_request(_request)
504+
505+
# Invoke the API call to fetch the response.
506+
_response = self.http_client.execute_as_string(_request)
507+
508+
# Wrap the request and the response in an HttpContext object
509+
_context = HttpContext(_request, _response)
510+
511+
# Invoke the on after response HttpCallBack if specified
512+
if self.http_call_back is not None:
513+
self.http_call_back.on_after_response(_context)
514+
515+
# Global error handling using HTTP status codes.
516+
self.validate_response(_context)
517+
518+
def update_subscriptions_batch(self, body):
519+
"""Does a POST request to /v1/subscriptions/batch.
520+
521+
Update multiple subscriptions in a single batch (batch size must be less
522+
than 250kb)
523+
524+
Args:
525+
body (list of SubscriptionModel): TODO: type description here.
526+
Example:
527+
528+
Returns:
529+
void: Response from the API. success
530+
531+
Raises:
532+
APIException: When an error occurs while fetching the data from
533+
the remote API. This exception includes the HTTP Response
534+
code, an error message, and the HTTP body that was received in
535+
the request.
536+
537+
"""
538+
539+
# The base uri for api requests
540+
_query_builder = Configuration.BASE_URI
541+
542+
# Prepare query string for API call
543+
_query_builder += '/v1/subscriptions/batch'
544+
545+
# Validate and preprocess url
546+
_query_url = APIHelper.clean_url(_query_builder)
547+
548+
# Prepare headers
549+
_headers = {
550+
'content-type': 'application/json; charset=utf-8',
551+
'X-Moesif-Application-Id': Configuration.application_id,
552+
'User-Agent': Configuration.version,
553+
}
554+
555+
# Prepare the API call.
556+
_request = self.http_client.post(_query_url, headers=_headers, parameters=APIHelper.json_serialize(body))
557+
558+
# Invoke the on before request HttpCallBack if specified
559+
if self.http_call_back is not None:
560+
self.http_call_back.on_before_request(_request)
561+
562+
# Invoke the API call to fetch the response.
563+
_response = self.http_client.execute_as_string(_request)
564+
565+
# Wrap the request and the response in an HttpContext object
566+
_context = HttpContext(_request, _response)
567+
568+
# Invoke the on after response HttpCallBack if specified
569+
if self.http_call_back is not None:
570+
self.http_call_back.on_after_response(_context)
571+
572+
# Global error handling using HTTP status codes.
573+
self.validate_response(_context)

moesifapi/models/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
from .user_model import *
66
from .company_model import *
77
from .campaign_model import *
8+
from .subscription_model import *
+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
2+
# -*- coding: utf-8 -*-
3+
4+
"""
5+
moesifapi.models.subscription_model
6+
7+
8+
"""
9+
import dateutil.parser
10+
from .base_model import BaseModel
11+
12+
class SubscriptionModel(BaseModel):
13+
14+
"""Implementation of the 'models.SubscriptionModel' model.
15+
16+
API Request
17+
18+
Attributes:
19+
subscription_id (string): the id of the subscription.
20+
company_id (string): the id of the company.
21+
current_period_start (DateTime): Time when current subscription period started.
22+
mcurrent_period_end (DateTime): Time when current subscription period ends.
23+
status (string): the status of the subscription.
24+
metadata (object): any custom data for the subscription .
25+
26+
"""
27+
28+
def __init__(self,
29+
subscription_id=None,
30+
company_id=None,
31+
current_period_start=None,
32+
current_period_end=None,
33+
status=None,
34+
metadata=None):
35+
"""Constructor for the SubscriptionModel class"""
36+
37+
# Initialize members of the class
38+
self.subscription_id = subscription_id
39+
self.company_id = company_id
40+
self.current_period_start = current_period_start
41+
self.current_period_end = current_period_end
42+
self.status = status
43+
self.metadata = metadata
44+
45+
# Create a mapping from Model property names to API property names
46+
self.names = {
47+
"subscription_id": "subscription_id",
48+
"company_id": "company_id",
49+
"current_period_start": "current_period_start",
50+
"current_period_end": "current_period_end",
51+
"status": "status",
52+
"metadata": "metadata",
53+
}
54+
55+
@classmethod
56+
def from_dictionary(cls,
57+
dictionary):
58+
"""Creates an instance of this model from a dictionary
59+
60+
Args:
61+
dictionary (dictionary): A dictionary representation of the object as
62+
obtained from the deserialization of the server's response. The keys
63+
MUST match property names in the API description.
64+
65+
Returns:
66+
object: An instance of this structure class.
67+
68+
"""
69+
if dictionary is None:
70+
return None
71+
else:
72+
# Extract variables from the dictionary
73+
subscription_id = dictionary.get("subscription_id")
74+
company_id = dictionary.get("company_id")
75+
current_period_start = dateutil.parser.parse(dictionary.get("current_period_start")) if dictionary.get("current_period_start") else None
76+
current_period_end = dateutil.parser.parse(dictionary.get("current_period_end")) if dictionary.get("current_period_end") else None
77+
status = dictionary.get("status")
78+
metadata = dictionary.get("metadata")
79+
80+
# Return an object of this model
81+
return cls(subscription_id,
82+
company_id,
83+
current_period_start,
84+
current_period_end,
85+
status,
86+
metadata)

requirements.txt

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
requests==2.20.0
1+
requests>=2.25.1
2+
urllib3>=1.26.5
23
jsonpickle==0.7.1
3-
python-dateutil==2.5.3
4-
nose==1.3.7
4+
python-dateutil>=2.8.2
55
isodatetimehandler==1.0.2
6+
pytest>=6.0

0 commit comments

Comments
 (0)