django-restit 4.2.62__py3-none-any.whl → 4.2.63__py3-none-any.whl
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.
- account/fcm/google.py +53 -0
- account/fcm/v1.py +47 -0
- account/models/device.py +30 -0
- account/models/feeds.py +2 -2
- auditlog/cloudwatch.py +93 -0
- auditlog/models.py +6 -1
- {django_restit-4.2.62.dist-info → django_restit-4.2.63.dist-info}/METADATA +1 -1
- {django_restit-4.2.62.dist-info → django_restit-4.2.63.dist-info}/RECORD +14 -11
- rest/__init__.py +1 -1
- taskqueue/models.py +12 -7
- taskqueue/transports/http.py +5 -1
- taskqueue/worker.py +2 -0
- {django_restit-4.2.62.dist-info → django_restit-4.2.63.dist-info}/LICENSE.md +0 -0
- {django_restit-4.2.62.dist-info → django_restit-4.2.63.dist-info}/WHEEL +0 -0
account/fcm/google.py
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
import json
|
2
|
+
import requests
|
3
|
+
import time
|
4
|
+
from jwt import JWT, jwk_from_dict
|
5
|
+
from datetime import datetime, timedelta
|
6
|
+
|
7
|
+
|
8
|
+
def oauthLogin(service_account_info):
|
9
|
+
# Token endpoint
|
10
|
+
token_uri = service_account_info["token_uri"]
|
11
|
+
|
12
|
+
# The current time and expiration time for the assertion
|
13
|
+
issued_at_time = datetime.utcnow()
|
14
|
+
expiration_time = issued_at_time + timedelta(minutes=60)
|
15
|
+
|
16
|
+
# JWT Header
|
17
|
+
jwt_header = {
|
18
|
+
"alg": "RS256",
|
19
|
+
"typ": "JWT",
|
20
|
+
"kid": service_account_info["private_key_id"]
|
21
|
+
}
|
22
|
+
|
23
|
+
# JWT Payload
|
24
|
+
jwt_payload = {
|
25
|
+
"iss": service_account_info["client_email"],
|
26
|
+
"sub": service_account_info["client_email"],
|
27
|
+
"aud": token_uri,
|
28
|
+
"iat": int(issued_at_time.timestamp()),
|
29
|
+
"exp": int(expiration_time.timestamp()),
|
30
|
+
"scope": "https://www.googleapis.com/auth/firebase.messaging"
|
31
|
+
}
|
32
|
+
|
33
|
+
# Create a JWT
|
34
|
+
jwt_instance = JWT()
|
35
|
+
private_key = jwk_from_dict({"k": service_account_info["private_key"], "kty": "RSA"})
|
36
|
+
assertion = jwt_instance.encode(jwt_header, jwt_payload, private_key)
|
37
|
+
|
38
|
+
# Exchange the JWT for an access token
|
39
|
+
response = requests.post(token_uri, data={
|
40
|
+
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
41
|
+
"assertion": assertion
|
42
|
+
})
|
43
|
+
|
44
|
+
response_data = response.json()
|
45
|
+
|
46
|
+
access_token = response_data.get("access_token")
|
47
|
+
expires_in = response_data.get("expires_in") # Seconds until the token expires
|
48
|
+
|
49
|
+
# You can now use this access_token to authenticate requests to Google APIs.
|
50
|
+
# Remember to refresh the token using a similar process once it's close to expiration.
|
51
|
+
|
52
|
+
print("Access Token:", access_token)
|
53
|
+
print("Expires In:", expires_in)
|
account/fcm/v1.py
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
from google.oauth2 import service_account
|
2
|
+
import google.auth.transport.requests
|
3
|
+
import requests
|
4
|
+
from rest import settings
|
5
|
+
from rest import log
|
6
|
+
|
7
|
+
|
8
|
+
FCM_ENDPOINT = 'https://fcm.googleapis.com/v1/projects/{}/messages:send'
|
9
|
+
|
10
|
+
logger = log.getLogger("fcm", filename="fcm.log")
|
11
|
+
|
12
|
+
|
13
|
+
def getCredentials(data):
|
14
|
+
# Load the credentials from the dictionary
|
15
|
+
credentials = service_account.Credentials.from_service_account_info(
|
16
|
+
data,
|
17
|
+
scopes=["https://www.googleapis.com/auth/firebase.messaging"])
|
18
|
+
# Use the credentials to authenticate a Requests session
|
19
|
+
auth_req = google.auth.transport.requests.Request()
|
20
|
+
credentials.refresh(auth_req)
|
21
|
+
return credentials
|
22
|
+
|
23
|
+
|
24
|
+
def sendToDevice(device, data):
|
25
|
+
return sendData(device.cm_token, data)
|
26
|
+
|
27
|
+
|
28
|
+
def sendNotification(to_token, title, body):
|
29
|
+
return postMessage(dict(token=to_token, notification=dict(title=title, body=body)))
|
30
|
+
|
31
|
+
|
32
|
+
def sendData(to_token, data, priority="high"):
|
33
|
+
return postMessage(dict(token=to_token, data=data, content_available=True, priority=priority))
|
34
|
+
|
35
|
+
|
36
|
+
def postMessage(credentials, payload):
|
37
|
+
logger.info("sending FCM", payload)
|
38
|
+
headers = {
|
39
|
+
'Authorization': 'Bearer ' + credentials.token,
|
40
|
+
'Content-Type': 'application/json; UTF-8',
|
41
|
+
}
|
42
|
+
body = dict(message=payload)
|
43
|
+
resp = requests.post(FCM_ENDPOINT.format(credentials.project_id), headers=headers, json=body)
|
44
|
+
logger.info("response", resp.text)
|
45
|
+
return resp
|
46
|
+
|
47
|
+
|
account/models/device.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
|
2
2
|
from django.db import models
|
3
3
|
from rest import models as rm
|
4
|
+
from rest import fields as rf
|
4
5
|
from rest import settings
|
5
6
|
from objict import objict
|
6
7
|
from datetime import datetime
|
@@ -110,7 +111,36 @@ class MemberDeviceMetaData(rm.MetaDataBase):
|
|
110
111
|
parent = models.ForeignKey(MemberDevice, related_name="properties", on_delete=models.CASCADE)
|
111
112
|
|
112
113
|
|
114
|
+
class CloudCredentials(models.Model, rm.RestModel, rm.MetaDataModel):
|
115
|
+
"""
|
116
|
+
MemberDevice Model tracks personal devices associated with a user.
|
117
|
+
This can include mobile and desktop devices.
|
118
|
+
"""
|
119
|
+
created = models.DateTimeField(auto_now_add=True)
|
120
|
+
modified = models.DateTimeField(auto_now=True)
|
121
|
+
group = models.ForeignKey("account.Group", related_name="cloud_credentials", on_delete=models.CASCADE)
|
122
|
+
|
123
|
+
name = models.CharField(max_length=128, blank=True, null=True, default=None)
|
124
|
+
uuid = models.CharField(db_index=True, max_length=64, blank=True, null=True, default=None)
|
125
|
+
state = models.IntegerField(db_index=True, default=1)
|
126
|
+
|
127
|
+
credentials = rf.JSONField()
|
128
|
+
|
129
|
+
def sendToDevice(self, device, message):
|
130
|
+
pass
|
131
|
+
|
132
|
+
def sendNotification(self, token, title, body):
|
133
|
+
pass
|
134
|
+
|
135
|
+
|
136
|
+
class CloudCredentialsMetaData(rm.MetaDataBase):
|
137
|
+
parent = models.ForeignKey(CloudCredentials, related_name="properties", on_delete=models.CASCADE)
|
138
|
+
|
139
|
+
|
113
140
|
def getCloudMessanger(name):
|
141
|
+
creds = CloudCredentials.objects.filter(uuid=name).last()
|
142
|
+
if creds is not None:
|
143
|
+
return creds
|
114
144
|
if name not in CM_BACKENDS:
|
115
145
|
if name == "fcm":
|
116
146
|
from account import fcm
|
account/models/feeds.py
CHANGED
@@ -39,9 +39,9 @@ class GroupFeed(FeedBase, rm.RestModel):
|
|
39
39
|
VIEW_PERMS = ["manage_groups", "manage_group", "view_all_groups"]
|
40
40
|
GRAPHS = {
|
41
41
|
"default": {
|
42
|
-
"recurse_into": ["generic__component"],
|
43
42
|
"graphs": {
|
44
|
-
"member": "basic"
|
43
|
+
"member": "basic",
|
44
|
+
"generic__component": "basic"
|
45
45
|
}
|
46
46
|
}
|
47
47
|
}
|
auditlog/cloudwatch.py
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
import boto3
|
2
|
+
import datetime
|
3
|
+
import time
|
4
|
+
import json
|
5
|
+
from objict import objict
|
6
|
+
from rest import settings
|
7
|
+
from concurrent.futures import ThreadPoolExecutor
|
8
|
+
|
9
|
+
|
10
|
+
LOG_CACHE = objict()
|
11
|
+
|
12
|
+
|
13
|
+
def getClient():
|
14
|
+
if LOG_CACHE.client is None:
|
15
|
+
key = settings.AWS_KEY
|
16
|
+
secret = settings.AWS_SECRET
|
17
|
+
region = settings.AWS_REGION
|
18
|
+
LOG_CACHE.client = boto3.client("logs", aws_access_key_id=key, aws_secret_access_key=secret, region_name=region)
|
19
|
+
return LOG_CACHE.client
|
20
|
+
|
21
|
+
|
22
|
+
def log(data, log_group, log_stream):
|
23
|
+
if LOG_CACHE.pool is None:
|
24
|
+
LOG_CACHE.pool = ThreadPoolExecutor(max_workers=1)
|
25
|
+
LOG_CACHE.pool.submit(logToCloudWatch, data, log_group, log_stream)
|
26
|
+
return True
|
27
|
+
|
28
|
+
|
29
|
+
def logToCloudWatch(data, log_group, log_stream):
|
30
|
+
message = data
|
31
|
+
if isinstance(message, dict):
|
32
|
+
message = json.dumps(message)
|
33
|
+
return logBatchToCloudWatch([
|
34
|
+
dict(
|
35
|
+
timestamp=int(datetime.datetime.utcnow().timestamp() * 1000),
|
36
|
+
message=message)
|
37
|
+
], log_group, log_stream)
|
38
|
+
|
39
|
+
|
40
|
+
def logBatchToCloudWatch(batch, log_group, log_stream):
|
41
|
+
return getClient().put_log_events(
|
42
|
+
logGroupName=log_group,
|
43
|
+
logStreamName=log_stream,
|
44
|
+
logEvents=batch
|
45
|
+
)
|
46
|
+
|
47
|
+
|
48
|
+
def getLogGroups():
|
49
|
+
response = getClient().describe_log_groups()
|
50
|
+
return response.get('logGroups', [])
|
51
|
+
|
52
|
+
|
53
|
+
def createLogStream(log_group, log_stream):
|
54
|
+
try:
|
55
|
+
getClient().create_log_stream(logGroupName=log_group, logStreamName=log_stream)
|
56
|
+
except Exception:
|
57
|
+
pass # Log stream already exists, no need to create it
|
58
|
+
|
59
|
+
|
60
|
+
def getInsights(log_group, start_time, end_time, query_string):
|
61
|
+
"""
|
62
|
+
Executes a CloudWatch Logs Insights query and returns the results.
|
63
|
+
|
64
|
+
:param log_group: The name of the log group to query.
|
65
|
+
:param start_time: The start time of the query (epoch time in seconds).
|
66
|
+
:param end_time: The end time of the query (epoch time in seconds).
|
67
|
+
:param query_string: The query string to use.
|
68
|
+
:param region_name: AWS region name.
|
69
|
+
:return: The query results.
|
70
|
+
"""
|
71
|
+
# Create a CloudWatch Logs client
|
72
|
+
client = getClient()
|
73
|
+
|
74
|
+
# Start the query
|
75
|
+
start_query_response = client.start_query(
|
76
|
+
logGroupName=log_group,
|
77
|
+
startTime=start_time,
|
78
|
+
endTime=end_time,
|
79
|
+
queryString=query_string,
|
80
|
+
)
|
81
|
+
|
82
|
+
query_id = start_query_response['queryId']
|
83
|
+
|
84
|
+
# Wait for the query to complete
|
85
|
+
response = None
|
86
|
+
while response is None or response['status'] == 'Running':
|
87
|
+
time.sleep(1) # Sleep to rate limit the polling
|
88
|
+
response = client.get_query_results(queryId=query_id)
|
89
|
+
|
90
|
+
if response['status'] == 'Complete':
|
91
|
+
return response['results']
|
92
|
+
else:
|
93
|
+
raise Exception(f"Query did not complete successfully. Status: {response['status']}")
|
auditlog/models.py
CHANGED
@@ -8,6 +8,7 @@ import copy
|
|
8
8
|
from rest.models import RestModel
|
9
9
|
from rest import helpers
|
10
10
|
from rest.log import getLogger
|
11
|
+
from auditlog import cloudwatch
|
11
12
|
|
12
13
|
import traceback
|
13
14
|
|
@@ -281,7 +282,9 @@ class PersistentLog(models.Model, RestModel):
|
|
281
282
|
|
282
283
|
@staticmethod
|
283
284
|
def log(message, level=0, request=None, component=None,
|
284
|
-
pkey=None, action=None, group=None, path=None,
|
285
|
+
pkey=None, action=None, group=None, path=None,
|
286
|
+
method=None, tid=None, no_truncate=False,
|
287
|
+
aws_log_group=None, aws_log_stream=None):
|
285
288
|
plog = PersistentLog.createLogFromRequest(
|
286
289
|
request, component=component, tid=tid, pkey=pkey, action=action, group=group,
|
287
290
|
path=path, method=method, level=level)
|
@@ -290,6 +293,8 @@ class PersistentLog(models.Model, RestModel):
|
|
290
293
|
|
291
294
|
try:
|
292
295
|
plog.save()
|
296
|
+
if aws_log_group and aws_log_stream:
|
297
|
+
cloudwatch.log(plog.toDict(), aws_log_group, aws_log_stream)
|
293
298
|
except Exception:
|
294
299
|
helpers.log_exception(plog.message)
|
295
300
|
|
@@ -1,6 +1,8 @@
|
|
1
1
|
account/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
2
|
account/admin.py,sha256=8MQ1gAgjpPUC_SGCVMwd7I8fqLetqcutLiasjssEPRY,1839
|
3
3
|
account/fcm/__init__.py,sha256=gSTChf99a5T20oKuf4Lh9UR-f3V5qI20AZxIhlPlnVs,980
|
4
|
+
account/fcm/google.py,sha256=T-TZZgrT90YY9sEtKC6rNGpwfBmVTCuFpB31vRDguu0,1710
|
5
|
+
account/fcm/v1.py,sha256=PGpSmAnq40cMao4SwDU2tv6m5PpteDWLbzvldjalRJ8,1434
|
4
6
|
account/migrations/0001_initial.py,sha256=PhYNDTiwjyUplErBmYc34ecynLIEJL2JuC02o8GCXes,15894
|
5
7
|
account/migrations/0003_member_phone_number.py,sha256=auAJCfxsK-y3Veo0vwZfrIZxvwHYBjg5CpYRgCWghCQ,738
|
6
8
|
account/migrations/0004_group_modified_alter_group_created.py,sha256=20iNFlUGtRCWUsxEqTJFRQKQ73z4REhfo-hGam8IHXY,551
|
@@ -21,8 +23,8 @@ account/migrations/0018_userpasskey.py,sha256=SdXYo4TkIeP5wLNfCza3Jq5-gKuUufzTHG
|
|
21
23
|
account/migrations/0019_group_location.py,sha256=EfMB_w4qWUGDqQeNc453PFZwpjpTeoA6xr6Qgo_YAOM,601
|
22
24
|
account/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
23
25
|
account/models/__init__.py,sha256=cV_lMnT2vL_mjiYtT4hlcIHo52ocFbGSNVkOIHHLXZY,385
|
24
|
-
account/models/device.py,sha256=
|
25
|
-
account/models/feeds.py,sha256=
|
26
|
+
account/models/device.py,sha256=9wq41JuP5hvDkGauZCDHF7hbRWsIAHwe1kP3uEQ0QI8,5220
|
27
|
+
account/models/feeds.py,sha256=vI7fG4ASY1M0Zjke24RdnfDcuWeATl_yR_25jPmT64g,2011
|
26
28
|
account/models/group.py,sha256=4fk-RavG1wNVzfuXMaD2XDiX2DhK1hgL0-OA54Uym18,21576
|
27
29
|
account/models/legacy.py,sha256=zYdtv4LC0ooxPVqWM-uToPwV-lYWQLorSE6p6yn1xDw,2720
|
28
30
|
account/models/member.py,sha256=CxxhNnFCQPEw7MGc5147J8eandYqUj6HhhQ_YRyFQX4,50397
|
@@ -57,11 +59,12 @@ account/templates/email/simple/reset_code.html,sha256=Dln4C8jC-PI1ToS-k2VpRUjXya
|
|
57
59
|
auditlog/README,sha256=q4DXhdz5CuMyuxYISHXzhlHnIkRJlojwOMchLzW2qOI,520
|
58
60
|
auditlog/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
59
61
|
auditlog/admin.py,sha256=-q7fstdFjNeDFfbwdrxVqy0WGKxMpBwrsM7AyG1p80g,1006
|
62
|
+
auditlog/cloudwatch.py,sha256=R-B_ByVM3We26YnDoFYIQeWV31CUyS63QTojRAkfWa8,2805
|
60
63
|
auditlog/decorators.py,sha256=ZoIv0fhZjxtMEV15NcKijW4xPF5UEScPna60zB3TxZo,6553
|
61
64
|
auditlog/middleware.py,sha256=Q4bXg8rnm8y2fMnAsN6ha3Fz6TW8jIzLnvpu4H9SpWE,1537
|
62
65
|
auditlog/migrations/0001_initial.py,sha256=X171gKQZIaTO9FGNG1yKTjGSZS0ZjZj5gvimF9-_kks,3309
|
63
66
|
auditlog/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
64
|
-
auditlog/models.py,sha256=
|
67
|
+
auditlog/models.py,sha256=skDAiuzR4chC-WNIaH2nm_VVcbnDD6ZtUxBwhk7UY8U,16517
|
65
68
|
auditlog/periodic.py,sha256=AUhDeVsZtC47BJ-lklvYEegHoxAzj1RpIvRFSsM7g5E,363
|
66
69
|
auditlog/rpc.py,sha256=lhme-ScqwVSKfHo3RlzMVm_C-Yx4xOxPogBEv7b3w1M,1720
|
67
70
|
auditlog/tq.py,sha256=OgzJVspWI6FL92GEhDPtabYoP_Hd3zGNh0E297abz3Y,2415
|
@@ -364,7 +367,7 @@ pushit/utils.py,sha256=IeTCGa-164nmB1jIsK1lu1O1QzUhS3BKfuXHGjCW-ck,2121
|
|
364
367
|
rest/.gitignore,sha256=TbEvWRMnAiajCTOdhiNrd9eeCAaIjRp9PRjE_VkMM5g,118
|
365
368
|
rest/README.md,sha256=V3ETc-cJu8PZIbKr9xSe_pA4JEUpC8Dhw4bQeVCDJPw,5460
|
366
369
|
rest/RemoteEvents.py,sha256=nL46U7AuxIrlw2JunphR1tsXyqi-ep_gD9CYGpYbNgE,72
|
367
|
-
rest/__init__.py,sha256=
|
370
|
+
rest/__init__.py,sha256=bERP1K_f9PlA9V_pCBU1-PcbHQxiWC19_283DRHe10o,121
|
368
371
|
rest/arc4.py,sha256=y644IbF1ec--e4cUJ3KEYsewTCITK0gmlwa5mJruFC0,1967
|
369
372
|
rest/cache.py,sha256=1Qg0rkaCJCaVP0-l5hZg2CIblTdeBSlj_0fP6vlKUpU,83
|
370
373
|
rest/crypto/__init__.py,sha256=Tl0U11rgj1eBYqd6OXJ2_XSdNLumW_JkBZnaJqI6Ldw,72
|
@@ -445,17 +448,17 @@ taskqueue/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
445
448
|
taskqueue/admin.py,sha256=E6zXoToS_ea3MdoGjZzF1JiepWFtDSoZUQdan8H-pXI,208
|
446
449
|
taskqueue/migrations/0001_initial.py,sha256=JwYib8CK5ftSXlfxKZUcKEEVsXktNB5q3h-2tu9inGk,4738
|
447
450
|
taskqueue/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
448
|
-
taskqueue/models.py,sha256=
|
451
|
+
taskqueue/models.py,sha256=N3_9jWHPGzs6UxlAzpjst6qPhvIs1RELTy1cMXMeXsA,22407
|
449
452
|
taskqueue/periodic.py,sha256=2i0271khrCow3hDmlNEcoAZnesBVl40jd7MIim2Cxs4,3543
|
450
453
|
taskqueue/rpc.py,sha256=If5E9D9AR2RqW4lHRaDuD9L9b9ZfL_PaBQ6iX91ehvU,5736
|
451
454
|
taskqueue/tq.py,sha256=PzSoDrawYcqZylruEgsK95gcJ4J_VhdM6rxg9V6_X8E,942
|
452
455
|
taskqueue/transports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
453
456
|
taskqueue/transports/email.py,sha256=H4GaomiyCck5R_AOcsrMawCl-_Bp_Zg-uWto9t1Xcoo,623
|
454
|
-
taskqueue/transports/http.py,sha256=
|
457
|
+
taskqueue/transports/http.py,sha256=AzliUnw_LuyO2zZZOoUAJGFcTV-Gxt1iE3hCVnIiyGQ,839
|
455
458
|
taskqueue/transports/s3.py,sha256=fMosL893u1iQdo6Y1djwb7KEoNo6TTsDPJl13OJdJP8,1913
|
456
459
|
taskqueue/transports/sftp.py,sha256=jT1_krjTHA7DCAukD85aGYRCg9m0cEH9EWzOC-wJGdk,1891
|
457
460
|
taskqueue/transports/sms.py,sha256=H1-LIGEMfbUNqJD9amRcsvKUSwtz9yBj1QNfB7EHjHE,142
|
458
|
-
taskqueue/worker.py,sha256=
|
461
|
+
taskqueue/worker.py,sha256=wzp44fk6LX94MdrXLp_IJmWgutLCBKqoobk433OiLqw,15822
|
459
462
|
telephony/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
460
463
|
telephony/admin.py,sha256=iOdsBfFFbBisdqKSZ36bIrh_z5sU0Wx_PkaFi8wd1iA,243
|
461
464
|
telephony/decorators.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -497,7 +500,7 @@ ws4redis/servers/uwsgi.py,sha256=VyhoCI1DnVFqBiJYHoxqn5Idlf6uJPHvfBKgkjs34mo,172
|
|
497
500
|
ws4redis/settings.py,sha256=K0yBiLUuY81iDM4Yr-k8hbvjn5VVHu5zQhmMK8Dtz0s,1536
|
498
501
|
ws4redis/utf8validator.py,sha256=S0OlfjeGRP75aO6CzZsF4oTjRQAgR17OWE9rgZdMBZA,5122
|
499
502
|
ws4redis/websocket.py,sha256=R0TUyPsoVRD7Y_oU7w2I6NL4fPwiz5Vl94-fUkZgLHA,14848
|
500
|
-
django_restit-4.2.
|
501
|
-
django_restit-4.2.
|
502
|
-
django_restit-4.2.
|
503
|
-
django_restit-4.2.
|
503
|
+
django_restit-4.2.63.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
|
504
|
+
django_restit-4.2.63.dist-info/METADATA,sha256=152iRXbYrfis4DIYRd86mMH6UeHPVTtKD8H2B0RgMD0,7594
|
505
|
+
django_restit-4.2.63.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
|
506
|
+
django_restit-4.2.63.dist-info/RECORD,,
|
rest/__init__.py
CHANGED
taskqueue/models.py
CHANGED
@@ -226,23 +226,25 @@ class Task(models.Model, RestModel):
|
|
226
226
|
self.state = TASK_STATE_COMPLETED
|
227
227
|
self.save()
|
228
228
|
|
229
|
-
def failed(self, reason=None):
|
229
|
+
def failed(self, reason=None, category="taskqueue_errors"):
|
230
230
|
if reason and len(reason) > 250:
|
231
231
|
reason = reason[:250]
|
232
232
|
self.reason = reason
|
233
233
|
self.state = TASK_STATE_FAILED
|
234
|
-
self.notifyError()
|
234
|
+
self.notifyError(category=category, reason=reason)
|
235
235
|
self.save()
|
236
236
|
|
237
|
-
def notifyError(self):
|
238
|
-
handler = f"{self.model}{self.fname}"
|
237
|
+
def notifyError(self, category="taskqueue_errors", reason=None):
|
238
|
+
handler = f"{self.model}.{self.fname}"
|
239
239
|
subject = f"TaskQueue - {handler}"
|
240
|
+
if reason is None:
|
241
|
+
reason = self.reason
|
240
242
|
|
241
|
-
msg = f"{handler}<br>\n{
|
243
|
+
msg = f"{handler}<br>\n{reason}"
|
242
244
|
metadata = {
|
243
245
|
"server": settings.get("HOSTNAME", "unknown"),
|
244
246
|
"task": self.pk,
|
245
|
-
"reason":
|
247
|
+
"reason": reason,
|
246
248
|
"app": self.model,
|
247
249
|
"fname": self.fname,
|
248
250
|
"channel": self.channel,
|
@@ -253,6 +255,9 @@ class Task(models.Model, RestModel):
|
|
253
255
|
if self.data:
|
254
256
|
if self.data.url:
|
255
257
|
metadata["url"] = self.data.url
|
258
|
+
from urllib.parse import urlparse
|
259
|
+
purl = urlparse(self.data.url)
|
260
|
+
metadata["host"] = purl.netloc
|
256
261
|
msg = f"{msg}<br>\n{self.data.url}"
|
257
262
|
if self.data.log_component:
|
258
263
|
metadata["component"] = self.data.log_component
|
@@ -261,7 +266,7 @@ class Task(models.Model, RestModel):
|
|
261
266
|
try:
|
262
267
|
import incident
|
263
268
|
incident.event_now(
|
264
|
-
|
269
|
+
category, description=subject, details=msg,
|
265
270
|
level=3, metadata=metadata)
|
266
271
|
except Exception as err:
|
267
272
|
self.log(str(err), kind="error")
|
taskqueue/transports/http.py
CHANGED
@@ -15,9 +15,13 @@ def REQUEST(task):
|
|
15
15
|
data=task.data.data, raw_response=True,
|
16
16
|
verify=False, timeout=REQ_TIMEOUT)
|
17
17
|
task.log(resp.text, kind="response")
|
18
|
-
|
18
|
+
if resp.status_code == 200:
|
19
|
+
return True
|
20
|
+
task.reason = f"invalid response of {resp.status_code}"
|
19
21
|
except requests.Timeout:
|
22
|
+
task.reason = "request timed out"
|
20
23
|
task.log("request timed out", kind="error")
|
21
24
|
except Exception as err:
|
25
|
+
task.reason = str(err)
|
22
26
|
task.log_exception(err)
|
23
27
|
return False
|
taskqueue/worker.py
CHANGED
@@ -198,6 +198,8 @@ class WorkManager(object):
|
|
198
198
|
task.completed()
|
199
199
|
elif task.attempts < task.max_attempts:
|
200
200
|
# -1 will auto calculate retry with back off
|
201
|
+
# lets report the issue
|
202
|
+
task.notifyError(reason=task.reason)
|
201
203
|
task.retry_later(from_now_secs=-1)
|
202
204
|
else:
|
203
205
|
task.failed("max attempts")
|
File without changes
|
File without changes
|