django-restit 4.2.128__py3-none-any.whl → 4.2.131__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- account/models/member.py +7 -0
- {django_restit-4.2.128.dist-info → django_restit-4.2.131.dist-info}/METADATA +1 -1
- {django_restit-4.2.128.dist-info → django_restit-4.2.131.dist-info}/RECORD +13 -12
- medialib/models.py +54 -13
- medialib/rpc/media.py +8 -0
- medialib/stores/s3.py +14 -0
- medialib/utils.py +2 -1
- rest/__init__.py +1 -1
- rest/datem.py +12 -4
- wiki/migrations/0003_page_perms.py +18 -0
- wiki/models/page.py +41 -2
- {django_restit-4.2.128.dist-info → django_restit-4.2.131.dist-info}/LICENSE.md +0 -0
- {django_restit-4.2.128.dist-info → django_restit-4.2.131.dist-info}/WHEEL +0 -0
account/models/member.py
CHANGED
@@ -10,6 +10,7 @@ import time
|
|
10
10
|
import re
|
11
11
|
import hashlib
|
12
12
|
import uuid
|
13
|
+
from objict import objict
|
13
14
|
|
14
15
|
from auditlog.models import PersistentLog
|
15
16
|
from sessionlog.models import SessionLog
|
@@ -387,6 +388,12 @@ class Member(User, RestModel, MetaDataModel):
|
|
387
388
|
return False
|
388
389
|
return self.getProperty(perm, 0, "permissions", bool)
|
389
390
|
|
391
|
+
def getPermissions(self):
|
392
|
+
return objict.fromdict(self.getProperties("permissions"))
|
393
|
+
|
394
|
+
def listPermissions(self):
|
395
|
+
return [k for k, v in self.getProperties("permissions").items() if v in [1, "1"]]
|
396
|
+
|
390
397
|
def hasGroupPerm(self, group, perm):
|
391
398
|
if group is None:
|
392
399
|
return False
|
@@ -30,7 +30,7 @@ account/models/device.py,sha256=0AFeLMGk4im4KZVd3eGSyRbK4eQEXiFM2cdY8GUzihs,5934
|
|
30
30
|
account/models/feeds.py,sha256=vI7fG4ASY1M0Zjke24RdnfDcuWeATl_yR_25jPmT64g,2011
|
31
31
|
account/models/group.py,sha256=KnLj0cOJBg1JYo33wL-7NehD4_PCsLyEjLdX6GZJZAo,22308
|
32
32
|
account/models/legacy.py,sha256=zYdtv4LC0ooxPVqWM-uToPwV-lYWQLorSE6p6yn1xDw,2720
|
33
|
-
account/models/member.py,sha256=
|
33
|
+
account/models/member.py,sha256=7JCf7HULo_CLqKLGbHFvFOVYSkKbVkDuUPjq0C1u2Ak,54450
|
34
34
|
account/models/membership.py,sha256=90EpAhOsGaqphDAkONP6j_qQ0OWSRaQsI8H7E7fgMkE,9249
|
35
35
|
account/models/notify.py,sha256=TOkuVBLAsbzT58FOxII_G3Cj_IDQx16vyehyEsNrDcY,15306
|
36
36
|
account/models/passkeys.py,sha256=TJxITUi4DT4_1tW2K7ZlOcRjJuMVl2NtKz7pKQU8-Tw,1516
|
@@ -173,7 +173,7 @@ medialib/fixtures/medialib_test_fixture.json,sha256=7M7zvGI2S5G3ENV8OQ3Ks4149lEi
|
|
173
173
|
medialib/forms.py,sha256=nrE6QTPNPiIeX7Nx4l9DEmAQeQXqFyCg1C3JEDBYJfE,5442
|
174
174
|
medialib/migrations/0001_initial.py,sha256=H3JliH5aw7tiHef8MhrJr_9rGetqgA7UjTF-eKziRSM,20518
|
175
175
|
medialib/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
176
|
-
medialib/models.py,sha256=
|
176
|
+
medialib/models.py,sha256=XVqqyMeikK5qPGQ_kMsM9H9VcTPko9s3JmTGGfIScvs,53647
|
177
177
|
medialib/ocr.py,sha256=zlP7-NBiXhW7jR9pljmEPl5xzLVZpLN5QLAELQgU0Fk,1189
|
178
178
|
medialib/pdf.py,sha256=l28WwM0JKbT9boV-b_9TFh9jhvGcrquR8GqC8wfEaLk,1275
|
179
179
|
medialib/qrcode.py,sha256=vHyA5egXOX70EFiUDgr1njI9zcF6bXQJ_hKAQrppRow,545
|
@@ -209,7 +209,7 @@ medialib/render/render_utils.py,sha256=ld0hMfiAWSqC8Nhi408ZPSjKHWYuQXtPdjbeBfav4
|
|
209
209
|
medialib/render/schedule.py,sha256=iDSekfsY31SEXF-MR-YdJ9-a3UJ3SoJsZJpiEcbiNZA,370
|
210
210
|
medialib/rpc/__init__.py,sha256=K84yMB6sUr7zTeECxca-_2jyHiUGCHTM-XYmJK6jQCo,82
|
211
211
|
medialib/rpc/legacy.py,sha256=KTNmNJIxfFkZfAj0LXx9-e8bJonOfCoNE0-c_cugsNc,37925
|
212
|
-
medialib/rpc/media.py,sha256=
|
212
|
+
medialib/rpc/media.py,sha256=118Ra_MnCtPZ-oSouA8x3inMb590JH9mwdF--cCqKdM,876
|
213
213
|
medialib/rpc/tools.py,sha256=PQYP0r0NMLU_QdrnKxrMIPNbefzguwe-U8QBm_jhung,956
|
214
214
|
medialib/scripts/init_config,sha256=jfXtOwYcSRFedKeSC8qcZo-ZpyvN8OvYZnQP0uXdURo,7875
|
215
215
|
medialib/static/css/base_medialibui.css,sha256=yxhNcfzSfrx7vkHjBf_KWq-txLdbnVxjCG_dtb7pTqI,4499
|
@@ -273,7 +273,7 @@ medialib/stores/oauth2client/tools.py,sha256=OLSW5Iu7rtjGankFpjXlHBw8aAFOcIsWdDh
|
|
273
273
|
medialib/stores/oauth2client/util.py,sha256=1Uc6qwqNhI3b507VtFnklX4sEZNt0MZbLAME2o6kCgg,5706
|
274
274
|
medialib/stores/oauth2client/xsrfutil.py,sha256=4Plq0y5xEkDwvrveVA32gBRP0A3FkJ_36dIsyGHeJeA,3367
|
275
275
|
medialib/stores/rtmpstore.py,sha256=CFRP6Ss4hbLKngbdaLvA8_oKCSe18B29-oWVgvTXMPA,500
|
276
|
-
medialib/stores/s3.py,sha256=
|
276
|
+
medialib/stores/s3.py,sha256=behvLC-ftoMVddJmgK5jfZsC5PVjRBPrSgXkwngNP9A,6280
|
277
277
|
medialib/stores/s3store.py,sha256=uKO6I-X83sD9xefCQytLyrV-7t9TSX2p476n_ZBkSHw,4583
|
278
278
|
medialib/stores/uritemplate/__init__.py,sha256=ONWR_KRz9au0O-XUUTrO_UN7GHTmZCTKyvflUQb8wxM,4996
|
279
279
|
medialib/stores/youtubestore.py,sha256=swXOJYfbhgzAv1NjOehjKtfYRZYk2wiPK7a7_boAulc,406
|
@@ -299,7 +299,7 @@ medialib/templates/medialib/testpicker.html,sha256=I7KnrAu9e4kQhuEEN-51HGzcuJ06E
|
|
299
299
|
medialib/tests.py,sha256=z1THDMo-R9HWMvCCOgX6aH6-2W2uWqrtbJ_k-zfpgyc,6045
|
300
300
|
medialib/tq.py,sha256=ZDRBZ9qEsqNAsk48cciLyX7DIziqD2uPEawtQny1Ja8,544
|
301
301
|
medialib/urls.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
302
|
-
medialib/utils.py,sha256=
|
302
|
+
medialib/utils.py,sha256=StQY7k9dOCksdTsYqUb3aGpwwrcYg07z7vskBQqCPnw,3774
|
303
303
|
medialib/views.py,sha256=h_Fm3FOX04VV2G-J141wEHxT36d46HVdzPJg_u8r2vI,4321
|
304
304
|
medialib/youtube/__init__.py,sha256=fmu9XPaDpadkb2OuroQsKiWpUPo7c5y8o83HmLLMIHA,4303
|
305
305
|
medialib/youtube/apiclient/__init__.py,sha256=iGdQFKwzm0VxArl8X183-_ZBhIsETZlbXxhBAUz3MfI,601
|
@@ -376,14 +376,14 @@ pushit/utils.py,sha256=IeTCGa-164nmB1jIsK1lu1O1QzUhS3BKfuXHGjCW-ck,2121
|
|
376
376
|
rest/.gitignore,sha256=TbEvWRMnAiajCTOdhiNrd9eeCAaIjRp9PRjE_VkMM5g,118
|
377
377
|
rest/README.md,sha256=V3ETc-cJu8PZIbKr9xSe_pA4JEUpC8Dhw4bQeVCDJPw,5460
|
378
378
|
rest/RemoteEvents.py,sha256=nL46U7AuxIrlw2JunphR1tsXyqi-ep_gD9CYGpYbNgE,72
|
379
|
-
rest/__init__.py,sha256=
|
379
|
+
rest/__init__.py,sha256=NmUDpJwDRPihaYYG56xnn8xE0-EGE9ysndPTc4P9bDQ,122
|
380
380
|
rest/arc4.py,sha256=y644IbF1ec--e4cUJ3KEYsewTCITK0gmlwa5mJruFC0,1967
|
381
381
|
rest/cache.py,sha256=1Qg0rkaCJCaVP0-l5hZg2CIblTdeBSlj_0fP6vlKUpU,83
|
382
382
|
rest/crypto/__init__.py,sha256=Tl0U11rgj1eBYqd6OXJ2_XSdNLumW_JkBZnaJqI6Ldw,72
|
383
383
|
rest/crypto/aes.py,sha256=NOVRBRSHCV-om68YpGySWWG-4kako3iEVjq8hxZWPUU,4372
|
384
384
|
rest/crypto/privpub.py,sha256=_FioylVcbMmDP80yPYjURmafEiDmEAMkskbc7WF10ac,4082
|
385
385
|
rest/crypto/util.py,sha256=agFN2OCPHC70tHNGWrMkkZX4Tt_Ty6imoKEMdTkZpKA,4514
|
386
|
-
rest/datem.py,sha256=
|
386
|
+
rest/datem.py,sha256=hX6bTbl5mQSg0x2hDK5P1TynkZFUfVTDwYkTuFObgbw,12626
|
387
387
|
rest/decorators.py,sha256=AuB4agpog587CUsF8HkAZiHDfs_pueb2rdxXZD7dUUE,15327
|
388
388
|
rest/encryption.py,sha256=x6Kiez0tVqfxK26MSsRL3k8OS05ni1gEX2aj3I0S9V0,788
|
389
389
|
rest/errors.py,sha256=uKwG9OkLme36etabqK54DMjMQc1fgEoUIAUxXa7WFQw,612
|
@@ -481,10 +481,11 @@ telephony/rpc.py,sha256=PXPDFvgoXkCKlfMzIbt6lYZPay3fcveNj2X4Pjby7p4,3473
|
|
481
481
|
wiki/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
482
482
|
wiki/migrations/0001_initial.py,sha256=9jvUyjrbJrbDilRnwzQUPhPV8Xi_olEPBk_N0nycvM0,3606
|
483
483
|
wiki/migrations/0002_alter_pagemedia_entry.py,sha256=9CUnfvBmj0D4akCkux7HFuXgw9B9avE8V-iMCm5cjds,485
|
484
|
+
wiki/migrations/0003_page_perms.py,sha256=qJBLI7t5mgiDTKCR9qhticmbhgo2KKYq7WbHaxH1Ykw,423
|
484
485
|
wiki/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
485
486
|
wiki/models/__init__.py,sha256=jE-9r_Hqpyo7ysKu9BschXOn5Zg34wUt894GwJpxA28,132
|
486
487
|
wiki/models/faq.py,sha256=nvcEFerllQKT61kIYlasvZzRKwpXyfmQpiqkpHP1V1o,1745
|
487
|
-
wiki/models/page.py,sha256=
|
488
|
+
wiki/models/page.py,sha256=06wyZsDX57B-d_wZhSNcrNAOv-ERHlKveJ15MZc9haQ,8751
|
488
489
|
wiki/models/revision.py,sha256=St5-vz8SGvogsDL6jTWqHLE23PS5mp9iA0DUt3hWTsU,729
|
489
490
|
wiki/periodic.py,sha256=t-UgXJIug-OLslJM_r03-5WrNKj39TxrvfuNFjVAhDs,334
|
490
491
|
wiki/renderers/__init__.py,sha256=lLEoJvjU3ezXwBGcjleKk_kMyNeMD9MpfBlEiKayEiM,461
|
@@ -511,7 +512,7 @@ ws4redis/servers/uwsgi.py,sha256=VyhoCI1DnVFqBiJYHoxqn5Idlf6uJPHvfBKgkjs34mo,172
|
|
511
512
|
ws4redis/settings.py,sha256=K0yBiLUuY81iDM4Yr-k8hbvjn5VVHu5zQhmMK8Dtz0s,1536
|
512
513
|
ws4redis/utf8validator.py,sha256=S0OlfjeGRP75aO6CzZsF4oTjRQAgR17OWE9rgZdMBZA,5122
|
513
514
|
ws4redis/websocket.py,sha256=R0TUyPsoVRD7Y_oU7w2I6NL4fPwiz5Vl94-fUkZgLHA,14848
|
514
|
-
django_restit-4.2.
|
515
|
-
django_restit-4.2.
|
516
|
-
django_restit-4.2.
|
517
|
-
django_restit-4.2.
|
515
|
+
django_restit-4.2.131.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
|
516
|
+
django_restit-4.2.131.dist-info/METADATA,sha256=lsS45ob1xhvxwvB4KRvDhmmLZSXP04I4797ajfnV5uc,7663
|
517
|
+
django_restit-4.2.131.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
518
|
+
django_restit-4.2.131.dist-info/RECORD,,
|
medialib/models.py
CHANGED
@@ -330,6 +330,7 @@ class MediaItem(models.Model, RestModel, MetaDataModel):
|
|
330
330
|
Media Item (a video or image)
|
331
331
|
"""
|
332
332
|
class RestMeta:
|
333
|
+
POST_SAVE_FIELDS = ["rendernow"]
|
333
334
|
SEARCH_FIELDS = ["name", "description"]
|
334
335
|
VIEW_PERMS = ["view_media", "manage_users", "manage_media"]
|
335
336
|
SAVE_PERMS = ["manage_media", "manage_users"]
|
@@ -451,6 +452,12 @@ class MediaItem(models.Model, RestModel, MetaDataModel):
|
|
451
452
|
return self.library.default_store()
|
452
453
|
return settings.MEDIALIB_DEFAULT_STORE
|
453
454
|
|
455
|
+
def s3_store(self):
|
456
|
+
return f's3://{settings.AWS_S3_BUCKET}'
|
457
|
+
|
458
|
+
def set_rendernow(self, value):
|
459
|
+
self.new_render()
|
460
|
+
|
454
461
|
def uses(self):
|
455
462
|
"""
|
456
463
|
List uses available for this item
|
@@ -551,6 +558,11 @@ class MediaItem(models.Model, RestModel, MetaDataModel):
|
|
551
558
|
return super(MediaItem, self).save()
|
552
559
|
|
553
560
|
def save(self, *args, **kwargs):
|
561
|
+
if self.pk is None:
|
562
|
+
return self.saveNew(*args, **kwargs)
|
563
|
+
return super(MediaItem, self).save(*args, **kwargs)
|
564
|
+
|
565
|
+
def saveNew(self, *args, **kwargs):
|
554
566
|
"""
|
555
567
|
When saving MediaItem set newfile attribute to upload new file and start rendering
|
556
568
|
"""
|
@@ -1023,6 +1035,25 @@ class MediaItem(models.Model, RestModel, MetaDataModel):
|
|
1023
1035
|
media.save()
|
1024
1036
|
return media
|
1025
1037
|
|
1038
|
+
@staticmethod
|
1039
|
+
def on_upload_s3(request):
|
1040
|
+
filename = request.DATA.get("filename")
|
1041
|
+
filesize = request.DATA.get("filesize")
|
1042
|
+
filetype = request.DATA.get("filetype")
|
1043
|
+
kind = utils.guessMediaKindByName(filename)
|
1044
|
+
if kind is None:
|
1045
|
+
kind = "*"
|
1046
|
+
obj = MediaItem(name=filename, owner=request.member, kind=kind, group=request.group)
|
1047
|
+
obj.save()
|
1048
|
+
rendition = MediaItemRendition(
|
1049
|
+
mediaitem=obj, name="Original", bytes=filesize,
|
1050
|
+
use='original', kind=kind, is_original=True)
|
1051
|
+
rendition.save()
|
1052
|
+
rendition.url = rendition.generateURL(filename, store=obj.s3_store())
|
1053
|
+
rendition.save()
|
1054
|
+
return dict(url=rendition.generateUploadURL(filetype), id=obj.pk)
|
1055
|
+
|
1056
|
+
|
1026
1057
|
class MediaItemMetaData(MetaDataBase):
|
1027
1058
|
parent = models.ForeignKey(MediaItem, related_name="properties", on_delete=models.CASCADE)
|
1028
1059
|
|
@@ -1073,6 +1104,7 @@ class CuePointMeta(models.Model):
|
|
1073
1104
|
def __str__(self):
|
1074
1105
|
return self.key
|
1075
1106
|
|
1107
|
+
|
1076
1108
|
class MediaItemRendition(models.Model):
|
1077
1109
|
"""
|
1078
1110
|
A rendition of a media item
|
@@ -1119,20 +1151,18 @@ class MediaItemRendition(models.Model):
|
|
1119
1151
|
except IndexError:
|
1120
1152
|
return ''
|
1121
1153
|
|
1122
|
-
def
|
1123
|
-
|
1124
|
-
|
1125
|
-
"""
|
1126
|
-
doclose = False
|
1127
|
-
if type(fp) == str:
|
1128
|
-
doclose = True
|
1129
|
-
fp = open(fp)
|
1154
|
+
def generateUploadURL(self, filetype):
|
1155
|
+
from medialib.stores import s3
|
1156
|
+
return s3.generate_upload_url(self.url, filetype)
|
1130
1157
|
|
1158
|
+
def generateURL(self, name, prefix="", store=None):
|
1159
|
+
if store is None:
|
1160
|
+
store = self.mediaitem.default_store()
|
1131
1161
|
paths = []
|
1132
|
-
paths.append(
|
1162
|
+
paths.append(store)
|
1133
1163
|
paths.append("/{}/".format(int_to_base36(self.mediaitem.pk)))
|
1134
1164
|
path = "".join(paths)
|
1135
|
-
if self.rendition_definition
|
1165
|
+
if self.rendition_definition is not None:
|
1136
1166
|
paths.append(int_to_base36(self.rendition_definition.pk))
|
1137
1167
|
else:
|
1138
1168
|
paths.append("0")
|
@@ -1140,13 +1170,24 @@ class MediaItemRendition(models.Model):
|
|
1140
1170
|
paths.append(utils.toMD5(path, int(time.time())))
|
1141
1171
|
paths.append(".")
|
1142
1172
|
ext = ".dat"
|
1143
|
-
if "." in
|
1144
|
-
ext =
|
1173
|
+
if "." in name:
|
1174
|
+
ext = name.split('.')[-1]
|
1145
1175
|
elif hasattr(self.mediaitem, "ext"):
|
1146
1176
|
ext = self.mediaitem.ext
|
1147
1177
|
paths.append(ext)
|
1148
1178
|
# print(paths)
|
1149
|
-
|
1179
|
+
return "".join(paths)
|
1180
|
+
|
1181
|
+
def upload(self, fp, prefix=""):
|
1182
|
+
"""
|
1183
|
+
Upload rendition to non-volatile storage
|
1184
|
+
"""
|
1185
|
+
doclose = False
|
1186
|
+
if type(fp) == str:
|
1187
|
+
doclose = True
|
1188
|
+
fp = open(fp)
|
1189
|
+
|
1190
|
+
self.url = self.generateURL(fp.name, prefix)
|
1150
1191
|
stores.upload(self.url, fp, background=True)
|
1151
1192
|
try:
|
1152
1193
|
self.bytes = fp.size
|
medialib/rpc/media.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
from rest import decorators as rd
|
2
|
+
from rest import views as rv
|
2
3
|
from medialib import models as medialib
|
3
4
|
|
4
5
|
|
@@ -9,6 +10,13 @@ def rest_on_media_item(request, pk=None):
|
|
9
10
|
return medialib.MediaItem.on_rest_request(request, pk)
|
10
11
|
|
11
12
|
|
13
|
+
@rd.urlPOST('media/item/s3')
|
14
|
+
@rd.login_required
|
15
|
+
@rd.requires_params(["filename", "filesize"])
|
16
|
+
def rest_on_media_upload_s3(request, pk=None):
|
17
|
+
return rv.restReturn(request, dict(data=medialib.MediaItem.on_upload_s3(request)))
|
18
|
+
|
19
|
+
|
12
20
|
@rd.url(r'media/ref/$')
|
13
21
|
@rd.url(r'media/ref/(?P<pk>\d+)$')
|
14
22
|
@rd.login_required
|
medialib/stores/s3.py
CHANGED
@@ -170,6 +170,20 @@ def get_file(url, fp=None):
|
|
170
170
|
return obj.download(fp)
|
171
171
|
|
172
172
|
|
173
|
+
def generate_upload_url(url, filetype, expires=3600, acl="public-read"):
|
174
|
+
u = urlparse(url)
|
175
|
+
bucket_name = u.netloc
|
176
|
+
key = u.path.lstrip('/')
|
177
|
+
client = getS3(False)
|
178
|
+
params = dict(Bucket=bucket_name, Key=key, ContentType=filetype)
|
179
|
+
from rest import helpers
|
180
|
+
helpers.log_error("generate_upload_url", params)
|
181
|
+
return client.generate_presigned_url(
|
182
|
+
'put_object',
|
183
|
+
ExpiresIn=expires,
|
184
|
+
Params=params)
|
185
|
+
|
186
|
+
|
173
187
|
def delete(url):
|
174
188
|
if url[-1] == "/":
|
175
189
|
prefix = url.path.lstrip("/")
|
medialib/utils.py
CHANGED
rest/__init__.py
CHANGED
rest/datem.py
CHANGED
@@ -182,7 +182,9 @@ def getWeek(start, start_day=0):
|
|
182
182
|
return week_start, week_end
|
183
183
|
|
184
184
|
|
185
|
-
def getStartOfMonth(d):
|
185
|
+
def getStartOfMonth(d, clear_time=False):
|
186
|
+
if clear_time:
|
187
|
+
return d.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
186
188
|
return d.replace(day=1)
|
187
189
|
|
188
190
|
|
@@ -190,13 +192,19 @@ def nextMonth(d):
|
|
190
192
|
return getStartOfMonth(getStartOfMonth(d) + timedelta(days=32))
|
191
193
|
|
192
194
|
|
193
|
-
def
|
195
|
+
def getEndOfMonthNoTime(start):
|
194
196
|
start = start.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
195
197
|
end = start + timedelta(days=calendar.monthrange(start.year, start.month)[1])
|
196
198
|
end = end.replace(hour=0, minute=0, second=0, microsecond=0)
|
197
199
|
return end
|
198
200
|
|
199
201
|
|
202
|
+
def getEndOfMonth(d, clear_time=False):
|
203
|
+
if clear_time:
|
204
|
+
return getEndOfMonthNoTime(d)
|
205
|
+
return getStartOfMonth(nextMonth(d)) - timedelta(days=1)
|
206
|
+
|
207
|
+
|
200
208
|
def parseDate(date_str, is_future=False, is_past=False, month_end=True, as_date=False):
|
201
209
|
res = parseDateTime(date_str, is_future, is_past, month_end)
|
202
210
|
if as_date and res:
|
@@ -284,10 +292,10 @@ def getDateRange(start, end=None, kind=None, zone=None, hour=0, eod=None, end_eo
|
|
284
292
|
start, end = getWeek(start)
|
285
293
|
elif kind == "month":
|
286
294
|
start = start.replace(hour=0, day=1)
|
287
|
-
end = getEndOfMonth(start)
|
295
|
+
end = getEndOfMonth(start, True)
|
288
296
|
elif kind == "year":
|
289
297
|
start = start.replace(hour=0, day=1, month=1)
|
290
|
-
end = getEndOfMonth(start.replace(month=12))
|
298
|
+
end = getEndOfMonth(start.replace(month=12), True)
|
291
299
|
elif isinstance(kind, int) or (isinstance(kind, str) and kind.isdigit()):
|
292
300
|
end = start + timedelta(days=1)
|
293
301
|
start = end - timedelta(days=int(kind))
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Generated by Django 4.2.11 on 2024-08-13 04:11
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
|
5
|
+
|
6
|
+
class Migration(migrations.Migration):
|
7
|
+
|
8
|
+
dependencies = [
|
9
|
+
('wiki', '0002_alter_pagemedia_entry'),
|
10
|
+
]
|
11
|
+
|
12
|
+
operations = [
|
13
|
+
migrations.AddField(
|
14
|
+
model_name='page',
|
15
|
+
name='perms',
|
16
|
+
field=models.CharField(db_index=True, default=None, max_length=255, null=True),
|
17
|
+
),
|
18
|
+
]
|
wiki/models/page.py
CHANGED
@@ -1,11 +1,17 @@
|
|
1
1
|
from django.db import models as dm
|
2
2
|
from rest import models as rm
|
3
|
+
from rest import settings
|
4
|
+
from rest import helpers as rh
|
3
5
|
from medialib import models as medialib
|
4
6
|
import re
|
5
7
|
import mistune
|
6
8
|
from wiki.renderers import WikiRenderer
|
7
9
|
from wiki.renderers.mistune import task_list
|
8
10
|
|
11
|
+
WIKI_PAGE_VIEW_PERMS = settings.get("WIKI_PAGE_VIEW_PERMS", ["view_wiki", "edit_wiki"])
|
12
|
+
WIKI_PAGE_EDIT_PERMS = settings.get("WIKI_PAGE_EDIT_PERMS", ["edit_wiki"])
|
13
|
+
|
14
|
+
|
9
15
|
class Page(dm.Model, rm.RestModel, rm.MetaDataModel):
|
10
16
|
"""
|
11
17
|
Blog (a collection of articles)
|
@@ -14,7 +20,8 @@ class Page(dm.Model, rm.RestModel, rm.MetaDataModel):
|
|
14
20
|
SEARCH_FIELDS = ["title", "body"]
|
15
21
|
SEARCH_TERMS = ["title", "body"]
|
16
22
|
QUERY_FIELDS = ["all_fields", "parent__path"]
|
17
|
-
VIEW_PERMS =
|
23
|
+
VIEW_PERMS = WIKI_PAGE_VIEW_PERMS
|
24
|
+
EDIT_PERMS = WIKI_PAGE_EDIT_PERMS
|
18
25
|
UNIQUE_LOOKUP = ["path"]
|
19
26
|
DEFAULT_SORT = "-order"
|
20
27
|
CAN_DELETE = True
|
@@ -30,6 +37,7 @@ class Page(dm.Model, rm.RestModel, rm.MetaDataModel):
|
|
30
37
|
"order",
|
31
38
|
"path",
|
32
39
|
"slug",
|
40
|
+
"perms"
|
33
41
|
],
|
34
42
|
},
|
35
43
|
"default": {
|
@@ -103,6 +111,7 @@ class Page(dm.Model, rm.RestModel, rm.MetaDataModel):
|
|
103
111
|
title = dm.CharField(max_length=255)
|
104
112
|
path = dm.CharField(max_length=255, db_index=True)
|
105
113
|
slug = dm.SlugField(db_index=True)
|
114
|
+
perms = dm.CharField(max_length=255, db_index=True, null=True, default=None)
|
106
115
|
|
107
116
|
body = dm.TextField(blank=True)
|
108
117
|
|
@@ -144,6 +153,35 @@ class Page(dm.Model, rm.RestModel, rm.MetaDataModel):
|
|
144
153
|
if qset.count():
|
145
154
|
self.slug = f"{sanitized_slug}_{qset.count()+1}"
|
146
155
|
|
156
|
+
def on_rest_can_get(self, request):
|
157
|
+
if request is None:
|
158
|
+
return True
|
159
|
+
if self.perms:
|
160
|
+
perms = [p.strip() for p in self.perms.split(',')]
|
161
|
+
elif self.parent and self.parent.perms:
|
162
|
+
perms = [p.strip() for p in self.parent.perms.split(',')]
|
163
|
+
else:
|
164
|
+
perms = getattr(self.RestMeta, "VIEW_PERMS", None)
|
165
|
+
if perms:
|
166
|
+
if "public" in perms:
|
167
|
+
return True
|
168
|
+
if "owner" in perms and self.checkIsOwner(request.member):
|
169
|
+
return True
|
170
|
+
# we need to check if this user has permission
|
171
|
+
group_field = "group"
|
172
|
+
status, error, code = rh.requestHasPerms(request, perms, getattr(self, group_field, None))
|
173
|
+
if not status:
|
174
|
+
return False
|
175
|
+
return True
|
176
|
+
|
177
|
+
@classmethod
|
178
|
+
def on_rest_list_ready(cls, request, qset=None):
|
179
|
+
out = []
|
180
|
+
for page in qset:
|
181
|
+
if page.on_rest_can_get(request):
|
182
|
+
out.append(page)
|
183
|
+
return out
|
184
|
+
|
147
185
|
def on_rest_pre_save(self, request):
|
148
186
|
if not self.slug:
|
149
187
|
self.set_slug(self.title)
|
@@ -206,7 +244,8 @@ class PageMetaData(rm.MetaDataBase):
|
|
206
244
|
|
207
245
|
class PageMedia(dm.Model, rm.RestModel):
|
208
246
|
class RestMeta:
|
209
|
-
VIEW_PERMS =
|
247
|
+
VIEW_PERMS = WIKI_PAGE_VIEW_PERMS
|
248
|
+
EDIT_PERMS = WIKI_PAGE_EDIT_PERMS
|
210
249
|
GRAPHS = {
|
211
250
|
"basic": {
|
212
251
|
"graphs": {
|
File without changes
|
File without changes
|