class PluginGroup(orm.PluginGroup): _kind = 85 _use_rule_engine = False subscriptions = orm.SuperKeyProperty('2', kind='84', repeated=True) plugins = orm.SuperPluginStorageProperty(('0',), '6', required=True, default=[], compressed=False) # First arg is list of plugin kind ids that user can create, e.g. ('1', '2', '3').
class Address(orm.BaseExpando): _kind = 9 _use_rule_engine = False internal_id = orm.SuperStringProperty( '1', required=True, indexed=False ) # md5 hash => <timestamp>-<random_str>-<name>-<city>-<postal code>-<street>-<default_shipping>-<default_billing> name = orm.SuperStringProperty('2', required=True, indexed=False) country = orm.SuperKeyProperty('3', kind='15', required=True, indexed=False) city = orm.SuperStringProperty('4', required=True, indexed=False) postal_code = orm.SuperStringProperty('5', required=True, indexed=False) street = orm.SuperStringProperty('6', required=True, indexed=False) default_shipping = orm.SuperBooleanProperty('7', required=True, default=True, indexed=False) default_billing = orm.SuperBooleanProperty('8', required=True, default=True, indexed=False) _default_indexed = False _expando_fields = { 'region': orm.SuperKeyProperty('9', kind='16'), 'email': orm.SuperStringProperty('10'), 'telephone': orm.SuperStringProperty('11') } _virtual_fields = { '_country': orm.SuperReferenceStructuredProperty('15', autoload=True, target_field='country'), '_region': orm.SuperReferenceStructuredProperty('16', autoload=True, target_field='region') }
class Configuration(orm.BaseExpando): _kind = 57 _use_record_engine = False _use_rule_engine = False created = orm.SuperDateTimeProperty('1', required=True, auto_now_add=True) updated = orm.SuperDateTimeProperty('2', required=True, auto_now=True) configuration_input = orm.SuperPickleProperty('3', required=True, compressed=False, indexed=False) setup = orm.SuperStringProperty('4', required=True, indexed=False) state = orm.SuperStringProperty('5', required=True) next_operation = orm.SuperStringProperty('6', indexed=False) next_operation_input = orm.SuperPickleProperty('7', indexed=False) _default_indexed = False _global_role = GlobalRole(permissions=[ orm.ActionPermission('57', [ orm.Action.build_key('57', 'install'), orm.Action.build_key('57', 'cron_install') ], True, 'user._is_taskqueue') ]) _actions = [ orm.Action( key=orm.Action.build_key('57', 'install'), arguments={'key': orm.SuperKeyProperty(required=True, kind='57')}, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), RulePrepare(cfg={'skip_user_roles': True}), RuleExec(), ConfigurationInstall() ]) ]), orm.Action(key=orm.Action.build_key('57', 'cron_install'), arguments={}, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), RulePrepare(cfg={'skip_user_roles': True}), RuleExec(), ConfigurationCronInstall( cfg={'time': settings.SETUP_ELAPSED_TIME}) ]) ]) ]
class MailTemplate(Template): _kind = 58 _use_rule_engine = False message_reciever = orm.SuperKeyProperty( '1', kind='60', required=True, indexed=False) # All users that have this role. message_subject = orm.SuperStringProperty('2', required=True, indexed=False) message_body = orm.SuperTextProperty('3', required=True) def run(self, **kwargs): callbacks = [] DomainUser = kwargs['models']['8'] domain_users = DomainUser.query( DomainUser.roles == self.message_reciever, namespace=self.message_reciever.namespace()).fetch() recievers = orm.get_multi_clean([ orm.Key('0', long(reciever.key.id())) for reciever in domain_users ]) template_values = {'entity': kwargs['caller_entity']} data = { 'action_id': 'send_mail', 'action_model': '61', 'recipient': [reciever._primary_email for reciever in recievers], 'body': render_template(self.message_body, template_values), 'subject': render_template(self.message_subject, template_values), 'caller_entity': kwargs['caller_entity'].key.urlsafe() } recipients_per_task = int( math.ceil(len(data['recipient']) / settings.RECIPIENTS_PER_TASK)) data_copy = data.copy() del data_copy['recipient'] for i in xrange(0, recipients_per_task + 1): recipients = data['recipient'][settings.RECIPIENTS_PER_TASK * i:settings.RECIPIENTS_PER_TASK * (i + 1)] if recipients: new_data = data_copy.copy() new_data['recipient'] = recipients callbacks.append(('send', new_data)) return callbacks
class Line(orm.BaseExpando): '''Notes: We always seqence lines that have debit > 0, and after them come lines that have credit > 0 In case that Entry.balanced=True, sum of all debit amounts must eqal to sum of all credit amounts. To make instances of lines, you must always provide parent key, that is entry's key. Otherwise it will break! Fields can only be properly loaded if are: - loaded from datastore - instanced with proper keyword argument Entry (journal or _model_schema) and Line (parent) ''' _kind = 51 _use_rule_engine = False _journal_fields_loaded = None # Expando # Some queries on Line require "join" with Entry. # That problem can be solved using search engine (or keeping some entry field values copied to lines)! #journal = orm.SuperKeyProperty('1', kind=Journal, required=True) # delete #company = orm.SuperKeyProperty('2', kind='44', required=True) # delete #state = orm.SuperIntegerProperty('3', required=True) # delete #date = orm.SuperDateTimeProperty('4', required=True) # delete sequence = orm.SuperIntegerProperty('5', required=True) categories = orm.SuperKeyProperty('6', kind='47', repeated=True) debit = orm.SuperDecimalProperty('7', required=True, indexed=False) # debit = 0 in case that credit > 0, negative values are forbidden. credit = orm.SuperDecimalProperty('8', required=True, indexed=False) # credit = 0 in case that debit > 0, negative values are forbidden. uom = orm.SuperLocalStructuredProperty(uom.UOM, '9', required=True) def __init__(self, *args, **kwargs): '''Caution! Making instances of Line() inside a transaction may cause performing non-entity group queries (see in add journal fields). As for get()s itself it will use in-memory cache when it can. ''' entry_key = kwargs.get('parent') complete_key = kwargs.get('key') # Also observe the complete key instances. journal_key = kwargs.pop('journal', None) # if journal key is provided use it. This is generally retarded but only way so far. if journal_key is not None: self.add_journal_fields(journal_key) elif entry_key is not None: self.add_journal_fields(entry_key.entity.journal) elif complete_key is not None: self.add_journal_fields(complete_key.parent_entity.journal) # we intentionally call this code before __init__ due __init__ ability to deepcopy the entity and other things beside that. super(Line, self).__init__(*args, **kwargs) def add_journal_fields(self, journal_key=None): if not self._journal_fields_loaded: if not journal_key and self.key: journal_key = self.parent_entity.journal journal = journal_key.get() if journal is None: raise Exception('Cannot find journal with key %r.' % journal_key) self._clone_properties() for name, prop in journal.line_fields.iteritems(): # still not 100% sure if we need to deepcopy these properties that get loaded from datastore prop._code_name = name self._properties[prop._name] = prop self.add_output(name) self._journal_fields_loaded = True def get_kind(self): return '%s_%s' % (self._get_kind(), self.journal.id()) def get_fields(self): fields = super(Line, self.__class__).get_fields() # Calling parent get_fields. for name, prop in self._properties.iteritems(): fields[prop._code_name] = prop return fields def _get_property_for(self, p, indexed=True, depth=0): '''It is always easier to override _get_property_for because you immidiately get self which tells you on which entity you operate, and if the entity itself has a key. ''' if self.key is None or self.key.parent() is None: raise Exception('Cannot load properties of %s because it does not have parent key provided.' % self) else: if self._journal_fields_loaded is None: self.add_journal_fields() return super(Line, self)._get_property_for(p, indexed, depth) @classmethod def get_meta(cls): '''This function returns dictionary of meta data (not stored or dynamically generated data) of the model. The returned dictionary can be transalted into other understandable code to clients (e.g. JSON). ''' dic = {} dic['_actions'] = getattr(cls, '_actions', []) dic.update(super(Line, cls).get_fields()) return dic
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 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)
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 Collection(orm.BaseModel): _kind = 10 notify = orm.SuperBooleanProperty('1', required=True, default=False) domains = orm.SuperKeyProperty('2', kind='6', repeated=True) _virtual_fields = { '_records': orm.SuperRecordProperty('10'), '_domains': orm.SuperReferenceStructuredProperty( '6', autoload=False, callback=lambda self: orm.get_multi_async( [domain_key for domain_key in self.domains]), format_callback=lambda self, entities: orm.get_async_results( entities)) } _global_role = GlobalRole(permissions=[ orm.ActionPermission( '10', [ orm.Action.build_key('10', 'update'), orm.Action.build_key('10', 'read') ], True, 'entity._original.key_parent == user.key and not user._is_guest'), orm.FieldPermission( '10', [ 'notify', 'domains', '_records', '_domains.name', '_domains.logo' ], True, True, 'entity._original.key_parent == user.key and not user._is_guest') ]) _actions = [ orm.Action(key=orm.Action.build_key('10', 'update'), arguments={ 'user': orm.SuperKeyProperty(kind='0', required=True), 'notify': orm.SuperBooleanProperty(default=True), 'domains': orm.SuperKeyProperty(kind='6', repeated=True), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), Set( cfg={ 'd': { '_collection.notify': 'input.notify', '_collection.domains': 'input.domains' } }), RulePrepare(cfg={'skip_user_roles': True}), RuleExec() ]), orm.PluginGroup( transactional=True, plugins=[ Write(), Set(cfg={'d': { 'output.entity': '_collection' }}) ]) ]), orm.Action(key=orm.Action.build_key('10', 'read'), arguments={ 'user': orm.SuperKeyProperty(kind='0', required=True), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), RulePrepare(cfg={'skip_user_roles': True}), RuleExec(), Set(cfg={'d': { 'output.entity': '_collection' }}) ]) ]) ] @classmethod def prepare_key(cls, input, **kwargs): user_key = input.get('user') return cls.build_key(user_key._id_str, parent=user_key)
class DomainRole(Role): _kind = 60 _virtual_fields = {'_records': orm.SuperRecordProperty('60')} _global_role = GlobalRole(permissions=[ orm.ActionPermission( '60', [ orm.Action.build_key('60', 'prepare'), orm.Action.build_key('60', 'create'), orm.Action.build_key('60', 'read'), orm.Action.build_key('60', 'update'), orm.Action.build_key('60', 'delete'), orm.Action.build_key('60', 'search') ], False, 'entity._original.namespace_entity._original.state != "active"'), orm.ActionPermission('60', [ orm.Action.build_key('60', 'create'), orm.Action.build_key('60', 'update'), orm.Action.build_key('60', 'delete') ], False, 'entity._is_system'), orm.FieldPermission( '60', ['name', 'active', 'permissions', '_records'], False, False, 'entity._original.namespace_entity._original.state != "active"'), orm.FieldPermission( '60', ['name', 'active', 'permissions', '_records'], False, None, 'entity._is_system') ]) _actions = [ orm.Action(key=orm.Action.build_key('60', 'prepare'), arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True) }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), RulePrepare(), RuleExec(), Set(cfg={'d': { 'output.entity': '_domainrole' }}) ]) ]), orm.Action( key=orm.Action.build_key('60', 'create'), arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True), 'name': orm.SuperStringProperty(required=True), 'permissions': orm.SuperMultiLocalStructuredProperty(('80', '79'), repeated=True), 'active': orm.SuperBooleanProperty(default=True) }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), Set( cfg={ 'd': { '_domainrole.name': 'input.name', '_domainrole.active': 'input.active', '_domainrole.permissions': 'input.permissions' } }), RulePrepare(), RuleExec() ]), orm.PluginGroup( transactional=True, plugins=[ Write(), Set(cfg={'d': { 'output.entity': '_domainrole' }}), CallbackNotify(), CallbackExec() ]) ]), orm.Action(key=orm.Action.build_key('60', 'read'), arguments={ 'key': orm.SuperKeyProperty(kind='60', required=True), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), RulePrepare(), RuleExec(), Set(cfg={'d': { 'output.entity': '_domainrole' }}) ]) ]), orm.Action( key=orm.Action.build_key('60', 'update'), arguments={ 'key': orm.SuperKeyProperty(kind='60', required=True), 'name': orm.SuperStringProperty(required=True), 'permissions': orm.SuperMultiLocalStructuredProperty(('80', '79'), repeated=True), 'active': orm.SuperBooleanProperty(default=True), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), Set( cfg={ 'd': { '_domainrole.name': 'input.name', '_domainrole.active': 'input.active', '_domainrole.permissions': 'input.permissions' } }), RulePrepare(), RuleExec() ]), orm.PluginGroup( transactional=True, plugins=[ Write(), Set(cfg={'d': { 'output.entity': '_domainrole' }}), CallbackNotify(), CallbackExec() ]) ]), orm.Action( key=orm.Action.build_key('60', 'delete'), arguments={'key': orm.SuperKeyProperty(kind='60', required=True)}, _plugin_groups=[ orm.PluginGroup( plugins=[Context( ), Read(), RulePrepare(), RuleExec()]), orm.PluginGroup( transactional=True, plugins=[ Delete(), Set(cfg={'d': { 'output.entity': '_domainrole' }}), CallbackNotify(), CallbackExec() ]) ]), orm.Action(key=orm.Action.build_key('60', 'search'), arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True), 'search': orm.SuperSearchProperty( default={ 'filters': [], 'orders': [{ 'field': 'name', 'operator': 'asc' }] }, cfg={ 'search_by_keys': True, 'search_arguments': { 'kind': '60', 'options': { 'limit': settings.SEARCH_PAGE } }, 'filters': { 'name': orm.SuperStringProperty(), 'active': orm.SuperBooleanProperty() }, 'indexes': [{ 'orders': [('name', ['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' } }) ]) ]) ] @property def _is_system(self): return self.key_id_str.startswith('system_')
class User(orm.BaseExpando): _kind = 0 _use_memcache = True created = orm.SuperDateTimeProperty('1', required=True, auto_now_add=True) updated = orm.SuperDateTimeProperty('2', required=True, auto_now=True) identities = orm.SuperStructuredProperty(Identity, '3', repeated=True) # Soft limit 100 instances. emails = orm.SuperStringProperty('4', repeated=True) # Soft limit 100 instances. state = orm.SuperStringProperty('5', required=True, choices=['active', 'suspended']) # @todo Shall we disable indexing here? sessions = orm.SuperLocalStructuredProperty(Session, '6', repeated=True) # Soft limit 100 instances. domains = orm.SuperKeyProperty('7', kind='6', repeated=True) # Soft limit 100 instances. @todo Shall we disable indexing here? _default_indexed = False _virtual_fields = { 'ip_address': orm.SuperComputedProperty(lambda self: os.environ.get('REMOTE_ADDR')), '_primary_email': orm.SuperComputedProperty(lambda self: self.primary_email()), '_records': orm.SuperRecordProperty('0') } _global_role = GlobalRole( permissions=[ orm.ActionPermission('0', orm.Action.build_key('0', 'login'), True, 'entity._is_guest or entity._original.state == "active"'), orm.ActionPermission('0', [orm.Action.build_key('0', 'read'), orm.Action.build_key('0', 'update'), orm.Action.build_key('0', 'logout'), orm.Action.build_key('0', 'read_domains')], True, 'not entity._is_guest and user.key == entity._original.key'), orm.FieldPermission('0', ['created', 'updated', 'state', 'domains'], False, True, 'not user._is_guest and user.key == entity._original.key'), orm.FieldPermission('0', ['identities', 'emails', 'sessions', '_primary_email'], True, True, 'not user._is_guest and user.key == entity._original.key'), # User is unit of administration, hence root admins need control over it! # Root admins can always: read user; search for users (exclusively); # read users history (exclusively); perform sudo operations (exclusively). orm.ActionPermission('0', [orm.Action.build_key('0', 'read'), orm.Action.build_key('0', 'search'), orm.Action.build_key('0', 'sudo')], True, 'user._root_admin'), orm.FieldPermission('0', ['created', 'updated', 'identities', 'emails', 'state', 'sessions', 'domains', 'ip_address', '_primary_email', '_records'], None, True, 'user._root_admin'), orm.FieldPermission('0', ['state'], True, None, 'action.key_id_str == "sudo" and user._root_admin') ] ) _actions = [ orm.Action( key=orm.Action.build_key('0', 'login'), arguments={ 'login_method': orm.SuperStringProperty(required=True, choices=settings.LOGIN_METHODS.keys()), 'code': orm.SuperStringProperty(), 'error': orm.SuperStringProperty() }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), UserLoginInit(cfg={'methods': settings.LOGIN_METHODS}) ] ), orm.PluginGroup( transactional=True, plugins=[ UserLoginWrite() ] ) ] ), orm.Action( key=orm.Action.build_key('0', 'read'), arguments={ 'key': orm.SuperKeyProperty(kind='0', required=True), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), RulePrepare(cfg={'skip_user_roles': True}), RuleExec(), Set(cfg={'d': {'output.entity': '_user'}}) ] ) ] ), orm.Action( key=orm.Action.build_key('0', 'update'), arguments={ 'key': orm.SuperKeyProperty(kind='0', required=True), 'primary_email': orm.SuperStringProperty(), 'disassociate': orm.SuperStringProperty(repeated=True), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), UserUpdateSet(), RulePrepare(cfg={'skip_user_roles': True}), RuleExec() ] ), orm.PluginGroup( transactional=True, plugins=[ Write(), Set(cfg={'d': {'output.entity': '_user'}}), # CallbackNotify(), # CallbackExec() notify cannot work here ] ) ] ), orm.Action( key=orm.Action.build_key('0', 'search'), arguments={ 'search': orm.SuperSearchProperty( default={'filters': [], 'orders': [{'field': 'created', 'operator': 'desc'}]}, cfg={ 'search_arguments': {'kind': '0', 'options': {'limit': settings.SEARCH_PAGE}}, 'filters': {'emails': orm.SuperStringProperty(), 'state': orm.SuperStringProperty()}, 'indexes': [{'orders': [('emails', ['asc', 'desc'])]}, {'orders': [('created', ['asc', 'desc'])]}, {'orders': [('updated', ['asc', 'desc'])]}, {'filters': [('emails', ['==', '!='])], 'orders': [('created', ['asc', 'desc'])]}, {'filters': [('state', ['==', '!='])], 'orders': [('created', ['asc', 'desc'])]}] } ) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), RulePrepare(cfg={'skip_user_roles': True}), RuleExec(), Search(), RulePrepare(cfg={'path': '_entities', 'skip_user_roles': True}), Set(cfg={'d': {'output.entities': '_entities', 'output.cursor': '_cursor', 'output.more': '_more'}}) ] ) ] ), # @todo Treba obratiti paznju na to da suspenzija usera ujedno znaci # i izuzimanje svih negativnih i neutralnih feedbackova koje je user ostavio dok je bio aktivan. orm.Action( key=orm.Action.build_key('0', 'sudo'), arguments={ 'key': orm.SuperKeyProperty(kind='0', required=True), 'state': orm.SuperStringProperty(required=True, choices=['active', 'suspended']), 'message': orm.SuperStringProperty(required=True), 'note': orm.SuperStringProperty() }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), Set(cfg={'d': {'_user.state': 'input.state'}, 's': {'_user.sessions': []}}), RulePrepare(cfg={'skip_user_roles': True}), RuleExec(), ] ), orm.PluginGroup( transactional=True, plugins=[ Write(cfg={'dra': {'message': 'input.message', 'note': 'input.note'}}), Set(cfg={'d': {'output.entity': '_user'}}), # CallbackNotify(), # CallbackExec() notify cannot work here ] ) ] ), orm.Action( key=orm.Action.build_key('0', 'logout'), arguments={ 'key': orm.SuperKeyProperty(kind='0', required=True) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), Set(cfg={'s': {'_user.sessions': []}}), RulePrepare(cfg={'skip_user_roles': True}), RuleExec() ] ), orm.PluginGroup( transactional=True, plugins=[ Write(cfg={'dra': {'ip_address': '_user.ip_address'}}), UserLogoutOutput() ] ) ] ), # We need this action in order to properly prepare entities for client side access control! orm.Action( key=orm.Action.build_key('0', 'read_domains'), arguments={ 'key': orm.SuperKeyProperty(kind='0', required=True) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), UserReadDomains() ] ) ] ) ] def get_output(self): dic = super(User, self).get_output() dic.update({'_csrf': self._csrf, # We will need the csrf but it has to be incorporated into security mechanism (http://en.wikipedia.org/wiki/Cross-site_request_forgery). '_is_guest': self._is_guest, '_root_admin': self._root_admin}) return dic @property def _root_admin(self): return self._primary_email in settings.ROOT_ADMINS @property def _is_taskqueue(self): return mem.temp_get('_current_request_is_taskqueue') @property def _is_cron(self): return mem.temp_get('_current_request_is_cron') def set_taskqueue(self, is_it): return mem.temp_set('_current_request_is_taskqueue', is_it) def set_cron(self, is_it): return mem.temp_set('_current_request_is_cron', is_it) def primary_email(self): if not self.identities.value: return None for identity in self.identities.value: if identity.primary == True: return identity.email return identity.email @property def _csrf(self): session = self.current_user_session() if not session: return None return hashlib.md5(session.session_id).hexdigest() @property def _is_guest(self): return self.key is None @classmethod def set_current_user(cls, user, session=None): mem.temp_set('_current_user', user) mem.temp_set('_current_user_session', session) @classmethod def current_user(cls): current_user = mem.temp_get('_current_user') if not current_user: current_user = cls() cls.set_current_user(current_user) return current_user @classmethod def get_system_user(cls): user_key = cls.build_key('system') user = user_key.get() if not user: identities = [Identity(email='System', identity='1-0', associated=True, primary=True)] user = cls(key=user_key, state='active', emails=['System'], identities=identities) user.put() return user @classmethod def current_user_session(cls): return mem.temp_get('_current_user_session') def session_by_id(self, session_id): for session in self.sessions.value: if session.session_id == session_id: return session return None @classmethod def set_current_user_from_auth_code(cls, auth_code): try: user_key, session_id = auth_code.split('|') except: return False # Fail silently if the authorization code is not set properly, or it is corrupted somehow. if not session_id: return False # Fail silently if the session id is not found in the split sequence. user_key = orm.Key(urlsafe=user_key) if user_key.kind() != cls.get_kind(): return False # Fail silently if the kind is not valid user = user_key.get() if user and user.key_id != 'system': user.read() session = user.session_by_id(session_id) if session: cls.set_current_user(user, session) return user
class Domain(orm.BaseExpando): _kind = 6 _use_memcache = True 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) primary_contact = orm.SuperKeyProperty('4', kind='8', indexed=False) # This field is required, and is handeled in update action via argument! state = orm.SuperStringProperty('5', required=True, choices=['active', 'suspended', 'su_suspended']) logo = SuperImageLocalStructuredProperty(Image, '6', required=True) _default_indexed = False _virtual_fields = { '_primary_contact_email': orm.SuperReferenceProperty(target_field='primary_contact', format_callback=lambda self, value: value._primary_email), '_records': orm.SuperRecordProperty('6') } _global_role = GlobalRole( permissions=[ orm.ActionPermission('6', [orm.Action.build_key('6', 'prepare'), orm.Action.build_key('6', 'create')], True, 'not user._is_guest'), orm.ActionPermission('6', orm.Action.build_key('6', 'update'), False, 'entity._original.state != "active"'), orm.ActionPermission('6', orm.Action.build_key('6', 'suspend'), False, 'entity._original.state != "active"'), orm.ActionPermission('6', orm.Action.build_key('6', 'activate'), False, 'entity._original.state == "active" or entity._original.state == "su_suspended"'), orm.FieldPermission('6', ['created', 'updated', 'state'], False, None, 'True'), orm.FieldPermission('6', ['name', 'primary_contact', 'logo', '_records', '_primary_contact_email'], False, None, 'entity._original.state != "active"'), orm.FieldPermission('6', ['state'], True, None, '(action.key_id_str == "activate" and entity.state == "active") or (action.key_id_str == "suspend" and entity.state == "suspended")'), # Domain is unit of administration, hence root admins need control over it! # Root admins can always: read domain; search for domains (exclusively); # read domain history; perform sudo operations (exclusively); log messages; read _records.note field (exclusively). orm.ActionPermission('6', [orm.Action.build_key('6', 'read'), orm.Action.build_key('6', 'search'), orm.Action.build_key('6', 'sudo'), orm.Action.build_key('6', 'log_message')], True, 'user._root_admin'), orm.ActionPermission('6', [orm.Action.build_key('6', 'search'), orm.Action.build_key('6', 'sudo')], False, 'not user._root_admin'), orm.FieldPermission('6', ['created', 'updated', 'name', 'primary_contact', 'state', 'logo', '_records', '_primary_contact_email'], None, True, 'user._root_admin'), orm.FieldPermission('6', ['_records.note'], True, True, 'user._root_admin'), orm.FieldPermission('6', ['_records.note'], False, False, 'not user._root_admin'), orm.FieldPermission('6', ['state'], True, None, '(action.key_id_str == "sudo") and user._root_admin and (entity.state == "active" or entity.state == "su_suspended")'), orm.FieldPermission('6', ['created', 'updated', 'name', 'state', 'logo'], None, True, 'entity._original.state == "active"') ] ) _actions = [ orm.Action( key=orm.Action.build_key('6', 'prepare'), arguments={ 'upload_url': orm.SuperStringProperty() }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), RulePrepare(cfg={'skip_user_roles': True}), RuleExec(), BlobURL(cfg={'bucket': settings.BUCKET_PATH}), Set(cfg={'d': {'output.entity': '_domain', 'output.upload_url': '_blob_url'}}) ] ) ] ), orm.Action( key=orm.Action.build_key('6', 'create'), arguments={ 'name': orm.SuperStringProperty(required=True), 'logo': SuperImageLocalStructuredProperty(Image, required=True, process_config={'measure': False, 'transform': True, 'width': 240, 'height': 100, 'crop_to_fit': True}) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), RulePrepare(cfg={'skip_user_roles': True}), RuleExec() ] ), orm.PluginGroup( transactional=True, plugins=[ DomainCreateWrite(), Set(cfg={'d': {'output.entity': '_domain'}}), CallbackExec(cfg=[('callback', {'action_id': 'install', 'action_model': '57'}, {'key': '_config.key_urlsafe'})]) ] ) ] ), orm.Action( key=orm.Action.build_key('6', 'read'), arguments={ 'key': orm.SuperKeyProperty(kind='6', required=True), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), RulePrepare(), RuleExec(), Set(cfg={'d': {'output.entity': '_domain'}}) ] ) ] ), orm.Action( key=orm.Action.build_key('6', 'update'), arguments={ 'key': orm.SuperKeyProperty(kind='6', required=True), 'name': orm.SuperStringProperty(required=True), 'primary_contact': orm.SuperKeyProperty(required=True, kind='8', validator=primary_contact_validator), 'logo': SuperImageLocalStructuredProperty(Image, process_config={'measure': False, 'transform': True, 'width': 240, 'height': 100, 'crop_to_fit': True}), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), Set(cfg={'d': {'_domain.name': 'input.name', '_domain.primary_contact': 'input.primary_contact', '_domain.logo': 'input.logo'}}), RulePrepare(), RuleExec() ] ), orm.PluginGroup( transactional=True, plugins=[ Write(), Set(cfg={'d': {'output.entity': '_domain'}}), CallbackNotify(), CallbackExec() ] ) ] ), orm.Action( key=orm.Action.build_key('6', 'search'), arguments={ 'search': orm.SuperSearchProperty( default={'filters': [], 'orders': [{'field': 'created', 'operator': 'desc'}]}, cfg={ 'search_arguments': {'kind': '6', 'options': {'limit': settings.SEARCH_PAGE}}, 'filters': {'name': orm.SuperStringProperty(), 'state': orm.SuperStringProperty()}, 'indexes': [{'orders': [('name', ['asc', 'desc'])]}, {'orders': [('created', ['asc', 'desc'])]}, {'orders': [('updated', ['asc', 'desc'])]}, {'filters': [('name', ['==', '!='])], 'orders': [('created', ['asc', 'desc'])]}, {'filters': [('state', ['==', '!='])], 'orders': [('created', ['asc', 'desc'])]}] } ) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), RulePrepare(cfg={'skip_user_roles': True}), RuleExec(), Search(), RulePrepare(cfg={'path': '_entities', 'skip_user_roles': True}), Set(cfg={'d': {'output.entities': '_entities', 'output.cursor': '_cursor', 'output.more': '_more'}}) ] ) ] ), orm.Action( key=orm.Action.build_key('6', 'suspend'), arguments={ 'key': orm.SuperKeyProperty(kind='6', required=True), 'message': orm.SuperTextProperty(required=True) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), Set(cfg={'s': {'_domain.state': 'suspended'}}), RulePrepare(), RuleExec() ] ), orm.PluginGroup( transactional=True, plugins=[ Write(cfg={'dra': {'message': 'input.message'}}), CallbackNotify(), CallbackExec() ] ), orm.PluginGroup( plugins=[ RulePrepare(), Set(cfg={'d': {'output.entity': '_domain'}}) ] ) ] ), orm.Action( key=orm.Action.build_key('6', 'activate'), arguments={ 'key': orm.SuperKeyProperty(kind='6', required=True), 'message': orm.SuperTextProperty(required=True) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), Set(cfg={'s': {'_domain.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': '_domain'}}) ] ) ] ), orm.Action( key=orm.Action.build_key('6', 'sudo'), arguments={ 'key': orm.SuperKeyProperty(kind='6', required=True), 'state': orm.SuperStringProperty(required=True, choices=['active', 'suspended', 'su_suspended']), 'message': orm.SuperTextProperty(required=True), 'note': orm.SuperTextProperty() }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), Set(cfg={'d': {'_domain.state': 'input.state'}}), RulePrepare(cfg={'skip_user_roles': True}), RuleExec() ] ), orm.PluginGroup( transactional=True, plugins=[ Write(cfg={'dra': {'message': 'input.message', 'note': 'input.note'}}), RulePrepare(cfg={'skip_user_roles': True}), Set(cfg={'d': {'output.entity': '_domain'}}), CallbackNotify(), CallbackExec() ] ) ] ), orm.Action( key=orm.Action.build_key('6', 'log_message'), arguments={ 'key': orm.SuperKeyProperty(kind='6', required=True), 'message': orm.SuperTextProperty(required=True), 'note': orm.SuperTextProperty() }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), RulePrepare(), RuleExec() ] ), orm.PluginGroup( transactional=True, plugins=[ Write(cfg={'dra': {'message': 'input.message', 'note': 'input.note'}}), Set(cfg={'d': {'output.entity': '_domain'}}), CallbackNotify(), CallbackExec() ] ) ] ) ] @property def key_namespace(self): return self.key.urlsafe() @property def namespace_entity(self): return self
class CountrySubdivision(orm.BaseModel): _kind = 16 _use_record_engine = False _use_cache = True _use_memcache = True parent_record = orm.SuperKeyProperty('1', kind='16', indexed=False) code = orm.SuperStringProperty('2', required=True, indexed=False) name = orm.SuperStringProperty('3', required=True) complete_name = orm.SuperTextProperty('4', required=True) type = orm.SuperStringProperty('5', required=True, indexed=False) active = orm.SuperBooleanProperty('6', required=True, default=True) _global_role = GlobalRole( permissions=[ orm.ActionPermission('16', [orm.Action.build_key('16', 'search')], True, 'not user._is_guest'), orm.FieldPermission('16', ['parent_record', 'code', 'name', 'complete_name', 'type', 'active'], False, True, 'True'), orm.FieldPermission('16', ['parent_record', 'code', 'name', 'complete_name', 'type', 'active'], True, True, 'user._root_admin or user._is_taskqueue') ] ) _actions = [ orm.Action( key=orm.Action.build_key('16', 'search'), arguments={ 'search': orm.SuperSearchProperty( default={'filters': [{'field': 'active', 'value': True, 'operator': '=='}], 'orders': [{'field': 'name', 'operator': 'asc'}]}, cfg={ 'ancestor_kind': '15', 'search_by_keys': True, 'search_arguments': {'kind': '16', 'options': {'limit': settings.SEARCH_PAGE}}, 'filters': {'name': orm.SuperStringProperty(value_filters=[lambda p, s: s.capitalize()]), 'active': orm.SuperBooleanProperty(choices=[True])}, 'indexes': [{'filters': [('active', ['=='])], 'orders': [('name', ['asc', 'desc'])]}, {'ancestor': True, 'filters': [('active', ['=='])], 'orders': [('name', ['asc', 'desc'])]}, {'filters': [('active', ['==']), ('name', ['==', '!=', 'contains'])], 'orders': [('name', ['asc', 'desc'])]}, {'ancestor': True, 'filters': [('active', ['==']), ('name', ['==', '!=', 'contains'])], 'orders': [('name', ['asc', 'desc'])]}] } ) }, _plugin_groups=[ orm.PluginGroup( plugins=[ Context(), Read(), RulePrepare(cfg={'skip_user_roles': True}), RuleExec(), Search(), RulePrepare(cfg={'path': '_entities', 'skip_user_roles': True}), Set(cfg={'d': {'output.entities': '_entities', 'output.cursor': '_cursor', 'output.more': '_more'}}) ] ) ] ) ]
class Addresses(orm.BaseModel): _kind = 77 addresses = orm.SuperLocalStructuredProperty(Address, '1', repeated=True) _virtual_fields = {'_records': orm.SuperRecordProperty('77')} _global_role = GlobalRole(permissions=[ orm.ActionPermission( '77', [ orm.Action.build_key('77', 'update'), orm.Action.build_key('77', 'read') ], True, 'entity._original.key_parent == user.key and not user._is_guest'), orm.FieldPermission( '77', ['addresses', '_records'], True, True, 'entity._original.key_parent == user.key and not user._is_guest') ]) _actions = [ orm.Action( key=orm.Action.build_key('77', 'update'), arguments={ 'user': orm.SuperKeyProperty(kind='0', required=True), 'addresses': orm.SuperLocalStructuredProperty(Address, repeated=True), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), Set(cfg={'d': { '_addresses.addresses': 'input.addresses' }}), AddressesUpdateSet(), RulePrepare(cfg={'skip_user_roles': True}), RuleExec() ]), orm.PluginGroup( transactional=True, plugins=[ Write(), Set(cfg={'d': { 'output.entity': '_addresses' }}) ]) ]), orm.Action(key=orm.Action.build_key('77', 'read'), arguments={ 'user': orm.SuperKeyProperty(kind='0', required=True), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), RulePrepare(cfg={'skip_user_roles': True}), RuleExec(), Set(cfg={'d': { 'output.entity': '_addresses' }}) ]) ]) ] @classmethod def prepare_key(cls, input, **kwargs): user_key = input.get('user') return cls.build_key(user_key._id_str, parent=user_key)
class Entry(orm.BaseExpando): '''Notes: In order to make proper instances of entries you must always either provide journal or _model_schema argument in constructor. Fields can only be properly loaded if are: - loaded from datastore - instanced with proper keyword argument Entry (journal or _model_schema) and Line (parent) ''' _kind = 50 _journal_fields_loaded = None # Used to flag if the journal fields were loaded. created = orm.SuperDateTimeProperty('1', required=True, auto_now_add=True) updated = orm.SuperDateTimeProperty('2', required=True, auto_now=True) journal = orm.SuperKeyProperty('3', kind=Journal, required=True) name = orm.SuperStringProperty('4', required=True) state = orm.SuperStringProperty('5', required=True) # @todo Bad thing about this prop being defined statically is that we can not have choices and default value, thus less abstraction! date = orm.SuperDateTimeProperty('6', required=True) _virtual_fields = { '_lines': orm.SuperRemoteStructuredProperty(Line, repeated=True) } _global_roles = {'system_sales_order': GlobalRole( permissions=[ orm.FieldPermission('50', ['created', 'updated', 'state'], False, None, 'True'), orm.FieldPermission('50', ['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('50', ['created', 'updated', 'name', 'state', 'entry_fields', 'line_fields', '_records', '_code'], False, None, 'entity._original.state != "draft"'), orm.FieldPermission('50', ['_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('50', ['_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('50', ['state'], True, None, '(action.key_id_str == "activate" and entity.state == "active") or (action.key_id_str == "decommission" and entity.state == "decommissioned")') ] )} @property def _global_role(self): return self._global_roles.get(self.journal._id_str) def __init__(self, *args, **kwargs): '''Caution! Making instances of Entry() inside a transaction may cause performing non-entity group queries (see journal_key.get() in add journal fields). As for get() itself it will use in-memory cache when it can. ''' journal = kwargs.get('journal') _model_schema = kwargs.pop('_model_schema', None) namespace = kwargs.get('namespace') if journal is None and (_model_schema is not None and namespace is not None): journal = Journal.build_key(_model_schema, namespace=namespace) kwargs['journal'] = journal if journal: self.add_journal_fields(journal) super(Entry, self).__init__(*args, **kwargs) def add_journal_fields(self, journal_key=None): if not self._journal_fields_loaded: # prevent from loading too many times if journal_key is None: journal_key = self.journal journal = journal_key.get() if journal is None: raise Exception('Cannot find journal with key %r.' % journal_key) self._clone_properties() for name, prop in journal.entry_fields.iteritems(): prop._code_name = name self._properties[prop._name] = prop self.add_output(name) self._journal_fields_loaded = True def get_kind(self): # @todo Do we have security breach here, without inclusion of namespace? return '%s_%s' % (self._get_kind(), self.journal.id()) @property def _actions(self): # @todo Cache if possible for performance gains! return Action.query(Action.active == True, ancestor=self.journal).fetch() def get_actions(self): return getattr(self, '_actions', []) def get_action(self, action): if isinstance(action, orm.Key): action_key = action else: try: action_key = orm.Key(urlsafe=action) except: action_key = Action.build_key(action, parent=self.journal) return action_key.get() def get_plugin_groups(self, action): return PluginGroup.query(PluginGroup.active == True, PluginGroup.subscriptions == action.key, ancestor=self.journal).order(PluginGroup.sequence).fetch() def get_fields(self): fields = super(Entry, self.__class__).get_fields() # Calling parent get_fields. for name, prop in self._properties.iteritems(): fields[prop._code_name] = prop return fields @classmethod def _from_pb(cls, pb, set_key=True, ent=None, key=None): '''Internal helper to create an entity from an EntityProto protobuf. First 10 lines of code are copied from original from_pb in order to mimic construction of entity instance based on its function args. The rest of the code bellow is used to forcefully attempt to attach properties from journal entry_fields. This is complicated because in order to properly deserialize from datastore, the deserialization process can only begin after we have successfully retrieved entry_fields from journal. ''' if not isinstance(pb, entity_pb.EntityProto): raise TypeError('pb must be an instance of EntityProto; received %r' % pb) if ent is None: ent = cls() # A key passed in overrides a key in the pb. if key is None and pb.key().path().element_size(): key = orm.Key(reference=pb.key()) # If set_key is not set, skip a trivial incomplete key. if key is not None and (set_key or key.id() or key.parent()): ent._key = key indexed_properties = pb.property_list() unindexed_properties = pb.raw_property_list() projection = [] all_props = [indexed_properties, unindexed_properties] added_fields = False for plist in all_props: for p in plist: # First find the journal. Then load all needed props and break the loop. journal_name = cls.journal._name if journal_name is None: journal_name = cls.journal._code_name if p.name() == journal_name: prop = ent._get_property_for(p, plist is indexed_properties) prop._deserialize(ent, p) # Calling deserialize on entities prop will unpack the property and set the value to the entity. ent.add_journal_fields() # Calling add_journal_fields without argument will use self.journal as journal key. added_fields = True break if not added_fields: raise Exception('Cannot proceed with loading of entry %s. Journal fields failed to set.' % ent) return super(Entry, cls)._from_pb(pb, set_key, ent, ent.key) # Calling parent from_pb to attempt to mantain compatibility with possible NDB upgrades? @classmethod def get_meta(cls): '''This function returns dictionary of meta data (not stored or dynamically generated data) of the model. The returned dictionary can be transalted into other understandable code to clients (e.g. JSON). ''' dic = {} dic['_actions'] = getattr(cls, '_actions', []) dic.update(super(Entry, cls).get_fields()) return dic
class DomainUser(orm.BaseExpando): _kind = 8 name = orm.SuperStringProperty('1', required=True) roles = orm.SuperKeyProperty( '2', kind='60', repeated=True ) # It's important to ensure that this list doesn't contain duplicate role keys, since that can pose security issue!! state = orm.SuperStringProperty('3', required=True, choices=['invited', 'accepted']) _default_indexed = False _virtual_fields = { '_primary_email': orm.SuperReferenceProperty( callback=lambda self: self._get_user_async(), format_callback=lambda self, value: value._primary_email), '_user': orm.SuperReferenceStructuredProperty( '0', callback=lambda self: self._get_user_async()), '_records': orm.SuperRecordProperty('8') } _global_role = GlobalRole(permissions=[ orm.ActionPermission( '8', [ orm.Action.build_key('8', 'prepare'), orm.Action.build_key('8', 'invite'), orm.Action.build_key('8', 'read'), orm.Action.build_key('8', 'update'), orm.Action.build_key('8', 'remove'), orm.Action.build_key('8', 'search'), orm.Action.build_key('8', 'accept'), orm.Action.build_key('8', 'clean_roles') ], False, 'entity._original.namespace_entity._original.state != "active"'), orm.ActionPermission( '8', orm.Action.build_key('8', 'remove'), False, 'entity._original.key_id_str == entity._original.namespace_entity._original.primary_contact.entity._original.key_id_str' ), orm.ActionPermission( '8', orm.Action.build_key('8', 'remove'), True, '(entity._original.namespace_entity._original.state == "active" and user.key_id_str == entity._original.key_id_str) and not (entity._original.key_id_str == entity._original.namespace_entity._original.primary_contact.entity._original.key_id_str)' ), orm.ActionPermission('8', orm.Action.build_key('8', 'accept'), False, 'user.key_id_str != entity._original.key_id_str'), orm.ActionPermission( '8', orm.Action.build_key('8', 'accept'), True, 'entity._original.namespace_entity._original.state == "active" and user.key_id_str == entity._original.key_id_str and entity._original.state == "invited"' ), orm.ActionPermission('8', orm.Action.build_key('8', 'clean_roles'), False, 'False'), orm.ActionPermission( '8', orm.Action.build_key('8', 'clean_roles'), True, 'entity._original.namespace_entity._original.state == "active" and user._is_taskqueue' ), orm.FieldPermission( '8', ['name', 'roles', 'state', '_primary_email', '_records'], False, False, 'entity._original.namespace_entity._original.state != "active"'), orm.FieldPermission('8', ['state'], False, None, 'True'), orm.FieldPermission( '8', ['roles'], False, None, 'entity._original.key_id_str == entity._original.namespace_entity._original.primary_contact.entity._original.key_id_str' ), orm.FieldPermission( '8', ['state'], True, None, '(action.key_id_str == "invite" and entity.state == "invited") or (action.key_id_str == "accept" and entity.state == "accepted")' ), orm.FieldPermission( '8', ['state'], None, True, 'entity._original.namespace_entity._original.state == "active" and user.key_id_str == entity._original.key_id_str' ) ]) _actions = [ orm.Action(key=orm.Action.build_key('8', 'prepare'), arguments={'domain': orm.SuperKeyProperty(kind='6')}, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), RulePrepare(), RuleExec(), Set(cfg={'d': { 'output.entity': '_domainuser' }}) ]) ]), orm.Action(key=orm.Action.build_key('8', 'invite'), arguments={ 'domain': orm.SuperKeyProperty(kind='6'), 'name': orm.SuperStringProperty(required=True), 'email': orm.SuperStringProperty(required=True), 'roles': orm.SuperKeyProperty(kind='60', repeated=True) }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), DomainUserInviteSet(), RulePrepare(), RuleExec() ]), orm.PluginGroup( transactional=True, plugins=[ Write(), Write(cfg={'path': '_user'}), Set(cfg={'d': { 'output.entity': '_domainuser' }}), CallbackNotify(), CallbackExec() ]) ]), orm.Action(key=orm.Action.build_key('8', 'read'), arguments={ 'key': orm.SuperKeyProperty(kind='8', required=True), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), RulePrepare(), RuleExec(), Set(cfg={'d': { 'output.entity': '_domainuser' }}) ]) ]), orm.Action(key=orm.Action.build_key('8', 'update'), arguments={ 'key': orm.SuperKeyProperty(kind='8', required=True), 'name': orm.SuperStringProperty(required=True), 'roles': orm.SuperKeyProperty(kind='60', repeated=True), 'read_arguments': orm.SuperJsonProperty() }, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), DomainUserUpdateSet(), RulePrepare(), RuleExec() ]), orm.PluginGroup( transactional=True, plugins=[ Write(), Set(cfg={'d': { 'output.entity': '_domainuser' }}), CallbackNotify(), CallbackExec() ]) ]), orm.Action( key=orm.Action.build_key('8', 'remove'), arguments={'key': orm.SuperKeyProperty(kind='8', required=True)}, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), DomainUserRemoveSet(), RulePrepare(), RuleExec() ]), orm.PluginGroup( transactional=True, plugins=[ Write(cfg={'path': '_user'}), Delete(), Set(cfg={'d': { 'output.entity': '_domainuser' }}), CallbackNotify(), CallbackExec() ]) ]), orm.Action(key=orm.Action.build_key('8', 'search'), arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True), 'search': orm.SuperSearchProperty( default={ 'filters': [], 'orders': [{ 'field': 'name', 'operator': 'asc' }] }, cfg={ 'search_by_keys': True, 'search_arguments': { 'kind': '8', 'options': { 'limit': settings.SEARCH_PAGE } }, 'filters': { 'name': orm.SuperStringProperty(), 'state': orm.SuperStringProperty( choices=['invited', 'accepted']) }, 'indexes': [{ 'orders': [('name', ['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('8', 'accept'), arguments={'key': orm.SuperKeyProperty(kind='8', required=True)}, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), Set(cfg={'s': { '_domainuser.state': 'accepted' }}), RulePrepare(), RuleExec() ]), orm.PluginGroup( transactional=True, plugins=[Write(), CallbackNotify(), CallbackExec()]), orm.PluginGroup(plugins=[ Set(cfg={'d': { '_domain': '_domainuser.namespace_entity' }}), RulePrepare(), RulePrepare(cfg={'path': '_domain'}), Set( cfg={ 'd': { 'output.entity': '_domainuser', 'output.domain': '_domain' } }) ]) ]), orm.Action( key=orm.Action.build_key('8', 'clean_roles'), arguments={'key': orm.SuperKeyProperty(kind='8', required=True)}, _plugin_groups=[ orm.PluginGroup(plugins=[ Context(), Read(), DomainUserCleanRolesSet(), RulePrepare(), RuleExec() ]), orm.PluginGroup(transactional=True, plugins=[Write()]) ]) ] def _get_user_async(self): return orm.Key('0', long(self.key_id_str)).get_async()
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 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_')
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 = []
def execute_create_order_journal(self): config_input = self.config.next_operation_input domain_key = config_input.get('domain_key') namespace = domain_key.urlsafe() models = self.context.models Journal = models['49'] Action = models['84'] PluginGroup = models['85'] CartInit = models['99'] PayPalPayment = models['108'] LinesInit = models['100'] AddressRule = models['107'] ProductToLine = models['101'] ProductSubtotalCalculate = models['104'] TaxSubtotalCalculate = models['110'] OrderTotalCalculate = models['105'] RulePrepare = models['93'] TransactionWrite = models['114'] CallbackNotify = models['115'] CallbackExec = models['97'] Unit = models['19'] entity = Journal(namespace=namespace, id='system_sales_order') entity.name = 'Sales Order Journal' entity.state = 'active' # this two need to be ordered Dictionaries because using unordered dict will cause # weird behaviour on user interface (e.g. on each refresh different order of properties entity.entry_fields = { 'company_address': orm.SuperLocalStructuredProperty('68', '7', required=True), 'party': orm.SuperKeyProperty('8', kind='0', required=True, indexed=False), # @todo buyer_reference ?? 'billing_address_reference': orm.SuperKeyProperty('9', kind='9', required=True, indexed=False), 'shipping_address_reference': orm.SuperKeyProperty('10', kind='9', required=True, indexed=False), 'billing_address': orm.SuperLocalStructuredProperty('68', '11', required=True), 'shipping_address': orm.SuperLocalStructuredProperty('68', '12', required=True), 'currency': orm.SuperLocalStructuredProperty('19', '13', required=True), 'untaxed_amount': orm.SuperDecimalProperty('14', required=True, indexed=False), 'tax_amount': orm.SuperDecimalProperty('15', required=True, indexed=False), 'total_amount': orm.SuperDecimalProperty('16', required=True, indexed=False), 'paypal_reciever_email': orm.SuperStringProperty('17', required=True, indexed=False), 'paypal_business': orm.SuperStringProperty('18', required=True, indexed=False) } entity.line_fields = { 'description': orm.SuperTextProperty('6', required=True), 'product_reference': orm.SuperKeyProperty('7', kind='38', required=True, indexed=False), 'product_variant_signature': orm.SuperJsonProperty('8', required=True), 'product_category_complete_name': orm.SuperTextProperty('9', required=True), 'product_category_reference': orm.SuperKeyProperty('10', kind='17', required=True, indexed=False), 'code': orm.SuperStringProperty('11', required=True, indexed=False), 'unit_price': orm.SuperDecimalProperty('12', required=True, indexed=False), 'product_uom': orm.SuperLocalStructuredProperty('19', '13', required=True), 'quantity': orm.SuperDecimalProperty('14', required=True, indexed=False), 'discount': orm.SuperDecimalProperty('15', required=True, indexed=False), 'taxes': orm.SuperLocalStructuredProperty('116', '16', required=True), 'subtotal': orm.SuperDecimalProperty('17', required=True, indexed=False), 'discount_subtotal': orm.SuperDecimalProperty('18', required=True, indexed=False) } entity._use_rule_engine = False entity.write() entity._transaction_actions = [ Action(key=Action.build_key('add_to_cart', parent=entity.key), name='Add to Cart', active=True, arguments={ 'domain': orm.SuperKeyProperty(kind='6', required=True), 'product': orm.SuperKeyProperty(kind='38', required=True), 'variant_signature': orm.SuperJsonProperty() }) # Other actions: update, checkout, cancel, pay, timeout, complete, message ] entity._transaction_plugin_groups = [ PluginGroup(name='Entry Init', active=True, sequence=0, transactional=False, subscriptions=[ Action.build_key('add_to_cart', parent=entity.key) ], plugins=[CartInit()]), PluginGroup(name='Payment Services Configuration', active=True, sequence=1, transactional=False, subscriptions=[ Action.build_key('add_to_cart', parent=entity.key) ], plugins=[ PayPalPayment( currency=Unit.build_key('usd'), reciever_email='*****@*****.**', business='*****@*****.**') ]), PluginGroup(name='Entry Lines Init', active=True, sequence=2, transactional=False, subscriptions=[ Action.build_key('add_to_cart', parent=entity.key) ], plugins=[LinesInit()]), PluginGroup(name='Address Exclusions, Taxes, Carriers...', active=True, sequence=3, transactional=False, subscriptions=[ Action.build_key('add_to_cart', parent=entity.key) ], plugins=[]), PluginGroup( name='Calculating Algorithms', active=True, sequence=4, transactional=False, subscriptions=[ Action.build_key('add_to_cart', parent=entity.key) ], plugins=[ AddressRule( exclusion=False, address_type='billing' ), # @todo For now we setup default address rules for both, billing & shipping addresses. AddressRule( exclusion=False, address_type='shipping' ), # @todo For now we setup default address rules for both, billing & shipping addresses. ProductToLine(), ProductSubtotalCalculate(), TaxSubtotalCalculate(), OrderTotalCalculate() ]), PluginGroup(name='Commit Transaction Plugins', active=True, sequence=5, transactional=True, subscriptions=[ Action.build_key('add_to_cart', parent=entity.key) ], plugins=[ RulePrepare(cfg={'path': '_group._entries'}), TransactionWrite(), CallbackNotify(), CallbackExec() ]), ] entity.write({ 'agent': self.context.user.key, 'action': self.context.action.key }) self.config.next_operation = 'complete' self.config.next_operation_input = {'domain_key': domain_key} self.config.write()