mirror of
				https://github.com/Telecominfraproject/wlan-cloud-owprov.git
				synced 2025-10-31 02:27:52 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			542 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			542 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //
 | |
| //	License type: BSD 3-Clause License
 | |
| //	License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
 | |
| //
 | |
| //	Created by Stephane Bourque on 2021-03-04.
 | |
| //	Arilia Wireless Inc.
 | |
| //
 | |
| 
 | |
| #include "RESTAPI_venue_handler.h"
 | |
| 
 | |
| #include "RESTAPI/RESTAPI_db_helpers.h"
 | |
| #include "RESTObjects/RESTAPI_ProvObjects.h"
 | |
| #include "StorageService.h"
 | |
| #include "Tasks/VenueConfigUpdater.h"
 | |
| #include "Tasks/VenueRebooter.h"
 | |
| #include "Tasks/VenueUpgrade.h"
 | |
| #include "framework/CIDR.h"
 | |
| #include "framework/MicroServiceFuncs.h"
 | |
| 
 | |
| #include "Kafka_ProvUpdater.h"
 | |
| 
 | |
| namespace OpenWifi {
 | |
| 
 | |
| 	static Types::UUIDvec_t GetDevices(const ProvObjects::Venue &V, bool GetChildren) {
 | |
| 		Types::UUIDvec_t R;
 | |
| 		std::copy(V.devices.begin(), V.devices.end(), std::back_inserter(R));
 | |
| 		if (GetChildren) {
 | |
| 			for (const auto &i : V.children) {
 | |
| 				ProvObjects::Venue V2;
 | |
| 				if (StorageService()->VenueDB().GetRecord("id", i, V2)) {
 | |
| 					std::copy(V2.devices.begin(), V2.devices.end(), std::back_inserter(R));
 | |
| 					auto LowerDevs = GetDevices(V2, GetChildren);
 | |
| 					std::copy(LowerDevs.begin(), LowerDevs.end(), std::back_inserter(R));
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		std::sort(R.begin(), R.end());
 | |
| 		auto Last = std::unique(R.begin(), R.end());
 | |
| 		R.erase(Last, R.end());
 | |
| 
 | |
| 		std::vector<std::string> SerialNumbers;
 | |
| 
 | |
| 		for (const auto &device : R) {
 | |
| 			ProvObjects::InventoryTag IT;
 | |
| 			if (StorageService()->InventoryDB().GetRecord("id", device, IT)) {
 | |
| 				SerialNumbers.push_back(IT.serialNumber);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return SerialNumbers;
 | |
| 	}
 | |
| 
 | |
| 	void RESTAPI_venue_handler::DoGet() {
 | |
| 		std::string UUID = GetBinding("uuid", "");
 | |
| 		ProvObjects::Venue Existing;
 | |
| 		if (UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) {
 | |
| 			return NotFound();
 | |
| 		}
 | |
| 
 | |
| 		if (GetBoolParameter("getDevices")) {
 | |
| 			ProvObjects::VenueDeviceList VDL;
 | |
| 			VDL.id = Existing.info.id;
 | |
| 			VDL.name = Existing.info.name;
 | |
| 			VDL.description = Existing.info.description;
 | |
| 			auto GetChildren = GetBoolParameter("getChildren");
 | |
| 			VDL.devices = GetDevices(Existing, GetChildren);
 | |
| 			Poco::JSON::Object Answer;
 | |
| 			VDL.to_json(Answer);
 | |
| 			return ReturnObject(Answer);
 | |
| 		}
 | |
| 
 | |
| 		Poco::JSON::Object Answer;
 | |
| 		if (QB_.AdditionalInfo)
 | |
| 			AddExtendedInfo(Existing, Answer);
 | |
| 
 | |
| 		Existing.to_json(Answer);
 | |
| 		ReturnObject(Answer);
 | |
| 	}
 | |
| 
 | |
| 	void RESTAPI_venue_handler::DoDelete() {
 | |
| 		std::string UUID = GetBinding("uuid", "");
 | |
| 		ProvObjects::Venue Existing;
 | |
| 		if (UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) {
 | |
| 			return NotFound();
 | |
| 		}
 | |
| 
 | |
| 		if (!Existing.children.empty() || !Existing.devices.empty()) {
 | |
| 			return BadRequest(RESTAPI::Errors::StillInUse);
 | |
| 		}
 | |
| 
 | |
| 		if (!Existing.contacts.empty()) {
 | |
| 			for (const auto &contact_uuid : Existing.contacts)
 | |
| 				StorageService()->ContactDB().DeleteInUse(
 | |
| 					"id", contact_uuid, StorageService()->VenueDB().Prefix(), UUID);
 | |
| 		}
 | |
| 		if (!Existing.location.empty())
 | |
| 			StorageService()->LocationDB().DeleteInUse("id", Existing.location,
 | |
| 													   StorageService()->VenueDB().Prefix(), UUID);
 | |
| 		if (!Existing.managementPolicy.empty())
 | |
| 			StorageService()->PolicyDB().DeleteInUse("id", Existing.managementPolicy,
 | |
| 													 StorageService()->VenueDB().Prefix(), UUID);
 | |
| 		if (!Existing.deviceConfiguration.empty()) {
 | |
| 			for (auto &configuration_uuid : Existing.deviceConfiguration)
 | |
| 				StorageService()->ConfigurationDB().DeleteInUse(
 | |
| 					"id", configuration_uuid, StorageService()->VenueDB().Prefix(), UUID);
 | |
| 		}
 | |
| 		if (!Existing.parent.empty())
 | |
| 			StorageService()->VenueDB().DeleteChild("id", Existing.parent, UUID);
 | |
| 		if (!Existing.entity.empty())
 | |
| 			StorageService()->EntityDB().DeleteVenue("id", Existing.entity, UUID);
 | |
| 		DB_.DeleteRecord("id", UUID);
 | |
| 
 | |
| 		UpdateKafkaProvisioningObject(ProvisioningOperation::removal, Existing);
 | |
| 
 | |
| 		return OK();
 | |
| 	}
 | |
| 
 | |
| 	void RESTAPI_venue_handler::DoPost() {
 | |
| 		std::string UUID = GetBinding("uuid", "");
 | |
| 		if (UUID.empty()) {
 | |
| 			return BadRequest(RESTAPI::Errors::MissingUUID);
 | |
| 		}
 | |
| 
 | |
| 		const auto &RawObject = ParsedBody_;
 | |
| 		ProvObjects::Venue NewObject;
 | |
| 		if (!NewObject.from_json(RawObject)) {
 | |
| 			return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
 | |
| 		}
 | |
| 
 | |
| 		if ((RawObject->has("deviceRules") && !ValidDeviceRules(NewObject.deviceRules, *this))) {
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		if (!CreateObjectInfo(RawObject, UserInfo_.userinfo, NewObject.info)) {
 | |
| 			return BadRequest(RESTAPI::Errors::NameMustBeSet);
 | |
| 		}
 | |
| 
 | |
| 		if (NewObject.parent.empty() && NewObject.entity.empty()) {
 | |
| 			return BadRequest(RESTAPI::Errors::ParentOrEntityMustBeSet);
 | |
| 		}
 | |
| 
 | |
| 		if (!NewObject.parent.empty() && !NewObject.entity.empty()) {
 | |
| 			return BadRequest(RESTAPI::Errors::NotBoth);
 | |
| 		}
 | |
| 
 | |
| 		if (!NewObject.parent.empty() && !DB_.Exists("id", NewObject.parent)) {
 | |
| 			return BadRequest(RESTAPI::Errors::VenueMustExist);
 | |
| 		}
 | |
| 
 | |
| 		if (NewObject.entity == EntityDB::RootUUID()) {
 | |
| 			return BadRequest(RESTAPI::Errors::ValidNonRootUUID);
 | |
| 		}
 | |
| 
 | |
| 		if (!NewObject.entity.empty() &&
 | |
| 			!StorageService()->EntityDB().Exists("id", NewObject.entity)) {
 | |
| 			return BadRequest(RESTAPI::Errors::EntityMustExist);
 | |
| 		}
 | |
| 
 | |
|         if(StorageService()->VenueDB().DoesVenueNameAlreadyExist(NewObject.info.name,NewObject.entity, NewObject.parent)) {
 | |
|             return BadRequest(RESTAPI::Errors::VenuesNameAlreadyExists);
 | |
|         }
 | |
| 
 | |
| 		if (!NewObject.contacts.empty()) {
 | |
| 			for (const auto &i : NewObject.contacts) {
 | |
| 				if (!StorageService()->ContactDB().Exists("id", i)) {
 | |
| 					return BadRequest(RESTAPI::Errors::ContactMustExist);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (!NewObject.location.empty() &&
 | |
| 			!StorageService()->LocationDB().Exists("id", NewObject.location)) {
 | |
| 			return BadRequest(RESTAPI::Errors::LocationMustExist);
 | |
| 		}
 | |
| 
 | |
| 		if (!NewObject.managementPolicy.empty() &&
 | |
| 			!StorageService()->PolicyDB().Exists("id", NewObject.managementPolicy)) {
 | |
| 			return BadRequest(RESTAPI::Errors::UnknownManagementPolicyUUID);
 | |
| 		}
 | |
| 
 | |
| 		if (!NewObject.deviceConfiguration.empty()) {
 | |
| 			for (auto &i : NewObject.deviceConfiguration) {
 | |
| 				if (!StorageService()->ConfigurationDB().Exists("id", i)) {
 | |
| 					return BadRequest(RESTAPI::Errors::UnknownManagementPolicyUUID);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (!NewObject.sourceIP.empty() && !CIDR::ValidateIpRanges(NewObject.sourceIP)) {
 | |
| 			return BadRequest(RESTAPI::Errors::InvalidIPRanges);
 | |
| 		}
 | |
| 
 | |
| 		NewObject.children.clear();
 | |
| 
 | |
| 		RESTAPI::Errors::msg Error = RESTAPI::Errors::SUCCESS;
 | |
| 		std::vector<std::string> Errors;
 | |
| 		auto ObjectsCreated = CreateObjects(NewObject, *this, Errors);
 | |
| 		if (Error.err_num != 0) {
 | |
| 			return BadRequest(RESTAPI::Errors::InternalError);
 | |
| 		}
 | |
| 
 | |
| 		if (DB_.CreateRecord(NewObject)) {
 | |
| 			MoveUsage(StorageService()->ContactDB(), DB_, {}, NewObject.contacts,
 | |
| 					  NewObject.info.id);
 | |
| 			MoveUsage(StorageService()->LocationDB(), DB_, "", NewObject.location,
 | |
| 					  NewObject.info.id);
 | |
| 			MoveUsage(StorageService()->PolicyDB(), DB_, "", NewObject.managementPolicy,
 | |
| 					  NewObject.info.id);
 | |
| 			ManageMembership(StorageService()->EntityDB(), &ProvObjects::Entity::venues, "",
 | |
| 							 NewObject.entity, NewObject.info.id);
 | |
| 			ManageMembership(StorageService()->VenueDB(), &ProvObjects::Venue::children, "",
 | |
| 							 NewObject.parent, NewObject.info.id);
 | |
| 			MoveUsage(StorageService()->ConfigurationDB(), DB_, {}, NewObject.deviceConfiguration,
 | |
| 					  NewObject.info.id);
 | |
| 
 | |
| 			ProvObjects::Venue NewRecord;
 | |
| 			DB_.GetRecord("id", NewObject.info.id, NewRecord);
 | |
| 			Poco::JSON::Object Answer;
 | |
| 			NewRecord.to_json(Answer);
 | |
| 			return ReturnObject(Answer);
 | |
| 		}
 | |
| 		InternalError(RESTAPI::Errors::RecordNotCreated);
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 *      Get all the device types for the devices in the venue
 | |
| 	 *      For each unique device type, get all the firmwares that apply for it
 | |
| 	 *      create the intersection of all resulting firmwares
 | |
| 	 *      create a list ordered in 3 types
 | |
| 	 *      - Releases
 | |
| 	 *      - RC of releases
 | |
| 	 *      - Dev
 | |
| 	 *
 | |
| 	 *      We obtain the revision by stripping and trimming the revision field previous to the "/"
 | |
| 	 *      The sets should be built on the revision and the URI of the images, all per devicetype
 | |
| 	 */
 | |
| 
 | |
| 	enum class RevisionTypes { release, release_candidate, development };
 | |
| 
 | |
| 	RevisionTypes RevisionIdentify(const std::string &r) {
 | |
| 		auto it = r.find_first_of('/');
 | |
| 		if (it == std::string::npos) {
 | |
| 			return RevisionTypes::development;
 | |
| 		}
 | |
| 		++it;
 | |
| 		if (r.find("TIP-devel-", it) != std::string::npos) {
 | |
| 			return RevisionTypes::development;
 | |
| 		}
 | |
| 		if (r.find("-rc", it) != std::string::npos) {
 | |
| 			return RevisionTypes::release_candidate;
 | |
| 		}
 | |
| 		if (r.find("TIP-v", it) != std::string::npos) {
 | |
| 			return RevisionTypes::release;
 | |
| 		}
 | |
| 		return RevisionTypes::development;
 | |
| 	}
 | |
| 
 | |
| 	std::uint64_t RevisionDate(const std::string &R, const std::vector<FMSObjects::Firmware> &F) {
 | |
| 
 | |
| 		for (const auto &f : F) {
 | |
| 			if (f.revision == R)
 | |
| 				return f.imageDate;
 | |
| 		}
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	void RESTAPI_venue_handler::DoPut() {
 | |
| 		std::string UUID = GetBinding("uuid", "");
 | |
| 
 | |
| 		ProvObjects::Venue Existing;
 | |
| 		if (UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) {
 | |
| 			return NotFound();
 | |
| 		}
 | |
| 
 | |
| 		auto testUpdateOnly = GetBoolParameter("testUpdateOnly");
 | |
| 		if (testUpdateOnly) {
 | |
| 			ProvObjects::SerialNumberList SNL;
 | |
|             StorageService()->InventoryDB().GetDevicesForVenue(UUID, SNL.serialNumbers);
 | |
| 			Poco::JSON::Object Answer;
 | |
| 			SNL.to_json(Answer);
 | |
| 			return ReturnObject(Answer);
 | |
| 		}
 | |
| 
 | |
| 		if (GetBoolParameter("updateAllDevices")) {
 | |
| 			ProvObjects::SerialNumberList SNL;
 | |
|             StorageService()->InventoryDB().GetDevicesForVenue(UUID, SNL.serialNumbers);
 | |
| 
 | |
| 			Poco::JSON::Object Answer;
 | |
| 			auto JobId = MicroServiceCreateUUID();
 | |
| 			Types::StringVec Parameters{UUID};
 | |
| 			auto NewJob = new VenueConfigUpdater(JobId, "VenueConfigurationUpdater", Parameters, 0,
 | |
| 												 UserInfo_.userinfo, Logger());
 | |
| 			JobController()->AddJob(dynamic_cast<Job *>(NewJob));
 | |
| 			SNL.to_json(Answer);
 | |
| 			Answer.set("jobId", JobId);
 | |
| 			return ReturnObject(Answer);
 | |
| 		}
 | |
| 
 | |
| 		if (GetBoolParameter("upgradeAllDevices")) {
 | |
| 			if (GetBoolParameter("revisionsAvailable")) {
 | |
| 				std::set<std::string> DeviceTypes;
 | |
|                 std::vector<ProvObjects::InventoryTag> ExistingDevices;
 | |
|                 StorageService()->InventoryDB().GetDevicesForVenue(UUID, ExistingDevices);
 | |
| 				for (const auto &device : ExistingDevices) {
 | |
|                     DeviceTypes.insert(device.deviceType);
 | |
| 				}
 | |
| 
 | |
| 				//  Get all the revisions for all the device types
 | |
| 				using FirmwareList = std::vector<FMSObjects::Firmware>;
 | |
| 				using FirmwareRevisions = std::set<std::string>;
 | |
| 
 | |
| 				std::map<std::string, FirmwareList> AllFMs;
 | |
| 				FirmwareRevisions AllRevisions;
 | |
| 				bool first_pass = true;
 | |
| 				for (const auto &device_type : DeviceTypes) {
 | |
| 					FirmwareList list;
 | |
| 					if (SDK::FMS::Firmware::GetDeviceTypeFirmwares(device_type, list)) {
 | |
| 						AllFMs[device_type] = list;
 | |
| 						FirmwareRevisions DeviceRevisions;
 | |
| 						if (first_pass) {
 | |
| 							for (const auto &revision : list) {
 | |
| 								AllRevisions.insert(revision.revision);
 | |
| 							}
 | |
| 						} else {
 | |
| 							FirmwareRevisions DeviceTypeRevisions;
 | |
| 							for (const auto &revision : list) {
 | |
| 								DeviceTypeRevisions.insert(revision.revision);
 | |
| 							}
 | |
| 							FirmwareRevisions NewRevisions;
 | |
| 							std::set_intersection(
 | |
| 								AllRevisions.begin(), AllRevisions.end(),
 | |
| 								DeviceTypeRevisions.begin(), DeviceTypeRevisions.end(),
 | |
| 								std::inserter(NewRevisions, NewRevisions.begin()));
 | |
| 							AllRevisions = NewRevisions;
 | |
| 						}
 | |
| 					}
 | |
| 					first_pass = false;
 | |
| 				}
 | |
| 
 | |
| 				//  OK we start the solution map with Our first device, and then we
 | |
| 				Poco::JSON::Array Releases, ReleaseCandidates, DevelReleases;
 | |
| 				for (const auto &revision : AllRevisions) {
 | |
| 					auto Date = RevisionDate(revision, AllFMs.begin()->second);
 | |
| 					switch (RevisionIdentify(revision)) {
 | |
| 					case RevisionTypes::release_candidate: {
 | |
| 						Poco::JSON::Object E;
 | |
| 						E.set("revision", revision);
 | |
| 						E.set("date", Date);
 | |
| 						ReleaseCandidates.add(E);
 | |
| 					} break;
 | |
| 					case RevisionTypes::release: {
 | |
| 						Poco::JSON::Object E;
 | |
| 						E.set("revision", revision);
 | |
| 						E.set("date", Date);
 | |
| 						Releases.add(E);
 | |
| 					} break;
 | |
| 					case RevisionTypes::development:
 | |
| 					default: {
 | |
| 						Poco::JSON::Object E;
 | |
| 						E.set("revision", revision);
 | |
| 						E.set("date", Date);
 | |
| 						DevelReleases.add(E);
 | |
| 					}
 | |
| 					}
 | |
| 				}
 | |
| 				Poco::JSON::Object Answer;
 | |
| 				Answer.set("releases", Releases);
 | |
| 				Answer.set("releasesCandidates", ReleaseCandidates);
 | |
| 				Answer.set("developmentReleases", DevelReleases);
 | |
| 				return ReturnObject(Answer);
 | |
| 			}
 | |
| 
 | |
| 			auto Revision = GetParameter("revision", "");
 | |
| 			if (Revision.empty()) {
 | |
| 				return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | |
| 			}
 | |
| 
 | |
|             ProvObjects::SerialNumberList SNL;
 | |
|             StorageService()->InventoryDB().GetDevicesForVenue(UUID, SNL.serialNumbers);
 | |
| 
 | |
| 			Poco::JSON::Object Answer;
 | |
| 			auto JobId = MicroServiceCreateUUID();
 | |
| 			Types::StringVec Parameters{UUID, Revision};
 | |
| 			auto NewJob = new VenueUpgrade(JobId, "VenueFirmwareUpgrade", Parameters, 0,
 | |
| 										   UserInfo_.userinfo, Logger());
 | |
| 			JobController()->AddJob(dynamic_cast<Job *>(NewJob));
 | |
| 			SNL.to_json(Answer);
 | |
| 			Answer.set("jobId", JobId);
 | |
| 			return ReturnObject(Answer);
 | |
| 		}
 | |
| 
 | |
| 		if (GetBoolParameter("rebootAllDevices")) {
 | |
| 			ProvObjects::SerialNumberList SNL;
 | |
|             StorageService()->InventoryDB().GetDevicesForVenue(UUID, SNL.serialNumbers);
 | |
| 
 | |
| 			Poco::JSON::Object Answer;
 | |
| 			auto JobId = MicroServiceCreateUUID();
 | |
| 			Types::StringVec Parameters{UUID};
 | |
| 			;
 | |
| 			auto NewJob = new VenueRebooter(JobId, "VenueRebooter", Parameters, 0,
 | |
| 											UserInfo_.userinfo, Logger());
 | |
| 			JobController()->AddJob(dynamic_cast<Job *>(NewJob));
 | |
| 			SNL.to_json(Answer);
 | |
| 			Answer.set("jobId", JobId);
 | |
| 			return ReturnObject(Answer);
 | |
| 		}
 | |
| 
 | |
| 		const auto &RawObject = ParsedBody_;
 | |
| 		ProvObjects::Venue NewObject;
 | |
| 		if (!NewObject.from_json(RawObject)) {
 | |
| 			return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
 | |
| 		}
 | |
| 
 | |
| 		if ((RawObject->has("deviceRules") && !ValidDeviceRules(NewObject.deviceRules, *this))) {
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		if (!UpdateObjectInfo(RawObject, UserInfo_.userinfo, Existing.info)) {
 | |
| 			return BadRequest(RESTAPI::Errors::NameMustBeSet);
 | |
| 		}
 | |
| 
 | |
| 		if (RawObject->has("deviceRules"))
 | |
| 			Existing.deviceRules = NewObject.deviceRules;
 | |
| 
 | |
| 		if (RawObject->has("sourceIP")) {
 | |
| 			if (!NewObject.sourceIP.empty() && !CIDR::ValidateIpRanges(NewObject.sourceIP)) {
 | |
| 				return BadRequest(RESTAPI::Errors::InvalidIPRanges);
 | |
| 			}
 | |
| 			Existing.sourceIP = NewObject.sourceIP;
 | |
| 		}
 | |
| 
 | |
| 		std::string MoveFromEntity, MoveToEntity;
 | |
| 		if (AssignIfPresent(RawObject, "entity", MoveToEntity)) {
 | |
| 			if (MoveToEntity.empty() || !StorageService()->EntityDB().Exists("id", MoveToEntity)) {
 | |
| 				return BadRequest(RESTAPI::Errors::EntityMustExist);
 | |
| 			}
 | |
| 			MoveFromEntity = Existing.entity;
 | |
| 			Existing.entity = MoveToEntity;
 | |
| 		}
 | |
| 
 | |
| 		std::string MoveToVenue, MoveFromVenue;
 | |
| 		if (AssignIfPresent(RawObject, "venue", MoveToVenue)) {
 | |
| 			if (MoveToVenue.empty() || !StorageService()->VenueDB().Exists("id", MoveToVenue)) {
 | |
| 				return BadRequest(RESTAPI::Errors::VenueMustExist);
 | |
| 			}
 | |
| 			MoveFromVenue = Existing.parent;
 | |
| 			Existing.parent = MoveToVenue;
 | |
| 		}
 | |
| 
 | |
| 		std::string MoveFromLocation, MoveToLocation;
 | |
| 		if (AssignIfPresent(RawObject, "location", MoveToLocation)) {
 | |
| 			if (MoveToLocation.empty() ||
 | |
| 				!StorageService()->LocationDB().Exists("id", MoveToLocation)) {
 | |
| 				return BadRequest(RESTAPI::Errors::LocationMustExist);
 | |
| 			}
 | |
| 			MoveFromLocation = Existing.location;
 | |
| 			Existing.location = MoveToLocation;
 | |
| 		}
 | |
| 
 | |
| 		Types::UUIDvec_t MoveFromContacts, MoveToContacts;
 | |
| 		if (AssignIfPresent(RawObject, "contacts", MoveToContacts)) {
 | |
| 			for (const auto &contact : NewObject.contacts) {
 | |
| 				if (!StorageService()->ContactDB().Exists("id", contact)) {
 | |
| 					return BadRequest(RESTAPI::Errors::ContactMustExist);
 | |
| 				}
 | |
| 			}
 | |
| 			MoveFromContacts = Existing.contacts;
 | |
| 			Existing.contacts = MoveToContacts;
 | |
| 		}
 | |
| 
 | |
| 		std::string MoveFromPolicy, MoveToPolicy;
 | |
| 		if (AssignIfPresent(RawObject, "managementPolicy", MoveToPolicy)) {
 | |
| 			if (MoveToPolicy.empty() || !StorageService()->PolicyDB().Exists("id", MoveToPolicy)) {
 | |
| 				return BadRequest(RESTAPI::Errors::UnknownManagementPolicyUUID);
 | |
| 			}
 | |
| 			MoveFromPolicy = Existing.managementPolicy;
 | |
| 			Existing.managementPolicy = MoveToPolicy;
 | |
| 		}
 | |
| 
 | |
| 		Types::UUIDvec_t MoveToConfigurations, MoveFromConfigurations;
 | |
| 		if (RawObject->has("deviceConfiguration")) {
 | |
| 			MoveToConfigurations = NewObject.deviceConfiguration;
 | |
| 			for (auto &configuration : MoveToConfigurations) {
 | |
| 				if (!StorageService()->ConfigurationDB().Exists("id", configuration)) {
 | |
| 					return BadRequest(RESTAPI::Errors::ConfigurationMustExist);
 | |
| 				}
 | |
| 			}
 | |
| 			MoveToConfigurations = NewObject.deviceConfiguration;
 | |
| 			MoveFromConfigurations = Existing.deviceConfiguration;
 | |
| 			Existing.deviceConfiguration = MoveToConfigurations;
 | |
| 		}
 | |
| 
 | |
| 		std::string ErrorText;
 | |
| 		NewObject.parent = Existing.parent;
 | |
| 		NewObject.entity = Existing.entity;
 | |
| 
 | |
| 		std::vector<std::string> Errors;
 | |
| 		auto ObjectsCreated = CreateObjects(NewObject, *this, Errors);
 | |
| 		if (!Errors.empty()) {
 | |
| 			return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
 | |
| 		}
 | |
| 
 | |
| 		if (!ObjectsCreated.empty()) {
 | |
| 			if (!ObjectsCreated.empty()) {
 | |
| 				auto it = ObjectsCreated.find("location");
 | |
| 				if (it != ObjectsCreated.end()) {
 | |
| 					MoveFromLocation = "";
 | |
| 					MoveToLocation = it->second;
 | |
| 					Existing.location = MoveToLocation;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (RawObject->has("boards")) {
 | |
| 			Existing.boards = NewObject.boards;
 | |
| 		}
 | |
| 
 | |
| 		if (StorageService()->VenueDB().UpdateRecord("id", UUID, Existing)) {
 | |
| 			UpdateKafkaProvisioningObject(ProvisioningOperation::modification, Existing);
 | |
| 			MoveUsage(StorageService()->ContactDB(), DB_, MoveFromContacts, MoveToContacts,
 | |
| 					  Existing.info.id);
 | |
| 			MoveUsage(StorageService()->LocationDB(), DB_, MoveFromLocation, MoveToLocation,
 | |
| 					  Existing.info.id);
 | |
| 			MoveUsage(StorageService()->PolicyDB(), DB_, MoveFromPolicy, MoveToPolicy,
 | |
| 					  Existing.info.id);
 | |
| 			ManageMembership(StorageService()->EntityDB(), &ProvObjects::Entity::venues,
 | |
| 							 MoveFromEntity, MoveToEntity, Existing.info.id);
 | |
| 			ManageMembership(StorageService()->VenueDB(), &ProvObjects::Venue::children,
 | |
| 							 MoveFromVenue, MoveToVenue, Existing.info.id);
 | |
| 			MoveUsage(StorageService()->ConfigurationDB(), DB_, MoveFromConfigurations,
 | |
| 					  MoveToConfigurations, Existing.info.id);
 | |
| 
 | |
| 			ProvObjects::Venue AddedRecord;
 | |
| 			DB_.GetRecord("id", UUID, AddedRecord);
 | |
| 			Poco::JSON::Object Answer;
 | |
| 			AddedRecord.to_json(Answer);
 | |
| 			return ReturnObject(Answer);
 | |
| 		}
 | |
| 		InternalError(RESTAPI::Errors::RecordNotUpdated);
 | |
| 	}
 | |
| } // namespace OpenWifi
 | 
