django-whatsapp-api-wrapper 0.2.2__tar.gz → 0.3.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.
Files changed (25) hide show
  1. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/PKG-INFO +102 -1
  2. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/README.md +101 -0
  3. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/pyproject.toml +1 -1
  4. django_whatsapp_api_wrapper-0.3.0/src/django_whatsapp_api_wrapper/authentication/__init__.py +4 -0
  5. django_whatsapp_api_wrapper-0.3.0/src/django_whatsapp_api_wrapper/authentication/api_key.py +32 -0
  6. django_whatsapp_api_wrapper-0.3.0/src/django_whatsapp_api_wrapper/authentication/base.py +54 -0
  7. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/templates/views.py +6 -6
  8. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/LICENSE +0 -0
  9. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/__init__.py +0 -0
  10. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/admin.py +0 -0
  11. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/apps.py +0 -0
  12. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/client.py +0 -0
  13. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/messages/__init__.py +0 -0
  14. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/messages/_template.py +0 -0
  15. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/messages/_text.py +0 -0
  16. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/migrations/__init__.py +0 -0
  17. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/shell_example.txt +0 -0
  18. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/signals.py +0 -0
  19. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/templates/__init__.py +0 -0
  20. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/templates/client.py +0 -0
  21. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/templates/serializers.py +0 -0
  22. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/templates/urls.py +0 -0
  23. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/tests.py +0 -0
  24. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/urls.py +0 -0
  25. {django_whatsapp_api_wrapper-0.2.2 → django_whatsapp_api_wrapper-0.3.0}/src/django_whatsapp_api_wrapper/views.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-whatsapp-api-wrapper
3
- Version: 0.2.2
3
+ Version: 0.3.0
4
4
  Summary:
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -74,6 +74,35 @@ WHATSAPP_CLOUD_API_WABA_ID=
74
74
  WHATSAPP_CLOUD_API_VERIFY_TOKEN=
75
75
  ```
76
76
 
77
+ 4) Configure a autenticação para as rotas de templates (opcional, mas recomendado):
78
+
79
+ ```python
80
+ # settings.py
81
+
82
+ # Opção 1: Usar Token Authentication do DRF (padrão)
83
+ WHATSAPP_API_AUTHENTICATION_CLASSES = [
84
+ 'rest_framework.authentication.TokenAuthentication',
85
+ ]
86
+
87
+ # Opção 2: Usar JWT (se você já tem configurado)
88
+ WHATSAPP_API_AUTHENTICATION_CLASSES = [
89
+ 'rest_framework_simplejwt.authentication.JWTAuthentication',
90
+ ]
91
+
92
+ # Opção 3: Usar API Key simples
93
+ WHATSAPP_API_AUTHENTICATION_CLASSES = [
94
+ 'django_whatsapp_api_wrapper.authentication.APIKeyAuthentication',
95
+ ]
96
+ WHATSAPP_API_KEY = "sua_api_key_secreta_aqui"
97
+
98
+ # Permissões (padrão: IsAuthenticated)
99
+ WHATSAPP_API_PERMISSION_CLASSES = [
100
+ 'rest_framework.permissions.IsAuthenticated',
101
+ ]
102
+ ```
103
+
104
+ **Importante:** Se não configurar a autenticação, as rotas de templates usarão `TokenAuthentication` por padrão.
105
+
77
106
  O endpoint de webhook ficará disponível em:
78
107
 
79
108
  - GET/POST: `/whatsapp-api-wrapper/webhook/`
@@ -142,10 +171,82 @@ m2.send()
142
171
 
143
172
  ---
144
173
 
174
+ ## Autenticação
175
+
176
+ ### Proteção das Rotas de Templates
177
+
178
+ Por padrão, todas as rotas de templates (`/templates/`) são protegidas e requerem autenticação. O webhook permanece público (necessário para o WhatsApp).
179
+
180
+ ### Opções de Autenticação
181
+
182
+ #### 1. Token Authentication (Padrão)
183
+ ```python
184
+ # settings.py
185
+ WHATSAPP_API_AUTHENTICATION_CLASSES = [
186
+ 'rest_framework.authentication.TokenAuthentication',
187
+ ]
188
+ ```
189
+
190
+ Uso:
191
+ ```bash
192
+ curl -H "Authorization: Token seu_token_aqui" \
193
+ "$BASE/whatsapp-api-wrapper/templates/"
194
+ ```
195
+
196
+ #### 2. JWT Authentication
197
+ ```python
198
+ # settings.py
199
+ WHATSAPP_API_AUTHENTICATION_CLASSES = [
200
+ 'rest_framework_simplejwt.authentication.JWTAuthentication',
201
+ ]
202
+ ```
203
+
204
+ Uso:
205
+ ```bash
206
+ curl -H "Authorization: Bearer seu_jwt_token" \
207
+ "$BASE/whatsapp-api-wrapper/templates/"
208
+ ```
209
+
210
+ #### 3. API Key Authentication
211
+ ```python
212
+ # settings.py
213
+ WHATSAPP_API_AUTHENTICATION_CLASSES = [
214
+ 'django_whatsapp_api_wrapper.authentication.APIKeyAuthentication',
215
+ ]
216
+ WHATSAPP_API_KEY = "sua_api_key_secreta"
217
+ ```
218
+
219
+ Uso:
220
+ ```bash
221
+ curl -H "X-WhatsApp-API-Key: sua_api_key_secreta" \
222
+ "$BASE/whatsapp-api-wrapper/templates/"
223
+ ```
224
+
225
+ #### 4. Múltiplas Autenticações
226
+ ```python
227
+ # settings.py
228
+ WHATSAPP_API_AUTHENTICATION_CLASSES = [
229
+ 'rest_framework.authentication.TokenAuthentication',
230
+ 'django_whatsapp_api_wrapper.authentication.APIKeyAuthentication',
231
+ ]
232
+ ```
233
+
234
+ ### Permissões Customizadas
235
+ ```python
236
+ # settings.py
237
+ WHATSAPP_API_PERMISSION_CLASSES = [
238
+ 'rest_framework.permissions.IsAuthenticated',
239
+ # ou 'rest_framework.permissions.IsAdminUser',
240
+ # ou 'myapp.permissions.CustomPermission',
241
+ ]
242
+ ```
243
+
145
244
  ## Templates
146
245
 
147
246
  Endpoints REST (DRF) para gerenciar Message Templates do WhatsApp (proxy para Graph API). Todos os endpoints abaixo partem do prefixo que você incluir no projeto, por exemplo: `.../whatsapp-api-wrapper/`.
148
247
 
248
+ **⚠️ Importante:** Todos os endpoints de templates requerem autenticação (veja seção Autenticação acima).
249
+
149
250
  Requisitos de ambiente: `WHATSAPP_CLOUD_API_TOKEN`, `WHATSAPP_CLOUD_API_VERSION`, `WHATSAPP_CLOUD_API_WABA_ID`.
150
251
 
151
252
  Aqui a documentação OFICIAL:
@@ -41,6 +41,35 @@ WHATSAPP_CLOUD_API_WABA_ID=
41
41
  WHATSAPP_CLOUD_API_VERIFY_TOKEN=
42
42
  ```
43
43
 
44
+ 4) Configure a autenticação para as rotas de templates (opcional, mas recomendado):
45
+
46
+ ```python
47
+ # settings.py
48
+
49
+ # Opção 1: Usar Token Authentication do DRF (padrão)
50
+ WHATSAPP_API_AUTHENTICATION_CLASSES = [
51
+ 'rest_framework.authentication.TokenAuthentication',
52
+ ]
53
+
54
+ # Opção 2: Usar JWT (se você já tem configurado)
55
+ WHATSAPP_API_AUTHENTICATION_CLASSES = [
56
+ 'rest_framework_simplejwt.authentication.JWTAuthentication',
57
+ ]
58
+
59
+ # Opção 3: Usar API Key simples
60
+ WHATSAPP_API_AUTHENTICATION_CLASSES = [
61
+ 'django_whatsapp_api_wrapper.authentication.APIKeyAuthentication',
62
+ ]
63
+ WHATSAPP_API_KEY = "sua_api_key_secreta_aqui"
64
+
65
+ # Permissões (padrão: IsAuthenticated)
66
+ WHATSAPP_API_PERMISSION_CLASSES = [
67
+ 'rest_framework.permissions.IsAuthenticated',
68
+ ]
69
+ ```
70
+
71
+ **Importante:** Se não configurar a autenticação, as rotas de templates usarão `TokenAuthentication` por padrão.
72
+
44
73
  O endpoint de webhook ficará disponível em:
45
74
 
46
75
  - GET/POST: `/whatsapp-api-wrapper/webhook/`
@@ -109,10 +138,82 @@ m2.send()
109
138
 
110
139
  ---
111
140
 
141
+ ## Autenticação
142
+
143
+ ### Proteção das Rotas de Templates
144
+
145
+ Por padrão, todas as rotas de templates (`/templates/`) são protegidas e requerem autenticação. O webhook permanece público (necessário para o WhatsApp).
146
+
147
+ ### Opções de Autenticação
148
+
149
+ #### 1. Token Authentication (Padrão)
150
+ ```python
151
+ # settings.py
152
+ WHATSAPP_API_AUTHENTICATION_CLASSES = [
153
+ 'rest_framework.authentication.TokenAuthentication',
154
+ ]
155
+ ```
156
+
157
+ Uso:
158
+ ```bash
159
+ curl -H "Authorization: Token seu_token_aqui" \
160
+ "$BASE/whatsapp-api-wrapper/templates/"
161
+ ```
162
+
163
+ #### 2. JWT Authentication
164
+ ```python
165
+ # settings.py
166
+ WHATSAPP_API_AUTHENTICATION_CLASSES = [
167
+ 'rest_framework_simplejwt.authentication.JWTAuthentication',
168
+ ]
169
+ ```
170
+
171
+ Uso:
172
+ ```bash
173
+ curl -H "Authorization: Bearer seu_jwt_token" \
174
+ "$BASE/whatsapp-api-wrapper/templates/"
175
+ ```
176
+
177
+ #### 3. API Key Authentication
178
+ ```python
179
+ # settings.py
180
+ WHATSAPP_API_AUTHENTICATION_CLASSES = [
181
+ 'django_whatsapp_api_wrapper.authentication.APIKeyAuthentication',
182
+ ]
183
+ WHATSAPP_API_KEY = "sua_api_key_secreta"
184
+ ```
185
+
186
+ Uso:
187
+ ```bash
188
+ curl -H "X-WhatsApp-API-Key: sua_api_key_secreta" \
189
+ "$BASE/whatsapp-api-wrapper/templates/"
190
+ ```
191
+
192
+ #### 4. Múltiplas Autenticações
193
+ ```python
194
+ # settings.py
195
+ WHATSAPP_API_AUTHENTICATION_CLASSES = [
196
+ 'rest_framework.authentication.TokenAuthentication',
197
+ 'django_whatsapp_api_wrapper.authentication.APIKeyAuthentication',
198
+ ]
199
+ ```
200
+
201
+ ### Permissões Customizadas
202
+ ```python
203
+ # settings.py
204
+ WHATSAPP_API_PERMISSION_CLASSES = [
205
+ 'rest_framework.permissions.IsAuthenticated',
206
+ # ou 'rest_framework.permissions.IsAdminUser',
207
+ # ou 'myapp.permissions.CustomPermission',
208
+ ]
209
+ ```
210
+
112
211
  ## Templates
113
212
 
114
213
  Endpoints REST (DRF) para gerenciar Message Templates do WhatsApp (proxy para Graph API). Todos os endpoints abaixo partem do prefixo que você incluir no projeto, por exemplo: `.../whatsapp-api-wrapper/`.
115
214
 
215
+ **⚠️ Importante:** Todos os endpoints de templates requerem autenticação (veja seção Autenticação acima).
216
+
116
217
  Requisitos de ambiente: `WHATSAPP_CLOUD_API_TOKEN`, `WHATSAPP_CLOUD_API_VERSION`, `WHATSAPP_CLOUD_API_WABA_ID`.
117
218
 
118
219
  Aqui a documentação OFICIAL:
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "django-whatsapp-api-wrapper"
3
- version = "0.2.2"
3
+ version = "0.3.0"
4
4
  description = ""
5
5
  authors = ["Your Name <you@example.com>"]
6
6
  readme = "README.md"
@@ -0,0 +1,4 @@
1
+ from .api_key import APIKeyAuthentication
2
+ from .base import BaseAuthenticatedAPIView
3
+
4
+ __all__ = ['APIKeyAuthentication', 'BaseAuthenticatedAPIView']
@@ -0,0 +1,32 @@
1
+ from django.contrib.auth.models import AnonymousUser
2
+ from django.conf import settings
3
+ from rest_framework import authentication
4
+ from rest_framework import exceptions
5
+
6
+
7
+ class APIKeyAuthentication(authentication.BaseAuthentication):
8
+ """
9
+ Simple API key authentication for WhatsApp API endpoints.
10
+
11
+ Clients should authenticate by passing the API key in the "X-WhatsApp-API-Key" header.
12
+ For example:
13
+ X-WhatsApp-API-Key: your_api_key_here
14
+ """
15
+
16
+ def authenticate(self, request):
17
+ api_key = request.META.get('HTTP_X_WHATSAPP_API_KEY')
18
+ if not api_key:
19
+ return None
20
+
21
+ expected_api_key = getattr(settings, 'WHATSAPP_API_KEY', None)
22
+ if not expected_api_key:
23
+ raise exceptions.AuthenticationFailed('WHATSAPP_API_KEY not configured in settings')
24
+
25
+ if api_key != expected_api_key:
26
+ raise exceptions.AuthenticationFailed('Invalid API key')
27
+
28
+ # Return a tuple of (user, auth) where user can be AnonymousUser for API key auth
29
+ return (AnonymousUser(), api_key)
30
+
31
+ def authenticate_header(self, request):
32
+ return 'X-WhatsApp-API-Key'
@@ -0,0 +1,54 @@
1
+ from django.conf import settings
2
+ from rest_framework.views import APIView
3
+ from rest_framework.authentication import TokenAuthentication
4
+ from rest_framework.permissions import IsAuthenticated
5
+
6
+
7
+ class BaseAuthenticatedAPIView(APIView):
8
+ """
9
+ Base API view with configurable authentication for WhatsApp API endpoints.
10
+
11
+ Authentication and permission classes can be configured via Django settings:
12
+
13
+ WHATSAPP_API_AUTHENTICATION_CLASSES = [
14
+ 'rest_framework.authentication.TokenAuthentication',
15
+ # or 'rest_framework_simplejwt.authentication.JWTAuthentication',
16
+ # or 'django_whatsapp_api_wrapper.authentication.APIKeyAuthentication',
17
+ ]
18
+
19
+ WHATSAPP_API_PERMISSION_CLASSES = [
20
+ 'rest_framework.permissions.IsAuthenticated',
21
+ ]
22
+ """
23
+
24
+ def __init__(self, *args, **kwargs):
25
+ super().__init__(*args, **kwargs)
26
+
27
+ # Get authentication classes from settings
28
+ auth_classes_setting = getattr(settings, 'WHATSAPP_API_AUTHENTICATION_CLASSES', None)
29
+ if auth_classes_setting:
30
+ self.authentication_classes = self._import_classes(auth_classes_setting)
31
+ else:
32
+ # Default to TokenAuthentication if no setting is provided
33
+ self.authentication_classes = [TokenAuthentication]
34
+
35
+ # Get permission classes from settings
36
+ perm_classes_setting = getattr(settings, 'WHATSAPP_API_PERMISSION_CLASSES', None)
37
+ if perm_classes_setting:
38
+ self.permission_classes = self._import_classes(perm_classes_setting)
39
+ else:
40
+ # Default to IsAuthenticated if no setting is provided
41
+ self.permission_classes = [IsAuthenticated]
42
+
43
+ def _import_classes(self, class_paths):
44
+ """Import classes from string paths."""
45
+ classes = []
46
+ for class_path in class_paths:
47
+ try:
48
+ module_path, class_name = class_path.rsplit('.', 1)
49
+ module = __import__(module_path, fromlist=[class_name])
50
+ cls = getattr(module, class_name)
51
+ classes.append(cls)
52
+ except (ImportError, AttributeError, ValueError) as e:
53
+ raise ImportError(f"Could not import '{class_path}': {e}")
54
+ return classes
@@ -1,7 +1,7 @@
1
- from rest_framework.views import APIView
2
1
  from rest_framework.response import Response
3
2
  from rest_framework import status
4
3
 
4
+ from ..authentication.base import BaseAuthenticatedAPIView
5
5
  from .client import TemplateAPI
6
6
  from .serializers import (
7
7
  TemplateCreateSerializer,
@@ -13,7 +13,7 @@ from .serializers import (
13
13
  )
14
14
 
15
15
 
16
- class TemplateByIdView(APIView):
16
+ class TemplateByIdView(BaseAuthenticatedAPIView):
17
17
  def get(self, request, template_id: str):
18
18
  api = TemplateAPI()
19
19
  resp = api.get_template_by_id(template_id)
@@ -27,7 +27,7 @@ class TemplateByIdView(APIView):
27
27
  return Response(resp.json() if resp.content else None, status=resp.status_code)
28
28
 
29
29
 
30
- class TemplateByNameView(APIView):
30
+ class TemplateByNameView(BaseAuthenticatedAPIView):
31
31
  def get(self, request):
32
32
  serializer = TemplateNameSerializer(data=request.query_params)
33
33
  serializer.is_valid(raise_exception=True)
@@ -43,7 +43,7 @@ class TemplateByNameView(APIView):
43
43
  return Response(resp.json() if resp.content else None, status=resp.status_code)
44
44
 
45
45
 
46
- class TemplateListCreateView(APIView):
46
+ class TemplateListCreateView(BaseAuthenticatedAPIView):
47
47
  def get(self, request):
48
48
  serializer = TemplateListQuerySerializer(data=request.query_params)
49
49
  serializer.is_valid(raise_exception=True)
@@ -59,14 +59,14 @@ class TemplateListCreateView(APIView):
59
59
  return Response(resp.json(), status=resp.status_code)
60
60
 
61
61
 
62
- class TemplateNamespaceView(APIView):
62
+ class TemplateNamespaceView(BaseAuthenticatedAPIView):
63
63
  def get(self, request):
64
64
  api = TemplateAPI()
65
65
  resp = api.get_namespace()
66
66
  return Response(resp.json(), status=resp.status_code)
67
67
 
68
68
 
69
- class TemplateDeleteByIdView(APIView):
69
+ class TemplateDeleteByIdView(BaseAuthenticatedAPIView):
70
70
  def delete(self, request):
71
71
  serializer = TemplateDeleteByIdSerializer(data=request.query_params)
72
72
  serializer.is_valid(raise_exception=True)