django-restit 4.2.176__py3-none-any.whl → 4.2.178__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/models/group.py +1 -0
- account/models/member.py +7 -1
- {django_restit-4.2.176.dist-info → django_restit-4.2.178.dist-info}/METADATA +1 -1
- {django_restit-4.2.176.dist-info → django_restit-4.2.178.dist-info}/RECORD +13 -12
- inbox/utils/render.py +10 -3
- medialib/models.py +4 -7
- metrics/client.py +3 -4
- rest/__init__.py +1 -1
- rest/filetypes.py +128 -0
- rest/mail.py +3 -2
- rest/models/base.py +3 -3
- {django_restit-4.2.176.dist-info → django_restit-4.2.178.dist-info}/LICENSE.md +0 -0
- {django_restit-4.2.176.dist-info → django_restit-4.2.178.dist-info}/WHEEL +0 -0
account/models/group.py
CHANGED
account/models/member.py
CHANGED
@@ -72,6 +72,7 @@ class Member(User, RestModel, MetaDataModel):
|
|
72
72
|
SEARCH_FIELDS = ["username", "email", "first_name", "last_name", "display_name", "phone_number"]
|
73
73
|
VIEW_PERMS = ["view_members", "manage_members", "manage_users", "owner"]
|
74
74
|
SAVE_PERMS = ["invite_members", "manage_members", "manage_users", "owner"]
|
75
|
+
CAN_BATCH = True
|
75
76
|
LIST_DEFAULT_FILTERS = {
|
76
77
|
"is_active": True
|
77
78
|
}
|
@@ -988,7 +989,12 @@ class Member(User, RestModel, MetaDataModel):
|
|
988
989
|
request.member.log("permission_denied", "attempting to set password for user: {}".format(self.username), method="password_change", level=3)
|
989
990
|
raise PermissionDeniedException("Permission Denied: attempting to change password")
|
990
991
|
if request.member.id != self.id:
|
991
|
-
self.
|
992
|
+
error = f"{self.username} password changed by: {request.member.username}"
|
993
|
+
self.reportIncident("account", error, details=error, error_code=497)
|
994
|
+
self.log("modified_by", error, method="password_change", level=31)
|
995
|
+
|
996
|
+
error = f"{self.username} password changed by: {request.member.username}"
|
997
|
+
request.member.reportIncident("account", error, details=error, error_code=497)
|
992
998
|
request.member.log("member_edit", "{} password changed".format(self.username), method="password_change", level=31)
|
993
999
|
self.setPassword(value, skip_history=True)
|
994
1000
|
else:
|
@@ -29,9 +29,9 @@ account/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
|
|
29
29
|
account/models/__init__.py,sha256=cV_lMnT2vL_mjiYtT4hlcIHo52ocFbGSNVkOIHHLXZY,385
|
30
30
|
account/models/device.py,sha256=8D-Sbv9PZWAnX6UVpp1lNJ03P24fknNnN1VOhqY7RVg,6306
|
31
31
|
account/models/feeds.py,sha256=vI7fG4ASY1M0Zjke24RdnfDcuWeATl_yR_25jPmT64g,2011
|
32
|
-
account/models/group.py,sha256=
|
32
|
+
account/models/group.py,sha256=Pmm6G5Qb9C-OQ70xUxp5M1_PAg1DtvUxb5WFFW-WmOY,22909
|
33
33
|
account/models/legacy.py,sha256=zYdtv4LC0ooxPVqWM-uToPwV-lYWQLorSE6p6yn1xDw,2720
|
34
|
-
account/models/member.py,sha256=
|
34
|
+
account/models/member.py,sha256=xlX0yqE3yFwPaZkcdU4e3g3yTommHimsLG8wBp09x90,55376
|
35
35
|
account/models/membership.py,sha256=90EpAhOsGaqphDAkONP6j_qQ0OWSRaQsI8H7E7fgMkE,9249
|
36
36
|
account/models/notify.py,sha256=YKYEXT56i98b7-ydLt5UuEVOqW7lipQMi-KuiPhcSwY,15627
|
37
37
|
account/models/passkeys.py,sha256=lObapudvL--ABSTZTIELmYvHE3dPF0tO_KmuYk0ZJXc,1699
|
@@ -93,7 +93,7 @@ inbox/models/template.py,sha256=i5vf0vsM1U0251UmVsF61MDCV_c7xt-zdCdx1SiKOG0,1013
|
|
93
93
|
inbox/rpc.py,sha256=7JXvpXlEGKG7by_NkANPGYLCzagyCnTIGM4rme_htpk,1534
|
94
94
|
inbox/utils/__init__.py,sha256=P_UR2rGK3L0tZNlTN-mf99tpeYM-tLkA18iDKXSSLDM,89
|
95
95
|
inbox/utils/parsing.py,sha256=y_71dwz8bm3JvF35ol8698XJ36sBF8fQWUrn0sYd2Fs,5597
|
96
|
-
inbox/utils/render.py,sha256=
|
96
|
+
inbox/utils/render.py,sha256=Jk_YYY6uztURh0qQfDDZYpOj9awvqkqkAaBmwJIWivU,4543
|
97
97
|
inbox/utils/sending.py,sha256=BKelTZnbkdSLGpjOY6IRTrzj-Hnw2pPZ7RYQGwe-tqk,2179
|
98
98
|
incident/README.md,sha256=4vbZTJj7uUmq8rogYngxqNYjFTlBOujfWUGheLoFKMc,1114
|
99
99
|
incident/__init__.py,sha256=FXNMmcGP6YAKjwik84ppze33uL0kDTa7YFr3aOEXhhk,3658
|
@@ -177,7 +177,7 @@ medialib/forms.py,sha256=nrE6QTPNPiIeX7Nx4l9DEmAQeQXqFyCg1C3JEDBYJfE,5442
|
|
177
177
|
medialib/migrations/0001_initial.py,sha256=H3JliH5aw7tiHef8MhrJr_9rGetqgA7UjTF-eKziRSM,20518
|
178
178
|
medialib/migrations/0002_alter_mediaitemrendition_bytes.py,sha256=igC1R02smbNoWlk2T4uCi9cNilOsxGKD-D24fQv92dM,414
|
179
179
|
medialib/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
180
|
-
medialib/models.py,sha256=
|
180
|
+
medialib/models.py,sha256=V-ouyUVgPKDIVvzGyqSoMWdhSBV8ZXHQKLXEyOTLAx0,54976
|
181
181
|
medialib/ocr.py,sha256=zlP7-NBiXhW7jR9pljmEPl5xzLVZpLN5QLAELQgU0Fk,1189
|
182
182
|
medialib/pdf.py,sha256=l28WwM0JKbT9boV-b_9TFh9jhvGcrquR8GqC8wfEaLk,1275
|
183
183
|
medialib/qrcode.py,sha256=vHyA5egXOX70EFiUDgr1njI9zcF6bXQJ_hKAQrppRow,545
|
@@ -339,7 +339,7 @@ medialib/youtube/upload.py,sha256=MTuPxm1ZC-y5pXAGtLNtp1hBSNZgCKYt1ewP5hwMQHI,28
|
|
339
339
|
medialib/youtube/uritemplate/__init__.py,sha256=ONWR_KRz9au0O-XUUTrO_UN7GHTmZCTKyvflUQb8wxM,4996
|
340
340
|
metrics/README.md,sha256=YwbCA2y6xJBlaO6yEtl1zWpqrQ4ZzkQSuQT-h6btET8,2307
|
341
341
|
metrics/__init__.py,sha256=70sdDZGOwGIEFWgDkHWPMVODFelo206jp1g-BFV2u_4,90
|
342
|
-
metrics/client.py,sha256
|
342
|
+
metrics/client.py,sha256=-YPZfNJqbg86V3rmHTDx_raRLaZDjzKmFIl6BjeSHN4,25565
|
343
343
|
metrics/eod.py,sha256=gnq-tNE7xfm2ah52e2TUyERgUQNwkFuT2rtDv8XOUVQ,9182
|
344
344
|
metrics/examples/eod_example.py,sha256=gYtansjsKILVxe8XJD12XPaxmBJ-B6dOXGZG2JTGWA8,1664
|
345
345
|
metrics/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -380,7 +380,7 @@ pushit/utils.py,sha256=IeTCGa-164nmB1jIsK1lu1O1QzUhS3BKfuXHGjCW-ck,2121
|
|
380
380
|
rest/.gitignore,sha256=TbEvWRMnAiajCTOdhiNrd9eeCAaIjRp9PRjE_VkMM5g,118
|
381
381
|
rest/README.md,sha256=V3ETc-cJu8PZIbKr9xSe_pA4JEUpC8Dhw4bQeVCDJPw,5460
|
382
382
|
rest/RemoteEvents.py,sha256=nL46U7AuxIrlw2JunphR1tsXyqi-ep_gD9CYGpYbNgE,72
|
383
|
-
rest/__init__.py,sha256=
|
383
|
+
rest/__init__.py,sha256=BF5iQVc_58Sj3--bfe7Nv0kMyoAmtLcNU6EnH6vA1bU,122
|
384
384
|
rest/arc4.py,sha256=y644IbF1ec--e4cUJ3KEYsewTCITK0gmlwa5mJruFC0,1967
|
385
385
|
rest/cache.py,sha256=1Qg0rkaCJCaVP0-l5hZg2CIblTdeBSlj_0fP6vlKUpU,83
|
386
386
|
rest/crypto/__init__.py,sha256=Tl0U11rgj1eBYqd6OXJ2_XSdNLumW_JkBZnaJqI6Ldw,72
|
@@ -395,12 +395,13 @@ rest/extra/__init__.py,sha256=YzmNsch5H5FFLkUK9mIAKyoRK_rJCA9HGb0kubp4h30,54
|
|
395
395
|
rest/extra/hostinfo.py,sha256=5R23EafcNbFARyNEqdjBkqcpC8rPfmPd1zqNqle6-nM,4298
|
396
396
|
rest/extra/json_metadata.py,sha256=p_ffzmANmOFix_oC3voR6_NNTjcn7-T7aXcH-I4_Npg,1078
|
397
397
|
rest/fields.py,sha256=_v1TJVc6vyWlqmwFRJ6mtuR5Fo-lS0KcUhPWIrzKZUo,9719
|
398
|
+
rest/filetypes.py,sha256=wZXljB1g6JbA5H41xC81Jk3Wy_gu64ecNKU4k7aMcig,4171
|
398
399
|
rest/forms.py,sha256=66Wm5cdy8tKib_mGicjq_yd-gNVMFWRECnrDksnNnwU,6316
|
399
400
|
rest/helpers.py,sha256=t7smlOUzchVno-zeq7xMJIwogAR2DeSrffWxgysOHX8,29531
|
400
401
|
rest/joke.py,sha256=0PpKaX2iN7jlS62kgjfmmqkFBYLPURz15aQ8R7OJkJ8,260
|
401
402
|
rest/jwtoken.py,sha256=F7Vvpm31rAplTXr8XFP-Lb4BnDB3j1B2nQq0P1iTCLQ,2576
|
402
403
|
rest/log.py,sha256=hd1_4HBOS395sfXJIL6BTw9yekm1SLgBwYx_PdfIhKA,20930
|
403
|
-
rest/mail.py,sha256=
|
404
|
+
rest/mail.py,sha256=rp88V-SVM9F6ZIupoyrQvDwArhG0mfbzjHrDBRiHbvI,8204
|
404
405
|
rest/mailman.py,sha256=v5O1G5s3HiAKmz-J1z0uT6_q3xsONPpxVl9saEyQQ2I,9174
|
405
406
|
rest/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
406
407
|
rest/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -413,7 +414,7 @@ rest/middleware/request.py,sha256=JchRNy5L-bGd-7h-KFYekGRvREe2eCkZXKOYqIkP2hI,41
|
|
413
414
|
rest/middleware/session.py,sha256=zHSoQpIzRLmpqr_JvW406wzpvU3W3gDbm5JhtzLAMlE,10240
|
414
415
|
rest/middleware/session_store.py,sha256=1nSdeXK8PyuYgGgIufqrS6j6QpIrQ7zbMNT0ol75e6U,1901
|
415
416
|
rest/models/__init__.py,sha256=M8pvFDq-WCF-QcM58X7pMufYYe0aaQ3U0PwGe9TKbbY,130
|
416
|
-
rest/models/base.py,sha256=
|
417
|
+
rest/models/base.py,sha256=lbl20SK27Dsz3N6wcbBVEscrZ2n3VDZZH-gnqFgZz9s,72637
|
417
418
|
rest/models/cacher.py,sha256=eKz8TINVhWEqKhJGMsRkKZTtBUIv5rN3NHbZwOC56Uk,578
|
418
419
|
rest/models/metadata.py,sha256=ni8-BRF07lv4CdPUWnUdfPTOClQAVEeRZvO-ic623HU,12904
|
419
420
|
rest/net.py,sha256=LcB2QV6VNRtsSdmiQvYZgwQUDwOPMn_VBdRiZ6OpI-I,2974
|
@@ -517,7 +518,7 @@ ws4redis/servers/uwsgi.py,sha256=VyhoCI1DnVFqBiJYHoxqn5Idlf6uJPHvfBKgkjs34mo,172
|
|
517
518
|
ws4redis/settings.py,sha256=KKq00EwoGnz1yLwCZr5Dfoq2izivmAdsNEEM4EhZwN4,1610
|
518
519
|
ws4redis/utf8validator.py,sha256=S0OlfjeGRP75aO6CzZsF4oTjRQAgR17OWE9rgZdMBZA,5122
|
519
520
|
ws4redis/websocket.py,sha256=R0TUyPsoVRD7Y_oU7w2I6NL4fPwiz5Vl94-fUkZgLHA,14848
|
520
|
-
django_restit-4.2.
|
521
|
-
django_restit-4.2.
|
522
|
-
django_restit-4.2.
|
523
|
-
django_restit-4.2.
|
521
|
+
django_restit-4.2.178.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
|
522
|
+
django_restit-4.2.178.dist-info/METADATA,sha256=7mIBsuAJDUF-6Mbw7FgAVHoc7zqWDFiIKuLpbbieMZ8,7714
|
523
|
+
django_restit-4.2.178.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
524
|
+
django_restit-4.2.178.dist-info/RECORD,,
|
inbox/utils/render.py
CHANGED
@@ -12,10 +12,17 @@ import re
|
|
12
12
|
|
13
13
|
|
14
14
|
def createMessage(sender, recipients, subject, text, html, attachments=None, replyto=None):
|
15
|
-
message = objict(sender=sender, recipients=recipients)
|
16
15
|
|
17
|
-
if
|
18
|
-
|
16
|
+
if isinstance(recipients, str):
|
17
|
+
if "," in recipients:
|
18
|
+
recipients = [t.strip() for t in recipients.split(',')]
|
19
|
+
elif ";" in recipients:
|
20
|
+
recipients = [t.strip() for t in recipients.split(';')]
|
21
|
+
|
22
|
+
if not isinstance(recipients, (tuple, list)):
|
23
|
+
recipients = [recipients]
|
24
|
+
|
25
|
+
message = objict(sender=sender, recipients=recipients)
|
19
26
|
|
20
27
|
if attachments is None:
|
21
28
|
attachments = []
|
medialib/models.py
CHANGED
@@ -16,16 +16,14 @@ import urllib.request, urllib.error, urllib.parse
|
|
16
16
|
from urllib.parse import urlparse
|
17
17
|
from datetime import datetime, date
|
18
18
|
import os
|
19
|
-
import hashlib
|
20
19
|
import time
|
21
|
-
import mimetypes
|
22
20
|
import tempfile
|
23
21
|
import re
|
24
22
|
|
25
23
|
from medialib import utils
|
26
24
|
from rest import settings
|
27
25
|
from rest.models import RestModel, MetaDataBase, MetaDataModel
|
28
|
-
from rest
|
26
|
+
from rest import filetypes
|
29
27
|
|
30
28
|
from taskqueue.models import Task
|
31
29
|
|
@@ -547,7 +545,7 @@ class MediaItem(models.Model, RestModel, MetaDataModel):
|
|
547
545
|
if kind in ["png", "jpg", "jpeg", "jfif", "bmp", "gif", "tif"]:
|
548
546
|
self.kind = "I"
|
549
547
|
return
|
550
|
-
|
548
|
+
mt = filetypes.guess_type(filename)
|
551
549
|
if mt == None:
|
552
550
|
self.kind = '*'
|
553
551
|
elif mt[:6] == 'image/':
|
@@ -833,7 +831,7 @@ class MediaItem(models.Model, RestModel, MetaDataModel):
|
|
833
831
|
return image
|
834
832
|
return {
|
835
833
|
"kind": image.kind,
|
836
|
-
"content_type":
|
834
|
+
"content_type": filetypes.guess_type(image.url),
|
837
835
|
"bytes":image.bytes,
|
838
836
|
"url":image.view_url(request=request, expires=None, is_secure=True),
|
839
837
|
"width":image.width,
|
@@ -860,7 +858,7 @@ class MediaItem(models.Model, RestModel, MetaDataModel):
|
|
860
858
|
return None
|
861
859
|
return {
|
862
860
|
"kind": orig.kind,
|
863
|
-
"content_type":
|
861
|
+
"content_type": filetypes.guess_type(self.name),
|
864
862
|
"bytes":orig.bytes,
|
865
863
|
"url":orig.view_url(request=request, expires=None, is_secure=True),
|
866
864
|
"width":orig.width,
|
@@ -1466,4 +1464,3 @@ class MediaItemParameterSetting(models.Model):
|
|
1466
1464
|
|
1467
1465
|
def __str__(self):
|
1468
1466
|
return "%s - %s" % (str(self.item), str(self.parameter))
|
1469
|
-
|
metrics/client.py
CHANGED
@@ -329,7 +329,7 @@ class R(object):
|
|
329
329
|
for s in slug:
|
330
330
|
self.metric(s, num, category, expire, date)
|
331
331
|
return
|
332
|
-
|
332
|
+
|
333
333
|
# Add the slug to the set of metric slugs
|
334
334
|
try:
|
335
335
|
self.r.sadd(self._metric_slugs_key, slug)
|
@@ -382,12 +382,12 @@ class R(object):
|
|
382
382
|
keys = utils.build_keys(slug, min_granularity=min_granularity, max_granularity=max_granularity)
|
383
383
|
|
384
384
|
for granularity, key in zip(granularities, keys):
|
385
|
-
rh.debug("-- get_metric --", granularity, key)
|
385
|
+
# rh.debug("-- get_metric --", granularity, key)
|
386
386
|
try:
|
387
387
|
results[granularity] = int(self.r.get(key))
|
388
388
|
except Exception:
|
389
389
|
results[granularity] = 0
|
390
|
-
rh.log_exception("get_metric", granularity, key)
|
390
|
+
# rh.log_exception("get_metric", granularity, key)
|
391
391
|
if min_granularity and min_granularity == max_granularity:
|
392
392
|
return results[min_granularity]
|
393
393
|
return results
|
@@ -661,4 +661,3 @@ class R(object):
|
|
661
661
|
key = self._gauge_key(slug)
|
662
662
|
self.r.delete(key) # Remove the Gauge
|
663
663
|
self.r.srem(self._gauge_slugs_key, slug) # Remove from the set of keys
|
664
|
-
|
rest/__init__.py
CHANGED
rest/filetypes.py
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
EXTENSION_TO_MIME = {
|
2
|
+
# Documents
|
3
|
+
'.pdf': 'application/pdf',
|
4
|
+
'.doc': 'application/msword',
|
5
|
+
'.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
6
|
+
'.xls': 'application/vnd.ms-excel',
|
7
|
+
'.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
8
|
+
'.ppt': 'application/vnd.ms-powerpoint',
|
9
|
+
'.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
10
|
+
'.csv': 'text/csv',
|
11
|
+
'.tsv': 'text/tab-separated-values',
|
12
|
+
'.txt': 'text/plain',
|
13
|
+
'.rtf': 'application/rtf',
|
14
|
+
'.odt': 'application/vnd.oasis.opendocument.text',
|
15
|
+
'.ods': 'application/vnd.oasis.opendocument.spreadsheet',
|
16
|
+
'.md': 'text/markdown',
|
17
|
+
'.epub': 'application/epub+zip',
|
18
|
+
'.ics': 'text/calendar',
|
19
|
+
|
20
|
+
# Images
|
21
|
+
'.jpg': 'image/jpeg',
|
22
|
+
'.jpeg': 'image/jpeg',
|
23
|
+
'.png': 'image/png',
|
24
|
+
'.gif': 'image/gif',
|
25
|
+
'.bmp': 'image/bmp',
|
26
|
+
'.webp': 'image/webp',
|
27
|
+
'.tiff': 'image/tiff',
|
28
|
+
'.svg': 'image/svg+xml',
|
29
|
+
'.heic': 'image/heic',
|
30
|
+
'.ico': 'image/vnd.microsoft.icon',
|
31
|
+
|
32
|
+
# Audio
|
33
|
+
'.mp3': 'audio/mpeg',
|
34
|
+
'.wav': 'audio/wav',
|
35
|
+
'.ogg': 'audio/ogg',
|
36
|
+
'.m4a': 'audio/mp4',
|
37
|
+
'.flac': 'audio/flac',
|
38
|
+
|
39
|
+
# Video
|
40
|
+
'.mp4': 'video/mp4',
|
41
|
+
'.mov': 'video/quicktime',
|
42
|
+
'.avi': 'video/x-msvideo',
|
43
|
+
'.wmv': 'video/x-ms-wmv',
|
44
|
+
'.webm': 'video/webm',
|
45
|
+
'.mkv': 'video/x-matroska',
|
46
|
+
|
47
|
+
# Archives
|
48
|
+
'.zip': 'application/zip',
|
49
|
+
'.tar': 'application/x-tar',
|
50
|
+
'.gz': 'application/gzip',
|
51
|
+
'.rar': 'application/vnd.rar',
|
52
|
+
'.7z': 'application/x-7z-compressed',
|
53
|
+
'.tar.gz': 'application/gzip', # Special case
|
54
|
+
'.tgz': 'application/gzip',
|
55
|
+
'.bz2': 'application/x-bzip2',
|
56
|
+
'.tar.bz2': 'application/x-bzip2',
|
57
|
+
|
58
|
+
# Code / Data
|
59
|
+
'.json': 'application/json',
|
60
|
+
'.xml': 'application/xml',
|
61
|
+
'.html': 'text/html',
|
62
|
+
'.htm': 'text/html',
|
63
|
+
'.css': 'text/css',
|
64
|
+
'.js': 'application/javascript',
|
65
|
+
'.py': 'text/x-python',
|
66
|
+
'.java': 'text/x-java-source',
|
67
|
+
'.c': 'text/x-c',
|
68
|
+
'.cpp': 'text/x-c++',
|
69
|
+
'.ts': 'application/typescript',
|
70
|
+
'.yml': 'application/x-yaml',
|
71
|
+
'.yaml': 'application/x-yaml',
|
72
|
+
'.sql': 'application/sql',
|
73
|
+
|
74
|
+
# Fonts
|
75
|
+
'.woff': 'font/woff',
|
76
|
+
'.woff2': 'font/woff2',
|
77
|
+
'.ttf': 'font/ttf',
|
78
|
+
'.otf': 'font/otf',
|
79
|
+
|
80
|
+
# Misc
|
81
|
+
'.apk': 'application/vnd.android.package-archive',
|
82
|
+
'.exe': 'application/vnd.microsoft.portable-executable',
|
83
|
+
'.dmg': 'application/x-apple-diskimage',
|
84
|
+
'.bat': 'application/x-bat',
|
85
|
+
'.sh': 'application/x-sh',
|
86
|
+
'.pdfa': 'application/pdf',
|
87
|
+
'.webmanifest': 'application/manifest+json',
|
88
|
+
}
|
89
|
+
|
90
|
+
def parse_extension(filename):
|
91
|
+
"""
|
92
|
+
Extract the extension from a filename, handling both single and double extensions,
|
93
|
+
and return the extension along with the filename without the extension.
|
94
|
+
|
95
|
+
Parameters:
|
96
|
+
filename (str): The name of the file for which to extract the extension.
|
97
|
+
|
98
|
+
Returns:
|
99
|
+
tuple: A tuple containing the extracted extension (or an empty string if no valid
|
100
|
+
extension is found) and the filename without the extension.
|
101
|
+
"""
|
102
|
+
filename = filename.lower()
|
103
|
+
parts = filename.rsplit('.', 2) # Max 2 splits: base.name.ext1.ext2
|
104
|
+
if len(parts) == 3:
|
105
|
+
double_ext = f".{parts[-2]}.{parts[-1]}"
|
106
|
+
if double_ext in EXTENSION_TO_MIME:
|
107
|
+
return double_ext, '.'.join(parts[:-1])
|
108
|
+
ext = f".{parts[-1]}" if '.' in filename else ''
|
109
|
+
base_filename = parts[0] if len(parts) == 1 else '.'.join(parts[:-1])
|
110
|
+
return ext.lower(), base_filename
|
111
|
+
|
112
|
+
def guess_type(filename):
|
113
|
+
"""
|
114
|
+
Guess the MIME type of a file based on its extension.
|
115
|
+
|
116
|
+
This function attempts to determine the MIME type of a file by examining
|
117
|
+
its extension. It can handle both single and double extensions, such as
|
118
|
+
".tar.gz" or ".tar.bz2".
|
119
|
+
|
120
|
+
Parameters:
|
121
|
+
filename (str): The name of the file whose MIME type needs to be guessed.
|
122
|
+
|
123
|
+
Returns:
|
124
|
+
str: The guessed MIME type if found in EXTENSION_TO_MIME mapping, or
|
125
|
+
'application/octet-stream' as a default fallback.
|
126
|
+
"""
|
127
|
+
ext, _ = parse_extension(filename)
|
128
|
+
return EXTENSION_TO_MIME.get(ext, 'application/octet-stream')
|
rest/mail.py
CHANGED
@@ -3,7 +3,6 @@ import os
|
|
3
3
|
import threading
|
4
4
|
from io import StringIO
|
5
5
|
import csv
|
6
|
-
import mimetypes
|
7
6
|
import boto3
|
8
7
|
|
9
8
|
from email.mime.multipart import MIMEMultipart
|
@@ -25,6 +24,7 @@ from django.template import TemplateDoesNotExist
|
|
25
24
|
|
26
25
|
import metrics
|
27
26
|
from rest import settings
|
27
|
+
from rest import filetypes
|
28
28
|
from rest.uberdict import UberDict
|
29
29
|
from rest.middleware import get_request
|
30
30
|
from rest.log import getLogger
|
@@ -163,7 +163,8 @@ def sendMail(msg, sender, recipients, fail_silently=True):
|
|
163
163
|
|
164
164
|
def makeAttachment(filename, data):
|
165
165
|
atment = UberDict(name=filename, data=data)
|
166
|
-
atment.mimetype, junk = mimetypes.MimeTypes().guess_type(filename)
|
166
|
+
# atment.mimetype, junk = mimetypes.MimeTypes().guess_type(filename)
|
167
|
+
atment.mimetype = filetypes.guess_type(filename)
|
167
168
|
return atment
|
168
169
|
|
169
170
|
|
rest/models/base.py
CHANGED
@@ -1226,8 +1226,8 @@ class RestModel(object):
|
|
1226
1226
|
@classmethod
|
1227
1227
|
def on_rest_batch(cls, request, action):
|
1228
1228
|
# this method is called when rest_batch='somme action'
|
1229
|
-
if not ALLOW_BATCHING or not getattr(cls.RestMeta, "CAN_BATCH",
|
1230
|
-
|
1229
|
+
if not ALLOW_BATCHING or not getattr(cls.RestMeta, "CAN_BATCH", False):
|
1230
|
+
raise re.PermissionDeniedException(f"{cls.__name__} model does not allow batch actions", 439)
|
1231
1231
|
cls._boundRest()
|
1232
1232
|
# if not request.member.hasPerm("can_batch_update"):
|
1233
1233
|
# raise re.PermissionDeniedException(f"batch updated not allowed by user")
|
@@ -1246,7 +1246,7 @@ class RestModel(object):
|
|
1246
1246
|
if not can_delete:
|
1247
1247
|
raise re.PermissionDeniedException(f"deletion not allowed for {cls.get_class_name()}", 438)
|
1248
1248
|
count = qset.delete()[0]
|
1249
|
-
return GRAPH_HELPERS.restStatus(request, True, error="
|
1249
|
+
return GRAPH_HELPERS.restStatus(request, True, error="deleted {} items".format(count))
|
1250
1250
|
elif action == "update":
|
1251
1251
|
update_fields = request.DATA.get(["batch_data", "batch_update"])
|
1252
1252
|
if not isinstance(update_fields, dict):
|
File without changes
|
File without changes
|