server/schemahooks.py
branchreldefsecurity
changeset 3877 7ca53fc72a0a
parent 3870 a6b029aa0f44
child 3889 8902b8745918
equal deleted inserted replaced
3876:1169d3154be6 3877:7ca53fc72a0a
   177         for i, op in enumerate(self.session.pending_operations):
   177         for i, op in enumerate(self.session.pending_operations):
   178             if not isinstance(op, MemSchemaEarlyOperation):
   178             if not isinstance(op, MemSchemaEarlyOperation):
   179                 return i
   179                 return i
   180         return i + 1
   180         return i + 1
   181 
   181 
   182 
       
   183 class MemSchemaPermissionOperation(MemSchemaOperation):
       
   184     """base class to synchronize schema permission definitions"""
       
   185     def __init__(self, session, perm, etype_eid):
       
   186         self.perm = perm
       
   187         try:
       
   188             self.name = session.entity_from_eid(etype_eid).name
       
   189         except IndexError:
       
   190             self.error('changing permission of a no more existant type #%s',
       
   191                 etype_eid)
       
   192         else:
       
   193             Operation.__init__(self, session)
       
   194 
   182 
   195 
   183 
   196 # operations for high-level source database alteration  ########################
   184 # operations for high-level source database alteration  ########################
   197 
   185 
   198 class SourceDbCWETypeRename(PreCommitOperation):
   186 class SourceDbCWETypeRename(PreCommitOperation):
   485         # so there is nothing to do here
   473         # so there is nothing to do here
   486         if rdef.eid in session.transaction_data.get('neweids', ()):
   474         if rdef.eid in session.transaction_data.get('neweids', ()):
   487             return
   475             return
   488         subjtype, rtype, objtype = session.schema.schema_by_eid(rdef.eid)
   476         subjtype, rtype, objtype = session.schema.schema_by_eid(rdef.eid)
   489         cstrtype = self.entity.type
   477         cstrtype = self.entity.type
   490         oldcstr = rtype.constraint_by_type(subjtype, objtype, cstrtype)
   478         oldcstr = rtype.rdef(subjtype, objtype).constraint_by_type(cstrtype)
   491         newcstr = CONSTRAINTS[cstrtype].deserialize(self.entity.value)
   479         newcstr = CONSTRAINTS[cstrtype].deserialize(self.entity.value)
   492         table = SQL_PREFIX + str(subjtype)
   480         table = SQL_PREFIX + str(subjtype)
   493         column = SQL_PREFIX + str(rtype)
   481         column = SQL_PREFIX + str(rtype)
   494         # alter the physical schema on size constraint changes
   482         # alter the physical schema on size constraint changes
   495         if newcstr.type() == 'SizeConstraint' and (
   483         if newcstr.type() == 'SizeConstraint' and (
   565 
   553 
   566 class MemSchemaCWRTypeAdd(MemSchemaEarlyOperation):
   554 class MemSchemaCWRTypeAdd(MemSchemaEarlyOperation):
   567     """actually add the relation type to the instance's schema"""
   555     """actually add the relation type to the instance's schema"""
   568     eid = None # make pylint happy
   556     eid = None # make pylint happy
   569     def commit_event(self):
   557     def commit_event(self):
   570         rschema = self.schema.add_relation_type(self.kobj)
   558         self.schema.add_relation_type(self.kobj)
   571         rschema.set_default_groups()
       
   572 
   559 
   573 
   560 
   574 class MemSchemaCWRTypeUpdate(MemSchemaOperation):
   561 class MemSchemaCWRTypeUpdate(MemSchemaOperation):
   575     """actually update some properties of a relation definition"""
   562     """actually update some properties of a relation definition"""
   576     rschema = values = None # make pylint happy
   563     rschema = values = None # make pylint happy
   604     rschema = values = None # make pylint happy
   591     rschema = values = None # make pylint happy
   605 
   592 
   606     def commit_event(self):
   593     def commit_event(self):
   607         # structure should be clean, not need to remove entity's relations
   594         # structure should be clean, not need to remove entity's relations
   608         # at this point
   595         # at this point
   609         self.rschema._rproperties[self.kobj].update(self.values)
   596         self.rschema.rdef[self.kobj].update(self.values)
   610 
   597 
   611 
   598 
   612 class MemSchemaRDefDel(MemSchemaOperation):
   599 class MemSchemaRDefDel(MemSchemaOperation):
   613     """actually remove the relation definition from the instance's schema"""
   600     """actually remove the relation definition from the instance's schema"""
   614     def commit_event(self):
   601     def commit_event(self):
   636             self.cancelled = True
   623             self.cancelled = True
   637             return
   624             return
   638         subjtype, rtype, objtype = self.session.schema.schema_by_eid(rdef.eid)
   625         subjtype, rtype, objtype = self.session.schema.schema_by_eid(rdef.eid)
   639         self.prepare_constraints(subjtype, rtype, objtype)
   626         self.prepare_constraints(subjtype, rtype, objtype)
   640         cstrtype = self.entity.type
   627         cstrtype = self.entity.type
   641         self.cstr = rtype.constraint_by_type(subjtype, objtype, cstrtype)
   628         self.cstr = rtype.rdef(subjtype, objtype).constraint_by_type(cstrtype)
   642         self.newcstr = CONSTRAINTS[cstrtype].deserialize(self.entity.value)
   629         self.newcstr = CONSTRAINTS[cstrtype].deserialize(self.entity.value)
   643         self.newcstr.eid = self.entity.eid
   630         self.newcstr.eid = self.entity.eid
   644 
   631 
   645     def commit_event(self):
   632     def commit_event(self):
   646         if self.cancelled:
   633         if self.cancelled:
   662 
   649 
   663     def commit_event(self):
   650     def commit_event(self):
   664         self.constraints.remove(self.cstr)
   651         self.constraints.remove(self.cstr)
   665 
   652 
   666 
   653 
   667 class MemSchemaPermissionCWGroupAdd(MemSchemaPermissionOperation):
   654 class MemSchemaPermissionAdd(MemSchemaOperation):
   668     """synchronize schema when a *_permission relation has been added on a group
   655     """synchronize schema when a *_permission relation has been added on a group
   669     """
   656     """
   670     def __init__(self, session, perm, etype_eid, group_eid):
   657 
   671         self.group = session.entity_from_eid(group_eid).name
   658     def commit_event(self):
   672         super(MemSchemaPermissionCWGroupAdd, self).__init__(
   659         """the observed connections pool has been commited"""
   673             session, perm, etype_eid)
   660         try:
       
   661             erschema = self.schema.schema_by_eid(self.eid)
       
   662         except KeyError:
       
   663             # duh, schema not found, log error and skip operation
       
   664             self.error('no schema for %s', self.name)
       
   665             return
       
   666         perms = list(erschema.action_permissions(self.action))
       
   667         if hasattr(self, group_eid):
       
   668             perm = self.session.entity_from_eid(self.group_eid).name
       
   669         else:
       
   670             perm = erschema.rql_expression(self.expr)
       
   671         try:
       
   672             perms.index(perm)
       
   673             self.warning('%s already in permissions for %s on %s',
       
   674                          perm, self.action, erschema)
       
   675         except ValueError:
       
   676             perms.append(perm)
       
   677             erschema.set_action_permissions(self.action, perms)
       
   678 
       
   679 
       
   680 class MemSchemaPermissionDel(MemSchemaPermissionAdd):
       
   681     """synchronize schema when a *_permission relation has been deleted from a
       
   682     group
       
   683     """
   674 
   684 
   675     def commit_event(self):
   685     def commit_event(self):
   676         """the observed connections pool has been commited"""
   686         """the observed connections pool has been commited"""
   677         try:
   687         try:
   678             erschema = self.schema[self.name]
   688             erschema = self.schema[self.name]
   679         except KeyError:
   689         except KeyError:
   680             # duh, schema not found, log error and skip operation
   690             # duh, schema not found, log error and skip operation
   681             self.error('no schema for %s', self.name)
   691             self.error('no schema for %s', self.name)
   682             return
   692             return
   683         groups = list(erschema.get_groups(self.perm))
   693         perms = list(erschema.action_permissions(self.action))
   684         try:
   694         if hasattr(self, group_eid):
   685             groups.index(self.group)
   695             perm = self.session.entity_from_eid(self.group_eid).name
   686             self.warning('group %s already have permission %s on %s',
   696         else:
   687                          self.group, self.perm, erschema.type)
   697             perm = erschema.rql_expression(self.expr)
       
   698         try:
       
   699             perms.remove(self.group)
       
   700             erschema.set_action_permissions(self.action, perms)
   688         except ValueError:
   701         except ValueError:
   689             groups.append(self.group)
   702             self.error('can\'t remove permission %s for %s on %s',
   690             erschema.set_groups(self.perm, groups)
   703                        perm, self.action, erschema)
   691 
       
   692 
       
   693 class MemSchemaPermissionCWGroupDel(MemSchemaPermissionCWGroupAdd):
       
   694     """synchronize schema when a *_permission relation has been deleted from a
       
   695     group
       
   696     """
       
   697 
       
   698     def commit_event(self):
       
   699         """the observed connections pool has been commited"""
       
   700         try:
       
   701             erschema = self.schema[self.name]
       
   702         except KeyError:
       
   703             # duh, schema not found, log error and skip operation
       
   704             self.error('no schema for %s', self.name)
       
   705             return
       
   706         groups = list(erschema.get_groups(self.perm))
       
   707         try:
       
   708             groups.remove(self.group)
       
   709             erschema.set_groups(self.perm, groups)
       
   710         except ValueError:
       
   711             self.error('can\'t remove permission %s on %s to group %s',
       
   712                 self.perm, erschema.type, self.group)
       
   713 
       
   714 
       
   715 class MemSchemaPermissionRQLExpressionAdd(MemSchemaPermissionOperation):
       
   716     """synchronize schema when a *_permission relation has been added on a rql
       
   717     expression
       
   718     """
       
   719     def __init__(self, session, perm, etype_eid, expression):
       
   720         self.expr = expression
       
   721         super(MemSchemaPermissionRQLExpressionAdd, self).__init__(
       
   722             session, perm, etype_eid)
       
   723 
       
   724     def commit_event(self):
       
   725         """the observed connections pool has been commited"""
       
   726         try:
       
   727             erschema = self.schema[self.name]
       
   728         except KeyError:
       
   729             # duh, schema not found, log error and skip operation
       
   730             self.error('no schema for %s', self.name)
       
   731             return
       
   732         exprs = list(erschema.get_rqlexprs(self.perm))
       
   733         exprs.append(erschema.rql_expression(self.expr))
       
   734         erschema.set_rqlexprs(self.perm, exprs)
       
   735 
       
   736 
       
   737 class MemSchemaPermissionRQLExpressionDel(MemSchemaPermissionRQLExpressionAdd):
       
   738     """synchronize schema when a *_permission relation has been deleted from an
       
   739     rql expression
       
   740     """
       
   741 
       
   742     def commit_event(self):
       
   743         """the observed connections pool has been commited"""
       
   744         try:
       
   745             erschema = self.schema[self.name]
       
   746         except KeyError:
       
   747             # duh, schema not found, log error and skip operation
       
   748             self.error('no schema for %s', self.name)
       
   749             return
       
   750         rqlexprs = list(erschema.get_rqlexprs(self.perm))
       
   751         for i, rqlexpr in enumerate(rqlexprs):
       
   752             if rqlexpr.expression == self.expr:
       
   753                 rqlexprs.pop(i)
       
   754                 break
       
   755         else:
       
   756             self.error('can\'t remove permission %s on %s for expression %s',
       
   757                 self.perm, erschema.type, self.expr)
       
   758             return
       
   759         erschema.set_rqlexprs(self.perm, rqlexprs)
       
   760 
   704 
   761 
   705 
   762 class MemSchemaSpecializesAdd(MemSchemaOperation):
   706 class MemSchemaSpecializesAdd(MemSchemaOperation):
   763 
   707 
   764     def commit_event(self):
   708     def commit_event(self):
   892                        meta=entity.get('meta')) # don't care about final
   836                        meta=entity.get('meta')) # don't care about final
   893     # fake we add it to the schema now to get a correctly initialized schema
   837     # fake we add it to the schema now to get a correctly initialized schema
   894     # but remove it before doing anything more dangerous...
   838     # but remove it before doing anything more dangerous...
   895     schema = session.schema
   839     schema = session.schema
   896     eschema = schema.add_entity_type(etype)
   840     eschema = schema.add_entity_type(etype)
   897     eschema.set_default_groups()
       
   898     # generate table sql and rql to add metadata
   841     # generate table sql and rql to add metadata
   899     tablesql = eschema2sql(session.pool.source('system').dbhelper, eschema,
   842     tablesql = eschema2sql(session.pool.source('system').dbhelper, eschema,
   900                            prefix=SQL_PREFIX)
   843                            prefix=SQL_PREFIX)
   901     relrqls = []
   844     relrqls = []
   902     for rtype in (META_RTYPES - VIRTUAL_RTYPES):
   845     for rtype in (META_RTYPES - VIRTUAL_RTYPES):
  1031     if not fromeid in session.transaction_data.get('pendingeids', ()):
   974     if not fromeid in session.transaction_data.get('pendingeids', ()):
  1032         schema = session.schema
   975         schema = session.schema
  1033         entity = session.entity_from_eid(toeid)
   976         entity = session.entity_from_eid(toeid)
  1034         subjtype, rtype, objtype = schema.schema_by_eid(fromeid)
   977         subjtype, rtype, objtype = schema.schema_by_eid(fromeid)
  1035         try:
   978         try:
  1036             cstr = rtype.constraint_by_type(subjtype, objtype,
   979             cstr = rtype.rdef(subjtype, objtype).constraint_by_type(
  1037                                             entity.cstrtype[0].name)
   980                 entity.cstrtype[0].name)
  1038         except IndexError:
   981         except IndexError:
  1039             session.critical('constraint type no more accessible')
   982             session.critical('constraint type no more accessible')
  1040         else:
   983         else:
  1041             SourceDbCWConstraintDel(session, subjtype=subjtype, rtype=rtype,
   984             SourceDbCWConstraintDel(session, subjtype=subjtype, rtype=rtype,
  1042                                     objtype=objtype, cstr=cstr)
   985                                     objtype=objtype, cstr=cstr)
  1051 
   994 
  1052 # permissions synchronization hooks ############################################
   995 # permissions synchronization hooks ############################################
  1053 
   996 
  1054 def after_add_permission(session, subject, rtype, object):
   997 def after_add_permission(session, subject, rtype, object):
  1055     """added entity/relation *_permission, need to update schema"""
   998     """added entity/relation *_permission, need to update schema"""
  1056     perm = rtype.split('_', 1)[0]
   999     action = rtype.split('_', 1)[0]
  1057     if session.describe(object)[0] == 'CWGroup':
  1000     if session.describe(object)[0] == 'CWGroup':
  1058         MemSchemaPermissionCWGroupAdd(session, perm, subject, object)
  1001         MemSchemaPermissionAdd(session, action=action, eid=subject,
       
  1002                                group_eid=object)
  1059     else: # RQLExpression
  1003     else: # RQLExpression
  1060         expr = session.execute('Any EXPR WHERE X eid %(x)s, X expression EXPR',
  1004         expr = session.entity_from_eid(object).expression
  1061                                {'x': object}, 'x')[0][0]
  1005         MemSchemaPermissionAdd(session, action=action, eid=subject,
  1062         MemSchemaPermissionRQLExpressionAdd(session, perm, subject, expr)
  1006                                expr=expr)
  1063 
  1007 
  1064 
  1008 
  1065 def before_del_permission(session, subject, rtype, object):
  1009 def before_del_permission(session, subject, rtype, object):
  1066     """delete entity/relation *_permission, need to update schema
  1010     """delete entity/relation *_permission, need to update schema
  1067 
  1011 
  1068     skip the operation if the related type is being deleted
  1012     skip the operation if the related type is being deleted
  1069     """
  1013     """
  1070     if subject in session.transaction_data.get('pendingeids', ()):
  1014     if subject in session.transaction_data.get('pendingeids', ()):
  1071         return
  1015         return
  1072     perm = rtype.split('_', 1)[0]
  1016     action = rtype.split('_', 1)[0]
  1073     if session.describe(object)[0] == 'CWGroup':
  1017     if session.describe(object)[0] == 'CWGroup':
  1074         MemSchemaPermissionCWGroupDel(session, perm, subject, object)
  1018         MemSchemaPermissionDel(session, action=action, eid=subject, group_eid=object)
  1075     else: # RQLExpression
  1019     else: # RQLExpression
  1076         expr = session.execute('Any EXPR WHERE X eid %(x)s, X expression EXPR',
  1020         expr = session.entity_from_eid(object).expression
  1077                                {'x': object}, 'x')[0][0]
  1021         MemSchemaPermissionDel(session, action=action, eid=subject, expr=expr)
  1078         MemSchemaPermissionRQLExpressionDel(session, perm, subject, expr)
       
  1079 
  1022 
  1080 
  1023 
  1081 def after_add_specializes(session, subject, rtype, object):
  1024 def after_add_specializes(session, subject, rtype, object):
  1082     MemSchemaSpecializesAdd(session, etypeeid=subject, parentetypeeid=object)
  1025     MemSchemaSpecializesAdd(session, etypeeid=subject, parentetypeeid=object)
  1083 
  1026