Example #1
0
class CategoryBalance(orm.BaseModel):
  
  _kind = 71
  
  _use_rule_engine = False
  
  from_date = orm.SuperDateTimeProperty('1', required=True, indexed=False)
  to_date = orm.SuperDateTimeProperty('2', required=True, indexed=False)
  debit = orm.SuperDecimalProperty('3', required=True, indexed=False)
  credit = orm.SuperDecimalProperty('4', required=True, indexed=False)
  balance = orm.SuperDecimalProperty('5', required=True, indexed=False)
  uom = orm.SuperLocalStructuredProperty(uom.UOM, '6', required=True, indexed=False)
Example #2
0
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})
                       ])
                   ])
    ]
Example #3
0
class Session(orm.BaseModel):
  
  _kind = 70
  
  _use_rule_engine = False
  
  created = orm.SuperDateTimeProperty('1', required=True, auto_now_add=True, indexed=False)
  session_id = orm.SuperStringProperty('2', required=True, indexed=False)
Example #4
0
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
Example #5
0
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_')
Example #6
0
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)
Example #7
0
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)
    return orm.Key(*new_args, **kwargs)
Example #8
0
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
Example #9
0
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