|
5 | 5 | from opengever.base.schema import IUTCDatetime |
6 | 6 | from persistent.interfaces import IPersistent |
7 | 7 | from plone.dexterity.interfaces import IDexterityContent |
| 8 | +from plone.namedfile.interfaces import INamedField |
8 | 9 | from plone.restapi.deserializer.dxfields import DatetimeFieldDeserializer |
9 | 10 | from plone.restapi.deserializer.dxfields import DefaultFieldDeserializer |
| 11 | +from plone.restapi.deserializer.dxfields import NamedFieldDeserializer |
10 | 12 | from plone.restapi.interfaces import IFieldDeserializer |
| 13 | +from plone.restapi.services.content.tus import TUSUpload |
11 | 14 | from pytz import utc |
12 | 15 | from zope.component import adapter |
13 | 16 | from zope.interface import implementer |
14 | 17 | from zope.publisher.interfaces.browser import IBrowserRequest |
15 | 18 | from zope.schema.interfaces import IDate |
16 | 19 | from zope.schema.interfaces import IDatetime |
17 | 20 | from zope.schema.interfaces import IField |
| 21 | +from zope.schema.interfaces import RequiredMissing |
18 | 22 | import dateutil |
19 | 23 |
|
20 | 24 |
|
@@ -84,3 +88,35 @@ def reject_year_before_1900(value): |
84 | 88 | if isinstance(value, (date, datetime)) and value.year < 1900: |
85 | 89 | raise ValueError( |
86 | 90 | 'year=%s is invalid. Year must be >= 1900.' % value.year) |
| 91 | + |
| 92 | + |
| 93 | +class TUSUploadNamedField(object): |
| 94 | + """Lightweight named file field used during TUS uploads instead of the |
| 95 | + original INamedField, to avoid loading the entire file content into RAM |
| 96 | + during field level validations. |
| 97 | + """ |
| 98 | + |
| 99 | + def __init__(self, original_field): |
| 100 | + self.required = original_field.required |
| 101 | + self.missing_value = original_field.missing_value |
| 102 | + self.__name__ = original_field.__name__ |
| 103 | + self._type = original_field._type |
| 104 | + |
| 105 | + def validate(self, value): |
| 106 | + if value == self.missing_value and self.required: |
| 107 | + raise RequiredMissing(self.__name__) |
| 108 | + |
| 109 | + |
| 110 | +@implementer(IFieldDeserializer) |
| 111 | +@adapter(INamedField, IDexterityContent, IOpengeverBaseLayer) |
| 112 | +class GeverNamedFieldDeserializer(NamedFieldDeserializer): |
| 113 | + """For TUS uploads, replaces self.field with a TUSUploadNamedField before |
| 114 | + delegating to the parent. The parent's self.field.validate(value) call then |
| 115 | + hits TUSUploadNamedField.validate(), which only checks the required |
| 116 | + constraint without loading the blob content into RAM. |
| 117 | + """ |
| 118 | + |
| 119 | + def __call__(self, value): |
| 120 | + if isinstance(value, TUSUpload): |
| 121 | + self.field = TUSUploadNamedField(self.field) |
| 122 | + return super(GeverNamedFieldDeserializer, self).__call__(value) |
0 commit comments