def towers_tower_id_processes_process_id_link_post(tower_id, process_id, link, api_key): """ towers_tower_id_processes_process_id_link_post :param tower_id: Tower Id number to look under. :type tower_id: int :param process_id: Process Id number to look under. :type process_id: int :param link: :type link: dict | bytes :param api_key: Operation Access Key :type api_key: str :rtype: None """ if connexion.request.is_json: link = Link.from_dict(connexion.request.get_json()) qEquipment = application_map.Equipment qEquipmentInfo = info_map.Equipment qTower = application_map.Tower qProcess = application_map.Process session = application_map.Session() # find the tower q_tower = session.query(qTower).filter(qTower.id == tower_id).one_or_none() if q_tower is None or q_tower.op_id != api_key.operation_id: error = Error('Tower `{}` not Found'.format(tower_id)) return error, 404 q_process = q_tower.processes.filter( qProcess.id == process_id).one_or_none() if q_process is None or q_process.id != process_id: error = Error('Process `{}` not Found'.format(process_id)) return error, 404 # testing to see if the equipment are even valid try: q_source = session.query(qEquipment).filter( and_(qEquipment.id == link.source, qEquipment.process_id == process_id)).one() q_target = session.query(qEquipment).filter( and_(qEquipment.id == link.target, qEquipment.process_id == process_id)).one() make_link(link.source, link.target, link.material) except NoResultFound: error = Error('Equipment to link not found.') return error, 400 except InvalidLinkMaterial as e: return Error(message=str(e)), 400
def is_valid_permission(perm): '''Check if `perm` permission is in the list of valid permissions database. False if invalid, True if valid. ''' session = application_map.Session() qPermission = application_map.Permission try: q_perm = session.query(qPermission).filter( qPermission.name == perm).one() return True except NoResultFound: return False
def towers_get(api_key): """ towers_get Gets summary information for every tower the request is authenticated to see. This includes `tower_id` number, `type_id`, fuel status, as well as what the tower is producing at the endpoints of its reaction/mining chains. :param api_key: Operation Access Key :type api_key: str :rtype: List[int] """ qOperation = application_map.Operation session = application_map.Session() q_operation = session.query(qOperation).filter( qOperation.id == api_key.operation_id).one() return [t.id for t in q_operation.towers], 200
def lookup(cls, key_value): qKey = application_map.Key session = application_map.Session() q = session.query(qKey).filter(qKey.value == key_value) q_key = q.one_or_none() if q_key is not None: key= cls( value=q_key.value, operation_id=q_key.operation_id, permissions=[q_key.permission], name=q_key.name ) return key else: raise KeyNotFound("Key {} was not found.".format(key_value))
def towers_tower_id_processes_process_id_get(tower_id, process_id, api_key): """ towers_tower_id_processes_process_id_get :param tower_id: Tower Id number to look under. :type tower_id: int :param process_id: Process Id number to look under. :type process_id: int :param api_key: Operation Access Key :type api_key: str :rtype: Process """ qProcess = application_map.Process qTower = application_map.Tower qEquipment = application_map.Equipment session = application_map.Session() # find the tower q_tower = session.query(qTower).filter(qTower.id == tower_id).one_or_none() if q_tower is None or q_tower.op_id != api_key.operation_id: error = Error('Tower `{}` not Found'.format(tower_id)) return error, 404 try: q_process = q_tower.processes.filter(qProcess.id == process_id).one() equipment = [e.id for e in q_process.equipment] process_tree = ProcessTree.fromId(q_process.id) endpoints = process_tree.production_endpoints() final_outputs = [ e.resource for e in q_process.equipment.filter(qEquipment.id.in_(endpoints)) ] # final_outputs = [e.id for e in endpoints] process = Process( id=q_process.id, equipment=equipment, final_outputs=final_outputs) # not fully implemnted yet return process, 200 except NoResultFound: error = Error('Process `{}` not Found'.format(process_id)) return error, 404
def towers_tower_id_processes_process_id_equipment_equipment_id_delete( tower_id, process_id, equipment_id, api_key): """ towers_tower_id_processes_process_id_equipment_equipment_id_delete :param tower_id: Tower Id number to look under. :type tower_id: int :param process_id: Process Id number to look under. :type process_id: int :param equipment_id: Id of equipment that needs fetched. :type equipment_id: int :param api_key: Operation Access Key :type api_key: str :rtype: None """ qEquipment = application_map.Equipment qEquipmentInfo = info_map.Equipment qTower = application_map.Tower qProcess = application_map.Process session = application_map.Session() # find the tower q_tower = session.query(qTower).filter(qTower.id == tower_id).one_or_none() if q_tower is None or q_tower.op_id != api_key.operation_id: error = Error('Tower `{}` not Found'.format(tower_id)) return error, 404 # find process q_process = q_tower.processes.filter( qProcess.id == process_id).one_or_none() if q_process is None or q_process.id != process_id: error = Error('Process `{}` not Found'.format(process_id)) return error, 404 q_equipment = q_process.equipment.filter( qEquipment.id == equipment_id).one_or_none() if q_equipment is None or q_equipment.id != equipment_id: error = Error('Equipment `{}` not Found'.format(equipment_id)) return error, 404 session.delete(q_equipment) session.commit() return None, 200
def operation_keys_get(api_key): """ operation_keys_get Returns `array` of operation access sub-keys that exist for this operation. :param api_key: Operation Master Access Key :type api_key: str :rtype: List[Key] """ qOperation = application_map.Operation qKey = application_map.Key session = application_map.Session() q_operation = session.query(qOperation).filter( qOperation.id == api_key.operation_id).one() keys = [Key(k.name, k.value, k.permission) for k in q_operation.keys] return keys, 200
def operation_delete(api_key): """ operation_delete Deletes the operation accessed by the given master key. Note that this invalidates the key and deletes _all_ information under the operation including api keys, towers, and thier configurations. :param api_key: Operation Master Access Key :type api_key: str :rtype: None """ session = application_map.Session() qOperation = application_map.Operation q_operation = session.query(qOperation).filter( qOperation.id == api_key.operation_id).one() session.delete(q_operation) session.commit() return None, 200
def operation_keys_sub_key_patch(sub_key, api_key, key_update): """ operation_keys_sub_key_patch Update key_update for the given access sub-key. :param sub_key: Operation Access Sub-key :type sub_key: str :param api_key: Operation Master Access Key :type api_key: str :param key_update: :type key_update: NewKey :rtype: NewKey """ if connexion.request.is_json: key_update = Key.from_dict(connexion.request.get_json()) qKey = application_map.Key session = application_map.Session() if not is_valid_permission(key_update.permission): error = Error('Bad Request: Permission {} is not valid.'.format( key_update.permission)) return error, 400 elif key_update.permission == 'master': error = Error('Cannot set a sub key with permission `master`.') return error, 400 q_key = session.query(qKey).filter(qKey.value == sub_key).filter( qKey.operation_id == api_key.operation_id).one_or_none() key_update.value = q_key.value if q_key is None: error = Error('Key `{}` not Found'.format(sub_key)) return error, 404 elif q_key.permission == 'master': error = Error('Cannot alter Master Key') return error, 400 else: q_key.name = q_key.name if key_update.name is None else key_update.name q_key.permission = q_key.permission if key_update.permission is None else key_update.permission session.commit() return key_update, 200
def operation_post(operation_name=None): """ operation_post Creates a new operation and returns operation details (including the `master key`). Optional parameters include the private name and public name of the operation. These can be changed later. :param operation_name: Operation Name and Public Name :type operation_name: dict | bytes :rtype: Operation """ if connexion.request.is_json: operation_name = OperationName.from_dict(connexion.request.get_json()) name = operation_name.name or "default operation" public_name = operation_name.public_name or "default operation - public" key_value = uuid.uuid4().hex qKey = application_map.Key qOperation = application_map.Operation session = application_map.Session() q_operation = qOperation(name=name, public_name=public_name) q_operation.master_key = qKey(value=key_value, permission='master', name='Master Key') operation = Operation(master_key=key_value, name=name, public_name=public_name, tower_count=0, sub_key_count=1) session.add(q_operation) session.commit() # let sqlite decide what the operation id should be, then make sure they match q_operation.master_key.operation_id = q_operation.id session.commit() return operation, 200
def towers_post(tower_details, api_key): """ towers_post Add new tower. :param tower_details: New tower information in json format. :type tower_details: dict | bytes :param api_key: Operation Access Key :type api_key: str :rtype: TowerDetails """ if connexion.request.is_json: tower_details = TowerDetails.from_dict(connexion.request.get_json()) if tower_details.fuel_last_update is None: tower_details.fuel_last_update = int(time.time()) qTower = application_map.Tower session = application_map.Session() newTower = qTower(op_id=api_key.operation_id, type=tower_details.type, name=tower_details.name, system=tower_details.system, planet=tower_details.planet, moon=tower_details.moon, cycles_at=tower_details.cycles_at, stront_count=tower_details.stront_count, fuel_count=tower_details.fuel_count, fuel_last_update=tower_details.fuel_last_update, online=tower_details.online, sov=tower_details.sov) session.add(newTower) session.commit() newTower.id += random.randint( 0, 999) # add some uncertainty so that id is not directly tower count tower_details.id = newTower.id session.commit() return tower_details, 200
def make_link(source_id, target_id, material_id): '''make_link(source_id, target_id, material_id) creates a link entry with the given parameters. if either the source or target equipment does not produce/consume the material_id, returns a InvalidLinkMaterial exception. If a material link slot is already occupied on either end of the equipment, the old link is replaced with the new one. This happens silently. ''' qLink = application_map.Link qEquipment = application_map.Equipment session = application_map.Session() source_linkable = available_links(source_id) target_linkable = available_links(target_id, outputs=False) if material_id in source_linkable and material_id in target_linkable: # see if this material has been linked to/from either source or target equipment q_link = session.query(qLink).filter( and_(qLink.resource == material_id, or_(qLink.source == source_id, qLink.target == target_id))).one_or_none() if q_link is None: # link does not exist, make a new one q_link = qLink(source=source_id, target=target_id, resource=material_id) session.add(q_link) else: # the material was linked already, just modify the old link q_link.source = source_id q_link.target = target_id session.commit() else: raise InvalidLinkMaterial( 'Not a valid Link Material (must be both an output at source and input at target).' )
def towers_tower_id_delete(tower_id, api_key): """ towers_tower_id_delete Delete a specific tower and all its equipment/processes. :param tower_id: Id number of the tower to be deleted. :type tower_id: int :param api_key: Operation Access Key :type api_key: str :rtype: None """ qTower = application_map.Tower session = application_map.Session() q_tower = session.query(qTower).filter(qTower.id == tower_id).one_or_none() if q_tower is None or q_tower.op_id != api_key.operation_id: error = Error('Tower `{}` not Found'.format(tower_id)) return error, 404 else: session.delete(q_tower) session.commit() return None, 200
def operation_keys_sub_key_get(sub_key, api_key): """ operation_keys_sub_key_get Gets the permission settings of the given access key. :param sub_key: Operation Access Sub-key :type sub_key: str :param api_key: Operation Master Access Key :type api_key: str :rtype: Key """ qKey = application_map.Key session = application_map.Session() q_key = session.query(qKey).filter(qKey.value == sub_key).filter( qKey.operation_id == api_key.operation_id).one_or_none() if q_key is None: error = Error('Key `{}` not Found'.format(sub_key)) return error, 404 else: key = Key(name=q_key.name, value=q_key.value, permission=q_key.permission) return key, 200
def towers_tower_id_get(tower_id, api_key): """ towers_tower_id_get Gets details for a specific tower with `type_id`. :param tower_id: Type of the item that needs fetched. :type tower_id: int :param api_key: Operation Access Key :type api_key: str :rtype: TowerDetails """ qTower = application_map.Tower session = application_map.Session() # find the tower q_tower = session.query(qTower).filter(qTower.id == tower_id).one_or_none() if q_tower is None or q_tower.op_id != api_key.operation_id: error = Error('Tower `{}` not Found'.format(tower_id)) return error, 404 else: tower_details = TowerDetails( id=q_tower.id, type=q_tower.type, system=q_tower.system, planet=q_tower.planet, moon=q_tower.moon, name=q_tower.name, cycles_at=q_tower.cycles_at, stront_count=q_tower.stront_count, fuel_count=q_tower.fuel_count, fuel_last_update=q_tower.fuel_last_update, online=q_tower.online, sov=q_tower.sov, processes=[p.id for p in q_tower.processes]) return tower_details, 200
def operation_get(api_key): """ operation_get Gets general information about the operation accessed by the given master key. :param api_key: Operation Master Access Key :type api_key: str :rtype: Operation """ session = application_map.Session() qOperation = application_map.Operation qKey = application_map.Key q_operation = session.query(qOperation).filter( qOperation.id == api_key.operation_id).one() master_key = q_operation.master_key operation = Operation(master_key=master_key.value, name=q_operation.name, public_name=q_operation.public_name, tower_count=len(q_operation.towers), sub_key_count=len(q_operation.keys)) return operation, 200
def available_links(equipment_id, outputs=True): qEquipment = application_map.Equipment qEquipmentInfo = info_map.Equipment qMaterial = info_map.Material qReaction = info_map.Reaction session = application_map.Session() info_session = info_map.Session() q_equipment = session.query(qEquipment).filter( qEquipment.id == equipment_id).one() # special handle for mining arrays (unlike silos they have no inputs) mining_equipment_type = info_session.query(qEquipmentInfo).filter( qEquipmentInfo.name == 'Moon Harvesting Array') if q_equipment.type == mining_equipment_type: if outputs: return [q_equipment.resource] else: return [] resource = q_equipment.resource if resource is None: return [] else: q_reaction = info_session.query(qReaction).filter( qReaction.type == resource).one_or_none() if q_reaction is None: q_material = info_session.query(qMaterial).filter( qMaterial.type == resource).one() return [resource] else: if outputs: return [m.material_id for m in q_reaction.outputs] else: return [m.material_id for m in q_reaction.inputs]
def towers_tower_id_processes_process_id_equipment_equipment_id_patch( tower_id, process_id, equipment_id, equipment, api_key): """ towers_tower_id_processes_process_id_equipment_equipment_id_patch :param tower_id: Tower Id number to look under. :type tower_id: int :param process_id: Process Id number to look under. :type process_id: int :param equipment_id: Id of equipment that needs fetched. :type equipment_id: int :param equipment: :type equipment: dict | bytes :param api_key: Operation Access Key :type api_key: str :rtype: Equipment """ if connexion.request.is_json: equipment = EquipmentUpdate.from_dict(connexion.request.get_json()) qEquipment = application_map.Equipment qEquipmentInfo = info_map.Equipment qTower = application_map.Tower qProcess = application_map.Process session = application_map.Session() # find the tower q_tower = session.query(qTower).filter(qTower.id == tower_id).one_or_none() if q_tower is None or q_tower.op_id != api_key.operation_id: error = Error('Tower `{}` not Found'.format(tower_id)) return error, 404 # find process q_process = q_tower.processes.filter( qProcess.id == process_id).one_or_none() if q_process is None or q_process.id != process_id: error = Error('Process `{}` not Found'.format(process_id)) return error, 404 q_equipment = q_process.equipment.filter( qEquipment.id == equipment_id).one_or_none() if q_equipment is None or q_equipment.id != equipment_id: error = Error('Equipment `{}` not Found'.format(equipment_id)) return error, 404 q_equipment.name = equipment.name or q_equipment.name if equipment.resource != q_equipment.resource: if resource_allowed(q_equipment.type, equipment.resource): for q_link in q_equipment.links: session.delete(q_link) q_equipment.resource = equipment.resource else: return Error('Invalid resource for this equipment.'), 400 q_equipment.contains = equipment.contains or q_equipment.resource q_equipment.last_updated = equipment.last_updated or q_equipment.last_updated q_equipment.online = equipment.online or q_equipment.online session.commit() equipment = Equipment(id=q_equipment.id, type=q_equipment.type, name=q_equipment.name, resource=q_equipment.resource, contains=q_equipment.contains, last_updated=q_equipment.last_updated, online=q_equipment.online, inputs=[ Link(source=l.source, material=l.resource) for l in q_equipment.inputs ], outputs=[ Link(target=l.target, material=l.resource) for l in q_equipment.outputs ]) return equipment, 200
def towers_tower_id_processes_process_id_equipment_post( tower_id, process_id, equipment, api_key): """ towers_tower_id_processes_process_id_equipment_post :param tower_id: Tower Id number to look under. :type tower_id: int :param process_id: Process Id number to look under. :type process_id: int :param equipment: :type equipment: dict | bytes :param api_key: Operation Access Key :type api_key: str :rtype: Equipment """ if connexion.request.is_json: equipment = Equipment.from_dict(connexion.request.get_json()) try: # check if equipment type is valid and set the default name info_session = info_map.Session() qEquipmentInfo = info_map.Equipment default_name = info_session.query(qEquipmentInfo).filter( qEquipmentInfo.type == equipment.type).one().name except NoResultFound: error = Error('Equipment of type `{}` not valid.'.format( equipment.type)) return error, 400 qEquipment = application_map.Equipment qTower = application_map.Tower qProcess = application_map.Process session = application_map.Session() # find the tower q_tower = session.query(qTower).filter(qTower.id == tower_id).one_or_none() if q_tower is None or q_tower.op_id != api_key.operation_id: error = Error('Tower `{}` not Found'.format(tower_id)) return error, 404 q_process = q_tower.processes.filter( qProcess.id == process_id).one_or_none() if q_process is None or q_process.id != process_id: error = Error('Process `{}` not Found'.format(process_id)) return error, 404 # validate resource if equipment.resource is not None: try: if not resource_allowed(equipment.type, equipment.resource): error = Error( 'Resource `{}` not allowed in equipment of type `{}`.'. format(equipment.resource, equipment.type)) return error, 400 except EquipmentNotFound as e: error = Error(message=str(e)) return error, 400 except ResourceNotFound as e: error = Error(message=str(e)) return error, 400 # set defaults if values not included equipment.name = equipment.name or default_name equipment.contains = equipment.contains or 0 equipment.online = equipment.online or False equipment.last_updated = int(time.time()) equipment.inputs = [] equipment.outputs = [] q_equipment = qEquipment(last_updated=equipment.last_updated, resource=equipment.resource, contains=equipment.contains, type=equipment.type, name=equipment.name, online=equipment.online) q_process.equipment.append(q_equipment) session.commit() q_equipment.id += random.randint( 0, 49) # add some uncertainty so that id is not directly count equipment.id = q_equipment.id session.commit() return equipment, 200
def towers_tower_id_patch(tower_id, api_key, tower_update=None): """ towers_tower_id_patch :param tower_id: Id number of the tower to be deleted. :type tower_id: int :param api_key: Operation Access Key :type api_key: str :param tower_update: Details to update tower with. :type tower_update: dict | bytes :rtype: TowerDetails """ if connexion.request.is_json: tower_update = TowerDetails.from_dict(connexion.request.get_json()) qTower = application_map.Tower session = application_map.Session() q_tower = session.query(qTower).filter(qTower.id == tower_id).one_or_none() if q_tower is None or q_tower.op_id != api_key.operation_id: error = Error('Tower `{}` not Found'.format(tower_id)) return error, 404 else: if tower_update.type is not None: q_tower.type = tower_update.type if tower_update.system is not None: q_tower.system = tower_update.system if tower_update.planet is not None: q_tower.planet = tower_update.planet if tower_update.moon is not None: q_tower.moon = tower_update.moon if tower_update.cycles_at is not None: q_tower.cycles_at = tower_update.cycles_at if tower_update.fuel_count is not None: q_tower.fuel_count = tower_update.fuel_count if tower_update.fuel_last_update is not None: q_tower.fuel_last_update = tower_update.fuel_last_update if tower_update.online is not None: q_tower.online = tower_update.online if tower_update.sov is not None: q_tower.sov = tower_update.sov if tower_update.name is not None: q_tower.name = tower_update.name if tower_update.stront_count is not None: q_tower.stront_count = tower_update.stront_count tower_details = TowerDetails(id=q_tower.id, type=q_tower.type, system=q_tower.system, planet=q_tower.planet, moon=q_tower.moon, name=q_tower.name, cycles_at=q_tower.cycles_at, stront_count=q_tower.stront_count, fuel_count=q_tower.fuel_count, fuel_last_update=q_tower.fuel_last_update, online=q_tower.online, sov=q_tower.sov, processes=[]) session.commit() return tower_details, 200