kambasms 1.0.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.
@@ -0,0 +1,20 @@
1
+ Metadata-Version: 2.4
2
+ Name: kambasms
3
+ Version: 1.0.0
4
+ Summary: SDK oficial da KambaSMS para envio de mensagens SMS em Angola
5
+ Author-email: KambaSMS <support@kambasms.ao>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/FranciiscoCampos170/kamba_sms_python_sdk
8
+ Project-URL: Repository, https://github.com/FranciiscoCampos170/kamba_sms_python_sdk
9
+ Project-URL: Issues, https://github.com/FranciiscoCampos170/kamba_sms_python_sdk/issues
10
+ Keywords: sms,angola,kambasms,api,messaging
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.8
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Requires-Python: >=3.8
20
+ Description-Content-Type: text/markdown
File without changes
@@ -0,0 +1,12 @@
1
+ from .client import KambaClient
2
+ from .resources.sms import SmsResource
3
+ from .resources.account import AccountResource
4
+ from .exceptions import KambaError, KambaValidationError, KambaAPIError
5
+
6
+ class KambaSMS(KambaClient):
7
+ def __init__(self, api_key: str, base_url: str = "https://nexasms-api.onrender.com"):
8
+ super().__init__(api_key, base_url)
9
+ self.sms = SmsResource(self)
10
+ self.account = AccountResource(self)
11
+
12
+ __all__ = ["KambaSMS", "KambaError", "KambaValidationError", "KambaAPIError"]
@@ -0,0 +1,36 @@
1
+ import json
2
+ import urllib.request
3
+ import urllib.error
4
+ from typing import Any
5
+ from .exceptions import KambaError, KambaAPIError
6
+
7
+ class KambaClient:
8
+ def __init__(self, api_key: str, base_url: str = "https://nexasms-api.onrender.com"):
9
+ if not api_key:
10
+ raise KambaError("A apiKey é obrigatória para inicializar o KambaSMS.")
11
+ self._api_key = api_key
12
+ self._base_url = base_url.rstrip("/")
13
+
14
+ def request(self, method: str, endpoint: str, data: dict | None = None) -> dict[str, Any]:
15
+ url = f"{self._base_url}{endpoint}"
16
+ headers = {
17
+ "Content-Type": "application/json",
18
+ "x-api-key": self._api_key,
19
+ }
20
+
21
+ body = json.dumps(data).encode("utf-8") if data else None
22
+ req = urllib.request.Request(url, data=body, headers=headers, method=method)
23
+
24
+ try:
25
+ with urllib.request.urlopen(req, timeout=30) as response:
26
+ return json.loads(response.read().decode("utf-8"))
27
+ except urllib.error.HTTPError as e:
28
+ error_body = e.read().decode("utf-8")
29
+ try:
30
+ error_data = json.loads(error_body)
31
+ message = error_data.get("error", "Erro desconhecido na API KambaSMS")
32
+ except json.JSONDecodeError:
33
+ message = "Erro desconhecido na API KambaSMS"
34
+ raise KambaAPIError(message, e.code, error_data if isinstance(error_data, dict) else {}) from e
35
+ except urllib.error.URLError as e:
36
+ raise KambaError(f"Erro de rede: {e.reason}") from e
@@ -0,0 +1,25 @@
1
+ from kambasms import KambaSMS, KambaValidationError, KambaAPIError
2
+
3
+ client = KambaSMS(api_key="kamba_tua_chave_de_teste_aqui")
4
+
5
+ try:
6
+ balance = client.account.get_balance()
7
+ print(f"✅ Saldo atual: {balance['balance']} SMS")
8
+
9
+ sms = client.sms.send(
10
+ to="+244923456789",
11
+ text="Teste do SDK Python KambaSMS.",
12
+ sender_id="KAMBA"
13
+ )
14
+ print(f"✅ SMS Enviado! ID: {sms['message_id']} | Saldo: {sms['remaining_balance']}")
15
+
16
+ # Teste de validação (deve falhar no cliente)
17
+ try:
18
+ client.sms.send(to="923456789", text="Visite www.kambasms.ao 🚀", sender_id="KAMBA")
19
+ except KambaValidationError as e:
20
+ print(f"🛡️ Validação funcionou: {e}")
21
+
22
+ except KambaAPIError as e:
23
+ print(f"❌ Erro API ({e.status_code}): {e}")
24
+ except Exception as e:
25
+ print(f"❌ Erro: {e}")
@@ -0,0 +1,14 @@
1
+ class KambaError(Exception):
2
+ """Exceção base da KambaSMS."""
3
+ pass
4
+
5
+ class KambaValidationError(KambaError):
6
+ """Erro de validação no lado do cliente."""
7
+ pass
8
+
9
+ class KambaAPIError(KambaError):
10
+ """Erro retornado pela API KambaSMS."""
11
+ def __init__(self, message: str, status_code: int, details: dict | None = None):
12
+ super().__init__(message)
13
+ self.status_code = status_code
14
+ self.details = details or {}
File without changes
@@ -0,0 +1,11 @@
1
+ from ..client import KambaClient
2
+
3
+ class AccountResource:
4
+ def __init__(self, client: KambaClient):
5
+ self._client = client
6
+
7
+ def get_balance(self) -> dict:
8
+ return self._client.request("GET", "/credits/balance")
9
+
10
+ def get_history(self, limit: int = 100) -> list[dict]:
11
+ return self._client.request("GET", f"/messages?limit={limit}")
@@ -0,0 +1,33 @@
1
+ from datetime import datetime
2
+ from ..client import KambaClient
3
+ from ..validators import validate_angolan_phone, validate_message_content
4
+
5
+ class SmsResource:
6
+ def __init__(self, client: KambaClient):
7
+ self._client = client
8
+
9
+ def send(self, to: str, text: str, sender_id: str | None = None) -> dict:
10
+ validate_angolan_phone(to)
11
+ validate_message_content(text)
12
+ payload = {"to": to, "text": text}
13
+ if sender_id:
14
+ payload["sender_id"] = sender_id
15
+ return self._client.request("POST", "/messages/send", payload)
16
+
17
+ def send_bulk(self, name: str, sender_id: str, text: str, recipients: list[str]) -> dict:
18
+ validate_message_content(text)
19
+ for phone in recipients:
20
+ validate_angolan_phone(phone)
21
+ if len(recipients) > 1000:
22
+ raise ValueError("O limite máximo é de 1000 destinatários por envio em massa.")
23
+ return self._client.request("POST", "/messages/bulk", {
24
+ "name": name, "sender_id": sender_id, "text": text, "recipients": recipients
25
+ })
26
+
27
+ def schedule(self, to: str, text: str, sender_id: str, scheduled_at: str | datetime) -> dict:
28
+ validate_angolan_phone(to)
29
+ validate_message_content(text)
30
+ ts = scheduled_at.isoformat() if isinstance(scheduled_at, datetime) else scheduled_at
31
+ return self._client.request("POST", "/messages/schedule", {
32
+ "to": to, "text": text, "sender_id": sender_id, "scheduled_at": ts
33
+ })
@@ -0,0 +1,28 @@
1
+ import re
2
+ from .exceptions import KambaValidationError
3
+
4
+ _PHONE_REGEX = re.compile(r'^\+244[0-9]{9}$')
5
+ _URL_REGEX = re.compile(r'https?://|www\.|\.com\b|\.ao\b|\.net\b|\.org\b|\.co\b|\.io\b', re.IGNORECASE)
6
+ _EMOJI_REGEX = re.compile(
7
+ r'[\U0001F600-\U0001F64F\U0001F300-\U0001F5FF\U0001F680-\U0001F6FF\U00002600-\U000026FF\U00002700-\U000027BF]'
8
+ )
9
+
10
+ def validate_angolan_phone(phone: str) -> None:
11
+ if not _PHONE_REGEX.match(phone):
12
+ raise KambaValidationError(
13
+ f"Número de telefone inválido: '{phone}'. Deve ser +244 seguido de 9 dígitos (ex: +244923456789)."
14
+ )
15
+
16
+ def validate_message_content(text: str) -> None:
17
+ if _URL_REGEX.search(text):
18
+ raise KambaValidationError(
19
+ "Mensagens com links ou URLs não são permitidas. As operadoras angolanas filtram este conteúdo como spam."
20
+ )
21
+ if len(text) > 160:
22
+ raise KambaValidationError(
23
+ f"Mensagem demasiado longa ({len(text)}/160 caracteres). O limite é de 160 caracteres por SMS."
24
+ )
25
+ if _EMOJI_REGEX.search(text):
26
+ raise KambaValidationError(
27
+ "Emojis não são suportados. As operadoras angolanas podem bloquear ou cobrar múltiplos SMS por mensagens com emojis."
28
+ )
@@ -0,0 +1,20 @@
1
+ Metadata-Version: 2.4
2
+ Name: kambasms
3
+ Version: 1.0.0
4
+ Summary: SDK oficial da KambaSMS para envio de mensagens SMS em Angola
5
+ Author-email: KambaSMS <support@kambasms.ao>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/FranciiscoCampos170/kamba_sms_python_sdk
8
+ Project-URL: Repository, https://github.com/FranciiscoCampos170/kamba_sms_python_sdk
9
+ Project-URL: Issues, https://github.com/FranciiscoCampos170/kamba_sms_python_sdk/issues
10
+ Keywords: sms,angola,kambasms,api,messaging
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.8
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Requires-Python: >=3.8
20
+ Description-Content-Type: text/markdown
@@ -0,0 +1,14 @@
1
+ README.md
2
+ pyproject.toml
3
+ kambasms/__init__.py
4
+ kambasms/client.py
5
+ kambasms/exceptions.py
6
+ kambasms/validators.py
7
+ kambasms.egg-info/PKG-INFO
8
+ kambasms.egg-info/SOURCES.txt
9
+ kambasms.egg-info/dependency_links.txt
10
+ kambasms.egg-info/top_level.txt
11
+ kambasms/examples/example.py
12
+ kambasms/resources/__init__.py
13
+ kambasms/resources/account.py
14
+ kambasms/resources/sms.py
@@ -0,0 +1 @@
1
+ kambasms
@@ -0,0 +1,29 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "kambasms"
7
+ version = "1.0.0"
8
+ description = "SDK oficial da KambaSMS para envio de mensagens SMS em Angola"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ authors = [{name = "KambaSMS", email = "support@kambasms.ao"}]
12
+ keywords = ["sms", "angola", "kambasms", "api", "messaging"]
13
+ classifiers = [
14
+ "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python :: 3.8",
16
+ "Programming Language :: Python :: 3.9",
17
+ "Programming Language :: Python :: 3.10",
18
+ "Programming Language :: Python :: 3.11",
19
+ "Programming Language :: Python :: 3.12",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: OS Independent",
22
+ ]
23
+ requires-python = ">=3.8"
24
+ dependencies = []
25
+
26
+ [project.urls]
27
+ Homepage = "https://github.com/FranciiscoCampos170/kamba_sms_python_sdk"
28
+ Repository = "https://github.com/FranciiscoCampos170/kamba_sms_python_sdk"
29
+ Issues = "https://github.com/FranciiscoCampos170/kamba_sms_python_sdk/issues"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+