briq 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- briq-0.1.0/LICENSE +21 -0
- briq-0.1.0/PKG-INFO +97 -0
- briq-0.1.0/README.md +70 -0
- briq-0.1.0/briq/__init__.py +15 -0
- briq-0.1.0/briq/campaign/__init__.py +92 -0
- briq-0.1.0/briq/client.py +104 -0
- briq-0.1.0/briq/config.py +72 -0
- briq-0.1.0/briq/exceptions.py +23 -0
- briq-0.1.0/briq/message/__init__.py +83 -0
- briq-0.1.0/briq/workspace/__init__.py +82 -0
- briq-0.1.0/briq.egg-info/PKG-INFO +97 -0
- briq-0.1.0/briq.egg-info/SOURCES.txt +20 -0
- briq-0.1.0/briq.egg-info/dependency_links.txt +1 -0
- briq-0.1.0/briq.egg-info/requires.txt +2 -0
- briq-0.1.0/briq.egg-info/top_level.txt +1 -0
- briq-0.1.0/pyproject.toml +31 -0
- briq-0.1.0/setup.cfg +4 -0
- briq-0.1.0/setup.py +30 -0
- briq-0.1.0/tests/test_campaign.py +144 -0
- briq-0.1.0/tests/test_client.py +108 -0
- briq-0.1.0/tests/test_message.py +113 -0
- briq-0.1.0/tests/test_workspace.py +112 -0
briq-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Briq Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
briq-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: briq
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client for the Briq messaging platform API
|
|
5
|
+
Home-page: https://github.com/BRIQ-BLOCK/BriqPythonSdk
|
|
6
|
+
Author: Briq Team
|
|
7
|
+
Author-email: Briq Team <info@briq.tz>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://github.com/briq/briq-python
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/briq/briq-python/issues
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Requires-Python: >=3.7
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: requests>=2.25.0
|
|
22
|
+
Requires-Dist: python-dotenv>=0.15.0
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: home-page
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
Dynamic: requires-python
|
|
27
|
+
|
|
28
|
+
# Briq Python Client
|
|
29
|
+
|
|
30
|
+
A Python client library for the Briq messaging platform API.
|
|
31
|
+
|
|
32
|
+
## Overview
|
|
33
|
+
|
|
34
|
+
The Briq Python client provides a simple and intuitive interface to interact with the Briq messaging platform API. It allows you to manage workspaces, campaigns, and send messages programmatically from your Python applications.
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
You can install the Briq client library using pip:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install briq
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Requirements
|
|
45
|
+
|
|
46
|
+
- Python 3.7 or higher
|
|
47
|
+
- requests
|
|
48
|
+
- python-dotenv
|
|
49
|
+
|
|
50
|
+
## Authentication
|
|
51
|
+
|
|
52
|
+
The Briq client requires an API key for authentication. You can provide your API key in several ways:
|
|
53
|
+
|
|
54
|
+
1. Set it in your environment as `BRIQ_API_KEY`
|
|
55
|
+
2. Store it in a `.env` file in your project directory
|
|
56
|
+
3. Pass it directly when initializing the client
|
|
57
|
+
|
|
58
|
+
Example `.env` file:
|
|
59
|
+
```
|
|
60
|
+
BRIQ_API_KEY=your_api_key_here
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Quick Start
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
import briq
|
|
67
|
+
|
|
68
|
+
# Initialize the client (will load API key from environment or .env file)
|
|
69
|
+
client = briq.Client()
|
|
70
|
+
|
|
71
|
+
# Or set the API key manually
|
|
72
|
+
client.set_api_key("your_api_key_here")
|
|
73
|
+
|
|
74
|
+
# Create a workspace
|
|
75
|
+
workspace = client.workspace.create(
|
|
76
|
+
name="My Workspace",
|
|
77
|
+
description="A workspace for my messaging campaigns"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# List all workspaces
|
|
81
|
+
workspaces = client.workspace.list()
|
|
82
|
+
|
|
83
|
+
# Send an instant message
|
|
84
|
+
result = client.message.send_instant(
|
|
85
|
+
content="Hello from the Briq Python client!",
|
|
86
|
+
recipients=["255788344348"],
|
|
87
|
+
sender_id="my-sender-id"
|
|
88
|
+
)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Documentation
|
|
92
|
+
|
|
93
|
+
For detailed documentation and examples, please refer to the [Usage Guide](docs/usage.md) and [API Reference](docs/api_reference.md).
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
briq-0.1.0/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Briq Python Client
|
|
2
|
+
|
|
3
|
+
A Python client library for the Briq messaging platform API.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Briq Python client provides a simple and intuitive interface to interact with the Briq messaging platform API. It allows you to manage workspaces, campaigns, and send messages programmatically from your Python applications.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
You can install the Briq client library using pip:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install briq
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Requirements
|
|
18
|
+
|
|
19
|
+
- Python 3.7 or higher
|
|
20
|
+
- requests
|
|
21
|
+
- python-dotenv
|
|
22
|
+
|
|
23
|
+
## Authentication
|
|
24
|
+
|
|
25
|
+
The Briq client requires an API key for authentication. You can provide your API key in several ways:
|
|
26
|
+
|
|
27
|
+
1. Set it in your environment as `BRIQ_API_KEY`
|
|
28
|
+
2. Store it in a `.env` file in your project directory
|
|
29
|
+
3. Pass it directly when initializing the client
|
|
30
|
+
|
|
31
|
+
Example `.env` file:
|
|
32
|
+
```
|
|
33
|
+
BRIQ_API_KEY=your_api_key_here
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
import briq
|
|
40
|
+
|
|
41
|
+
# Initialize the client (will load API key from environment or .env file)
|
|
42
|
+
client = briq.Client()
|
|
43
|
+
|
|
44
|
+
# Or set the API key manually
|
|
45
|
+
client.set_api_key("your_api_key_here")
|
|
46
|
+
|
|
47
|
+
# Create a workspace
|
|
48
|
+
workspace = client.workspace.create(
|
|
49
|
+
name="My Workspace",
|
|
50
|
+
description="A workspace for my messaging campaigns"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# List all workspaces
|
|
54
|
+
workspaces = client.workspace.list()
|
|
55
|
+
|
|
56
|
+
# Send an instant message
|
|
57
|
+
result = client.message.send_instant(
|
|
58
|
+
content="Hello from the Briq Python client!",
|
|
59
|
+
recipients=["255788344348"],
|
|
60
|
+
sender_id="my-sender-id"
|
|
61
|
+
)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Documentation
|
|
65
|
+
|
|
66
|
+
For detailed documentation and examples, please refer to the [Usage Guide](docs/usage.md) and [API Reference](docs/api_reference.md).
|
|
67
|
+
|
|
68
|
+
## License
|
|
69
|
+
|
|
70
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Briq Python Client Library
|
|
3
|
+
|
|
4
|
+
A Python client for the Briq messaging platform API.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
__version__ = "0.1.0"
|
|
8
|
+
|
|
9
|
+
from .client import Client
|
|
10
|
+
from .config import Config
|
|
11
|
+
|
|
12
|
+
# Create a default client instance that can be imported directly
|
|
13
|
+
client = Client()
|
|
14
|
+
|
|
15
|
+
__all__ = ["Client", "Config", "client"]
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Campaign management module for the Briq API.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
class CampaignAPI:
|
|
6
|
+
"""
|
|
7
|
+
Campaign management API for Briq.
|
|
8
|
+
|
|
9
|
+
Provides methods for creating, listing, retrieving, and updating campaigns.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, client):
|
|
13
|
+
"""
|
|
14
|
+
Initialize the Campaign API module.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
client: The Briq client instance
|
|
18
|
+
"""
|
|
19
|
+
self.client = client
|
|
20
|
+
|
|
21
|
+
def create(self, workspace_id, name, description=None, launch_date=None):
|
|
22
|
+
"""
|
|
23
|
+
Create a new campaign.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
workspace_id (str): ID of the workspace to create the campaign in
|
|
27
|
+
name (str): Name of the campaign
|
|
28
|
+
description (str, optional): Description of the campaign
|
|
29
|
+
launch_date (str, optional): Launch date of the campaign in ISO format (e.g., "2023-12-01T00:00:00")
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
dict: Created campaign data
|
|
33
|
+
"""
|
|
34
|
+
data = {
|
|
35
|
+
"workspace_id": workspace_id,
|
|
36
|
+
"name": name
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if description:
|
|
40
|
+
data["description"] = description
|
|
41
|
+
|
|
42
|
+
if launch_date:
|
|
43
|
+
data["launch_date"] = launch_date
|
|
44
|
+
|
|
45
|
+
return self.client.post("campaign/create/", data=data)
|
|
46
|
+
|
|
47
|
+
def list(self):
|
|
48
|
+
"""
|
|
49
|
+
List all campaigns.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
list: List of campaigns
|
|
53
|
+
"""
|
|
54
|
+
return self.client.get("campaign/all/")
|
|
55
|
+
|
|
56
|
+
def get(self, campaign_id):
|
|
57
|
+
"""
|
|
58
|
+
Get a campaign by ID.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
campaign_id (str): ID of the campaign to retrieve
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
dict: Campaign data
|
|
65
|
+
"""
|
|
66
|
+
return self.client.get(f"campaign/{campaign_id}/")
|
|
67
|
+
|
|
68
|
+
def update(self, campaign_id, name=None, description=None, launch_date=None):
|
|
69
|
+
"""
|
|
70
|
+
Update a campaign.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
campaign_id (str): ID of the campaign to update
|
|
74
|
+
name (str, optional): New name for the campaign
|
|
75
|
+
description (str, optional): New description for the campaign
|
|
76
|
+
launch_date (str, optional): New launch date in ISO format
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
dict: Updated campaign data
|
|
80
|
+
"""
|
|
81
|
+
data = {}
|
|
82
|
+
|
|
83
|
+
if name:
|
|
84
|
+
data["name"] = name
|
|
85
|
+
|
|
86
|
+
if description:
|
|
87
|
+
data["description"] = description
|
|
88
|
+
|
|
89
|
+
if launch_date:
|
|
90
|
+
data["launch_date"] = launch_date
|
|
91
|
+
|
|
92
|
+
return self.client.patch(f"campaign/update/{campaign_id}", data=data)
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Client implementation for the Briq API.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import requests
|
|
7
|
+
from .config import Config
|
|
8
|
+
from .workspace import WorkspaceAPI
|
|
9
|
+
from .campaign import CampaignAPI
|
|
10
|
+
from .message import MessageAPI
|
|
11
|
+
|
|
12
|
+
class Client:
|
|
13
|
+
"""
|
|
14
|
+
Main client class for interacting with the Briq API.
|
|
15
|
+
|
|
16
|
+
Provides access to all API endpoints through dedicated modules.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, api_key=None, base_url=None):
|
|
20
|
+
"""
|
|
21
|
+
Initialize the Briq client.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
api_key (str, optional): API key for authentication. If not provided,
|
|
25
|
+
will attempt to load from environment.
|
|
26
|
+
base_url (str, optional): Base URL for the API. If not provided,
|
|
27
|
+
will use the default URL.
|
|
28
|
+
"""
|
|
29
|
+
self.config = Config(api_key=api_key, base_url=base_url)
|
|
30
|
+
self.session = requests.Session()
|
|
31
|
+
|
|
32
|
+
# Initialize API modules
|
|
33
|
+
self.workspace = WorkspaceAPI(self)
|
|
34
|
+
self.campaign = CampaignAPI(self)
|
|
35
|
+
self.message = MessageAPI(self)
|
|
36
|
+
|
|
37
|
+
def request(self, method, endpoint, data=None, params=None):
|
|
38
|
+
"""
|
|
39
|
+
Make a request to the Briq API.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
method (str): HTTP method (GET, POST, PATCH, etc.)
|
|
43
|
+
endpoint (str): API endpoint path
|
|
44
|
+
data (dict, optional): Request body data
|
|
45
|
+
params (dict, optional): Query parameters
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
dict: Response data
|
|
49
|
+
|
|
50
|
+
Raises:
|
|
51
|
+
BriqAPIError: If the API returns an error
|
|
52
|
+
BriqAuthError: If authentication fails
|
|
53
|
+
BriqRequestError: If the request fails
|
|
54
|
+
"""
|
|
55
|
+
from .exceptions import BriqAPIError, BriqAuthError, BriqRequestError
|
|
56
|
+
|
|
57
|
+
url = f"{self.config.base_url}/v1/{endpoint.lstrip('/')}"
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
response = self.session.request(
|
|
61
|
+
method=method,
|
|
62
|
+
url=url,
|
|
63
|
+
headers=self.config.headers,
|
|
64
|
+
json=data,
|
|
65
|
+
params=params
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
response.raise_for_status()
|
|
69
|
+
|
|
70
|
+
if response.content:
|
|
71
|
+
return response.json()
|
|
72
|
+
return {}
|
|
73
|
+
|
|
74
|
+
except requests.exceptions.HTTPError as e:
|
|
75
|
+
if response.status_code == 401:
|
|
76
|
+
raise BriqAuthError("Authentication failed. Check your API key.")
|
|
77
|
+
elif response.status_code == 400:
|
|
78
|
+
error_data = response.json() if response.content else {"error": "Bad request"}
|
|
79
|
+
raise BriqAPIError(f"API error: {error_data}")
|
|
80
|
+
else:
|
|
81
|
+
raise BriqAPIError(f"API error: {str(e)}")
|
|
82
|
+
except requests.exceptions.RequestException as e:
|
|
83
|
+
raise BriqRequestError(f"Request failed: {str(e)}")
|
|
84
|
+
|
|
85
|
+
def get(self, endpoint, params=None):
|
|
86
|
+
"""Convenience method for GET requests."""
|
|
87
|
+
return self.request("GET", endpoint, params=params)
|
|
88
|
+
|
|
89
|
+
def post(self, endpoint, data=None):
|
|
90
|
+
"""Convenience method for POST requests."""
|
|
91
|
+
return self.request("POST", endpoint, data=data)
|
|
92
|
+
|
|
93
|
+
def patch(self, endpoint, data=None):
|
|
94
|
+
"""Convenience method for PATCH requests."""
|
|
95
|
+
return self.request("PATCH", endpoint, data=data)
|
|
96
|
+
|
|
97
|
+
def set_api_key(self, api_key):
|
|
98
|
+
"""
|
|
99
|
+
Set the API key for authentication.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
api_key (str): The API key to use
|
|
103
|
+
"""
|
|
104
|
+
self.config.api_key = api_key
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configuration management for the Briq client.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from dotenv import load_dotenv
|
|
8
|
+
|
|
9
|
+
class Config:
|
|
10
|
+
"""
|
|
11
|
+
Configuration class for the Briq client.
|
|
12
|
+
|
|
13
|
+
Handles API key management, loading from environment variables or .env files,
|
|
14
|
+
and allows manual setting of configuration values.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, api_key=None, base_url=None):
|
|
18
|
+
"""
|
|
19
|
+
Initialize the Config object.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
api_key (str, optional): API key for authentication. If not provided,
|
|
23
|
+
will attempt to load from environment.
|
|
24
|
+
base_url (str, optional): Base URL for the API. If not provided,
|
|
25
|
+
will use the default URL.
|
|
26
|
+
"""
|
|
27
|
+
# Try to load from .env file if it exists
|
|
28
|
+
env_path = Path('.') / '.env'
|
|
29
|
+
if env_path.exists():
|
|
30
|
+
load_dotenv(dotenv_path=env_path)
|
|
31
|
+
|
|
32
|
+
self._api_key = api_key or os.environ.get('BRIQ_API_KEY')
|
|
33
|
+
self._base_url = base_url or os.environ.get('BRIQ_BASE_URL', 'http://karibu.briq.tz')
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def api_key(self):
|
|
37
|
+
"""Get the API key."""
|
|
38
|
+
return self._api_key
|
|
39
|
+
|
|
40
|
+
@api_key.setter
|
|
41
|
+
def api_key(self, value):
|
|
42
|
+
"""Set the API key."""
|
|
43
|
+
self._api_key = value
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def base_url(self):
|
|
47
|
+
"""Get the base URL."""
|
|
48
|
+
return self._base_url
|
|
49
|
+
|
|
50
|
+
@base_url.setter
|
|
51
|
+
def base_url(self, value):
|
|
52
|
+
"""Set the base URL."""
|
|
53
|
+
self._base_url = value
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def headers(self):
|
|
57
|
+
"""
|
|
58
|
+
Get the headers for API requests.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
dict: Headers including the API key.
|
|
62
|
+
|
|
63
|
+
Raises:
|
|
64
|
+
ValueError: If API key is not set.
|
|
65
|
+
"""
|
|
66
|
+
if not self._api_key:
|
|
67
|
+
raise ValueError("API key not set. Set it using client.config.api_key = 'your_api_key' or by setting the BRIQ_API_KEY environment variable.")
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
"X-API-Key": self._api_key,
|
|
71
|
+
"Content-Type": "application/json"
|
|
72
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Exception classes for the Briq client.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
class BriqError(Exception):
|
|
6
|
+
"""Base exception for all Briq-related errors."""
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
class BriqAuthError(BriqError):
|
|
10
|
+
"""Raised when authentication fails."""
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
class BriqAPIError(BriqError):
|
|
14
|
+
"""Raised when the API returns an error."""
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
class BriqRequestError(BriqError):
|
|
18
|
+
"""Raised when a request to the API fails."""
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
class BriqConfigError(BriqError):
|
|
22
|
+
"""Raised when there's a configuration error."""
|
|
23
|
+
pass
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Message management module for the Briq API.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
class MessageAPI:
|
|
6
|
+
"""
|
|
7
|
+
Message management API for Briq.
|
|
8
|
+
|
|
9
|
+
Provides methods for sending instant messages, campaign messages, and retrieving message logs.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, client):
|
|
13
|
+
"""
|
|
14
|
+
Initialize the Message API module.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
client: The Briq client instance
|
|
18
|
+
"""
|
|
19
|
+
self.client = client
|
|
20
|
+
|
|
21
|
+
def send_instant(self, content, recipients, sender_id, campaign_id=None):
|
|
22
|
+
"""
|
|
23
|
+
Send an instant message.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
content (str): Message content
|
|
27
|
+
recipients (list): List of recipient phone numbers
|
|
28
|
+
sender_id (str): Registered sender ID name
|
|
29
|
+
campaign_id (str, optional): Campaign ID to associate the message with
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
dict: Message sending result
|
|
33
|
+
"""
|
|
34
|
+
data = {
|
|
35
|
+
"content": content,
|
|
36
|
+
"recipients": recipients,
|
|
37
|
+
"sender_id": sender_id
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if campaign_id:
|
|
41
|
+
data["campaign_id"] = campaign_id
|
|
42
|
+
|
|
43
|
+
return self.client.post("message/send-instant", data=data)
|
|
44
|
+
|
|
45
|
+
def send_campaign(self, campaign_id, group_id, content, sender_id):
|
|
46
|
+
"""
|
|
47
|
+
Send a campaign message.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
campaign_id (str): ID of the campaign
|
|
51
|
+
group_id (str): ID of the recipient group
|
|
52
|
+
content (str): Message content
|
|
53
|
+
sender_id (str): Registered sender ID name
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
dict: Message sending result
|
|
57
|
+
"""
|
|
58
|
+
data = {
|
|
59
|
+
"campaign_id": campaign_id,
|
|
60
|
+
"group_id": group_id,
|
|
61
|
+
"content": content,
|
|
62
|
+
"sender_id": sender_id
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return self.client.post("message/send-campaign", data=data)
|
|
66
|
+
|
|
67
|
+
def get_logs(self):
|
|
68
|
+
"""
|
|
69
|
+
Get message logs.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
list: Message logs
|
|
73
|
+
"""
|
|
74
|
+
return self.client.get("message/logs")
|
|
75
|
+
|
|
76
|
+
def get_history(self):
|
|
77
|
+
"""
|
|
78
|
+
Get user message history.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
list: Message history
|
|
82
|
+
"""
|
|
83
|
+
return self.client.get("message/history")
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Workspace management module for the Briq API.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
class WorkspaceAPI:
|
|
6
|
+
"""
|
|
7
|
+
Workspace management API for Briq.
|
|
8
|
+
|
|
9
|
+
Provides methods for creating, listing, retrieving, and updating workspaces.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, client):
|
|
13
|
+
"""
|
|
14
|
+
Initialize the Workspace API module.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
client: The Briq client instance
|
|
18
|
+
"""
|
|
19
|
+
self.client = client
|
|
20
|
+
|
|
21
|
+
def create(self, name, description=None):
|
|
22
|
+
"""
|
|
23
|
+
Create a new workspace.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
name (str): Name of the workspace
|
|
27
|
+
description (str, optional): Description of the workspace
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
dict: Created workspace data
|
|
31
|
+
"""
|
|
32
|
+
data = {
|
|
33
|
+
"name": name
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if description:
|
|
37
|
+
data["description"] = description
|
|
38
|
+
|
|
39
|
+
return self.client.post("workspace/create/", data=data)
|
|
40
|
+
|
|
41
|
+
def list(self):
|
|
42
|
+
"""
|
|
43
|
+
List all workspaces.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
list: List of workspaces
|
|
47
|
+
"""
|
|
48
|
+
return self.client.get("workspace/all/")
|
|
49
|
+
|
|
50
|
+
def get(self, workspace_id):
|
|
51
|
+
"""
|
|
52
|
+
Get a workspace by ID.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
workspace_id (str): ID of the workspace to retrieve
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
dict: Workspace data
|
|
59
|
+
"""
|
|
60
|
+
return self.client.get(f"workspace/{workspace_id}")
|
|
61
|
+
|
|
62
|
+
def update(self, workspace_id, name=None, description=None):
|
|
63
|
+
"""
|
|
64
|
+
Update a workspace.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
workspace_id (str): ID of the workspace to update
|
|
68
|
+
name (str, optional): New name for the workspace
|
|
69
|
+
description (str, optional): New description for the workspace
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
dict: Updated workspace data
|
|
73
|
+
"""
|
|
74
|
+
data = {}
|
|
75
|
+
|
|
76
|
+
if name:
|
|
77
|
+
data["name"] = name
|
|
78
|
+
|
|
79
|
+
if description:
|
|
80
|
+
data["description"] = description
|
|
81
|
+
|
|
82
|
+
return self.client.patch(f"workspace/update/{workspace_id}", data=data)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: briq
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client for the Briq messaging platform API
|
|
5
|
+
Home-page: https://github.com/BRIQ-BLOCK/BriqPythonSdk
|
|
6
|
+
Author: Briq Team
|
|
7
|
+
Author-email: Briq Team <info@briq.tz>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://github.com/briq/briq-python
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/briq/briq-python/issues
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Requires-Python: >=3.7
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: requests>=2.25.0
|
|
22
|
+
Requires-Dist: python-dotenv>=0.15.0
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: home-page
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
Dynamic: requires-python
|
|
27
|
+
|
|
28
|
+
# Briq Python Client
|
|
29
|
+
|
|
30
|
+
A Python client library for the Briq messaging platform API.
|
|
31
|
+
|
|
32
|
+
## Overview
|
|
33
|
+
|
|
34
|
+
The Briq Python client provides a simple and intuitive interface to interact with the Briq messaging platform API. It allows you to manage workspaces, campaigns, and send messages programmatically from your Python applications.
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
You can install the Briq client library using pip:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install briq
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Requirements
|
|
45
|
+
|
|
46
|
+
- Python 3.7 or higher
|
|
47
|
+
- requests
|
|
48
|
+
- python-dotenv
|
|
49
|
+
|
|
50
|
+
## Authentication
|
|
51
|
+
|
|
52
|
+
The Briq client requires an API key for authentication. You can provide your API key in several ways:
|
|
53
|
+
|
|
54
|
+
1. Set it in your environment as `BRIQ_API_KEY`
|
|
55
|
+
2. Store it in a `.env` file in your project directory
|
|
56
|
+
3. Pass it directly when initializing the client
|
|
57
|
+
|
|
58
|
+
Example `.env` file:
|
|
59
|
+
```
|
|
60
|
+
BRIQ_API_KEY=your_api_key_here
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Quick Start
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
import briq
|
|
67
|
+
|
|
68
|
+
# Initialize the client (will load API key from environment or .env file)
|
|
69
|
+
client = briq.Client()
|
|
70
|
+
|
|
71
|
+
# Or set the API key manually
|
|
72
|
+
client.set_api_key("your_api_key_here")
|
|
73
|
+
|
|
74
|
+
# Create a workspace
|
|
75
|
+
workspace = client.workspace.create(
|
|
76
|
+
name="My Workspace",
|
|
77
|
+
description="A workspace for my messaging campaigns"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# List all workspaces
|
|
81
|
+
workspaces = client.workspace.list()
|
|
82
|
+
|
|
83
|
+
# Send an instant message
|
|
84
|
+
result = client.message.send_instant(
|
|
85
|
+
content="Hello from the Briq Python client!",
|
|
86
|
+
recipients=["255788344348"],
|
|
87
|
+
sender_id="my-sender-id"
|
|
88
|
+
)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Documentation
|
|
92
|
+
|
|
93
|
+
For detailed documentation and examples, please refer to the [Usage Guide](docs/usage.md) and [API Reference](docs/api_reference.md).
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.py
|
|
5
|
+
briq/__init__.py
|
|
6
|
+
briq/client.py
|
|
7
|
+
briq/config.py
|
|
8
|
+
briq/exceptions.py
|
|
9
|
+
briq.egg-info/PKG-INFO
|
|
10
|
+
briq.egg-info/SOURCES.txt
|
|
11
|
+
briq.egg-info/dependency_links.txt
|
|
12
|
+
briq.egg-info/requires.txt
|
|
13
|
+
briq.egg-info/top_level.txt
|
|
14
|
+
briq/campaign/__init__.py
|
|
15
|
+
briq/message/__init__.py
|
|
16
|
+
briq/workspace/__init__.py
|
|
17
|
+
tests/test_campaign.py
|
|
18
|
+
tests/test_client.py
|
|
19
|
+
tests/test_message.py
|
|
20
|
+
tests/test_workspace.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
briq
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=42", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "briq"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Python client for the Briq messaging platform API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [
|
|
11
|
+
{name = "Briq Team", email = "info@briq.tz"}
|
|
12
|
+
]
|
|
13
|
+
license = {text = "MIT"}
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3.7",
|
|
17
|
+
"Programming Language :: Python :: 3.8",
|
|
18
|
+
"Programming Language :: Python :: 3.9",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
]
|
|
23
|
+
requires-python = ">=3.7"
|
|
24
|
+
dependencies = [
|
|
25
|
+
"requests>=2.25.0",
|
|
26
|
+
"python-dotenv>=0.15.0",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
"Homepage" = "https://github.com/briq/briq-python"
|
|
31
|
+
"Bug Tracker" = "https://github.com/briq/briq-python/issues"
|
briq-0.1.0/setup.cfg
ADDED
briq-0.1.0/setup.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="briq",
|
|
8
|
+
version="0.0.7",
|
|
9
|
+
author="Briq Team",
|
|
10
|
+
author_email="sms@briq.tz",
|
|
11
|
+
description="Python client for the Briq messaging platform API",
|
|
12
|
+
long_description=long_description,
|
|
13
|
+
long_description_content_type="text/markdown",
|
|
14
|
+
url="https://github.com/BRIQ-BLOCK/BriqPythonSdk",
|
|
15
|
+
packages=find_packages(),
|
|
16
|
+
classifiers=[
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.7",
|
|
19
|
+
"Programming Language :: Python :: 3.8",
|
|
20
|
+
"Programming Language :: Python :: 3.9",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"License :: OSI Approved :: MIT License",
|
|
23
|
+
"Operating System :: OS Independent",
|
|
24
|
+
],
|
|
25
|
+
python_requires=">=3.7",
|
|
26
|
+
install_requires=[
|
|
27
|
+
"requests>=2.25.0",
|
|
28
|
+
"python-dotenv>=0.15.0",
|
|
29
|
+
],
|
|
30
|
+
)
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest.mock import patch, MagicMock
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
|
6
|
+
|
|
7
|
+
from briq.campaign import CampaignAPI
|
|
8
|
+
|
|
9
|
+
class TestCampaignAPI(unittest.TestCase):
|
|
10
|
+
def setUp(self):
|
|
11
|
+
# Create a mock client
|
|
12
|
+
self.mock_client = MagicMock()
|
|
13
|
+
self.campaign_api = CampaignAPI(self.mock_client)
|
|
14
|
+
|
|
15
|
+
def test_init(self):
|
|
16
|
+
# Test initialization
|
|
17
|
+
self.assertIsNotNone(self.campaign_api)
|
|
18
|
+
self.assertEqual(self.campaign_api.client, self.mock_client)
|
|
19
|
+
|
|
20
|
+
def test_create(self):
|
|
21
|
+
# Test create method with all parameters
|
|
22
|
+
self.campaign_api.create(
|
|
23
|
+
"workspace-1",
|
|
24
|
+
"Test Campaign",
|
|
25
|
+
"Test Description",
|
|
26
|
+
"2023-12-01T00:00:00"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# Verify client.post was called with correct arguments
|
|
30
|
+
self.mock_client.post.assert_called_once_with(
|
|
31
|
+
"campaign/create/",
|
|
32
|
+
data={
|
|
33
|
+
"workspace_id": "workspace-1",
|
|
34
|
+
"name": "Test Campaign",
|
|
35
|
+
"description": "Test Description",
|
|
36
|
+
"launch_date": "2023-12-01T00:00:00"
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Test create with only required parameters
|
|
41
|
+
self.mock_client.post.reset_mock()
|
|
42
|
+
self.campaign_api.create("workspace-1", "Test Campaign")
|
|
43
|
+
|
|
44
|
+
# Verify client.post was called with correct arguments
|
|
45
|
+
self.mock_client.post.assert_called_once_with(
|
|
46
|
+
"campaign/create/",
|
|
47
|
+
data={
|
|
48
|
+
"workspace_id": "workspace-1",
|
|
49
|
+
"name": "Test Campaign"
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
def test_list(self):
|
|
54
|
+
# Mock response
|
|
55
|
+
mock_response = [
|
|
56
|
+
{"id": "campaign-1", "name": "Campaign 1"},
|
|
57
|
+
{"id": "campaign-2", "name": "Campaign 2"}
|
|
58
|
+
]
|
|
59
|
+
self.mock_client.get.return_value = mock_response
|
|
60
|
+
|
|
61
|
+
# Test list method
|
|
62
|
+
result = self.campaign_api.list()
|
|
63
|
+
|
|
64
|
+
# Verify client.get was called with correct arguments
|
|
65
|
+
self.mock_client.get.assert_called_once_with("campaign/all/")
|
|
66
|
+
|
|
67
|
+
# Verify result
|
|
68
|
+
self.assertEqual(result, mock_response)
|
|
69
|
+
|
|
70
|
+
def test_get(self):
|
|
71
|
+
# Mock response
|
|
72
|
+
mock_response = {"id": "campaign-1", "name": "Campaign 1"}
|
|
73
|
+
self.mock_client.get.return_value = mock_response
|
|
74
|
+
|
|
75
|
+
# Test get method
|
|
76
|
+
result = self.campaign_api.get("campaign-1")
|
|
77
|
+
|
|
78
|
+
# Verify client.get was called with correct arguments
|
|
79
|
+
self.mock_client.get.assert_called_once_with("campaign/campaign-1/")
|
|
80
|
+
|
|
81
|
+
# Verify result
|
|
82
|
+
self.assertEqual(result, mock_response)
|
|
83
|
+
|
|
84
|
+
def test_update(self):
|
|
85
|
+
# Test update method with all parameters
|
|
86
|
+
self.campaign_api.update(
|
|
87
|
+
"campaign-1",
|
|
88
|
+
"Updated Name",
|
|
89
|
+
"Updated Description",
|
|
90
|
+
"2023-12-15T00:00:00"
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# Verify client.patch was called with correct arguments
|
|
94
|
+
self.mock_client.patch.assert_called_once_with(
|
|
95
|
+
"campaign/update/campaign-1",
|
|
96
|
+
data={
|
|
97
|
+
"name": "Updated Name",
|
|
98
|
+
"description": "Updated Description",
|
|
99
|
+
"launch_date": "2023-12-15T00:00:00"
|
|
100
|
+
}
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
# Test update with only name
|
|
104
|
+
self.mock_client.patch.reset_mock()
|
|
105
|
+
self.campaign_api.update("campaign-1", "Updated Name")
|
|
106
|
+
|
|
107
|
+
# Verify client.patch was called with correct arguments
|
|
108
|
+
self.mock_client.patch.assert_called_once_with(
|
|
109
|
+
"campaign/update/campaign-1",
|
|
110
|
+
data={"name": "Updated Name"}
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Test update with only description
|
|
114
|
+
self.mock_client.patch.reset_mock()
|
|
115
|
+
self.campaign_api.update("campaign-1", description="Updated Description")
|
|
116
|
+
|
|
117
|
+
# Verify client.patch was called with correct arguments
|
|
118
|
+
self.mock_client.patch.assert_called_once_with(
|
|
119
|
+
"campaign/update/campaign-1",
|
|
120
|
+
data={"description": "Updated Description"}
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
# Test update with only launch_date
|
|
124
|
+
self.mock_client.patch.reset_mock()
|
|
125
|
+
self.campaign_api.update("campaign-1", launch_date="2023-12-15T00:00:00")
|
|
126
|
+
|
|
127
|
+
# Verify client.patch was called with correct arguments
|
|
128
|
+
self.mock_client.patch.assert_called_once_with(
|
|
129
|
+
"campaign/update/campaign-1",
|
|
130
|
+
data={"launch_date": "2023-12-15T00:00:00"}
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# Test update with no changes
|
|
134
|
+
self.mock_client.patch.reset_mock()
|
|
135
|
+
self.campaign_api.update("campaign-1")
|
|
136
|
+
|
|
137
|
+
# Verify client.patch was called with correct arguments
|
|
138
|
+
self.mock_client.patch.assert_called_once_with(
|
|
139
|
+
"campaign/update/campaign-1",
|
|
140
|
+
data={}
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
if __name__ == '__main__':
|
|
144
|
+
unittest.main()
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest.mock import patch, MagicMock
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
|
6
|
+
|
|
7
|
+
from briq.client import Client
|
|
8
|
+
from briq.exceptions import BriqAuthError, BriqAPIError, BriqRequestError
|
|
9
|
+
|
|
10
|
+
class TestClient(unittest.TestCase):
|
|
11
|
+
def setUp(self):
|
|
12
|
+
# Create a client with a dummy API key for testing
|
|
13
|
+
self.client = Client(api_key="test_api_key")
|
|
14
|
+
|
|
15
|
+
def test_init(self):
|
|
16
|
+
# Test client initialization
|
|
17
|
+
self.assertIsNotNone(self.client)
|
|
18
|
+
self.assertEqual(self.client.config.api_key, "test_api_key")
|
|
19
|
+
self.assertEqual(self.client.config.base_url, "http://karibu.briq.tz")
|
|
20
|
+
|
|
21
|
+
# Test initialization with custom base URL
|
|
22
|
+
client = Client(api_key="test_api_key", base_url="http://custom-url")
|
|
23
|
+
self.assertEqual(client.config.base_url, "http://custom-url")
|
|
24
|
+
|
|
25
|
+
def test_set_api_key(self):
|
|
26
|
+
# Test setting API key
|
|
27
|
+
self.client.set_api_key("new_api_key")
|
|
28
|
+
self.assertEqual(self.client.config.api_key, "new_api_key")
|
|
29
|
+
|
|
30
|
+
@patch('requests.Session.request')
|
|
31
|
+
def test_request_success(self, mock_request):
|
|
32
|
+
# Mock successful response
|
|
33
|
+
mock_response = MagicMock()
|
|
34
|
+
mock_response.status_code = 200
|
|
35
|
+
mock_response.content = b'{"key": "value"}'
|
|
36
|
+
mock_response.json.return_value = {"key": "value"}
|
|
37
|
+
mock_request.return_value = mock_response
|
|
38
|
+
|
|
39
|
+
# Test request method
|
|
40
|
+
result = self.client.request("GET", "test/endpoint")
|
|
41
|
+
|
|
42
|
+
# Verify request was made correctly
|
|
43
|
+
mock_request.assert_called_once_with(
|
|
44
|
+
method="GET",
|
|
45
|
+
url="http://karibu.briq.tz/v1/test/endpoint",
|
|
46
|
+
headers=self.client.config.headers,
|
|
47
|
+
json=None,
|
|
48
|
+
params=None
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Verify result
|
|
52
|
+
self.assertEqual(result, {"key": "value"})
|
|
53
|
+
|
|
54
|
+
@patch('requests.Session.request')
|
|
55
|
+
def test_request_auth_error(self, mock_request):
|
|
56
|
+
# Mock 401 response
|
|
57
|
+
mock_response = MagicMock()
|
|
58
|
+
mock_response.status_code = 401
|
|
59
|
+
mock_response.raise_for_status.side_effect = Exception("401 Client Error")
|
|
60
|
+
mock_request.return_value = mock_response
|
|
61
|
+
|
|
62
|
+
# Test request method with auth error
|
|
63
|
+
with self.assertRaises(BriqAuthError):
|
|
64
|
+
self.client.request("GET", "test/endpoint")
|
|
65
|
+
|
|
66
|
+
@patch('requests.Session.request')
|
|
67
|
+
def test_request_api_error(self, mock_request):
|
|
68
|
+
# Mock 400 response
|
|
69
|
+
mock_response = MagicMock()
|
|
70
|
+
mock_response.status_code = 400
|
|
71
|
+
mock_response.content = b'{"error": "Bad request"}'
|
|
72
|
+
mock_response.json.return_value = {"error": "Bad request"}
|
|
73
|
+
mock_response.raise_for_status.side_effect = Exception("400 Client Error")
|
|
74
|
+
mock_request.return_value = mock_response
|
|
75
|
+
|
|
76
|
+
# Test request method with API error
|
|
77
|
+
with self.assertRaises(BriqAPIError):
|
|
78
|
+
self.client.request("GET", "test/endpoint")
|
|
79
|
+
|
|
80
|
+
@patch('requests.Session.request')
|
|
81
|
+
def test_request_network_error(self, mock_request):
|
|
82
|
+
# Mock network error
|
|
83
|
+
mock_request.side_effect = Exception("Connection error")
|
|
84
|
+
|
|
85
|
+
# Test request method with network error
|
|
86
|
+
with self.assertRaises(BriqRequestError):
|
|
87
|
+
self.client.request("GET", "test/endpoint")
|
|
88
|
+
|
|
89
|
+
@patch('briq.client.Client.request')
|
|
90
|
+
def test_get(self, mock_request):
|
|
91
|
+
# Test get method
|
|
92
|
+
self.client.get("test/endpoint", params={"param": "value"})
|
|
93
|
+
mock_request.assert_called_once_with("GET", "test/endpoint", params={"param": "value"})
|
|
94
|
+
|
|
95
|
+
@patch('briq.client.Client.request')
|
|
96
|
+
def test_post(self, mock_request):
|
|
97
|
+
# Test post method
|
|
98
|
+
self.client.post("test/endpoint", data={"key": "value"})
|
|
99
|
+
mock_request.assert_called_once_with("POST", "test/endpoint", data={"key": "value"})
|
|
100
|
+
|
|
101
|
+
@patch('briq.client.Client.request')
|
|
102
|
+
def test_patch(self, mock_request):
|
|
103
|
+
# Test patch method
|
|
104
|
+
self.client.patch("test/endpoint", data={"key": "value"})
|
|
105
|
+
mock_request.assert_called_once_with("PATCH", "test/endpoint", data={"key": "value"})
|
|
106
|
+
|
|
107
|
+
if __name__ == '__main__':
|
|
108
|
+
unittest.main()
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest.mock import patch, MagicMock
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
|
6
|
+
|
|
7
|
+
from briq.message import MessageAPI
|
|
8
|
+
|
|
9
|
+
class TestMessageAPI(unittest.TestCase):
|
|
10
|
+
def setUp(self):
|
|
11
|
+
# Create a mock client
|
|
12
|
+
self.mock_client = MagicMock()
|
|
13
|
+
self.message_api = MessageAPI(self.mock_client)
|
|
14
|
+
|
|
15
|
+
def test_init(self):
|
|
16
|
+
# Test initialization
|
|
17
|
+
self.assertIsNotNone(self.message_api)
|
|
18
|
+
self.assertEqual(self.message_api.client, self.mock_client)
|
|
19
|
+
|
|
20
|
+
def test_send_instant(self):
|
|
21
|
+
# Test send_instant method with all parameters
|
|
22
|
+
self.message_api.send_instant(
|
|
23
|
+
"Hello, this is a test message",
|
|
24
|
+
["255788344348", "255712345678"],
|
|
25
|
+
"test-sender",
|
|
26
|
+
"campaign-1"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# Verify client.post was called with correct arguments
|
|
30
|
+
self.mock_client.post.assert_called_once_with(
|
|
31
|
+
"message/send-instant",
|
|
32
|
+
data={
|
|
33
|
+
"content": "Hello, this is a test message",
|
|
34
|
+
"recipients": ["255788344348", "255712345678"],
|
|
35
|
+
"sender_id": "test-sender",
|
|
36
|
+
"campaign_id": "campaign-1"
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Test send_instant without campaign_id
|
|
41
|
+
self.mock_client.post.reset_mock()
|
|
42
|
+
self.message_api.send_instant(
|
|
43
|
+
"Hello, this is a test message",
|
|
44
|
+
["255788344348"],
|
|
45
|
+
"test-sender"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Verify client.post was called with correct arguments
|
|
49
|
+
self.mock_client.post.assert_called_once_with(
|
|
50
|
+
"message/send-instant",
|
|
51
|
+
data={
|
|
52
|
+
"content": "Hello, this is a test message",
|
|
53
|
+
"recipients": ["255788344348"],
|
|
54
|
+
"sender_id": "test-sender"
|
|
55
|
+
}
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def test_send_campaign(self):
|
|
59
|
+
# Test send_campaign method
|
|
60
|
+
self.message_api.send_campaign(
|
|
61
|
+
"campaign-1",
|
|
62
|
+
"group-1",
|
|
63
|
+
"Campaign message content",
|
|
64
|
+
"test-sender"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Verify client.post was called with correct arguments
|
|
68
|
+
self.mock_client.post.assert_called_once_with(
|
|
69
|
+
"message/send-campaign",
|
|
70
|
+
data={
|
|
71
|
+
"campaign_id": "campaign-1",
|
|
72
|
+
"group_id": "group-1",
|
|
73
|
+
"content": "Campaign message content",
|
|
74
|
+
"sender_id": "test-sender"
|
|
75
|
+
}
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def test_get_logs(self):
|
|
79
|
+
# Mock response
|
|
80
|
+
mock_response = [
|
|
81
|
+
{"id": "message-1", "content": "Message 1", "status": "delivered"},
|
|
82
|
+
{"id": "message-2", "content": "Message 2", "status": "sent"}
|
|
83
|
+
]
|
|
84
|
+
self.mock_client.get.return_value = mock_response
|
|
85
|
+
|
|
86
|
+
# Test get_logs method
|
|
87
|
+
result = self.message_api.get_logs()
|
|
88
|
+
|
|
89
|
+
# Verify client.get was called with correct arguments
|
|
90
|
+
self.mock_client.get.assert_called_once_with("message/logs")
|
|
91
|
+
|
|
92
|
+
# Verify result
|
|
93
|
+
self.assertEqual(result, mock_response)
|
|
94
|
+
|
|
95
|
+
def test_get_history(self):
|
|
96
|
+
# Mock response
|
|
97
|
+
mock_response = [
|
|
98
|
+
{"id": "message-1", "content": "Message 1", "sent_at": "2023-01-01T12:00:00"},
|
|
99
|
+
{"id": "message-2", "content": "Message 2", "sent_at": "2023-01-02T12:00:00"}
|
|
100
|
+
]
|
|
101
|
+
self.mock_client.get.return_value = mock_response
|
|
102
|
+
|
|
103
|
+
# Test get_history method
|
|
104
|
+
result = self.message_api.get_history()
|
|
105
|
+
|
|
106
|
+
# Verify client.get was called with correct arguments
|
|
107
|
+
self.mock_client.get.assert_called_once_with("message/history")
|
|
108
|
+
|
|
109
|
+
# Verify result
|
|
110
|
+
self.assertEqual(result, mock_response)
|
|
111
|
+
|
|
112
|
+
if __name__ == '__main__':
|
|
113
|
+
unittest.main()
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest.mock import patch, MagicMock
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
|
6
|
+
|
|
7
|
+
from briq.workspace import WorkspaceAPI
|
|
8
|
+
|
|
9
|
+
class TestWorkspaceAPI(unittest.TestCase):
|
|
10
|
+
def setUp(self):
|
|
11
|
+
# Create a mock client
|
|
12
|
+
self.mock_client = MagicMock()
|
|
13
|
+
self.workspace_api = WorkspaceAPI(self.mock_client)
|
|
14
|
+
|
|
15
|
+
def test_init(self):
|
|
16
|
+
# Test initialization
|
|
17
|
+
self.assertIsNotNone(self.workspace_api)
|
|
18
|
+
self.assertEqual(self.workspace_api.client, self.mock_client)
|
|
19
|
+
|
|
20
|
+
def test_create(self):
|
|
21
|
+
# Test create method
|
|
22
|
+
self.workspace_api.create("Test Workspace", "Test Description")
|
|
23
|
+
|
|
24
|
+
# Verify client.post was called with correct arguments
|
|
25
|
+
self.mock_client.post.assert_called_once_with(
|
|
26
|
+
"workspace/create/",
|
|
27
|
+
data={"name": "Test Workspace", "description": "Test Description"}
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Test create with only name
|
|
31
|
+
self.mock_client.post.reset_mock()
|
|
32
|
+
self.workspace_api.create("Test Workspace")
|
|
33
|
+
|
|
34
|
+
# Verify client.post was called with correct arguments
|
|
35
|
+
self.mock_client.post.assert_called_once_with(
|
|
36
|
+
"workspace/create/",
|
|
37
|
+
data={"name": "Test Workspace"}
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def test_list(self):
|
|
41
|
+
# Mock response
|
|
42
|
+
mock_response = [
|
|
43
|
+
{"id": "workspace-1", "name": "Workspace 1"},
|
|
44
|
+
{"id": "workspace-2", "name": "Workspace 2"}
|
|
45
|
+
]
|
|
46
|
+
self.mock_client.get.return_value = mock_response
|
|
47
|
+
|
|
48
|
+
# Test list method
|
|
49
|
+
result = self.workspace_api.list()
|
|
50
|
+
|
|
51
|
+
# Verify client.get was called with correct arguments
|
|
52
|
+
self.mock_client.get.assert_called_once_with("workspace/all/")
|
|
53
|
+
|
|
54
|
+
# Verify result
|
|
55
|
+
self.assertEqual(result, mock_response)
|
|
56
|
+
|
|
57
|
+
def test_get(self):
|
|
58
|
+
# Mock response
|
|
59
|
+
mock_response = {"id": "workspace-1", "name": "Workspace 1"}
|
|
60
|
+
self.mock_client.get.return_value = mock_response
|
|
61
|
+
|
|
62
|
+
# Test get method
|
|
63
|
+
result = self.workspace_api.get("workspace-1")
|
|
64
|
+
|
|
65
|
+
# Verify client.get was called with correct arguments
|
|
66
|
+
self.mock_client.get.assert_called_once_with("workspace/workspace-1")
|
|
67
|
+
|
|
68
|
+
# Verify result
|
|
69
|
+
self.assertEqual(result, mock_response)
|
|
70
|
+
|
|
71
|
+
def test_update(self):
|
|
72
|
+
# Test update method with both name and description
|
|
73
|
+
self.workspace_api.update("workspace-1", "Updated Name", "Updated Description")
|
|
74
|
+
|
|
75
|
+
# Verify client.patch was called with correct arguments
|
|
76
|
+
self.mock_client.patch.assert_called_once_with(
|
|
77
|
+
"workspace/update/workspace-1",
|
|
78
|
+
data={"name": "Updated Name", "description": "Updated Description"}
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# Test update with only name
|
|
82
|
+
self.mock_client.patch.reset_mock()
|
|
83
|
+
self.workspace_api.update("workspace-1", "Updated Name")
|
|
84
|
+
|
|
85
|
+
# Verify client.patch was called with correct arguments
|
|
86
|
+
self.mock_client.patch.assert_called_once_with(
|
|
87
|
+
"workspace/update/workspace-1",
|
|
88
|
+
data={"name": "Updated Name"}
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# Test update with only description
|
|
92
|
+
self.mock_client.patch.reset_mock()
|
|
93
|
+
self.workspace_api.update("workspace-1", description="Updated Description")
|
|
94
|
+
|
|
95
|
+
# Verify client.patch was called with correct arguments
|
|
96
|
+
self.mock_client.patch.assert_called_once_with(
|
|
97
|
+
"workspace/update/workspace-1",
|
|
98
|
+
data={"description": "Updated Description"}
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Test update with no changes
|
|
102
|
+
self.mock_client.patch.reset_mock()
|
|
103
|
+
self.workspace_api.update("workspace-1")
|
|
104
|
+
|
|
105
|
+
# Verify client.patch was called with correct arguments
|
|
106
|
+
self.mock_client.patch.assert_called_once_with(
|
|
107
|
+
"workspace/update/workspace-1",
|
|
108
|
+
data={}
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
if __name__ == '__main__':
|
|
112
|
+
unittest.main()
|