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 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,2 @@
1
+ requests>=2.25.0
2
+ python-dotenv>=0.15.0
@@ -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
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
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()