django-restit 4.2.130__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-restit
3
- Version: 4.2.130
3
+ Version: 4.2.131
4
4
  Summary: A Rest Framework for DJANGO
5
5
  License: MIT
6
6
  Author: Ian Starnes
@@ -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=CrTS5znW8JMuj8gaAnJ5boYvN-deF8zyOuCmW3cFQVE,52228
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=nZf5OvTZ6vMoJATqOiGJjWBecXkxoXQK9VU521xnVT0,617
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=gAFiVHQkbYHZQ_2LU5nl2EXyoSs1mW4VdVCjsImisuE,5836
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=Hw2lZ5vZg_JFjgbt2nhqTYdXwbERCvgnefl8rEdCUKQ,3756
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=SVzE--w6i3jhZDS773pK0TONhXDz7k3o4fmQrPAa99w,122
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=JHMvWG8A-n4g915wrZiCtfuhgcLMgNYMXuzXIEtgaPg,12335
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
@@ -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.130.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
516
- django_restit-4.2.130.dist-info/METADATA,sha256=9xgoIJG_Or13Bbw9zbbFb5sByRnWrAdkF2pKjC_0jTU,7663
517
- django_restit-4.2.130.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
518
- django_restit-4.2.130.dist-info/RECORD,,
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 upload(self, fp, prefix=""):
1123
- """
1124
- Upload rendition to non-volatile storage
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(self.mediaitem.default_store())
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 != None:
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 fp.name:
1144
- ext = fp.name.split('.')[-1]
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
- self.url = "".join(paths)
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
@@ -14,7 +14,8 @@ EXT_MAP = {
14
14
  KIND_MAP = {
15
15
  "video": "V",
16
16
  "image": "I",
17
- "http": "E"
17
+ "http": "E",
18
+ "other": "O"
18
19
  }
19
20
 
20
21
  def getFileExt(file):
rest/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  from .uberdict import UberDict # noqa: F401
2
2
  from .settings_helper import settings # noqa: F401
3
3
 
4
- __version__ = "4.2.130"
4
+ __version__ = "4.2.131"
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 getEndOfMonth(start):
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))