def __init__(self, model, viewCode, model_admin, protoMeta ): self.model = model # the model to use as reference self.title = self.model._meta.verbose_name.title() # importa las definiciones del modelo y del admin self.model_admin = model_admin self.protoMeta = protoMeta # garantiza la llave self.viewCode = viewCode # Inicializa self.fields = [] self.fieldsDict = {} self.gridConfig = self.protoMeta.get( 'gridConfig', {}) # Los campos deben ser inicialmente un diccionario para poder validarlos protoMeta[ 'fields' ] = protoMeta.get( 'fields', []) if isinstance( protoMeta[ 'fields' ], list ) : self.fieldsDict = list2dict( protoMeta[ 'fields' ], 'name') #UDPs para poder determinar el valor por defecto ROnly self.pUDP = self.protoMeta.get( 'usrDefProps', {}) verifyUdpDefinition( self.pUDP ) # lista de campos para la presentacion en la grilla pListDisplay = verifyList( self.gridConfig.get( 'listDisplay', []) ) if not pListDisplay: pListDisplay = verifyList( getattr(self.model_admin , 'list_display', [])) # Por defecto solo vienen Chk, _str_ try: pListDisplay.remove('action_checkbox') except ValueError: pass # if pListDisplay and (pListDisplay[0] == '__str__'): pListDisplay = [] if len(pListDisplay) == 0: pListDisplay = [ '__str__' ] self.gridConfig['listDisplay'] = pListDisplay # Se leen los excluidos del admin, no se requiere # en la protoDef, pues los campos se enumeran explicitamente protoExclude = verifyList( self.protoMeta.get( 'exclude', [])) #Se leen los readonly fields para setear el attr readOnly = true pReadOnlyFlds = verifyList( self.gridConfig.get( 'readOnlyFields', []) ) if not pReadOnlyFlds: pReadOnlyFlds = verifyList( getattr(self.model_admin , 'readonly_fields', [])) self.gridConfig['readOnlyFields'] = pReadOnlyFlds # @@ Por alguna Ext no retiene el IdProperty ( idInternal al hacer click en las filas ) # idName = model._meta.pk.name # La lista de campos del admin sirve de base, pues puede haber muchos mas campos en proto q en admin # Si solo queda el __str__ , asume todos los campos del modelo # iCount = len( pListDisplay ) # if ( iCount == 0 ) or ( iCount == 1 and (pListDisplay[0] == '__str__')) : # Se crean los campos con base al modelo ( trae todos los campos del modelo ) for field in self.model._meta._fields(): if field.name in protoExclude: continue setFieldDict ( self.fieldsDict , field ) # for field in self.model._meta._many_to_many(): # if field.name in protoExclude: continue # setFieldDict ( self.fieldsDict , field ) # Agrega el __str__ que sirve de base para los zooms fName = '__str__' fdict = self.fieldsDict.get( fName , {}) if not fdict: fdict['name'] = fName self.fieldsDict[ fName ] = fdict setDefaultField ( fdict, self.model, self.viewCode ) # Genera la lista de campos y agrega el nombre al diccionario for key in self.fieldsDict: fdict = self.fieldsDict[ key ] if (fdict.get( 'name', '') == '') : fdict[ 'name' ] = key if key in pReadOnlyFlds: fdict[ 'readOnly' ] = True # Repasa las propiedades de base, ver por q no esta pasando trayendo las props de base ( ie: defaulValue ) if ( not ( key.startswith( 'udp__') )): try: field = self.model._meta.get_field( key ) setFieldDict ( self.fieldsDict , field ) fdict = self.fieldsDict[ key ] except: #Es posible q se puedan configuar propiedades no pertenecientes a la tabla como editables??? fdict[ 'readOnly' ] = True pass self.fields.append(fdict)
def _protoEdit(request, myAction ): if not request.user.is_authenticated(): return doReturn ({'success':False ,'message' : 'readOnly User'}) if request.method != 'POST': return doReturn ({'success':False, 'message' : 'invalid message'}) message = '' # Carga el modelo protoMeta = request.POST.get('protoMeta', '') protoMeta = json.loads( protoMeta ) viewEntity = protoMeta.get('viewEntity', '') model = getDjangoModel(viewEntity) # Autentica if not getModelPermissions( request.user, model, myAction ): return doReturn ({'success':False ,'message' : 'No ' + myAction + 'permission'}) # Obtiene el profile para saber el teamhierarchi userProfile = getUserProfile( request.user, 'edit', viewEntity ) # Verfica si es un protoModel ( maneja TeamHierarchy ) isProtoModel = hasattr( model , '_protoObj' ) # Verifica si hay registros que son solo de referencia userNodes = [] refAllow = False if myAction in ['delete', 'change'] and isProtoModel and not request.user.is_superuser : refAllow = getModelPermissions( request.user, model, 'refallow' ) if refAllow: userNodes = getUserNodes( request.user, viewEntity ) # WorkFlow hasWFlow = hasattr( model , '_WorkFlow' ) and isProtoModel if hasWFlow: wfadmin = getModelPermissions( request.user , model, 'wfadmin' ) WFlowControl = getattr( model, '_WorkFlow', {} ) initialWfStatus = WFlowControl.get( 'initialStatus', '0') # Decodifica los eltos rows = request.POST.get('rows', []) rows = json.loads( rows ) fieldsDict = list2dict( protoMeta[ 'fields' ], 'name') # JsonField jsonField = protoMeta.get('jsonField', '') if not isinstance( jsonField, (str, unicode) ): jsonField = '' # TOOD: Log # activityLog ( myAction, request.user , viewEntity, { 'protoMeta' : protoMeta , 'rows' : rows }) # Genera la clase UDP pUDP = protoMeta.get('usrDefProps', {}) cUDP = verifyUdpDefinition( pUDP ) # Verifica q sea una lista de registros, (no deberia pasar, ya desde Extjs se controla ) if type(rows).__name__=='dict': rows = [rows] pList = [] for data in rows: data['_ptStatus'] = '' if myAction == 'add': rec = model() else: try: rec = model.objects.get( pk = data['id'] ) except: data['_ptStatus'] = data['_ptStatus'] + ERR_NOEXIST + '<br>' pList.append( data ) continue # refAllow verifica si corresponde a los registros modificables ( solo es true en myAction in ['delete', 'change'] ) if refAllow and isProtoModel : if not ( str( rec.smOwningTeam_id ) in userNodes ) : data['_ptStatus'] = ERR_REFONLY + '<br>' pList.append( data ) continue if not ( myAction == 'delete' ): # Upd, Ins for key in data: key = smart_str( key ) if key in ['id', '_ptStatus', '_ptId', '__str__']: continue vFld = fieldsDict[key] if vFld.get( 'crudType' ) in ["screenOnly", "linked" ]: continue # Los campos de seguridad se manejan a nivel registro if isProtoModel: if key in ['smOwningUser','smOwningTeam','smCreatedBy','smModifiedBy', 'smWflowStatus','smRegStatus','smCreatedOn','smModifiedOn', 'smOwningUser_id','smOwningTeam_id','smCreatedBy_id','smModifiedBy_id']: continue # Udps if (cUDP.udpTable and key.startswith( cUDP.propertyPrefix + '__')): continue # JsonField if key == jsonField: continue if key.startswith( jsonField + '__'): continue try: setRegister( model, rec, key, data ) except Exception as e: data['_ptStatus'] = data['_ptStatus'] + getReadableError( e ) if isProtoModel: setSecurityInfo( rec, data, userProfile, ( myAction == 'add' ) ) if len( jsonField ) > 0: jsonInfo = {} for key in data: if not key.startswith( jsonField + '__'): continue jKey = key[ len(jsonField) + 2 : ] jsonInfo[ jKey ] = data[ key ] setattr( rec, jsonField , jsonInfo ) # Inicializa el estado del WF if hasWFlow: setattr( rec, 'smWflowStatus' , initialWfStatus ) # Guarda el idInterno para concatenar registros nuevos en la grilla try: _ptId = data['_ptId'] except: _ptId = '' try: rec.save() # Guardar las Udps if cUDP.udpTable: try: saveUDP( rec, data, cUDP ) except Exception as e: raise Exception( 'UdpError: saveActiob') # -- Los tipos complejos ie. date, generan un error, es necesario hacerlo detalladamente # Convierte el registro en una lista y luego toma solo el primer elto de la lista resultado. data = Q2Dict(protoMeta , [rec], False )[0] data['_ptId'] = _ptId except Exception as e: data['_ptStatus'] = data['_ptStatus'] + getReadableError( e ) data['_ptId'] = _ptId #traceback.print_exc() #return doReturn ({'success':False ,'message' : str( e )}) else: # Action Delete try: rec.delete() except Exception, e: data['_ptStatus'] = data['_ptStatus'] + getReadableError( e ) pass pList.append( data ) if data.get('_ptStatus', ''): message += data['_ptStatus'] + ';'
def Q2Dict (protoMeta, pRows, fakeId, userNodes=[]): """ userNodes : Para el manejo de refAllow : contiene los Id de los teams validos return the row list from given queryset """ # pStyle = protoMeta.get( 'pciStyle', '') JsonField = protoMeta.get('jsonField', '') if not isinstance(JsonField, (str, unicode)): JsonField = '' pUDP = protoMeta.get('usrDefProps', {}) cUDP = verifyUdpDefinition(pUDP) rows = [] # Tablas de zoom para absorcion de campos relModels = {} # Identifica las Udps para solo leer las definidas en la META if cUDP.udpTable : udpTypes = {} udpList = [] for lField in protoMeta['fields']: fName = lField['name'] if fName.startswith(cUDP.propertyPrefix + '__'): udpList.append(fName) udpTypes[ fName ] = lField['type'] # Alimenta la coleccion de zooms, por cada campo pues hay q hacer un select para esto for lField in protoMeta['fields']: fName = lField['name'] myZoomModel = lField.get('zoomModel', '') if (len(myZoomModel) > 0) and (myZoomModel != protoMeta['viewEntity']): relModels[ fName ] = { 'zoomModel' : myZoomModel, 'fkId' : lField.get('fkId', '') , 'loaded' : False } # Verifica si existen reemplazos por hacer ( cpFromField ) # 1. Marca los zooms q estan referenciados bCopyFromFld = False for lField in protoMeta['fields']: fName = lField['name'] if (lField.get('cpFromField') is None or lField.get('cpFromZoom') is None): continue bCopyFromFld = True # Marca el campo lField[ 'isAbsorbed' ] = True # Marca el zoom try: relModel = relModels[ lField.get('cpFromZoom') ] relModel[ 'loaded'] = True except: pass # 2. borra los q no tienen marca for relName in relModels.keys(): relModel = relModels[ relName ] if not relModel[ 'loaded']: del relModels[ relName ] # Esta forma permite agregar las funciones entre ellas el __unicode__ rowId = 0 for rowData in pRows: rowId += 1 rowdict = {} # limpia los datos de tablas relacionadas for relName in relModels: relModel = relModels[ relName ] relModel[ 'rowData'] = {} relModel[ 'loaded'] = False # recorre los campos para obtener su valor for lField in protoMeta['fields']: fName = lField['name'] pName = lField.get('physicalName', fName) if lField.get('crudType') == "screenOnly" : continue # UDP Se evaluan despues if cUDP.udpTable and fName.startswith(cUDP.propertyPrefix + '__'): continue elif (lField['type'] == 'protoN2N'): continue # Si el campo es absorbido ( bCopyFromFld es un shortcut para evitar la evulacion en caso de q no haya ningun cpFromField ) elif bCopyFromFld and isAbsorbedField(lField, protoMeta) : continue rowdict[ fName ] = getFieldValue(pName, lField[ 'type'], rowData, JsonField) if cUDP.udpTable: # rowDict : se actualizara con los datos de la UDP # rowData es el registro de base, en caso de q sea un MD la lectura es automatica rowData.udpTable... # udpTypes : lista de Udps a leer readUdps(rowdict, rowData , cUDP, udpList, udpTypes) # REaliza la absorcion de datos provenientes de un zoom if bCopyFromFld: rowdict = copyValuesFromFields(protoMeta, rowdict, relModels, JsonField) # Dont delete ( Dgt ) # if pStyle == 'tree': # rowdict[ 'viewEntity' ] = protoMeta.get('viewEntity', '') # rowdict[ 'leaf' ] = False; rowdict[ 'children' ] = [] # Agrega el Id Siempre como idInterno ( no representa una col, idProperty ) rowdict[ 'id'] = rowData.pk if fakeId: rowdict[ 'id'] = rowId # Verifica el refAllow if len(userNodes) > 0 and not (str(rowData.smOwningTeam_id) in userNodes) : rowdict['_ptStatus'] = REFONLY # Agrega la fila al diccionario rows.append(rowdict) return rows
def Q2Dict(protoMeta, pRows, fakeId, userNodes=[]): """ userNodes : Para el manejo de refAllow : contiene los Id de los teams validos return the row list from given queryset """ # pStyle = protoMeta.get( 'pciStyle', '') JsonField = protoMeta.get('jsonField', '') if not isinstance(JsonField, (str, unicode)): JsonField = '' pUDP = protoMeta.get('usrDefProps', {}) cUDP = verifyUdpDefinition(pUDP) rows = [] # Tablas de zoom para absorcion de campos relModels = {} # Identifica las Udps para solo leer las definidas en la META if cUDP.udpTable: udpTypes = {} udpList = [] for lField in protoMeta['fields']: fName = lField['name'] if fName.startswith(cUDP.propertyPrefix + '__'): udpList.append(fName) udpTypes[fName] = lField['type'] # Alimenta la coleccion de zooms, por cada campo pues hay q hacer un select para esto for lField in protoMeta['fields']: fName = lField['name'] myZoomModel = lField.get('zoomModel', '') if (len(myZoomModel) > 0) and (myZoomModel != protoMeta['viewEntity']): relModels[fName] = { 'zoomModel': myZoomModel, 'fkId': lField.get('fkId', ''), 'loaded': False } # Verifica si existen reemplazos por hacer ( cpFromField ) # 1. Marca los zooms q estan referenciados bCopyFromFld = False for lField in protoMeta['fields']: fName = lField['name'] if (lField.get('cpFromField') is None or lField.get('cpFromZoom') is None): continue bCopyFromFld = True # Marca el campo lField['isAbsorbed'] = True # Marca el zoom try: relModel = relModels[lField.get('cpFromZoom')] relModel['loaded'] = True except: pass # 2. borra los q no tienen marca for relName in relModels.keys(): relModel = relModels[relName] if not relModel['loaded']: del relModels[relName] # Esta forma permite agregar las funciones entre ellas el __unicode__ rowId = 0 for rowData in pRows: rowId += 1 rowdict = {} # limpia los datos de tablas relacionadas for relName in relModels: relModel = relModels[relName] relModel['rowData'] = {} relModel['loaded'] = False # recorre los campos para obtener su valor for lField in protoMeta['fields']: fName = lField['name'] pName = lField.get('physicalName', fName) if lField.get('crudType') == "screenOnly": continue # UDP Se evaluan despues if cUDP.udpTable and fName.startswith(cUDP.propertyPrefix + '__'): continue elif (lField['type'] == 'protoN2N'): continue # Si el campo es absorbido ( bCopyFromFld es un shortcut para evitar la evulacion en caso de q no haya ningun cpFromField ) elif bCopyFromFld and isAbsorbedField(lField, protoMeta): continue rowdict[fName] = getFieldValue(pName, lField['type'], rowData, JsonField) if cUDP.udpTable: # rowDict : se actualizara con los datos de la UDP # rowData es el registro de base, en caso de q sea un MD la lectura es automatica rowData.udpTable... # udpTypes : lista de Udps a leer readUdps(rowdict, rowData, cUDP, udpList, udpTypes) # REaliza la absorcion de datos provenientes de un zoom if bCopyFromFld: rowdict = copyValuesFromFields(protoMeta, rowdict, relModels, JsonField) # Dont delete ( Dgt ) # if pStyle == 'tree': # rowdict[ 'viewEntity' ] = protoMeta.get('viewEntity', '') # rowdict[ 'leaf' ] = False; rowdict[ 'children' ] = [] # Agrega el Id Siempre como idInterno ( no representa una col, idProperty ) rowdict['id'] = rowData.pk if fakeId: rowdict['id'] = rowId # Verifica el refAllow if len(userNodes) > 0 and not (str(rowData.smOwningTeam_id) in userNodes): rowdict['_ptStatus'] = REFONLY # Agrega la fila al diccionario rows.append(rowdict) return rows
def __init__(self, model, viewCode, model_admin, protoMeta): self.model = model # the model to use as reference self.title = self.model._meta.verbose_name.title() # importa las definiciones del modelo y del admin self.model_admin = model_admin self.protoMeta = protoMeta # garantiza la llave self.viewCode = viewCode # Inicializa self.fields = [] self.fieldsDict = {} self.gridConfig = self.protoMeta.get('gridConfig', {}) # Los campos deben ser inicialmente un diccionario para poder validarlos protoMeta['fields'] = protoMeta.get('fields', []) if isinstance(protoMeta['fields'], list): self.fieldsDict = list2dict(protoMeta['fields'], 'name') # UDPs para poder determinar el valor por defecto ROnly self.pUDP = self.protoMeta.get('usrDefProps', {}) verifyUdpDefinition(self.pUDP) # lista de campos para la presentacion en la grilla pListDisplay = verifyList(self.gridConfig.get('listDisplay', [])) if not pListDisplay: pListDisplay = verifyList( getattr(self.model_admin, 'list_display', [])) # Por defecto solo vienen Chk, _str_ try: pListDisplay.remove('action_checkbox') except ValueError: pass if len(pListDisplay) == 0: pListDisplay = ['__str__'] self.gridConfig['listDisplay'] = pListDisplay # Se leen los excluidos del admin, no se requiere # en la protoDef, pues los campos se enumeran explicitamente protoExclude = verifyList(self.protoMeta.get('exclude', [])) # Se leen los readonly fields para setear el attr readOnly = true pReadOnlyFlds = verifyList(self.gridConfig.get('readOnlyFields', [])) if not pReadOnlyFlds: pReadOnlyFlds = verifyList( getattr(self.model_admin, 'readonly_fields', [])) self.gridConfig['readOnlyFields'] = pReadOnlyFlds # @@ Por alguna Ext no retiene el IdProperty ( idInternal al hacer click en las filas ) # idName = model._meta.pk.name # La lista de campos del admin sirve de base, pues puede haber muchos mas campos en proto q en admin # Si solo queda el __str__ , asume todos los campos del modelo # iCount = len( pListDisplay ) # if ( iCount == 0 ) or ( iCount == 1 and (pListDisplay[0] == '__str__')) : # Se crean los campos con base al modelo ( trae todos los campos del modelo ) # for field in self.model._meta._fields(): #only for django 1.4 for field in self.model._meta.fields: if field.name in protoExclude: continue setFieldDict(self.fieldsDict, field) # Agrega el __str__ que sirve de base para los zooms fName = '__str__' fdict = self.fieldsDict.get(fName, {}) if not fdict: fdict['name'] = fName self.fieldsDict[fName] = fdict setDefaultField(fdict, self.model, self.viewCode) # Genera la lista de campos y agrega el nombre al diccionario for key in self.fieldsDict: fdict = self.fieldsDict[key] if (fdict.get('name', '') == ''): fdict['name'] = key if key in pReadOnlyFlds: fdict['readOnly'] = True # Repasa las propiedades de base, ver por q no esta pasando trayendo las props de base ( ie: defaulValue ) if (not (key.startswith('udp__'))): try: field = self.model._meta.get_field(key) setFieldDict(self.fieldsDict, field) fdict = self.fieldsDict[key] except: # Es posible q se puedan configuar propiedades no pertenecientes a la tabla como editables??? fdict['readOnly'] = True self.fields.append(fdict)
def _protoEdit(request, myAction): if not request.user.is_authenticated(): return doReturn({'success': False, 'message': 'readOnly User'}) if request.method != 'POST': return doReturn({'success': False, 'message': 'invalid message'}) message = '' # Carga el modelo protoMeta = request.POST.get('protoMeta', '') protoMeta = json.loads(protoMeta) viewEntity = protoMeta.get('viewEntity', '') model = getDjangoModel(viewEntity) # Autentica if not getModelPermissions(request.user, model, myAction): return doReturn({ 'success': False, 'message': 'No ' + myAction + 'permission' }) # Obtiene el profile para saber el teamhierarchi userProfile = getUserProfile(request.user, 'edit', viewEntity) # Verfica si es un protoModel ( maneja TeamHierarchy ) isProtoModel = hasattr(model, '_protoObj') # Verifica si hay registros que son solo de referencia userNodes = [] refAllow = False if myAction in ['DEL', 'UPD' ] and isProtoModel and not request.user.is_superuser: refAllow = getModelPermissions(request.user, model, 'refallow') if refAllow: userNodes = getUserNodes(request.user, viewEntity) # WorkFlow hasWFlow = hasattr(model, '_WorkFlow') and isProtoModel if hasWFlow: wfadmin = getModelPermissions(request.user, model, 'wfadmin') WFlowControl = getattr(model, '_WorkFlow', {}) initialWfStatus = WFlowControl.get('initialStatus', '0') # Decodifica los eltos rows = request.POST.get('rows', []) rows = json.loads(rows) # LogInfo logEvent(viewEntity, rows, request.user, userProfile.userTeam, '', myAction) # Fields fieldsDict = list2dict(protoMeta['fields'], 'name') # JsonField jsonField = protoMeta.get('jsonField', '') if not isinstance(jsonField, (str, unicode)): jsonField = '' # TOOD: Log # activityLog ( myAction, request.user , viewEntity, { 'protoMeta' : protoMeta , 'rows' : rows }) # Genera la clase UDP pUDP = protoMeta.get('usrDefProps', {}) cUDP = verifyUdpDefinition(pUDP) # Verifica q sea una lista de registros, (no deberia pasar, ya desde Extjs se controla ) if type(rows).__name__ == 'dict': rows = [rows] pList = [] for data in rows: data['_ptStatus'] = '' if myAction == 'INS': rec = model() else: try: rec = model.objects.get(pk=data['id']) except: data['_ptStatus'] = data['_ptStatus'] + ERR_NOEXIST + '<br>' pList.append(data) continue # refAllow verifica si corresponde a los registros modificables ( solo es true en myAction in ['DEL', 'UPD'] ) if refAllow and isProtoModel: if not (str(rec.smOwningTeam_id) in userNodes): data['_ptStatus'] = ERR_REFONLY + '<br>' pList.append(data) continue if not (myAction == 'DEL'): # Upd, Ins for key in data: key = smart_str(key) if key in ['id', '_ptStatus', '_ptId', '__str__']: continue vFld = fieldsDict[key] if vFld.get('crudType') in ["screenOnly", "linked"]: continue # Los campos de seguridad se manejan a nivel registro if isProtoModel: if key in [ 'smOwningUser', 'smOwningTeam', 'smOwningUser_id', 'smOwningTeam_id', 'smCreatedBy', 'smModifiedBy', 'smCreatedBy_id', 'smModifiedBy_id', 'smCreatedOn', 'smModifiedOn', 'smWflowStatus', 'smRegStatus', 'smUUID' ]: continue # Udps if (cUDP.udpTable and key.startswith(cUDP.propertyPrefix + '__')): continue # JsonField if key == jsonField: continue if key.startswith(jsonField + '__'): continue try: setRegister(model, rec, key, data) except Exception as e: data['_ptStatus'] = data['_ptStatus'] + getReadableError(e) if isProtoModel: setSecurityInfo(rec, data, userProfile, (myAction == 'INS')) if len(jsonField) > 0: jsonInfo = {} for key in data: if not key.startswith(jsonField + '__'): continue jKey = key[len(jsonField) + 2:] jsonInfo[jKey] = data[key] setattr(rec, jsonField, jsonInfo) # Inicializa el estado del WF if hasWFlow: setattr(rec, 'smWflowStatus', initialWfStatus) # Guarda el idInterno para concatenar registros nuevos en la grilla try: _ptId = data['_ptId'] except: _ptId = '' try: rec.save() # Guardar las Udps if cUDP.udpTable: try: saveUDP(rec, data, cUDP) except Exception as e: raise Exception('UdpError: saveActiob') # -- Los tipos complejos ie. date, generan un error, es necesario hacerlo detalladamente # Convierte el registro en una lista y luego toma solo el primer elto de la lista resultado. data = Q2Dict(protoMeta, [rec], False)[0] data['_ptId'] = _ptId except Exception as e: data['_ptStatus'] = data['_ptStatus'] + getReadableError(e) data['_ptId'] = _ptId # traceback.print_exc() # return doReturn ({'success':False ,'message' : str( e )}) else: # Action Delete try: rec.delete() except Exception, e: data['_ptStatus'] = data['_ptStatus'] + getReadableError(e) pList.append(data) if data.get('_ptStatus', ''): message += data['_ptStatus'] + ';'