|
4 | 4 | from __future__ import division |
5 | 5 | from __future__ import print_function |
6 | 6 |
|
7 | | -import time |
8 | 7 | import copy |
9 | 8 | import json |
10 | 9 |
|
11 | | -import iso8601 |
12 | | -from werkzeug import LocalProxy |
| 10 | +from werkzeug.local import LocalProxy |
13 | 11 |
|
14 | 12 | import leancloud |
15 | 13 | from leancloud import utils |
@@ -80,6 +78,7 @@ def __init__(self, **attrs): |
80 | 78 | self._class_name = self._class_name # for IDE |
81 | 79 | self._changes = {} |
82 | 80 | self._attributes = {} |
| 81 | + self._flags = {} |
83 | 82 | self.created_at = None |
84 | 83 | self.updated_at = None |
85 | 84 |
|
@@ -152,13 +151,32 @@ def destroy_all(cls, objs): |
152 | 151 | """ |
153 | 152 | if not objs: |
154 | 153 | return |
155 | | - if not all(x._class_name == objs[0]._class_name for x in objs): |
156 | | - raise ValueError("destroy_all requires the argument object list's _class_names must be the same") |
157 | 154 | if any(x.is_new() for x in objs): |
158 | 155 | raise ValueError("Could not destroy unsaved object") |
159 | | - ids = {x.id for x in objs} |
160 | | - ids = ','.join(ids) |
161 | | - client.delete('/classes/{0}/{1}'.format(objs[0]._class_name, ids)) |
| 156 | + |
| 157 | + dumped_objs = [] |
| 158 | + for obj in objs: |
| 159 | + dumped_obj = { |
| 160 | + 'method': 'DELETE', |
| 161 | + 'path': '/{0}/classes/{1}/{2}'.format(client.SERVER_VERSION, obj._class_name, obj.id), |
| 162 | + 'body': obj._flags, |
| 163 | + } |
| 164 | + dumped_objs.append(dumped_obj) |
| 165 | + |
| 166 | + response = client.post('/batch', params={'requests': dumped_objs}).json() |
| 167 | + |
| 168 | + errors = [] |
| 169 | + for idx, obj in enumerate(objs): |
| 170 | + content = response[idx] |
| 171 | + error = content.get('error') |
| 172 | + if error: |
| 173 | + errors.append(leancloud.LeanCloudError(error.get('code'), error.get('error'))) |
| 174 | + |
| 175 | + if errors: |
| 176 | + # TODO: how to raise list of errors? |
| 177 | + # raise MultipleValidationErrors(errors) |
| 178 | + # add test |
| 179 | + raise errors[0] |
162 | 180 |
|
163 | 181 | def dump(self): |
164 | 182 | obj = self._dump() |
@@ -186,7 +204,7 @@ def destroy(self): |
186 | 204 | """ |
187 | 205 | if not self.id: |
188 | 206 | return |
189 | | - client.delete('/classes/{0}/{1}'.format(self._class_name, self.id)) |
| 207 | + client.delete('/classes/{0}/{1}'.format(self._class_name, self.id), self._flags) |
190 | 208 |
|
191 | 209 | def save(self, where=None, fetch_when_save=None): |
192 | 210 | """ |
@@ -464,7 +482,9 @@ def clear(self): |
464 | 482 | self.set(self._attributes, unset=True) |
465 | 483 |
|
466 | 484 | def _dump_save(self): |
467 | | - return {k:v.dump() for k,v in iteritems(self._changes)} |
| 485 | + data = {k: v.dump() for k, v in iteritems(self._changes)} |
| 486 | + data.update(self._flags) |
| 487 | + return data |
468 | 488 |
|
469 | 489 | def fetch(self, select=None, include=None): |
470 | 490 | """ |
@@ -515,18 +535,29 @@ def set_acl(self, acl): |
515 | 535 | return self.set('ACL', acl) |
516 | 536 |
|
517 | 537 | def disable_before_hook(self): |
518 | | - master_key = client.get_app_info().get('master_key') |
519 | | - if not master_key: |
520 | | - raise ValueError('disable_before_hook need LeanCloud master key') |
521 | | - timestamp = int(time.time() * 1000) |
522 | | - return self.set('__before', utils.sign_hook('__before_for_' + self._class_name, master_key, timestamp)) |
| 538 | + hook_key = client.get_app_info().get('hook_key') |
| 539 | + if not hook_key: |
| 540 | + raise ValueError('disable_before_hook need LeanCloud hook key') |
| 541 | + self.ignore_hook('beforeSave') |
| 542 | + self.ignore_hook('beforeUpdate') |
| 543 | + self.ignore_hook('beforeDelete') |
| 544 | + return self |
523 | 545 |
|
524 | 546 | def disable_after_hook(self): |
525 | | - master_key = client.get_app_info().get('master_key') |
526 | | - if not master_key: |
527 | | - raise ValueError('disable_before_hook need LeanCloud master key') |
528 | | - timestamp = int(time.time() * 1000) |
529 | | - return self.set('__after', utils.sign_hook('__after_for_' + self._class_name, master_key, timestamp)) |
| 547 | + hook_key = client.get_app_info().get('hook_key') |
| 548 | + if not hook_key: |
| 549 | + raise ValueError('`disable_before_hook` need LeanCloud hook key') |
| 550 | + self.ignore_hook('afterSave') |
| 551 | + self.ignore_hook('afterUpdate') |
| 552 | + self.ignore_hook('afterDelete') |
| 553 | + return self |
| 554 | + |
| 555 | + def ignore_hook(self, hook_name): |
| 556 | + if hook_name not in {'beforeSave', 'afterSave', 'beforeUpdate', 'afterUpdate', 'beforeDelete', 'afterDelete'}: |
| 557 | + raise ValueError('invalid hook name: ' + hook_name) |
| 558 | + if '__ignore_hooks' not in self._flags: |
| 559 | + self._flags['__ignore_hooks'] = [] |
| 560 | + self._flags['__ignore_hooks'].append(hook_name) |
530 | 561 |
|
531 | 562 | def _update_data(self, server_data): |
532 | 563 | self._merge_metadata(server_data) |
|
0 commit comments