class CatalogCronDiscontinue(orm.BaseModel): cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} limit = self.cfg.get('page', 10) Catalog = context.models['35'] if context.domain.state == 'active': catalogs = Catalog.query( Catalog.state == 'published', Catalog.discontinue_date <= datetime.datetime.now(), namespace=context.namespace).fetch(limit=limit) else: catalogs = Catalog.query( Catalog.state == 'published', namespace=context.namespace).fetch(limit=limit) for catalog in catalogs: data = { 'action_id': 'discontinue', 'action_model': '35', 'message': 'Expired', 'key': catalog.key.urlsafe() } context._callbacks.append(('callback', data))
class CronConfigProcessCatalogs(orm.BaseModel): cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} limit = self.cfg.get('page', 10) Domain = context.models['6'] cursor = None if context._cronconfig.data.get('more'): cursor = Cursor(urlsafe=context._cronconfig.data.get('cursor')) entities, cursor, more = Domain.query().order( Domain.created).fetch_page(limit, start_cursor=cursor, keys_only=True) if cursor: cursor = cursor.urlsafe() context._cronconfig.data['cursor'] = cursor context._cronconfig.data['more'] = more for key in entities: data = { 'action_id': 'cron', 'action_model': '35', 'domain': key.urlsafe() } context._callbacks.append(('callback', data))
class UnitUpdateWrite(orm.BaseModel): cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} update_file_path = self.cfg.get('file', None) if not update_file_path: raise orm.TerminateAction() Unit = context.models['19'] with file(update_file_path) as f: tree = ElementTree.fromstring(f.read()) root = tree.findall('data') measurements = {} uoms = [] for child in root[0]: if child.attrib.get('model') == 'product.uom.category': for child2 in child: name = child2.text measurements[child.attrib.get('id')] = name for child in root[0]: if child.attrib.get('model') == 'product.uom': new_uom = {'id': child.attrib.get('id')[4:]} new_uom_data = {} for child2 in child: new_uom_data[child2.attrib.get('name')] = child2 rounding = new_uom_data.get('rounding') digits = new_uom_data.get('digits') if rounding != None: rounding = Decimal(eval(rounding.attrib.get('eval'))) if digits != None: digits = long(eval(digits.attrib.get('eval'))) new_uom.update({ 'name': new_uom_data['name'].text, 'active': True, 'symbol': new_uom_data['symbol'].text, 'measurement': measurements.get( new_uom_data['category'].attrib.get('ref')), 'factor': Decimal(eval( new_uom_data['factor'].attrib.get('eval'))), 'rate': Decimal(eval(new_uom_data['rate'].attrib.get('eval'))), 'rounding': rounding, 'digits': digits }) uoms.append(new_uom) to_put = [Unit(**d) for d in uoms] for entity in to_put: entity._use_rule_engine = False orm.put_multi(to_put)
class Filter(orm.BaseModel): _kind = 65 _use_rule_engine = False name = orm.SuperStringProperty('1', required=True, indexed=False) model = orm.SuperStringProperty('2', required=True, indexed=False) query = orm.SuperJsonProperty('3', required=True, indexed=False, default={})
class RuleExec(orm.BaseModel): _kind = 94 cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} entity_path = self.cfg.get('path', '_' + context.model.__name__.lower()) action_path = self.cfg.get('action', 'action') entity = get_attr(context, entity_path) action = get_attr(context, action_path) rule_exec(entity, action)
class UploadImages(orm.BaseModel): _kind = 92 cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} entity_path = self.cfg.get('path', '_' + context.model.__name__.lower()) images_path = self.cfg.get('images_path') manager = get_attr(context, entity_path) if manager is not None and hasattr(manager, 'add') and callable( manager.add): manager.add(get_attr(context, images_path))
class BlobURL(orm.BaseModel): _kind = 98 cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} gs_bucket = self.cfg.get('bucket', None) sufix = self.cfg.get('sufix', '/' + context.model.__name__.lower()) upload_url = context.input.get('upload_url') if upload_url and gs_bucket: gs_bucket_name = gs_bucket + sufix context._blob_url = blob_create_upload_url(upload_url, gs_bucket_name)
class ProductCategoryUpdateWrite(orm.BaseModel): cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): # This code builds leaf categories for selection with complete names, 3.8k of them. if not isinstance(self.cfg, dict): self.cfg = {} update_file_path = self.cfg.get('file', None) production_environment = self.cfg.get('prod_env', False) if not update_file_path: raise orm.TerminateAction() Category = context.models['17'] data = [] with file(update_file_path) as f: for line in f: if not line.startswith('#'): data.append(line.replace('\n', '')) write_data = [] sep = ' > ' parent = None dig = 0 for i, item in enumerate(data): if i == 100 and not production_environment: break new_cat = {} current = item.split(sep) try: next = data[i + 1].split(sep) except IndexError as e: next = current if len(next) == len(current): current_total = len(current) - 1 last = current[current_total] parent = current[current_total - 1] new_cat['id'] = hashlib.md5(last).hexdigest() new_cat['parent_record'] = Category.build_key( hashlib.md5(parent).hexdigest()) new_cat['name'] = last new_cat['complete_name'] = ' / '.join(current[:current_total + 1]) new_cat['state'] = 'indexable' new_cat = Category(**new_cat) new_cat._use_rule_engine = False new_cat._use_record_engine = False write_data.append(new_cat) orm.put_multi(write_data)
class UserLoginInit(orm.BaseModel): cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} login_methods = self.cfg.get('methods', {}) context._user = context.model.current_user() context.user = context.model.current_user() kwargs = {'user': context.user, 'action': context.action} rule_prepare(context._user, True, False, **kwargs) rule_exec(context._user, context.action) login_method = context.input.get('login_method') error = context.input.get('error') code = context.input.get('code') oauth2_cfg = login_methods[login_method]['oauth2'] client = oauth2.Client(**oauth2_cfg) context.output['authorization_url'] = client.get_authorization_code_uri() urls = {} for urls_login_method, cfg in login_methods.iteritems(): urls_oauth2_cfg = cfg['oauth2'] urls_client = oauth2.Client(**urls_oauth2_cfg) urls[urls_oauth2_cfg['type']] = urls_client.get_authorization_code_uri() context.output['authorization_urls'] = urls if error: raise OAuth2Error('rejected_account_access') if code: client.get_token(code) if not client.access_token: raise OAuth2Error('failed_access_token') userinfo = oauth2_cfg['userinfo'] info = client.resource_request(url=userinfo) if info and 'email' in info: identity = oauth2_cfg['type'] context._identity_id = '%s-%s' % (info['id'], identity) context._email = info['email'] user = context.model.query(context.model.identities.identity == context._identity_id).get() if not user: user = context.model.query(context.model.emails == context._email).get() if user: context._user = user context.user = user kwargs = {'user': context.user, 'action': context.action} rule_prepare(context._user, True, False, **kwargs) rule_exec(context._user, context.action)
class NotificationMailSend(orm.BaseModel): cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} message_sender = self.cfg.get('sender', None) if not message_sender: raise orm.TerminateAction() message = mail.EmailMessage() message.sender = message_sender message.bcc = context.input['recipient'] message.subject = context.input['subject'] message.body = context.input[ 'body'] # We can add html argument in addition to body if we want to send html version! message.check_initialized() message.send()
class ConfigurationCronInstall(orm.BaseModel): cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} elapsed_time = self.cfg.get('time', 10) limit = self.cfg.get('page', 50) time_difference = datetime.datetime.now() - datetime.timedelta( minutes=elapsed_time) configurations = context.model.query( context.model.state == 'active', context.model.updated < time_difference).fetch(limit=limit) for config in configurations: context.user = config.parent_entity SetupClass = get_system_setup(config.setup) setup = SetupClass(config, context) setup.run()
class Set(orm.BaseModel): _kind = 87 cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} static_values = self.cfg.get('s', {}) dynamic_values = self.cfg.get('d', {}) remove_values = self.cfg.get('rm', []) for key, value in static_values.iteritems(): set_attr(context, key, value) for key, value in dynamic_values.iteritems(): set_value = get_attr(context, value, Nonexistent) if set_value is not Nonexistent: set_attr(context, key, set_value) for key in remove_values: del_attr(context, key)
class Read(orm.BaseModel): _kind = 88 cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default=[]) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} source_path = self.cfg.get('source', 'input.key') model_path = self.cfg.get('model', 'model') parent_path = self.cfg.get('parent', None) namespace_path = self.cfg.get('namespace', 'namespace') read_arguments_path = self.cfg.get('read', 'input.read_arguments') save_path = self.cfg.get('path', '_' + context.model.__name__.lower()) source = get_attr(context, source_path, None) model = get_attr(context, model_path) parent = get_attr(context, parent_path) namespace = get_attr(context, namespace_path) read_arguments = get_attr(context, read_arguments_path, {}) if parent is not None: namespace = None if source and isinstance(source, orm.Key): entity = source.get() entity.read(read_arguments) elif hasattr(model, 'prepare_key'): model_key = model.prepare_key( context.input, parent=parent, namespace=namespace ) # @todo Perhaps, all context system wide variables should be passed to prepare_key (input, output, action, model, models, domain, namespace...) if model_key.id() is not None: entity = model_key.get() if entity is None: entity = model(key=model_key) else: entity.read(read_arguments) else: entity = model(key=model_key) else: entity = model(parent=parent, namespace=namespace) entity.make_original() set_attr(context, save_path, entity)
class RulePrepare(orm.BaseModel): _kind = 93 cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} entity_path = self.cfg.get('path', '_' + context.model.__name__.lower()) skip_user_roles = self.cfg.get('skip_user_roles', False) strict = self.cfg.get('strict', False) static_kwargs = self.cfg.get('s', {}) dynamic_kwargs = self.cfg.get('d', {}) kwargs = {'user': context.user, 'action': context.action} kwargs.update(static_kwargs) for key, value in dynamic_kwargs.iteritems(): kwargs[key] = get_attr(context, value) entities = get_attr(context, entity_path) rule_prepare(entities, skip_user_roles, strict, **kwargs)
class CallbackExec(orm.BaseModel): _kind = 97 cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default=[]) def run(self, context): if not isinstance(self.cfg, list): self.cfg = [] queues = {} for config in self.cfg: queue_name, static_data, dynamic_data = config for key, value in dynamic_data.iteritems(): static_data[key] = get_attr(context, value) context._callbacks.append((queue_name, static_data)) for callback in context._callbacks: if callback[1].get('caller_user') is None: callback[1]['caller_user'] = context.user.key_urlsafe if callback[1].get('caller_action') is None: callback[1]['caller_action'] = context.action.key_urlsafe callback_exec('/task/io_engine_run', context._callbacks) context._callbacks = []
class CatalogCronDelete(orm.BaseModel): cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} limit = self.cfg.get('page', 10) catalog_unpublished_life = self.cfg.get('unpublished_life', 7) catalog_discontinued_life = self.cfg.get('discontinued_life', 180) Catalog = context.models['35'] catalogs = [] locked_catalogs = [] if context.domain.state != 'active': locked_catalogs = Catalog.query( Catalog.state == 'locked', namespace=context.namespace).fetch(limit=limit) unpublished_catalogs = Catalog.query( Catalog.state == 'unpublished', Catalog.created < (datetime.datetime.now() - datetime.timedelta(days=catalog_unpublished_life)), namespace=context.namespace).fetch(limit=limit) discontinued_catalogs = Catalog.query( Catalog.state == 'discontinued', Catalog.updated < (datetime.datetime.now() - datetime.timedelta(days=catalog_discontinued_life)), namespace=context.namespace).fetch(limit=limit) catalogs.extend(locked_catalogs) catalogs.extend(unpublished_catalogs) catalogs.extend(discontinued_catalogs) for catalog in catalogs: data = { 'action_id': 'delete', 'action_model': '35', 'key': catalog.key.urlsafe() } context._callbacks.append(('callback', data))
class CatalogSearchDocumentDelete(orm.BaseModel): cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} entities = [] index_name = self.cfg.get('index', None) entities.append(context._catalog.key) context._catalog._images.read({'config': {'cursor': -1}}) product_keys = [] for image in context._catalog._images.value: product_keys.extend([ pricetag.product._urlsafe for pricetag in image.pricetags.value ]) context._catalog._products.read({'config': {'keys': product_keys}}) products = context._catalog._products.value context._catalog._images = [] entities.extend([product.key for product in products]) context._catalog._delete_custom_indexes = {} context._catalog._delete_custom_indexes[index_name] = entities context._catalog._products = []
class Delete(orm.BaseModel): _kind = 90 cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} entity_path = self.cfg.get('path', '_' + context.model.__name__.lower()) static_record_arguments = self.cfg.get('sra', {}) dynamic_record_arguments = self.cfg.get('dra', {}) entity = get_attr(context, entity_path) if entity and isinstance(entity, orm.Model): record_arguments = { 'agent': context.user.key, 'action': context.action.key } record_arguments.update(static_record_arguments) for key, value in dynamic_record_arguments.iteritems(): record_arguments[key] = get_attr(context, value) entity.delete(record_arguments)
class CronConfig(orm.BaseModel): _kind = 83 _use_record_engine = False _use_rule_engine = False data = orm.SuperJsonProperty('1', indexed=False, default={}) _global_role = GlobalRole(permissions=[ orm.ActionPermission( '83', [orm.Action.build_key('83', 'process_catalogs')], True, 'user._is_cron') ]) _actions = [ orm.Action(key=orm.Action.build_key('83', 'process_catalogs'), arguments={}, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), RulePrepare(cfg={'skip_user_roles': True}), RuleExec(), CronConfigProcessCatalogs( cfg={'page': settings.DOMAINS_PER_CRON}), Write(), CallbackExec() ]) ]) ] # @todo Right now this will work however, once we implement other cron actions, prepare_key will be useless (see plugins/base.py Read plugin)! # One way this could work with multiple actions is if we use CronConfig.data to store action specific parameters! @classmethod def prepare_key(cls, input, **kwargs): return cls.build_key('process_catalogs_key')
class Duplicate(orm.BaseModel): _kind = 91 cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} entity_path = self.cfg.get('source', '_' + context.model.__name__.lower()) save_path = self.cfg.get('path', '_' + context.model.__name__.lower()) child_entity_path = self.cfg.get('copy_path') entity = get_attr(context, entity_path) if child_entity_path: child_entity = get_attr(entity, child_entity_path) parent_entity_path = ".".join(child_entity_path.split('.')[:-1]) parent_entity = get_attr(entity, parent_entity_path) parent_entity.append(child_entity.duplicate()) duplicate_entity = entity else: if entity and isinstance(entity, orm.Model): duplicate_entity = entity.duplicate() set_attr(context, save_path, duplicate_entity)
class Search(orm.BaseModel): _kind = 95 cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} search_arguments = context.input.get('search') search_arguments['namespace'] = context.namespace result = context.model.search(search_arguments) if search_arguments.get('keys'): context._entities = result context._cursor = None context._more = False elif context.model._use_search_engine: context._total_matches = result.number_found context._entities_count = len(result.results) context._entities = map(context.model.search_document_to_entity, result.results) more = False cursor = result.cursor if cursor is not None: cursor = cursor.web_safe_string more = True context._cursor = cursor context._more = more else: context._entities_count = len(result[0]) context._entities = result[0] cursor = result[1] if cursor is not None: cursor = cursor.urlsafe() context._cursor = cursor context._more = result[2]
class CatalogSearch(orm.BaseModel): cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} index_name = self.cfg.get('index', None) search_arguments = context.input.get('search') query = search_arguments['property'].build_search_query( search_arguments) index = search.Index(name=index_name) result = index.search(query) context._total_matches = result.number_found context._entities_count = len(result.results) context._entities = map(context.model.search_document_to_dict, result.results) more = False cursor = result.cursor if cursor is not None: cursor = cursor.web_safe_string more = True context._cursor = cursor context._more = more
class Journal(orm.BaseExpando): _kind = 49 created = orm.SuperDateTimeProperty('1', required=True, auto_now_add=True) updated = orm.SuperDateTimeProperty('2', required=True, auto_now=True) name = orm.SuperStringProperty('3', required=True) state = orm.SuperStringProperty('4', required=True, default='draft', choices=['draft', 'active', 'decommissioned']) entry_fields = orm.SuperPickleProperty('5', required=True, indexed=False, compressed=False) line_fields = orm.SuperPickleProperty('6', required=True, indexed=False, compressed=False) _default_indexed = False _virtual_fields = { '_records': orm.SuperRecordProperty('49'), '_code': orm.SuperComputedProperty(lambda self: self.key_id_str), '_transaction_actions': orm.SuperRemoteStructuredProperty(Action, repeated=True), '_transaction_plugin_groups': orm.SuperRemoteStructuredProperty(PluginGroup, repeated=True) } _global_role = GlobalRole( permissions=[ orm.ActionPermission('49', [orm.Action.build_key('49', 'prepare'), orm.Action.build_key('49', 'create'), orm.Action.build_key('49', 'read'), orm.Action.build_key('49', 'update'), orm.Action.build_key('49', 'delete'), orm.Action.build_key('49', 'search'), orm.Action.build_key('49', 'activate'), orm.Action.build_key('49', 'decommission')], False, 'entity._original.namespace_entity._original.state != "active"'), orm.ActionPermission('49', [orm.Action.build_key('49', 'delete')], False, 'entity._original.state != "draft"'), orm.ActionPermission('49', [orm.Action.build_key('49', 'activate')], False, 'entity._original.state == "active"'), orm.ActionPermission('49', [orm.Action.build_key('49', 'decommission')], False, 'entity._is_system or entity._original.state != "active"'), orm.FieldPermission('49', ['created', 'updated', 'state'], False, None, 'True'), orm.FieldPermission('49', ['created', 'updated', 'name', 'state', 'entry_fields', 'line_fields', '_records', '_code', '_transaction_actions', '_transaction_plugin_groups'], False, False, 'entity._original.namespace_entity._original.state != "active"'), orm.FieldPermission('49', ['created', 'updated', 'name', 'state', 'entry_fields', 'line_fields', '_records', '_code'], False, None, 'entity._original.state != "draft"'), orm.FieldPermission('49', ['_transaction_actions', '_transaction_plugin_groups.name', '_transaction_plugin_groups.subscriptions', '_transaction_plugin_groups.active', '_transaction_plugin_groups.sequence', '_transaction_plugin_groups.transactional'], False, None, 'entity._is_system'), orm.FieldPermission('49', ['_transaction_plugin_groups.plugins'], False, None, 'entity._is_system and entity._original._transaction_plugin_groups.name != "User Plugins"'), # @todo Missing index between _transaction_plugin_groups and name! orm.FieldPermission('49', ['state'], True, None, '(action.key_id_str == "activate" and entity.state == "active") or (action.key_id_str == "decommission" and entity.state == "decommissioned")') ] ) _actions = [ orm.Action( key=orm.Action.build_key('49', 'prepare'), arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), RulePrepare(), RuleExec(), Set(cfg={'d': {'output.entity': '_journal'}}) ] ) ] ), orm.Action( key=orm.Action.build_key('49', 'create'), arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True), '_code': orm.SuperStringProperty(required=True, max_size=64), # Regarding max_size, take a look at the transaction.JournalUpdateRead() plugin! 'name': orm.SuperStringProperty(required=True), 'entry_fields': orm.SuperPropertyStorageProperty(required=True, cfg=JOURNAL_FIELDS), 'line_fields': orm.SuperPropertyStorageProperty(required=True, cfg=JOURNAL_FIELDS) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), Set(cfg={'s': {'_journal.state': 'draft'}, 'd': {'_journal.name': 'input.name', '_journal.entry_fields': 'input.entry_fields', '_journal.line_fields': 'input.line_fields'}}), RulePrepare(), RuleExec() ] ), orm.PluginGroup( transactional=True, plugins=[ Write(), Set(cfg={'d': {'output.entity': '_journal'}}), CallbackNotify(), CallbackExec() ] ) ] ), orm.Action( key=orm.Action.build_key('49', 'read'), arguments={ 'key': orm.SuperKeyProperty(kind='49', required=True), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), RulePrepare(), RuleExec(), Set(cfg={'d': {'output.entity': '_journal'}}) ] ) ] ), orm.Action( key=orm.Action.build_key('49', 'update'), arguments={ 'key': orm.SuperKeyProperty(kind='49', required=True), 'name': orm.SuperStringProperty(required=True), 'entry_fields': orm.SuperPropertyStorageProperty(required=True, cfg=JOURNAL_FIELDS), 'line_fields': orm.SuperPropertyStorageProperty(required=True, cfg=JOURNAL_FIELDS), '_transaction_actions': orm.SuperLocalStructuredProperty(Action, repeated=True), '_transaction_plugin_groups': orm.SuperLocalStructuredProperty(PluginGroup, repeated=True) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), Set(cfg={'d': {'_journal.name': 'input.name', '_journal.entry_fields': 'input.entry_fields', '_journal.line_fields': 'input.line_fields', '_journal._transaction_actions': 'input._transaction_actions', '_journal._transaction_plugin_groups': 'input._transaction_plugin_groups'}}), RulePrepare(), RuleExec() ] ), orm.PluginGroup( transactional=True, plugins=[ Write(), Set(cfg={'d': {'output.entity': '_journal'}}), CallbackNotify(), CallbackExec() ] ) ] ), orm.Action( key=orm.Action.build_key('49', 'delete'), arguments={ 'key': orm.SuperKeyProperty(kind='49', required=True) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), RulePrepare(), RuleExec() ] ), orm.PluginGroup( transactional=True, plugins=[ Delete(), Set(cfg={'d': {'output.entity': '_journal'}}), CallbackNotify(), CallbackExec() ] ) ] ), orm.Action( key=orm.Action.build_key('49', 'search'), arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True), 'search': orm.SuperSearchProperty( default={'filters': [], 'orders': [{'field': 'name', 'operator': 'asc'}]}, cfg={ 'search_arguments': {'kind': '49', 'options': {'limit': settings.SEARCH_PAGE}}, 'filters': {'name': orm.SuperStringProperty(), 'state': orm.SuperStringProperty(choices=[])}, 'indexes': [{'orders': [('name', ['asc', 'desc'])]}, {'orders': [('state', ['asc', 'desc'])]}, {'filters': [('name', ['==', '!='])], 'orders': [('name', ['asc', 'desc'])]}, {'filters': [('state', ['==', '!='])], 'orders': [('name', ['asc', 'desc'])]}, {'filters': [('state', ['==', '!=']), ('name', ['==', '!='])], 'orders': [('name', ['asc', 'desc'])]}] } ) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), RulePrepare(), RuleExec(), Search(), RulePrepare(cfg={'path': '_entities'}), Set(cfg={'d': {'output.entities': '_entities', 'output.cursor': '_cursor', 'output.more': '_more'}}) ] ) ] ), orm.Action( key=orm.Action.build_key('49', 'activate'), arguments={ 'key': orm.SuperKeyProperty(kind='49', required=True), 'message': orm.SuperTextProperty(required=True) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), Set(cfg={'s': {'_journal.state': 'active'}}), RulePrepare(), RuleExec() ] ), orm.PluginGroup( transactional=True, plugins=[ Write(cfg={'dra': {'message': 'input.message'}}), CallbackNotify(), CallbackExec() ] ), orm.PluginGroup( plugins=[ RulePrepare(), Set(cfg={'d': {'output.entity': '_journal'}}) ] ) ] ), orm.Action( key=orm.Action.build_key('49', 'decommission'), arguments={ 'key': orm.SuperKeyProperty(kind='49', required=True), 'message': orm.SuperTextProperty(required=True) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), Set(cfg={'s': {'_journal.state': 'decommissioned'}}), RulePrepare(), RuleExec() ] ), orm.PluginGroup( transactional=True, plugins=[ Write(cfg={'dra': {'message': 'input.message'}}), CallbackNotify(), CallbackExec() ] ), orm.PluginGroup( plugins=[ RulePrepare(), Set(cfg={'d': {'output.entity': '_journal'}}) ] ) ] ) ] @classmethod def prepare_key(cls, input, **kwargs): code = input.get('_code') return cls.build_key(code, namespace=kwargs.get('namespace')) # @todo Possible prefix? @property def _is_system(self): return self.key_id_str.startswith('system_')
class CatalogSearchDocumentWrite(orm.BaseModel): cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} documents = [] index_name = self.cfg.get('index', None) catalog_fields = { 'namespace_entity.name': orm.SuperStringProperty(search_document_field_name='seller_name'), 'namespace_entity.logo.value.serving_url': orm.SuperStringProperty(search_document_field_name='seller_logo'), 'cover.value.serving_url': orm.SuperStringProperty(search_document_field_name='cover') } # name='seller_feedback', value=context._catalog.namespace_entity.feedback product_fields = { 'parent_entity.name': orm.SuperStringProperty(search_document_field_name='catalog_name'), 'namespace_entity.name': orm.SuperStringProperty(search_document_field_name='seller_name'), 'namespace_entity.logo.value.serving_url': orm.SuperStringProperty(search_document_field_name='seller_logo'), '_product_category.value.parent_record': orm.SuperKeyProperty( kind='17', search_document_field_name='product_category_parent_record'), '_product_category.value.name': orm.SuperStringProperty( search_document_field_name='product_category_name'), '_product_category.value.complete_name': orm.SuperTextProperty( search_document_field_name='product_category_complete_name') } context._catalog._images.read({'config': {'cursor': -1}}) product_keys = [] for image in context._catalog._images.value: product_keys.extend([ pricetag.product._urlsafe for pricetag in image.pricetags.value ]) context._catalog._products.read({ '_product_category': {}, 'config': { 'keys': product_keys } }) products = context._catalog._products.value context._catalog._images = [] write_index = True if not len(products): # write_index = False @todo We shall not allow indexing of catalogs without products attached! pass for product in products: if product._product_category.value.state != 'indexable': write_index = False break results = None if write_index: documents.extend( [context._catalog.get_search_document(catalog_fields)]) documents.extend([ product.get_search_document(product_fields) for product in products ]) context._catalog._write_custom_indexes = {} context._catalog._write_custom_indexes[index_name] = documents context._catalog._products = []
class CountryUpdateWrite(orm.BaseModel): cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} update_file_path = self.cfg.get('file', None) production_environment = self.cfg.get('prod_env', False) if not update_file_path: raise orm.TerminateAction() Country = context.models['15'] CountrySubdivision = context.models['16'] with file(update_file_path) as f: tree = ElementTree.fromstring(f.read()) root = tree.findall('data') to_put = [] def make_complete_name_for_subdivision(entity, parent_id, process): separator = unicode(' / ') parent_property = 'parent_record' name_property = 'name' path = entity names = [] while True: parent = None if parent_property is None: parent_key = path.key.parent() parent = parent_key.get() else: parent_key = getattr(path, parent_property) if parent_key: parent = process.get(parent_key.urlsafe()) if not parent: names.append(getattr(path, name_property)) break else: names.append(getattr(path, name_property)) path = parent names.reverse() return separator.join(names) i = 0 for child in root[1]: i += 1 dat = dict() dat['id'] = child.attrib['id'] for child2 in child: name = child2.attrib.get('name') if name is None: continue if child2.text: dat[name] = child2.text to_put.append( Country(name=dat['name'], id=dat['id'], code=dat['code'], active=True)) if i == 100 and not production_environment: break processed_keys = {} processed_ids = {} i = 0 for child in [c for c in root[2]] + [c for c in root[3]]: i += 1 dat = dict() dat['id'] = child.attrib['id'] for child2 in child: k = child2.attrib.get('name') if k is None: continue if child2.text: dat[k] = child2.text if 'ref' in child2.attrib: dat[k] = child2.attrib['ref'] kw = dict(name=dat['name'], id=dat['id'], type=dat['type'], code=dat['code'], active=True) if 'country' in dat: kw['parent'] = Country.build_key(dat['country']) if 'parent' in dat: parent = processed_ids.get(dat['parent']) if parent: kw['parent_record'] = parent.key new_sub_divison = CountrySubdivision(**kw) new_sub_divison.complete_name = '' if 'parent' in dat: new_sub_divison.complete_name = make_complete_name_for_subdivision( new_sub_divison, dat['parent'], processed_keys) processed_keys[new_sub_divison.key_urlsafe] = new_sub_divison processed_ids[dat['id']] = new_sub_divison new_sub_divison._use_rule_engine = False to_put.append(new_sub_divison) if i == 100 and not production_environment: break orm.put_multi(to_put)
class Widget(orm.BaseExpando): _kind = 62 _use_search_engine = True # @todo This is extra added for testing functions of google seach! name = orm.SuperStringProperty( '1', required=True, searchable=True ) # @todo This is extra added for testing functions of google seach! sequence = orm.SuperIntegerProperty( '2', required=True, searchable=True ) # @todo This is extra added for testing functions of google seach! active = orm.SuperBooleanProperty( '3', required=True, default=True, searchable=True ) # @todo This is extra added for testing functions of google seach! role = orm.SuperKeyProperty('4', kind='60', required=True) search_form = orm.SuperBooleanProperty('5', required=True, indexed=False, default=True) filters = orm.SuperLocalStructuredProperty(Filter, '6', repeated=True) _default_indexed = False _virtual_fields = {'_records': orm.SuperRecordProperty('62')} _global_role = GlobalRole(permissions=[ orm.ActionPermission( '62', [ orm.Action.build_key('62', 'prepare'), orm.Action.build_key('62', 'create'), orm.Action.build_key('62', 'read'), orm.Action.build_key('62', 'update'), orm.Action.build_key('62', 'delete'), orm.Action.build_key('62', 'search'), orm.Action.build_key('62', 'build_menu') ], False, 'entity._original.namespace_entity._original.state != "active"'), orm.ActionPermission('62', [ orm.Action.build_key('62', 'create'), orm.Action.build_key('62', 'update'), orm.Action.build_key('62', 'delete') ], False, 'entity._is_system'), orm.FieldPermission( '62', [ 'name', 'sequence', 'active', 'role', 'search_form', 'filters', '_records' ], False, False, 'entity._original.namespace_entity._original.state != "active"'), orm.FieldPermission('62', [ 'name', 'sequence', 'active', 'role', 'search_form', 'filters', '_records' ], False, None, 'entity._is_system'), orm.FieldPermission( '62', ['role'], False, None, '(action.key_id_str == "create" or action.key_id_str == "update") and (entity.role and entity.role._namespace != entity._original.key_namespace)' ) ]) _actions = [ orm.Action(key=orm.Action.build_key('62', 'prepare'), arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True) }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), RulePrepare(), RuleExec(), Set(cfg={'d': { 'output.entity': '_widget' }}) ]) ]), orm.Action( key=orm.Action.build_key('62', 'create'), arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True), 'name': orm.SuperStringProperty(required=True), 'sequence': orm.SuperIntegerProperty(required=True), 'active': orm.SuperBooleanProperty(default=True), 'role': orm.SuperKeyProperty(kind='60', required=True), 'search_form': orm.SuperBooleanProperty(default=True), 'filters': orm.SuperLocalStructuredProperty(Filter, repeated=True) }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), Set( cfg={ 'd': { '_widget.name': 'input.name', '_widget.sequence': 'input.sequence', '_widget.active': 'input.active', '_widget.role': 'input.role', '_widget.search_form': 'input.search_form', '_widget.filters': 'input.filters' } }), RulePrepare(), RuleExec() ]), orm.PluginGroup( transactional=True, plugins=[ Write(), Set(cfg={'d': { 'output.entity': '_widget' }}), CallbackNotify(), CallbackExec() ]) ]), orm.Action(key=orm.Action.build_key('62', 'read'), arguments={ 'key': orm.SuperKeyProperty(kind='62', required=True), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), RulePrepare(), RuleExec(), Set(cfg={'d': { 'output.entity': '_widget' }}) ]) ]), orm.Action( key=orm.Action.build_key('62', 'update'), arguments={ 'key': orm.SuperKeyProperty(kind='62', required=True), 'name': orm.SuperStringProperty(required=True), 'sequence': orm.SuperIntegerProperty(required=True), 'active': orm.SuperBooleanProperty(default=True), 'role': orm.SuperKeyProperty(kind='60', required=True), 'search_form': orm.SuperBooleanProperty(default=True), 'filters': orm.SuperLocalStructuredProperty(Filter, repeated=True), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), Set( cfg={ 'd': { '_widget.name': 'input.name', '_widget.sequence': 'input.sequence', '_widget.active': 'input.active', '_widget.role': 'input.role', '_widget.search_form': 'input.search_form', '_widget.filters': 'input.filters' } }), RulePrepare(), RuleExec() ]), orm.PluginGroup( transactional=True, plugins=[ Write(), Set(cfg={'d': { 'output.entity': '_widget' }}), CallbackNotify(), CallbackExec() ]) ]), orm.Action( key=orm.Action.build_key('62', 'delete'), arguments={'key': orm.SuperKeyProperty(kind='62', required=True)}, _plugin_groups=[ orm.PluginGroup( plugins=[Context( ), Read(), RulePrepare(), RuleExec()]), orm.PluginGroup( transactional=True, plugins=[ Delete(), Set(cfg={'d': { 'output.entity': '_widget' }}), CallbackNotify(), CallbackExec() ]) ]), orm.Action( key=orm.Action.build_key('62', 'search'), arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True), 'search': orm.SuperSearchProperty( default={ 'filters': [], 'orders': [{ 'field': 'sequence', 'operator': 'asc' }] }, cfg={ 'use_search_engine': True, # @todo This is extra added for testing functions of google seach! 'search_arguments': { 'kind': '62', 'options': { 'limit': settings.SEARCH_PAGE } }, 'filters': { 'name': orm.SuperStringProperty(), 'role': orm.SuperKeyProperty(kind='60'), 'active': orm.SuperBooleanProperty() }, 'orders': { 'name': { 'default_value': { 'asc': 'a', 'desc': 'z' } }, # @todo This is extra added for testing functions of google seach! 'sequence': { 'default_value': { 'asc': 0, 'desc': 1000000 } } }, # @todo This is extra added for testing functions of google seach! 'indexes': [{ 'orders': [('name', ['asc', 'desc'])] }, { 'orders': [('sequence', ['asc', 'desc'])] }, { 'filters': [('name', ['==', '!='])], 'orders': [('sequence', ['asc', 'desc'])] }, { 'filters': [('active', ['=='])], 'orders': [('sequence', ['asc', 'desc'])] }, { 'filters': [('role', ['==', '!='])], 'orders': [('sequence', ['asc', 'desc'])] }, { 'filters': [('active', ['==']), ('name', ['==', '!='])], 'orders': [('sequence', ['asc', 'desc'])] }, { 'filters': [('active', ['==']), ('role', ['==', '!='])], 'orders': [('sequence', ['asc', 'desc'])] }] }) }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), RulePrepare(), RuleExec(), Search(), RulePrepare(cfg={'path': '_entities'}), Set( cfg={ 'd': { 'output.entities': '_entities', 'output.cursor': '_cursor', 'output.more': '_more' } }) ]) ]), orm.Action(key=orm.Action.build_key('62', 'build_menu'), arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True) }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), RulePrepare(), RuleExec(), WidgetBuildMenu(), Set( cfg={ 'd': { 'output.menu': '_widgets', 'output.domain': 'domain' } }) ]) ]) ] @property def _is_system(self): return self.key_id_str.startswith('system_')
class UnitCurrencyUpdateWrite(orm.BaseModel): cfg = orm.SuperJsonProperty('1', indexed=False, required=True, default={}) def run(self, context): if not isinstance(self.cfg, dict): self.cfg = {} update_file_path = self.cfg.get('file', None) if not update_file_path: raise orm.TerminateAction() Unit = context.models['19'] with file(update_file_path) as f: tree = ElementTree.fromstring(f.read()) root = tree.findall('data') uoms = [] def __text(item, key, op=None): if op == None: op = str gets = item.get(key) if gets != None: return op(gets.text) return gets def __eval(item, key): gets = item.get(key) if gets != None: return eval(gets.attrib.get('eval')) return gets for child in root[1]: if child.attrib.get('model') == 'currency.currency': new_uom = {'id': child.attrib.get('id')} new_uom_data = {} for child2 in child: new_uom_data[child2.attrib.get('name')] = child2 rounding = new_uom_data.get('rounding') digits = new_uom_data.get('digits') grouping = new_uom_data.get('mon_grouping') if rounding != None: rounding = Decimal(eval(rounding.attrib.get('eval'))) if digits != None: digits = long(eval(digits.attrib.get('eval'))) if grouping != None: grouping = eval(grouping.text) else: grouping = [] new_uom.update({ 'measurement': 'Currency', 'name': new_uom_data['name'].text, 'code': new_uom_data['code'].text, 'numeric_code': new_uom_data['numeric_code'].text, 'symbol': new_uom_data['symbol'].text, 'rounding': rounding, 'digits': digits, 'grouping': grouping, 'decimal_separator': __text(new_uom_data, 'mon_decimal_point'), 'thousands_separator': __text(new_uom_data, 'mon_thousands_sep'), 'positive_sign_position': __eval(new_uom_data, 'p_sign_posn'), 'negative_sign_position': __eval(new_uom_data, 'n_sign_posn'), 'positive_sign': __text(new_uom_data, 'positive_sign'), 'negative_sign': __text(new_uom_data, 'negative_sign'), 'positive_currency_symbol_precedes': __eval(new_uom_data, 'p_cs_precedes'), 'negative_currency_symbol_precedes': __eval(new_uom_data, 'n_cs_precedes'), 'positive_separate_by_space': __eval(new_uom_data, 'p_sep_by_space'), 'negative_separate_by_space': __eval(new_uom_data, 'n_sep_by_space'), 'active': True }) uoms.append(new_uom) to_put = [Unit(**d) for d in uoms] for entity in to_put: entity._use_rule_engine = False orm.put_multi(to_put)
from google.appengine.ext.ndb.google_imports import entity_pb from app import orm, settings from app.models import uom from app.models.base import * from app.plugins.base import * from app.plugins.transaction import * defaults1 = () defaults2 = ('required',) JOURNAL_FIELDS = ((orm.SuperStringProperty(), defaults1, defaults2), (orm.SuperTextProperty(), defaults1, defaults2), (orm.SuperIntegerProperty(), defaults1, defaults2), (orm.SuperFloatProperty(), defaults1, defaults2), (orm.SuperDecimalProperty(), defaults1, defaults2), (orm.SuperBooleanProperty(), defaults1, defaults2), (orm.SuperJsonProperty(), defaults1, defaults2), (orm.SuperKeyProperty(), defaults1, defaults2), (orm.SuperDateTimeProperty(), defaults1, defaults2)) class Action(orm.Action): _kind = 84 _use_rule_engine = False arguments = orm.SuperPropertyStorageProperty('2', required=True, default={}, compressed=False, cfg=JOURNAL_FIELDS) @classmethod def build_key(cls, *args, **kwargs): new_args = [cls._get_kind()] new_args.extend(args)
class Notification(orm.BaseExpando): _kind = 61 name = orm.SuperStringProperty('1', required=True) action = orm.SuperKeyProperty('2', kind='56', required=True) condition = orm.SuperStringProperty('3', required=True, indexed=False) active = orm.SuperBooleanProperty('4', required=True, default=True) templates = orm.SuperPickleProperty('5', required=True, indexed=False, compressed=False) _default_indexed = False _virtual_fields = {'_records': orm.SuperRecordProperty('61')} _global_role = GlobalRole(permissions=[ orm.ActionPermission( '61', [ orm.Action.build_key('61', 'prepare'), orm.Action.build_key('61', 'create'), orm.Action.build_key('61', 'read'), orm.Action.build_key('61', 'update'), orm.Action.build_key('61', 'delete'), orm.Action.build_key('61', 'search') ], False, 'entity._original.namespace_entity._original.state != "active"'), orm.ActionPermission('61', [ orm.Action.build_key('61', 'initiate'), orm.Action.build_key('61', 'send_mail'), orm.Action.build_key('61', 'send_http') ], False, 'True'), orm.ActionPermission( '61', [ orm.Action.build_key('61', 'initiate'), orm.Action.build_key('61', 'send_mail'), orm.Action.build_key('61', 'send_http') ], True, 'entity._original.namespace_entity._original.state == "active" and user._is_taskqueue' ), orm.FieldPermission( '61', ['name', 'action', 'condition', 'active', 'templates', '_records'], False, False, 'entity._original.namespace_entity._original.state != "active"') ]) _actions = [ orm.Action(key=orm.Action.build_key('61', 'prepare'), arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True) }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), RulePrepare(), RuleExec(), Set(cfg={'d': { 'output.entity': '_notification' }}) ]) ]), orm.Action( key=orm.Action.build_key('61', 'create'), arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True), 'name': orm.SuperStringProperty(required=True), 'action': orm.SuperVirtualKeyProperty(required=True, kind='56'), 'condition': orm.SuperTextProperty(required=True), 'active': orm.SuperBooleanProperty(), 'templates': orm.SuperMultiLocalStructuredProperty(('58', '63'), repeated=True) }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), Set( cfg={ 'd': { '_notification.name': 'input.name', '_notification.action': 'input.action', '_notification.condition': 'input.condition', '_notification.active': 'input.active', '_notification.templates': 'input.templates' } }), RulePrepare(), RuleExec() ]), orm.PluginGroup( transactional=True, plugins=[ Write(), Set(cfg={'d': { 'output.entity': '_notification' }}), CallbackNotify(), CallbackExec() ]) ]), orm.Action(key=orm.Action.build_key('61', 'read'), arguments={ 'key': orm.SuperKeyProperty(kind='61', required=True), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), RulePrepare(), RuleExec(), Set(cfg={'d': { 'output.entity': '_notification' }}) ]) ]), orm.Action( key=orm.Action.build_key('61', 'update'), arguments={ 'key': orm.SuperKeyProperty(required=True, kind='61'), 'name': orm.SuperStringProperty(required=True), 'action': orm.SuperVirtualKeyProperty(required=True, kind='56'), 'condition': orm.SuperTextProperty(required=True), 'active': orm.SuperBooleanProperty(), 'templates': orm.SuperMultiLocalStructuredProperty(('58', '63'), repeated=True), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), Set( cfg={ 'd': { '_notification.name': 'input.name', '_notification.action': 'input.action', '_notification.condition': 'input.condition', '_notification.active': 'input.active', '_notification.templates': 'input.templates' } }), RulePrepare(), RuleExec() ]), orm.PluginGroup( transactional=True, plugins=[ Write(), Set(cfg={'d': { 'output.entity': '_notification' }}), CallbackNotify(), CallbackExec() ]) ]), orm.Action( key=orm.Action.build_key('61', 'delete'), arguments={'key': orm.SuperKeyProperty(required=True, kind='61')}, _plugin_groups=[ orm.PluginGroup( plugins=[Context( ), Read(), RulePrepare(), RuleExec()]), orm.PluginGroup( transactional=True, plugins=[ Delete(), Set(cfg={'d': { 'output.entity': '_notification' }}), CallbackNotify(), CallbackExec() ]) ]), orm.Action(key=orm.Action.build_key('61', 'search'), arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True), 'search': orm.SuperSearchProperty( default={ 'filters': [], 'orders': [{ 'field': 'name', 'operator': 'asc' }] }, cfg={ 'search_arguments': { 'kind': '61', 'options': { 'limit': settings.SEARCH_PAGE } }, 'filters': { 'name': orm.SuperStringProperty(), 'action': orm.SuperVirtualKeyProperty(kind='56'), 'active': orm.SuperBooleanProperty() }, 'indexes': [{ 'orders': [('name', ['asc', 'desc'])] }, { 'filters': [('name', ['==', '!='])], 'orders': [('name', ['asc', 'desc'])] }, { 'filters': [('action', ['==', '!='])], 'orders': [('name', ['asc', 'desc'])] }, { 'filters': [('active', ['=='])], 'orders': [('name', ['asc', 'desc'])] }, { 'filters': [('active', ['==']), ('name', ['==', '!='])], 'orders': [('name', ['asc', 'desc'])] }, { 'filters': [('active', ['==']), ('action', ['==', '!='])], 'orders': [('name', ['asc', 'desc'])] }, { 'filters': [('active', ['==']), ('name', ['==', '!=']), ('action', ['==', '!='])], 'orders': [('name', ['asc', 'desc'])] }] }) }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), RulePrepare(), RuleExec(), Search(), RulePrepare(cfg={'path': '_entities'}), Set( cfg={ 'd': { 'output.entities': '_entities', 'output.cursor': '_cursor', 'output.more': '_more' } }) ]) ]), orm.Action( key=orm.Action.build_key('61', 'initiate'), arguments={ 'caller_entity': orm.SuperKeyProperty(required=True), 'caller_user': orm.SuperKeyProperty(required=True, kind='0'), 'caller_action': orm.SuperVirtualKeyProperty(required=True) }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Set(cfg={ 'd': { '_caller_entity': 'input.caller_entity.entity' } }), Read(cfg={'namespace': '_caller_entity.key_namespace'}), RulePrepare(), RuleExec(), NotificationInitiate(), CallbackExec() ]) ]), orm.Action( key=orm.Action.build_key('61', 'send_mail'), arguments={ 'recipient': orm.SuperStringProperty(repeated=True), 'subject': orm.SuperTextProperty(required=True), 'body': orm.SuperTextProperty(required=True), 'caller_entity': orm.SuperKeyProperty(required=True) }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Set(cfg={ 'd': { '_caller_entity': 'input.caller_entity.entity' } }), Read(cfg={'namespace': '_caller_entity.key_namespace'}), RulePrepare(), RuleExec(), NotificationMailSend(cfg={'sender': settings.NOTIFY_EMAIL}) ]) ]), orm.Action( key=orm.Action.build_key('61', 'send_http'), arguments={ 'recipient': orm.SuperStringProperty(required=True), 'subject': orm.SuperTextProperty(required=True), 'body': orm.SuperTextProperty(required=True), 'caller_entity': orm.SuperKeyProperty(required=True) }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Set(cfg={ 'd': { '_caller_entity': 'input.caller_entity.entity' } }), Read(cfg={'namespace': '_caller_entity.key_namespace'}), RulePrepare(), RuleExec(), NotificationHttpSend() ]) ]) ]
class Category(orm.BaseExpando): _kind = 47 created = orm.SuperDateTimeProperty('1', required=True, auto_now_add=True) updated = orm.SuperDateTimeProperty('2', required=True, auto_now=True) parent_record = orm.SuperKeyProperty('3', kind='47') name = orm.SuperStringProperty('4', required=True) complete_name = orm.SuperTextProperty('5', required=True) active = orm.SuperBooleanProperty('6', required=True, default=True) _default_indexed = False ###################################################### # Primitive example of real time balance calculator! # ###################################################### @classmethod def _get_children(cls, parent_records, children): entities = [] for parent_record in parent_records: entities.extend(cls.query(cls.parent_record == parent_record).fetch(keys_only=True)) if len(entities): children.extend(entities) cls._get_children(entities, children) @classmethod def _get_balance(cls, category): debit = 0 credit = 0 lines = Line.query(Line.categories.IN(category._children_records)).fetch() for line in lines: debit += line.debit credit += line.credit return (debit, credit, (debit - credit)) @classmethod def _post_get_hook(cls, key, future): # @todo Missing super extension! entity = future.get_result() if entity is not None and entity.key: entity._children_records = [entity.key] entity._get_children([entity.key], entity._children_records) entity._debit, entity._credit, entity._balance = entity._get_balance(entity) ################### # End of example! # ################### _expando_fields = { 'description': orm.SuperTextProperty('7'), 'balances': orm.SuperLocalStructuredProperty(CategoryBalance, '8', repeated=True) } _virtual_fields = { '_records': orm.SuperRecordProperty('47'), '_code': orm.SuperComputedProperty(lambda self: self.key_id_str) #'_debit': orm.SuperComputedProperty(lambda self: self._debit), #'_credit': orm.SuperComputedProperty(lambda self: self._credit), #'_balance': orm.SuperComputedProperty(lambda self: self._balance), } _global_role = GlobalRole( permissions=[ orm.ActionPermission('47', [orm.Action.build_key('47', 'prepare'), orm.Action.build_key('47', 'create'), orm.Action.build_key('47', 'read'), orm.Action.build_key('47', 'update'), orm.Action.build_key('47', 'delete'), orm.Action.build_key('47', 'search')], False, 'entity._original.namespace_entity._original.state != "active"'), orm.ActionPermission('47', [orm.Action.build_key('47', 'create'), orm.Action.build_key('47', 'update'), orm.Action.build_key('47', 'delete')], False, 'entity._is_system'), orm.ActionPermission('47', [orm.Action.build_key('47', 'delete')], False, 'entity._is_used'), orm.FieldPermission('47', ['created', 'updated'], False, None, 'True'), orm.FieldPermission('47', ['created', 'updated', 'parent_record', 'name', 'complete_name', 'active', 'description', 'balances', '_records', '_code'], False, False, 'entity._original.namespace_entity._original.state != "active"'), orm.FieldPermission('47', ['created', 'updated', 'parent_record', 'name', 'complete_name', 'active', 'description', 'balances', '_records', '_code'], False, None, 'entity._is_system') ] ) _actions = [ orm.Action( key=orm.Action.build_key('47', 'prepare'), arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), RulePrepare(), RuleExec(), Set(cfg={'d': {'output.entity': '_category'}}) ] ) ] ), orm.Action( key=orm.Action.build_key('47', 'create'), arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True), '_code': orm.SuperStringProperty(required=True, max_size=64), # Regarding max_size, take a look at the transaction.CategoryUpdateRead() plugin! 'parent_record': orm.SuperKeyProperty(kind='47'), 'name': orm.SuperStringProperty(required=True), 'active': orm.SuperBooleanProperty(required=True, default=True), 'description': orm.SuperTextProperty() }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), CategoryUpdateSet(), # @todo Unless we decide to implement that complete_name handling property, this will stay. RulePrepare(), RuleExec() ] ), orm.PluginGroup( transactional=True, plugins=[ Write(), Set(cfg={'d': {'output.entity': '_category'}}), CallbackNotify(), CallbackExec() ] ) ] ), orm.Action( key=orm.Action.build_key('47', 'read'), arguments={ 'key': orm.SuperKeyProperty(kind='47', required=True), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), RulePrepare(), RuleExec(), Set(cfg={'d': {'output.entity': '_category'}}) ] ) ] ), orm.Action( key=orm.Action.build_key('47', 'update'), arguments={ 'key': orm.SuperKeyProperty(kind='47', required=True), 'parent_record': orm.SuperKeyProperty(kind='47'), 'name': orm.SuperStringProperty(required=True), 'active': orm.SuperBooleanProperty(required=True, default=True), 'description': orm.SuperTextProperty() }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), CategoryUpdateSet(), # @todo Unless we decide to implement that complete_name handling property, this will stay. RulePrepare(), RuleExec() ] ), orm.PluginGroup( transactional=True, plugins=[ Write(), Set(cfg={'d': {'output.entity': '_category'}}), CallbackNotify(), CallbackExec() ] ) ] ), orm.Action( key=orm.Action.build_key('47', 'delete'), arguments={ 'key': orm.SuperKeyProperty(kind='47', required=True) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), RulePrepare(), RuleExec() ] ), orm.PluginGroup( transactional=True, plugins=[ Delete(), Set(cfg={'d': {'output.entity': '_category'}}), CallbackNotify(), CallbackExec() ] ) ] ), orm.Action( key=orm.Action.build_key('47', 'search'), arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True), 'search': orm.SuperSearchProperty( default={'filters': [{'field': 'active', 'value': True, 'operator': '=='}], 'orders': [{'field': 'name', 'operator': 'asc'}]}, cfg={ 'search_by_keys': True, 'search_arguments': {'kind': '47', 'options': {'limit': settings.SEARCH_PAGE}}, 'filters': {'name': orm.SuperStringProperty(), 'active': orm.SuperBooleanProperty()}, 'indexes': [{'orders': [('name', ['asc', 'desc'])]}, {'orders': [('created', ['asc', 'desc'])]}, {'orders': [('updated', ['asc', 'desc'])]}, {'orders': [('active', ['asc', 'desc'])]}, {'filters': [('name', ['==', '!='])], 'orders': [('name', ['asc', 'desc'])]}, {'filters': [('active', ['=='])], 'orders': [('name', ['asc', 'desc'])]}, {'filters': [('active', ['==']), ('name', ['==', '!='])], 'orders': [('name', ['asc', 'desc'])]}] } ) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), RulePrepare(), RuleExec(), Search(), RulePrepare(cfg={'path': '_entities'}), Set(cfg={'d': {'output.entities': '_entities', 'output.cursor': '_cursor', 'output.more': '_more'}}) ] ) ] ) ] @classmethod def prepare_key(cls, input, **kwargs): code = input.get('_code') return cls.build_key(code, namespace=kwargs.get('namespace')) # @todo Possible prefix? @property def _is_system(self): return self.key_id_str.startswith('system_') @property def _is_used(self): if self.key.id() is None: return False category = self.query(self.__class__.parent_record == self.key).get() line = Line.query(Line.categories == self.key).get() return (category is not None) or (line is not None)