Merge branch 'master' into doc-updates

dependabot/pip/requests-2.20.0
Maria Bermudez 7 years ago committed by GitHub
commit 922906ee80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 68
      README.md
  2. 25
      cnam_demo.py
  3. 27
      e911_demo.py
  4. 46
      flowroutenumbersandmessaging/controllers/e911s_controller.py
  5. 24
      number_route_message_demo.py

@ -54,10 +54,6 @@ The Flowroute Python Library v3 provides methods for interacting with [Numbers v
* [unassociate_cnam](#unassociate_cnamnumber_id) * [unassociate_cnam](#unassociate_cnamnumber_id)
* [remove_cnam](#remove_cnamcnam_id) * [remove_cnam](#remove_cnamcnam_id)
* [Messaging](#messaging)
* [send_a_message](#send_a_messagemessage_body)
* [look_up_a_set_of_messagesstart_date](#look_up_a_set_of_messagesstart_date)
* [look_up_a_message_detail_record](#look_up_a_message_detail_recordmessage_id)
* [Errors](#errors) * [Errors](#errors)
* [Testing](#testing) * [Testing](#testing)
@ -902,7 +898,7 @@ All of the E911 address management methods are encapsulated in `e911_demo.py`.
#### list\_e911s() #### list\_e911s()
The method accepts `limit`, `offset`, and `state` as parameters which you can learn more about in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/list-account-e911-addresses/). The method accepts `limit`, `offset`, and `state` as parameters which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/list-account-e911-addresses/).
##### Example Request ##### Example Request
```python ```python
@ -951,9 +947,9 @@ On success, the HTTP status code in the response header is `200 OK` and the resp
'self': 'https://api.flowroute.com/v2/e911s?limit=2&offset=0'}} 'self': 'https://api.flowroute.com/v2/e911s?limit=2&offset=0'}}
``` ```
#### get\_e911(e911_id) #### get\_e911(e911\_id)
The method accepts an `e911_id` as a path parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/list-e911-record-details/). The method accepts an `e911_id` as a path parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/list-e911-record-details/).
##### Example Request ##### Example Request
```python ```python
@ -975,20 +971,28 @@ On success, the HTTP status code in the response header is `200 OK` and the resp
``` ```
--Get Details for a specific E911 Record --Get Details for a specific E911 Record
{'data': {'attributes': {'address_type': 'L', {
'address_type_number': '12', "data": {
'city': 'Seattle', "attributes": {
'country': 'USA', "address_type": "Suite",
'first_name': 'Maria', "address_type_number": "333",
'label': 'Example E911', "city": "Seattle",
'last_name': 'Bermudez', "country": "US",
'state': 'WA', "first_name": "Albus",
'street_name': '20th Ave SW', "label": "Office Space III",
'street_number': '7742', "last_name": "Rasputin, Jr.",
'zip': '98106'}, "state": "WA",
'id': '20930', "street_name": "Main St",
'links': {'self': 'https://api.flowroute.com/v2/e911s/20930'}, "street_number": "666",
'type': 'e911'}} "zip": "98101"
},
"id": "21845",
"links": {
"self": "https://api.flowroute.com/v2/e911s/21845"
},
"type": "e911"
}
}
``` ```
#### validate_address(e911_attributes) #### validate_address(e911_attributes)
@ -1068,7 +1072,7 @@ On success, the HTTP status code in the response header is `201 Created` and the
``` ```
#### update_address(e911_id, e911_attributes) #### update_address(e911_id, e911_attributes)
The method accepts an E911 record id and the different attributes of an E911 address as parameters: `label`, `first_name`, `last_name`, `street_name`, `street_number`, `city`, `state`, `country`, and `zipcode`. Learn more about the different E911 attributes that you can update in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/update-and-validate-existing-e911-address/). In the following example, we will retrieve the record ID of our newly created E911 address and assign it to a variable, `record_id`. We then update the `last_name` of our selected E911 address to "Wiley". The method accepts an E911 record id and the different attributes of an E911 address as parameters: `label`, `first_name`, `last_name`, `street_name`, `street_number`, optional `address_type` and `address_type_number`, `city`, `state`, `country`, and `zipcode`. Learn more about the different E911 attributes that you can update in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/update-and-validate-existing-e911-address/). In the following example, we will retrieve the record ID of our newly created E911 address and assign it to a variable, `record_id`. We then update the `last_name` of our selected E911 address to "Wiley".
##### Example Request ##### Example Request
``` ```
@ -1105,7 +1109,7 @@ On success, the HTTP status code in the response header is `200 OK` and the resp
``` ```
#### associate(e911_id, number_id) #### associate(e911_id, number_id)
The method accepts an E911 record id and a phone number as parameters which you can learn more about in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/assign-valid-e911-address-to-phone-number/). In the following example, we call the [list_account_phone_numbers](#list_account_phone_numbers) covered under Number Management and [list_e911s](#list_e911s), extract the values of the first items in the returned JSON arrays into variables `e911_id` and `did` then make the association between them. The method accepts an E911 record id and a phone number as parameters which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/assign-valid-e911-address-to-phone-number/). In the following example, we call the [list_account_phone_numbers](#list_account_phone_numbers) covered under Number Management and [list_e911s](#list_e911s), extract the values of the first items in the returned JSON arrays into variables `e911_id` and `did` then make the association between them.
##### Example Request ##### Example Request
``` ```
@ -1137,7 +1141,7 @@ On success, the HTTP status code in the response header is `204 No Content` whic
#### list_dids_for_e911(e911_id) #### list_dids_for_e911(e911_id)
The method accepts an E911 record id as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/list-phone-numbers-associated-with-e911-record/). In the following example, we retrieve the list of phone numbers associated with our previously assigned `e911_id`. The method accepts an E911 record id as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/list-phone-numbers-associated-with-e911-record/). In the following example, we retrieve the list of phone numbers associated with our previously assigned `e911_id`.
##### Example Request ##### Example Request
``` ```
@ -1171,7 +1175,7 @@ On success, the HTTP status code in the response header is `200 OK` and the resp
#### disconnect(number_id) #### disconnect(number_id)
The method accepts a phone number as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/deactivate-e911-service-for-phone-number/). In the following example, we deactivate the E911 service for our previously assigned `did`. The method accepts a phone number as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/deactivate-e911-service-for-phone-number/). In the following example, we deactivate the E911 service for our previously assigned `did`.
##### Example Request ##### Example Request
``` ```
@ -1193,7 +1197,7 @@ On success, the HTTP status code in the response header is `204 No Content` whic
``` ```
#### delete_address(e911_id) #### delete_address(e911_id)
The method accepts an E911 record ID as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/remove-e911-address-from-account/). Note that all phone number associations must be removed first before you are able to delete the specified `e911_id`. In the following example, we will attempt to delete the previously assigned `e911_id`. The method accepts an E911 record ID as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/remove-e911-address-from-account/). Note that all phone number associations must be removed first before you are able to delete the specified `e911_id`. In the following example, we will attempt to delete the previously assigned `e911_id`.
##### Example Request ##### Example Request
``` ```
@ -1224,7 +1228,7 @@ All of the CNAM record management methods are encapsulated in `cnam_demo.py`.
#### list\_cnams() #### list\_cnams()
The method accepts `limit`, `offset`, and `is_approved` as parameters which you can learn more about in the [API reference](https://developer.flowroute.com/api/cnams/v2.0/list-account-cnam-records/). The method accepts `limit`, `offset`, and `is_approved` as parameters which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/list-account-cnam-records/).
##### Example Request ##### Example Request
```python ```python
@ -1303,7 +1307,7 @@ On success, the HTTP status code in the response header is `200 OK` and the resp
``` ```
#### get_cnam(cnam_id) #### get_cnam(cnam_id)
The method accepts a CNAM record ID as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/cnams/v2.0/list-cnam-record-details/). In the following example, we query for approved CNAM records on your account and then extract the ID of the first record returned and retrieve the details of that specific CNAM record. The method accepts a CNAM record ID as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/list-cnam-record-details/). In the following example, we query for approved CNAM records on your account and then extract the ID of the first record returned and retrieve the details of that specific CNAM record.
##### Example Request ##### Example Request
``` ```
@ -1333,7 +1337,7 @@ On success, the HTTP status code in the response header is `200 OK` and the resp
``` ```
#### create_cnam_record(cnam_value) #### create_cnam_record(cnam_value)
The method accepts a Caller ID value as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/cnams/v2.0/create-a-new-cnam-record/). In the following example, we reuse the `random_generator()` function to generate a four-character random string which we will concatenate with FR and assign as our CNAM value. The method accepts a Caller ID value as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/create-a-new-cnam-record/). In the following example, we reuse the `random_generator()` function to generate a four-character random string which we will concatenate with FR and assign as our CNAM value.
##### Example Request ##### Example Request
``` ```
@ -1368,7 +1372,7 @@ NOTE: Newly created CNAM records need to be approved first before they can be as
``` ```
#### associate_cnam(cnam_id, number_id) #### associate_cnam(cnam_id, number_id)
The method accepts a CNAM record ID and a phone number as parameters which you can learn more about in the [API reference](https://developer.flowroute.com/api/cnams/v2.0/assign-cnam-record-to-phone-number/). In the following example, we will call `list_account_phone_numbers()` and associate the first number in the returned array with our previously assigned `cnam_id`. The method accepts a CNAM record ID and a phone number as parameters which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/assign-cnam-record-to-phone-number/). In the following example, we will call `list_account_phone_numbers()` and associate the first number in the returned array with our previously assigned `cnam_id`.
##### Example Request ##### Example Request
``` ```
@ -1394,7 +1398,7 @@ On success, the HTTP status code in the response header is `202 Accepted` and th
``` ```
#### unassociate_cnam(number_id) #### unassociate_cnam(number_id)
The method accepts a phone number as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/cnams/v2.0/unassign-a-cnam-record-from-phone-number/). In the following example, we will disassociate the same phone number that we've used in `associate_cnam()`. The method accepts a phone number as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/unassign-a-cnam-record-from-phone-number/). In the following example, we will disassociate the same phone number that we've used in `associate_cnam()`.
##### Example Request ##### Example Request
``` ```
@ -1414,7 +1418,7 @@ On success, the HTTP status code in the response header is `202 Accepted` and th
``` ```
#### remove_cnam(cnam_id) #### remove_cnam(cnam_id)
The method accepts a CNAM record ID as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/cnams/v2.0/remove-cnam-record-from-account/). In the following example, we will be deleting our previously extracted `cnam_id` from the "List Approved CNAM Records" function call. The method accepts a CNAM record ID as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/remove-cnam-record-from-account/). In the following example, we will be deleting our previously extracted `cnam_id` from the "List Approved CNAM Records" function call.
##### Example Request ##### Example Request
``` ```

@ -3,19 +3,22 @@ import pprint
import os import os
import random import random
import string import string
from flowroutenumbersandmessaging.flowroutenumbersandmessaging_client import FlowroutenumbersandmessagingClient from flowroutenumbersandmessaging.flowroutenumbersandmessaging_client \
import FlowroutenumbersandmessagingClient
# Helper function for random strings # Helper function for random strings
def random_generator(size=4, chars=string.ascii_uppercase + string.digits): def random_generator(size=4, chars=string.ascii_uppercase + string.digits):
return ''.join(random.choice(chars) for x in range(size)) return ''.join(random.choice(chars) for x in range(size))
# Set up your api credentials and test mobile number for outbound SMS or MMS # Set up your api credentials and test mobile number for outbound SMS or MMS
basic_auth_user_name = os.environ.get('FR_ACCESS_KEY') basic_auth_user_name = os.environ.get('FR_ACCESS_KEY')
basic_auth_password = os.environ.get('FR_SECRET_KEY') basic_auth_password = os.environ.get('FR_SECRET_KEY')
# Instantiate API client and create controllers for Numbers and E911s # Instantiate API client and create controllers for Numbers and E911s
client = FlowroutenumbersandmessagingClient(basic_auth_user_name, basic_auth_password) client = FlowroutenumbersandmessagingClient(basic_auth_user_name,
basic_auth_password)
numbers_controller = client.numbers numbers_controller = client.numbers
cnams_controller = client.cnams cnams_controller = client.cnams
cnam_id = None cnam_id = None
@ -36,11 +39,27 @@ if len(result['data']):
result = cnams_controller.get_cnam(cnam_id) result = cnams_controller.get_cnam(cnam_id)
pprint.pprint(result) pprint.pprint(result)
if len(result['data']):
cnam_id = result['data']['id']
print("\n--Search for CNAM Record by contains")
result = cnams_controller.search_cnams(contains='CHRIS')
pprint.pprint(result)
print("\n--Search for CNAM Record by startswith")
result = cnams_controller.search_cnams(starts_with='CHRIS')
pprint.pprint(result)
print("\n--Search for CNAM Record by endswith")
result = cnams_controller.search_cnams(ends_with='CHRIS')
pprint.pprint(result)
print("\n--Create a CNAM Record") print("\n--Create a CNAM Record")
cnam_value = 'FR ' + random_generator() cnam_value = 'FR ' + random_generator()
result = cnams_controller.create_cnam_record(cnam_value) result = cnams_controller.create_cnam_record(cnam_value)
pprint.pprint(result) pprint.pprint(result)
print("\nNOTE: Newly created CNAM records need to be approved first before they can be associated with your long code number.") print("\nNOTE: Newly created CNAM records need to be approved first before "
"they can be associated with your long code number.")
print("\n--Associate a CNAM Record to a DID") print("\n--Associate a CNAM Record to a DID")
our_numbers = numbers_controller.list_account_phone_numbers() our_numbers = numbers_controller.list_account_phone_numbers()

@ -42,7 +42,9 @@ try:
city="Seattle", city="Seattle",
state="WA", state="WA",
country="US", country="US",
zipcode="98101") zipcode="98101",
address_type="Suite",
address_type_number="600")
pprint.pprint(result) pprint.pprint(result)
except Exception as e: except Exception as e:
print(str(e)) print(str(e))
@ -59,7 +61,28 @@ try:
city="Seattle", city="Seattle",
state="WA", state="WA",
country="US", country="US",
zipcode="98101") zipcode="98101",
address_type="Suite",
address_type_number="600")
pprint.pprint(result)
except Exception as e:
print(str(e))
print(e.context.response.raw_body)
print("\n--Create and Validate an Address")
try:
result = e911s_controller.create_address(
label="E911 Test",
first_name="Chris",
last_name="Smith",
street_name="3rd Ave",
street_number="1218",
city="Seattle",
state="WA",
country="US",
zipcode="98101",
address_type='Suite',
address_type_number='700')
pprint.pprint(result) pprint.pprint(result)
except Exception as e: except Exception as e:
print(str(e)) print(str(e))

@ -103,7 +103,9 @@ class E911sController(BaseController):
city, city,
state, state,
country, country,
zipcode): zipcode,
address_type=None,
address_type_number=None):
"""Does a POST request to /v2/e911s/validate. """Does a POST request to /v2/e911s/validate.
Returns a 204 No Content on success, or a 404 with error data Returns a 204 No Content on success, or a 404 with error data
@ -118,6 +120,8 @@ class E911sController(BaseController):
state (2 character string): state (2 character string):
country (string USA or Canada): country (string USA or Canada):
zipcode (string postal code) zipcode (string postal code)
address_type (string address type)
address_type_number (string when address_type used, required)
Returns: Returns:
mixed: Response from the API. A 204 - No Content or a mixed: Response from the API. A 204 - No Content or a
@ -142,11 +146,15 @@ class E911sController(BaseController):
'city': city, 'city': city,
'state': state, 'state': state,
'country': country, 'country': country,
'zip': zipcode 'zip': zipcode,
} }
} }
} }
if address_type and address_type_number:
body['data']['attributes']['address_type'] = address_type
body['data']['attributes']['address_type_number'] = address_type_number
# Prepare query URL # Prepare query URL
_query_builder = Configuration.base_uri _query_builder = Configuration.base_uri
_query_builder += '/v2/e911s/validate' _query_builder += '/v2/e911s/validate'
@ -156,7 +164,7 @@ class E911sController(BaseController):
# Prepare headers # Prepare headers
_headers = { _headers = {
'accept': 'application/json' 'accept': 'application/vnd.api+json'
} }
# Prepare and execute request # Prepare and execute request
@ -175,7 +183,9 @@ class E911sController(BaseController):
city, city,
state, state,
country, country,
zipcode): zipcode,
address_type=None,
address_type_number=None):
"""Does a POST request to /v2/e911s. """Does a POST request to /v2/e911s.
Creates an address record that can then be associated Creates an address record that can then be associated
@ -191,6 +201,8 @@ class E911sController(BaseController):
state (2 character string): state (2 character string):
country (string USA or Canada): country (string USA or Canada):
zipcode (string postal code) zipcode (string postal code)
address_type (string address type)
address_type_number (string required if address_type specified)
Returns: Returns:
mixed: Response from the API. A JSON object containing the new mixed: Response from the API. A JSON object containing the new
@ -215,11 +227,15 @@ class E911sController(BaseController):
'city': city, 'city': city,
'state': state, 'state': state,
'country': country, 'country': country,
'zip': zipcode 'zip': zipcode,
} }
} }
} }
if address_type and address_type_number:
body['data']['attributes']['address_type'] = address_type
body['data']['attributes']['address_type_number'] = address_type_number
# Prepare query URL # Prepare query URL
_query_builder = Configuration.base_uri _query_builder = Configuration.base_uri
_query_builder += '/v2/e911s' _query_builder += '/v2/e911s'
@ -229,7 +245,7 @@ class E911sController(BaseController):
# Prepare headers # Prepare headers
_headers = { _headers = {
'accept': 'application/json' 'accept': 'application/vnd.api+json'
} }
# Prepare and execute request # Prepare and execute request
@ -249,7 +265,9 @@ class E911sController(BaseController):
city=None, city=None,
state=None, state=None,
country=None, country=None,
zipcode=None): zipcode=None,
address_type=None,
address_type_number=None):
"""Does a PATCH request to /v2/e911s/<e911_id>. """Does a PATCH request to /v2/e911s/<e911_id>.
@ -303,6 +321,10 @@ class E911sController(BaseController):
record_data['data']['attributes']['zip'] = str(zipcode) record_data['data']['attributes']['zip'] = str(zipcode)
record_data['data']['attributes']['zip_code'] = str(zipcode) record_data['data']['attributes']['zip_code'] = str(zipcode)
record_data['data']['attributes']['address_type'] = address_type
record_data['data']['attributes']['address_type_number'] = \
address_type_number
# Fix address_type if not used # Fix address_type if not used
if 'address_type' in record_data['data']['attributes'] and \ if 'address_type' in record_data['data']['attributes'] and \
record_data['data']['attributes']['address_type'] == u'': record_data['data']['attributes']['address_type'] == u'':
@ -318,7 +340,7 @@ class E911sController(BaseController):
# Prepare headers # Prepare headers
_headers = { _headers = {
'accept': 'application/json' 'accept': 'application/vnd.api+json'
} }
# Prepare and execute request # Prepare and execute request
@ -356,7 +378,7 @@ class E911sController(BaseController):
# Prepare headers # Prepare headers
_headers = { _headers = {
'accept': 'application/json' 'accept': 'application/vnd.api+json'
} }
# Prepare and execute request # Prepare and execute request
@ -394,7 +416,7 @@ class E911sController(BaseController):
# Prepare headers # Prepare headers
_headers = { _headers = {
'accept': 'application/json' 'accept': 'application/vnd.api+json'
} }
# Prepare and execute request # Prepare and execute request
@ -430,7 +452,7 @@ class E911sController(BaseController):
# Prepare headers # Prepare headers
_headers = { _headers = {
'accept': 'application/json' 'accept': 'application/vnd.api+json'
} }
# Prepare and execute request # Prepare and execute request
@ -458,7 +480,7 @@ class E911sController(BaseController):
""" """
# Prepare query URL # Prepare query URL
_query_builder = Configuration.base_uri _query_builder = Configuration.base_uri
_query_builder += '/v2/e911s/{}'.format(e911_id) _query_builder += '/v2/e911s/{}/relationships/numbers'.format(e911_id)
_query_url = APIHelper.clean_url(_query_builder) _query_url = APIHelper.clean_url(_query_builder)
# Prepare and execute request # Prepare and execute request

@ -13,7 +13,7 @@ print("Number/Route Management v2 & Messaging v2.1 Demo")
# Set up your api credentials and test mobile number for outbound SMS or MMS # Set up your api credentials and test mobile number for outbound SMS or MMS
# basic_auth_user_name = os.environ.get('FR_ACCESS_KEY') # basic_auth_user_name = os.environ.get('FR_ACCESS_KEY')
# basic_auth_password = os.environ.get('FR_SECRET_KEY') # basic_auth_password = os.environ.get('FR_SECRET_KEY')
mobile_number = "YOUR_MOBILE_NUMBER" mobile_number = "YOUR MOBILE NUMBER HERE"
# Instantiate API client and create controllers for Numbers, # Instantiate API client and create controllers for Numbers,
@ -67,10 +67,15 @@ pprint.pprint(result)
purchasable_number = None purchasable_number = None
if len(result['data']): if len(result['data']):
print("--Purchase a Phone Number") print("--Purchase a Phone Number")
print("NOTE: This demo has been disabled as it pulls credit from your account") print("NOTE: This demo has been disabled as it pulls "
"credit from your account")
# purchasable_number = result['data'][0]['id'] # purchasable_number = result['data'][0]['id']
# try:
# result = numbers_controller.purchase_a_phone_number(purchasable_number) # result = numbers_controller.purchase_a_phone_number(purchasable_number)
# pprint.pprint(result) # pprint.pprint(result)
# except Exception as e:
# pprint.pprint(e.context.response.raw_body)
# purchasable_number = None
print("--List Account Phone Numbers") print("--List Account Phone Numbers")
starts_with = None starts_with = None
@ -212,14 +217,27 @@ request_body_with_dlr = '{ \
} \ } \
}' }'
print("---Send A Message") print("---Send an SMS Message")
try:
result = messages_controller.send_a_message(request_body) result = messages_controller.send_a_message(request_body)
pprint.pprint(result) pprint.pprint(result)
except Exception as e:
pprint.pprint(e.context.response.raw_body)
print("---Send an MMS Message")
try:
result = messages_controller.send_a_message(request_body_mms)
pprint.pprint(result)
except Exception as e:
pprint.pprint(e.context.response.raw_body)
print("---Send A Message with a DLR") print("---Send A Message with a DLR")
sms_url = 'http://example.com/sms/special' sms_url = 'http://example.com/sms/special'
try:
result = messages_controller.send_a_message(request_body_with_dlr) result = messages_controller.send_a_message(request_body_with_dlr)
pprint.pprint(result) pprint.pprint(result)
except Exception as e:
pprint.pprint(e.context.response.raw_body)
print("---Look Up A Set Of Messages") print("---Look Up A Set Of Messages")
start_date = datetime.datetime.now() - relativedelta(days=30) start_date = datetime.datetime.now() - relativedelta(days=30)

Loading…
Cancel
Save