django-restit 4.2.130__py3-none-any.whl → 4.2.132__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- {django_restit-4.2.130.dist-info → django_restit-4.2.132.dist-info}/METADATA +1 -1
- {django_restit-4.2.130.dist-info → django_restit-4.2.132.dist-info}/RECORD +12 -12
- medialib/models.py +84 -14
- medialib/render/render_utils.py +1 -1
- 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/renderers/mistune/media.py +3 -0
- {django_restit-4.2.130.dist-info → django_restit-4.2.132.dist-info}/LICENSE.md +0 -0
- {django_restit-4.2.130.dist-info → django_restit-4.2.132.dist-info}/WHEEL +0 -0
@@ -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=snD9Lyskp6i1YTOcERrclPUPIbINkGOhGOTbDKC8dFk,54791
|
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
|
@@ -205,11 +205,11 @@ medialib/render/presets/video_still.py,sha256=VSWtr6k3UJta3YdOpEfU9d7p46XKi98aPt
|
|
205
205
|
medialib/render/presets/video_validate.py,sha256=pC6MzzgVWZKGJj6NkQ8SHcDj8z45kxHMuwxK82f8vIU,3228
|
206
206
|
medialib/render/presets/websnap.py,sha256=RSxJ7T2ICU_KQn48yHWLj4qXCABTC7uVIPwe-z_CSkI,863
|
207
207
|
medialib/render/presets/youtube.py,sha256=M4bTZju1u7rrvwLOG89cNUaelHUtnRFss7hggvZCAuE,2282
|
208
|
-
medialib/render/render_utils.py,sha256=
|
208
|
+
medialib/render/render_utils.py,sha256=kJlluBmkXoABQqZ6cJFQ3u07cl5ela-Gvu6w96hd6uA,16460
|
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=-RkqJ1C1aVmCpKUVK79846yJzPNqTf7-orNjsU35Rjo,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
|
@@ -492,7 +492,7 @@ wiki/renderers/__init__.py,sha256=lLEoJvjU3ezXwBGcjleKk_kMyNeMD9MpfBlEiKayEiM,46
|
|
492
492
|
wiki/renderers/mistune/__init__.py,sha256=baClLWELOwy5n8UUFi7qmoFBU6QaeegD-wRNZ7fIW_w,84
|
493
493
|
wiki/renderers/mistune/highlight.py,sha256=BosglMQUxc_KVbLapQ4gCt6rCc0rAF1vCtUR7R1Ad4c,1264
|
494
494
|
wiki/renderers/mistune/math.py,sha256=dgQpH9CIDiqyESphoK5XUVFxK5Yb5VhEIoLgjp3Vtcs,1901
|
495
|
-
wiki/renderers/mistune/media.py,sha256=
|
495
|
+
wiki/renderers/mistune/media.py,sha256=SYwjhX6_DKfqJ00yLxfKrIHu6JnnwKnroqRm6ySDMfY,2688
|
496
496
|
wiki/renderers/mistune/meta.py,sha256=1lry9m-4wiwsivWnqYHYjwmGv91BGUSB7niJuZ1Xx54,805
|
497
497
|
wiki/renderers/mistune/task_list.py,sha256=Ex0gUPX_d9jtbPbnEEktlqAJsM6wIt5Md2wsltX7LIY,1889
|
498
498
|
wiki/renderers/mistune/toc.py,sha256=TKGiuMVpKqzDGUx5bAjJYpZIzG6n3wTjtuBdBc-TM_8,2302
|
@@ -512,7 +512,7 @@ ws4redis/servers/uwsgi.py,sha256=VyhoCI1DnVFqBiJYHoxqn5Idlf6uJPHvfBKgkjs34mo,172
|
|
512
512
|
ws4redis/settings.py,sha256=K0yBiLUuY81iDM4Yr-k8hbvjn5VVHu5zQhmMK8Dtz0s,1536
|
513
513
|
ws4redis/utf8validator.py,sha256=S0OlfjeGRP75aO6CzZsF4oTjRQAgR17OWE9rgZdMBZA,5122
|
514
514
|
ws4redis/websocket.py,sha256=R0TUyPsoVRD7Y_oU7w2I6NL4fPwiz5Vl94-fUkZgLHA,14848
|
515
|
-
django_restit-4.2.
|
516
|
-
django_restit-4.2.
|
517
|
-
django_restit-4.2.
|
518
|
-
django_restit-4.2.
|
515
|
+
django_restit-4.2.132.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
|
516
|
+
django_restit-4.2.132.dist-info/METADATA,sha256=NeQ9W-DZO4uEAlKI7xrNkeWyD8YQ60YuSsK3cxTsxjg,7663
|
517
|
+
django_restit-4.2.132.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
518
|
+
django_restit-4.2.132.dist-info/RECORD,,
|
medialib/models.py
CHANGED
@@ -20,6 +20,7 @@ import hashlib
|
|
20
20
|
import time
|
21
21
|
import mimetypes
|
22
22
|
import tempfile
|
23
|
+
import re
|
23
24
|
|
24
25
|
from medialib import utils
|
25
26
|
from rest import settings
|
@@ -29,6 +30,7 @@ from rest.decorators import rest_async
|
|
29
30
|
from taskqueue.models import Task
|
30
31
|
|
31
32
|
|
33
|
+
MEDIA_FRIENDLY_FILENAMES = settings.get("MEDIA_FRIENDLY_FILENAMES", True)
|
32
34
|
TASKQUEUE_RENDERING = settings.get("TASKQUEUE_RENDERING", False)
|
33
35
|
|
34
36
|
from rest.log import getLogger
|
@@ -330,6 +332,7 @@ class MediaItem(models.Model, RestModel, MetaDataModel):
|
|
330
332
|
Media Item (a video or image)
|
331
333
|
"""
|
332
334
|
class RestMeta:
|
335
|
+
POST_SAVE_FIELDS = ["rendernow"]
|
333
336
|
SEARCH_FIELDS = ["name", "description"]
|
334
337
|
VIEW_PERMS = ["view_media", "manage_users", "manage_media"]
|
335
338
|
SAVE_PERMS = ["manage_media", "manage_users"]
|
@@ -451,6 +454,12 @@ class MediaItem(models.Model, RestModel, MetaDataModel):
|
|
451
454
|
return self.library.default_store()
|
452
455
|
return settings.MEDIALIB_DEFAULT_STORE
|
453
456
|
|
457
|
+
def s3_store(self):
|
458
|
+
return f's3://{settings.AWS_S3_BUCKET}'
|
459
|
+
|
460
|
+
def set_rendernow(self, value):
|
461
|
+
self.new_render()
|
462
|
+
|
454
463
|
def uses(self):
|
455
464
|
"""
|
456
465
|
List uses available for this item
|
@@ -551,6 +560,11 @@ class MediaItem(models.Model, RestModel, MetaDataModel):
|
|
551
560
|
return super(MediaItem, self).save()
|
552
561
|
|
553
562
|
def save(self, *args, **kwargs):
|
563
|
+
if self.pk is None:
|
564
|
+
return self.saveNew(*args, **kwargs)
|
565
|
+
return super(MediaItem, self).save(*args, **kwargs)
|
566
|
+
|
567
|
+
def saveNew(self, *args, **kwargs):
|
554
568
|
"""
|
555
569
|
When saving MediaItem set newfile attribute to upload new file and start rendering
|
556
570
|
"""
|
@@ -1023,6 +1037,25 @@ class MediaItem(models.Model, RestModel, MetaDataModel):
|
|
1023
1037
|
media.save()
|
1024
1038
|
return media
|
1025
1039
|
|
1040
|
+
@staticmethod
|
1041
|
+
def on_upload_s3(request):
|
1042
|
+
filename = request.DATA.get("filename")
|
1043
|
+
filesize = request.DATA.get("filesize")
|
1044
|
+
filetype = request.DATA.get("filetype")
|
1045
|
+
kind = utils.guessMediaKindByName(filename)
|
1046
|
+
if kind is None:
|
1047
|
+
kind = "*"
|
1048
|
+
obj = MediaItem(name=filename, owner=request.member, kind=kind, group=request.group)
|
1049
|
+
obj.save()
|
1050
|
+
rendition = MediaItemRendition(
|
1051
|
+
mediaitem=obj, name="Original", bytes=filesize,
|
1052
|
+
use='original', kind=kind, is_original=True)
|
1053
|
+
rendition.save()
|
1054
|
+
rendition.url = rendition.generateURL(filename, store=obj.s3_store())
|
1055
|
+
rendition.save()
|
1056
|
+
return dict(url=rendition.generateUploadURL(filetype), id=obj.pk)
|
1057
|
+
|
1058
|
+
|
1026
1059
|
class MediaItemMetaData(MetaDataBase):
|
1027
1060
|
parent = models.ForeignKey(MediaItem, related_name="properties", on_delete=models.CASCADE)
|
1028
1061
|
|
@@ -1073,6 +1106,7 @@ class CuePointMeta(models.Model):
|
|
1073
1106
|
def __str__(self):
|
1074
1107
|
return self.key
|
1075
1108
|
|
1109
|
+
|
1076
1110
|
class MediaItemRendition(models.Model):
|
1077
1111
|
"""
|
1078
1112
|
A rendition of a media item
|
@@ -1119,34 +1153,70 @@ class MediaItemRendition(models.Model):
|
|
1119
1153
|
except IndexError:
|
1120
1154
|
return ''
|
1121
1155
|
|
1122
|
-
def
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1156
|
+
def generateUploadURL(self, filetype):
|
1157
|
+
from medialib.stores import s3
|
1158
|
+
return s3.generate_upload_url(self.url, filetype)
|
1159
|
+
|
1160
|
+
def generateFriendlyURL(self, name, prefix="", store=None):
|
1161
|
+
from rest import helpers as rh
|
1162
|
+
rh.log_error("generateFriendlyURL", name, self.use, self.mediaitem.name, " ")
|
1163
|
+
if store is None:
|
1164
|
+
store = self.mediaitem.default_store()
|
1165
|
+
if self.use != "original":
|
1166
|
+
if "." in self.mediaitem.name:
|
1167
|
+
orig_name = self.mediaitem.name.split('.')
|
1168
|
+
orig_ext = orig_name.pop()
|
1169
|
+
orig_name = "".join(orig_name)
|
1170
|
+
if "." in name:
|
1171
|
+
ext = name.split('.')[-1]
|
1172
|
+
else:
|
1173
|
+
ext = orig_ext
|
1174
|
+
name = f"{orig_name}__{self.name}.{ext}"
|
1175
|
+
rh.log_error("--- now ---", name, " ")
|
1176
|
+
name = name.replace(" ", "_")
|
1177
|
+
name = re.sub(r'[^A-Za-z0-9._-]', '', name)
|
1178
|
+
paths = []
|
1179
|
+
paths.append(store)
|
1180
|
+
paths.append("/")
|
1181
|
+
paths.append(int_to_base36(self.mediaitem.pk))
|
1182
|
+
paths.append("/")
|
1183
|
+
paths.append(name)
|
1184
|
+
return "".join(paths)
|
1185
|
+
|
1186
|
+
def generateURL(self, name, prefix="", store=None):
|
1187
|
+
if MEDIA_FRIENDLY_FILENAMES:
|
1188
|
+
return self.generateFriendlyURL(name, prefix, store)
|
1130
1189
|
|
1131
1190
|
paths = []
|
1132
|
-
paths.append(
|
1191
|
+
paths.append(store)
|
1133
1192
|
paths.append("/{}/".format(int_to_base36(self.mediaitem.pk)))
|
1134
1193
|
path = "".join(paths)
|
1135
|
-
if self.rendition_definition
|
1194
|
+
if self.rendition_definition is not None:
|
1136
1195
|
paths.append(int_to_base36(self.rendition_definition.pk))
|
1137
1196
|
else:
|
1138
1197
|
paths.append("0")
|
1139
1198
|
paths.append("_")
|
1140
1199
|
paths.append(utils.toMD5(path, int(time.time())))
|
1141
1200
|
paths.append(".")
|
1142
|
-
ext = "
|
1143
|
-
if "." in
|
1144
|
-
ext =
|
1201
|
+
ext = "dat"
|
1202
|
+
if "." in name:
|
1203
|
+
ext = name.split('.')[-1]
|
1145
1204
|
elif hasattr(self.mediaitem, "ext"):
|
1146
1205
|
ext = self.mediaitem.ext
|
1147
1206
|
paths.append(ext)
|
1148
1207
|
# print(paths)
|
1149
|
-
|
1208
|
+
return "".join(paths)
|
1209
|
+
|
1210
|
+
def upload(self, fp, prefix=""):
|
1211
|
+
"""
|
1212
|
+
Upload rendition to non-volatile storage
|
1213
|
+
"""
|
1214
|
+
doclose = False
|
1215
|
+
if type(fp) == str:
|
1216
|
+
doclose = True
|
1217
|
+
fp = open(fp)
|
1218
|
+
|
1219
|
+
self.url = self.generateURL(fp.name, prefix)
|
1150
1220
|
stores.upload(self.url, fp, background=True)
|
1151
1221
|
try:
|
1152
1222
|
self.bytes = fp.size
|
medialib/render/render_utils.py
CHANGED
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))
|
wiki/renderers/mistune/media.py
CHANGED
@@ -38,6 +38,7 @@ class MediaMixin(object):
|
|
38
38
|
return url
|
39
39
|
|
40
40
|
def link(self, link, text=None, title=None):
|
41
|
+
label = text
|
41
42
|
if text is None:
|
42
43
|
text = link
|
43
44
|
o = urllib.parse.urlparse(link)
|
@@ -47,6 +48,8 @@ class MediaMixin(object):
|
|
47
48
|
params = {"href":href}
|
48
49
|
if title:
|
49
50
|
params["title"] = title
|
51
|
+
if label:
|
52
|
+
params["download"] = label
|
50
53
|
if not href.startswith("http"):
|
51
54
|
params["data-action"] = "local_page"
|
52
55
|
flat_params = ' '.join("{}='{}'".format(key,val) for (key,val) in list(params.items()))
|
File without changes
|
File without changes
|