def GET( self, entityType, localID, remoteID, testdata = None ): """ retrieve an object GET-request at /[entityType]/[localID][/[remoteID]] examples: /Node/-1/23 Node with remoteID=23 /Project/34/23 Project with remoteID=23 and local_id=34 retrieve multiple objects GET-request at /[entityType]?attribute=value examples: /Node?project=(Project,-1,23) parameters: __orderby=[attributename] order by attribute __limit=1 limit results __details=1 deliver detailed entity dicts instead of ids only """ if testdata == None: self._nocache() if localID or remoteID: entity = self._getEntity( entityType, localID, remoteID ) if entity: return json.dumps( entity.getDict(), indent = 4 ) else: return web.notfound() else: if testdata: userData = testdata else: userData = web.input() filters = [] filterValues = [] for attribute in userData.keys(): if attribute.startswith("__"): continue filters.append( "%s=%s" % ( attribute, "%s" ) ) filterValues.append( userData[attribute] ) orderby = None if userData.has_key("__orderby"): orderby = userData["__orderby"] limit = None if userData.has_key("__limit"): limit = userData["__limit"] entities = factories.getObjects( entityType, " AND ".join( filters ), filterValues, orderby = orderby, limit = limit ) json_entities = [] for entity in entities: if userData.has_key("__details"): json_entities.append( entity.getDict() ) else: json_entities.append( entity.getShortDict() ) return json.dumps( json_entities, indent = 4 )
def changeEntity( myObj, changes ): """change entity in local database and add corresponding change-events for shotgun-sync""" # myObj.reload() src = connectors.DatabaseModificator() src.changeInDB( myObj, changes = changes ) for ( key, value ) in changes.iteritems(): if type( value ) == datetime.datetime: changes[key] = value.strftime( "%Y-%m-%d %H:%M:%S" ) if type( value ) == datetime.date: changes[key] = value.strftime( "%Y-%m-%d" ) elif type( value ) == datetime.timedelta: changes[key] = float( value.days ) * 24 + float( value.seconds ) / 3600 elif type( value ) == connectors.PostgresEntityType: changes[key] = value.getShortDict() elif isinstance( value, base_entity.ShotgunBaseEntity ): changes[key] = value.getShortDict() elif type( value ) == type( [] ): changes[key] = [] for entry in value: if isinstance( entry, base_entity.ShotgunBaseEntity ) or type( entry ) == connectors.PostgresEntityType: changes[key].append( entry.getShortDict() ) else: changes[key].append( entry ) attributeName = key fieldValues = value entityType = myObj.getType() connEntityName = entityNaming.getConnectionEntityName( entityType, attributeName ) if connEntityName != None: reverseAttribute = entityNaming.getReverseAttributeName( entityType, attributeName ) linkedEntityType = myObj.shotgun_fields[attributeName]["properties"]["valid_types"]["value"][0] baseEntityType = entityType ( baseAttrName, linkedAttrName ) = entityNaming.getConnectionEntityAttrName( baseEntityType, linkedEntityType, connEntityName ) basePgObj = myObj.getPgObj() # get connections filters = "%s=%s" % ( baseAttrName, "%s" ) filterValues = [ basePgObj ] connections = factories.getObjects( connEntityName, filters, filterValues ) # create new connection entities for linkedDict in changes[key]: linkedPostgresObj = getPgObj( linkedDict ) fieldNames = [ baseAttrName, linkedAttrName ] fieldValues = [ basePgObj, linkedPostgresObj ] # check if existing first connectionExists = False for i in range( len( connections ) ): connection = connections[i] if connection.getRawField( linkedAttrName ) == linkedPostgresObj: connections.remove( connection ) connectionExists = True break if not connectionExists: debug.debug( dict( zip( fieldNames, fieldValues ) ), prefix = "OOOOOOOOO" ) src._addToDatabase( connEntityName, fieldValues, fieldNames ) # setting reverse attribute as well linkedObj = factories.getObject( linkedDict["type"], local_id = linkedDict["__local_id"], remote_id = linkedDict["id"] ) retValues = linkedObj.getRawField( reverseAttribute ) if retValues == None: retValues = [] if basePgObj not in retValues: retValues.append( basePgObj ) src.changeInDB( linkedObj, reverseAttribute, retValues ) # delete unused connection entities for connection in connections: linkedObj = connection.getField( linkedAttrName ) retValues = linkedObj.getRawField( reverseAttribute ) retValues.remove( basePgObj ) src.changeInDB( linkedObj, reverseAttribute, retValues ) src.delete( connection ) _createChangeEvent( src, "change", corr_entity = myObj.getPgObj(), changed_values = json.dumps( changes ) ) return myObj
def testAddOutput(self): lastevent = self.sg.find( "EventLogEntry", filters=[], fields=['id', 'event_type', 'attribute_name', 'meta', 'entity'], order=[{ 'column': 'id', 'direction': 'desc' }], filter_operator='all', limit=1)[0] self.lastID = lastevent["id"] data = { "project": { "type": "Project", "id": testProjectID }, "code": "newoutput", "sg_link": { "type": "Task", "id": testTaskID }, } newOutputDict = self.sg.create(InOut().getType(), data, []) self.deleteEntities.append(newOutputDict) newevents = self._getNewEvents() self.assertEqual(newevents[0]["event_type"], "Shotgun_CustomEntity02_New", "event not as expected") self.assertEqual(newevents[1]["event_type"], "Shotgun_CustomEntity02_Change", "event not as expected") self.assertEqual(newevents[2]["event_type"], "Shotgun_CustomEntity02_Change", "event not as expected") self.assertEqual(newevents[3]["event_type"], "Shotgun_CustomEntity02_Change", "event not as expected") self._processEvents(newevents) newOutput = factories.getObject("CustomEntity02", remote_id=newOutputDict["id"]) changedData = { 'sg_sink_tasks': [ { "type": "Task", "id": testTaskID }, { "type": "Task", "id": testTaskID_2 }, ] } self.sg.update(newOutputDict["type"], newOutputDict["id"], changedData) newevents = self._getNewEvents() self.assertEqual(len(newevents), 5) self.assertEqual( newevents[0]["event_type"], "Shotgun_CustomEntity02_sg_sink_tasks_Connection_New") self.assertEqual( newevents[1]["event_type"], "Shotgun_CustomEntity02_sg_sink_tasks_Connection_New") self.assertEqual(newevents[2]["event_type"], "Shotgun_CustomEntity02_Change") self.assertEqual(newevents[3]["event_type"], "Shotgun_Task_Change") self.assertEqual(newevents[4]["event_type"], "Shotgun_Task_Change") self._processEvents(newevents) # check if Connection-Entities are available filters = "custom_entity02=%s and task=ANY(%s)" taskSgObj1 = PostgresEntityType("Task", remote_id=testTaskID) taskSgObj2 = PostgresEntityType("Task", remote_id=testTaskID_2) outputSgObj = PostgresEntityType(newOutputDict["type"], remote_id=newOutputDict["id"]) filterValues = [outputSgObj, [taskSgObj1, taskSgObj2]] connObjs = factories.getObjects( "CustomEntity02_sg_sink_tasks_Connection", filters, filterValues) self.assertEqual( len(connObjs), 2, "no conn-objs: %s" % pprint.pformat(connObjs, indent=2)) # check if return attribute of Task contains this CustomEntity02 retAttr = entityNaming.getReverseAttributeName("CustomEntity02", "sg_sink_tasks") for taskID in [testTaskID, testTaskID_2]: taskTmpObj = factories.getObject("Task", remote_id=taskID) retOutputs = taskTmpObj.__getattribute__(retAttr) self.assertTrue(newOutput in retOutputs) changedData["sg_sink_tasks"] = [] self.sg.update(newOutputDict["type"], newOutputDict["id"], changedData) newevents = self._getNewEvents() # unfortunately there are two events missing: # see: https://support.shotgunsoftware.com/requests/7380 self.assertEqual(len(newevents), 3) self.assertEqual(newevents[0]["event_type"], "Shotgun_CustomEntity02_Change") self.assertEqual(newevents[1]["event_type"], "Shotgun_Task_Change") self.assertEqual(newevents[2]["event_type"], "Shotgun_Task_Change") self._processEvents(newevents) retAttr = entityNaming.getReverseAttributeName("CustomEntity02", "sg_sink_tasks") for taskID in [testTaskID, testTaskID_2]: taskTmpObj = factories.getObject("Task", remote_id=taskID) retOutputs = taskTmpObj.__getattribute__(retAttr) if retOutputs: self.assertFalse(newOutput in retOutputs) # check if Connection-Entities are deleted connObjs = factories.getObjects( "CustomEntity02_sg_sink_tasks_Connection", filters, filterValues) self.assertEqual( len(connObjs), 0, "conn-objs still available: %s" % pprint.pformat(connObjs, indent=2))
def testAddOutput( self ): lastevent = self.sg.find( "EventLogEntry", filters = [], fields = ['id', 'event_type', 'attribute_name', 'meta', 'entity'], order = [{'column':'id', 'direction':'desc'}], filter_operator = 'all', limit = 1 )[0] self.lastID = lastevent["id"] data = { "project": {"type": "Project", "id": testProjectID }, "code": "newoutput", "sg_link": {"type": "Task", "id": testTaskID }, } newOutputDict = self.sg.create( InOut().getType(), data, [] ) self.deleteEntities.append( newOutputDict ) newevents = self._getNewEvents() self.assertEqual( newevents[0]["event_type"], "Shotgun_CustomEntity02_New", "event not as expected" ) self.assertEqual( newevents[1]["event_type"], "Shotgun_CustomEntity02_Change", "event not as expected" ) self.assertEqual( newevents[2]["event_type"], "Shotgun_CustomEntity02_Change", "event not as expected" ) self.assertEqual( newevents[3]["event_type"], "Shotgun_CustomEntity02_Change", "event not as expected" ) self._processEvents( newevents ) newOutput = factories.getObject( "CustomEntity02", remote_id = newOutputDict["id"] ) changedData = { 'sg_sink_tasks': [ { "type": "Task", "id": testTaskID }, { "type": "Task", "id": testTaskID_2 }, ] } self.sg.update( newOutputDict["type"], newOutputDict["id"], changedData ) newevents = self._getNewEvents() self.assertEqual( len( newevents ), 5 ) self.assertEqual( newevents[0]["event_type"], "Shotgun_CustomEntity02_sg_sink_tasks_Connection_New" ) self.assertEqual( newevents[1]["event_type"], "Shotgun_CustomEntity02_sg_sink_tasks_Connection_New" ) self.assertEqual( newevents[2]["event_type"], "Shotgun_CustomEntity02_Change" ) self.assertEqual( newevents[3]["event_type"], "Shotgun_Task_Change" ) self.assertEqual( newevents[4]["event_type"], "Shotgun_Task_Change" ) self._processEvents( newevents ) # check if Connection-Entities are available filters = "custom_entity02=%s and task=ANY(%s)" taskSgObj1 = PostgresEntityType( "Task", remote_id = testTaskID ) taskSgObj2 = PostgresEntityType( "Task", remote_id = testTaskID_2 ) outputSgObj = PostgresEntityType( newOutputDict["type"], remote_id = newOutputDict["id"] ) filterValues = [ outputSgObj, [ taskSgObj1, taskSgObj2 ] ] connObjs = factories.getObjects( "CustomEntity02_sg_sink_tasks_Connection", filters, filterValues ) self.assertEqual( len( connObjs ), 2, "no conn-objs: %s" % pprint.pformat( connObjs, indent = 2 ) ) # check if return attribute of Task contains this CustomEntity02 retAttr = entityNaming.getReverseAttributeName( "CustomEntity02", "sg_sink_tasks" ) for taskID in [ testTaskID, testTaskID_2 ]: taskTmpObj = factories.getObject( "Task", remote_id = taskID ) retOutputs = taskTmpObj.__getattribute__( retAttr ) self.assertTrue( newOutput in retOutputs ) changedData["sg_sink_tasks"] = [] self.sg.update( newOutputDict["type"], newOutputDict["id"], changedData ) newevents = self._getNewEvents() # unfortunately there are two events missing: # see: https://support.shotgunsoftware.com/requests/7380 self.assertEqual( len( newevents ), 3 ) self.assertEqual( newevents[0]["event_type"], "Shotgun_CustomEntity02_Change" ) self.assertEqual( newevents[1]["event_type"], "Shotgun_Task_Change" ) self.assertEqual( newevents[2]["event_type"], "Shotgun_Task_Change" ) self._processEvents( newevents ) retAttr = entityNaming.getReverseAttributeName( "CustomEntity02", "sg_sink_tasks" ) for taskID in [ testTaskID, testTaskID_2 ]: taskTmpObj = factories.getObject( "Task", remote_id = taskID ) retOutputs = taskTmpObj.__getattribute__( retAttr ) if retOutputs: self.assertFalse( newOutput in retOutputs ) # check if Connection-Entities are deleted connObjs = factories.getObjects( "CustomEntity02_sg_sink_tasks_Connection", filters, filterValues ) self.assertEqual( len( connObjs ), 0, "conn-objs still available: %s" % pprint.pformat( connObjs, indent = 2 ) )