diff --git a/Source/Unrealzilla/Private/BugMarkerSubsystem.cpp b/Source/Unrealzilla/Private/BugMarkerSubsystem.cpp index b0a2a52..ab816be 100644 Binary files a/Source/Unrealzilla/Private/BugMarkerSubsystem.cpp and b/Source/Unrealzilla/Private/BugMarkerSubsystem.cpp differ diff --git a/Source/Unrealzilla/Private/ServerAPI.cpp b/Source/Unrealzilla/Private/ServerAPI.cpp new file mode 100644 index 0000000..585326e --- /dev/null +++ b/Source/Unrealzilla/Private/ServerAPI.cpp @@ -0,0 +1,609 @@ +// ©2022 Batty Bovine Productions, LLC. All Rights Reserved. + + +#include "ServerAPI.h" + +#include "HttpModule.h" +#include "JsonObjectConverter.h" +#include "UnrealzillaGlobalSettings.h" + +#include "Kismet/GameplayStatics.h" + + +const FString GetGameVersion() +{ + FString GameVersion; + GConfig->GetString(TEXT("/Script/EngineSettings.GeneralProjectSettings"), TEXT("ProjectVersion"), GameVersion, GGameIni); + if (GameVersion.IsEmpty()) + { + GameVersion = "1.0.0.0"; + } + return GameVersion; +} + + +void UServerAPI::ReturnListOfBugs() +{ + const FString FullURL = GetDefault()->SubmissionServer + "/rest.cgi"; + + TArray StatusQueries; + if (GetDefault()->bShowUnresolvedBugs) + { + for (const FString Unresolved : GetDefault()->UnresolvedStatuses) + { + StatusQueries.Add("status=" + Unresolved); + } + } + if (GetDefault()->bShowInProgressBugs) + { + for (const FString InProgress : GetDefault()->InProgressStatuses) + { + StatusQueries.Add("status=" + InProgress); + } + } + if (GetDefault()->bShowResolvedBugs) + { + for (const FString Resolved : GetDefault()->ResolvedStatuses) + { + StatusQueries.Add("status=" + Resolved); + } + } + StatusQueries.Add("cf_mapname=" + this->GetWorld()->GetMapName().RightChop(this->GetWorld()->StreamingLevelsPrefix.Len())); + StatusQueries.Add("api_key=" + GetDefault()->APIKey); + const FString QueryString = FString::Join(StatusQueries, TEXT("&")); + + FHttpModule &HttpModule = FHttpModule::Get(); + TSharedRef SeverityRequest = HttpModule.CreateRequest(); + SeverityRequest->SetVerb(TEXT("GET")); + SeverityRequest->SetHeader(TEXT("Content-Type"), TEXT("application/json")); + SeverityRequest->SetURL(FullURL + "/bug" + "?" + QueryString); + SeverityRequest->OnProcessRequestComplete().BindUObject(this, &UServerAPI::ListOfBugsResponse); + SeverityRequest->ProcessRequest(); +} + +void UServerAPI::ListOfBugsResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool Success) +{ + if (Success) + { + FBugzillaJSONBugResponse ResponseData; + FString JSONResponse = Response->GetContentAsString(); + FJsonObjectConverter::JsonObjectStringToUStruct(JSONResponse, &ResponseData); + + if (!ResponseData.error) + { + TArray BugData; + for (const FBugzillaJSONBugData &BugzillaData : ResponseData.bugs) + { + FUnrealzillaBugData Bug; + Bug.ID = BugzillaData.id; + Bug.Summary = BugzillaData.summary; + Bug.Component = BugzillaData.component; + Bug.MapName = BugzillaData.cf_mapname; + Bug.MapLocation = BugzillaData.cf_location; + Bug.Platform = BugzillaData.platform; + Bug.OperatingSystem = BugzillaData.op_sys; + Bug.Severity = BugzillaData.severity; + Bug.Status = BugzillaData.status; + Bug.Resolution = BugzillaData.resolution; + Bug.DuplicateOf = BugzillaData.dupe_of; + Bug.bIsOpen = BugzillaData.is_open; + BugData.Add(Bug); + } + this->BugDataResponse.Execute(BugData); + } + else + { + this->CreateError(EErrorVerb::GET, ResponseData); + } + } +} + +void UServerAPI::PrepareForm() +{ + const FString FullURL = GetDefault()->SubmissionServer + "/rest.cgi"; + + // Assemble query data into key:value pairs + TMap QueryData; + QueryData.Add("api_key", GetDefault()->APIKey); + const FString QueryString = UServerAPI::FormatQueryString(QueryData); + + // Query the server for information about the current product + FHttpModule &HttpModule = FHttpModule::Get(); + TSharedRef ProductRequest = HttpModule.CreateRequest(); + ProductRequest->SetVerb(TEXT("GET")); + ProductRequest->SetHeader(TEXT("Content-Type"), TEXT("application/json")); + ProductRequest->SetURL(FullURL + "/product/" + GetDefault()->ProductName + "?" + QueryString); + ProductRequest->OnProcessRequestComplete().BindUObject(this, &UServerAPI::ServerProductInfoResponse); + ProductRequest->ProcessRequest(); + + // Send a second query to retrieve severity options + TSharedRef SeverityRequest = HttpModule.CreateRequest(); + SeverityRequest->SetVerb(TEXT("GET")); + SeverityRequest->SetHeader(TEXT("Content-Type"), TEXT("application/json")); + SeverityRequest->SetURL(FullURL + "/field/bug/bug_severity" + "?" + QueryString); + SeverityRequest->OnProcessRequestComplete().BindUObject(this, &UServerAPI::ServerSeverityInfoResponse); + SeverityRequest->ProcessRequest(); + + // Send a third query to retrieve platform options + TSharedRef PlatformsRequest = HttpModule.CreateRequest(); + PlatformsRequest->SetVerb(TEXT("GET")); + PlatformsRequest->SetHeader(TEXT("Content-Type"), TEXT("application/json")); + PlatformsRequest->SetURL(FullURL + "/field/bug/rep_platform" + "?" + QueryString); + PlatformsRequest->OnProcessRequestComplete().BindUObject(this, &UServerAPI::ServerPlatformInfoResponse); + PlatformsRequest->ProcessRequest(); + + // Send a final query to retrieve OS options + TSharedRef OSRequest = HttpModule.CreateRequest(); + OSRequest->SetVerb(TEXT("GET")); + OSRequest->SetHeader(TEXT("Content-Type"), TEXT("application/json")); + OSRequest->SetURL(FullURL + "/field/bug/op_sys" + "?" + QueryString); + OSRequest->OnProcessRequestComplete().BindUObject(this, &UServerAPI::ServerOSInfoResponse); + OSRequest->ProcessRequest(); +} + +void UServerAPI::SendFormData(const FUnrealzillaPostData &PostData) +{ + const FString FullURL = GetDefault()->SubmissionServer + "/rest.cgi"; + const FString RequestURL = "/bug"; + + // Assemble query data into key:value pairs + TMap QueryData; + QueryData.Add("api_key", GetDefault()->APIKey); + + const FString DefaultStatus = GetDefault()->DefaultStatus; + + FBugzillaJSONPostBug PostDataJSON; + PostDataJSON.product = GetDefault()->ProductName; + PostDataJSON.version = PostData.Version; + PostDataJSON.platform = PostData.Platform; + PostDataJSON.op_sys = PostData.OS; + PostDataJSON.component = PostData.Component; + PostDataJSON.severity = PostData.Severity; + PostDataJSON.cf_mapname = PostData.MapName; + PostDataJSON.cf_location = PostData.MapLocation; + PostDataJSON.summary = PostData.Summary; + PostDataJSON.description = PostData.Comment; + if (!DefaultStatus.IsEmpty()) + { + PostDataJSON.status = DefaultStatus; + } + + if (PostDataJSON.version.IsEmpty()) + { + this->CreateError("You must select a version number."); + return; + } + if (PostDataJSON.platform.IsEmpty() || PostDataJSON.op_sys.IsEmpty()) + { + PostDataJSON.platform = "All"; + PostDataJSON.op_sys = "All"; + } + if (PostDataJSON.component.IsEmpty()) + { + this->CreateError("You must select a component."); + return; + } + if (PostDataJSON.severity.IsEmpty()) + { + this->CreateError("You must select a severity level."); + return; + } + if (PostDataJSON.summary.IsEmpty()) + { + this->CreateError("You must provide a summary."); + return; + } + + FString PostJsonString; + FJsonObjectConverter::UStructToJsonObjectString(PostDataJSON, PostJsonString); + + FHttpModule &HttpModule = FHttpModule::Get(); + TSharedRef Request = HttpModule.CreateRequest(); + Request->SetVerb(TEXT("POST")); + Request->SetHeader(TEXT("Content-Type"), TEXT("application/json")); + Request->SetURL(FullURL + RequestURL + "?" + UServerAPI::FormatQueryString(QueryData)); + Request->SetContentAsString(PostJsonString); + Request->OnProcessRequestComplete().BindUObject(this, &UServerAPI::ServerPOSTResponse); + Request->ProcessRequest(); +} + + +void UServerAPI::ServerPOSTResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool Success) +{ + if (Success) + { + FBugzillaJSONPostResponse ResponseData; + FString JSONResponse = Response->GetContentAsString(); + FJsonObjectConverter::JsonObjectStringToUStruct(JSONResponse, &ResponseData); + + if (ResponseData.error) + { + this->CreateError(EErrorVerb::POST, ResponseData); + } + else + { + // Use the response's bug ID to get the info from the newly filed bug report and update its marker + + const FString FullURL = GetDefault()->SubmissionServer + "/rest.cgi"; + + TArray StatusQueries; + StatusQueries.Add("id=" + FString::FromInt(ResponseData.id)); + if (GetDefault()->bShowUnresolvedBugs) + { + for (const FString Unresolved : GetDefault()->UnresolvedStatuses) + { + StatusQueries.Add("status=" + Unresolved); + } + } + if (GetDefault()->bShowInProgressBugs) + { + for (const FString InProgress : GetDefault()->InProgressStatuses) + { + StatusQueries.Add("status=" + InProgress); + } + } + if (GetDefault()->bShowResolvedBugs) + { + for (const FString Resolved : GetDefault()->ResolvedStatuses) + { + StatusQueries.Add("status=" + Resolved); + } + } + StatusQueries.Add("cf_mapname=" + this->GetWorld()->GetMapName().RightChop(this->GetWorld()->StreamingLevelsPrefix.Len())); + StatusQueries.Add("api_key=" + GetDefault()->APIKey); + const FString QueryString = FString::Join(StatusQueries, TEXT("&")); + + FHttpModule &HttpModule = FHttpModule::Get(); + TSharedRef SeverityRequest = HttpModule.CreateRequest(); + SeverityRequest->SetVerb(TEXT("GET")); + SeverityRequest->SetHeader(TEXT("Content-Type"), TEXT("application/json")); + SeverityRequest->SetURL(FullURL + "/bug" + "?" + QueryString); + SeverityRequest->OnProcessRequestComplete().BindUObject(this, &UServerAPI::ServerPOSTUpdateMarkerResponse); + SeverityRequest->ProcessRequest(); + } + } + else + { + this->ServerConnectionError(Request->GetStatus()); + } +} + +void UServerAPI::ServerPOSTUpdateMarkerResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool Success) +{ + if (Success) + { + FBugzillaJSONBugResponse ResponseData; + FString JSONResponse = Response->GetContentAsString(); + FJsonObjectConverter::JsonObjectStringToUStruct(JSONResponse, &ResponseData); + + if (ResponseData.error) + { + this->CreateError(EErrorVerb::GET, ResponseData); + } + else + { + if (!ResponseData.bugs.IsEmpty()) + { + TArray BugData; + FUnrealzillaBugData Bug; + Bug.ID = ResponseData.bugs[0].id; + Bug.Summary = ResponseData.bugs[0].summary; + Bug.Component = ResponseData.bugs[0].component; + Bug.MapName = ResponseData.bugs[0].cf_mapname; + Bug.MapLocation = ResponseData.bugs[0].cf_location; + Bug.Platform = ResponseData.bugs[0].platform; + Bug.OperatingSystem = ResponseData.bugs[0].op_sys; + Bug.Severity = ResponseData.bugs[0].severity; + Bug.Status = ResponseData.bugs[0].status; + Bug.Resolution = ResponseData.bugs[0].resolution; + Bug.DuplicateOf = ResponseData.bugs[0].dupe_of; + Bug.bIsOpen = ResponseData.bugs[0].is_open; + BugData.Add(Bug); + this->BugDataResponse.Execute(BugData); + } + } + } + else + { + this->ServerConnectionError(Request->GetStatus()); + } +} + +void UServerAPI::ServerProductInfoResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool Success) +{ + if (Success) + { + FBugzillaJSONProductResponse ResponseData; + FString JSONResponse = Response->GetContentAsString(); + FJsonObjectConverter::JsonObjectStringToUStruct(JSONResponse, &ResponseData); + + if (ResponseData.error) + { + //this->ShowProcessingOverlayMessage(ResponseData.message); + this->CreateError(EErrorVerb::GET, ResponseData); + } + else + { + if (!ResponseData.products.IsEmpty()) + { + const FBugzillaJSONProductData &ProductData = ResponseData.products[0]; + if (ProductData.name == GetDefault()->ProductName) + { + for (const FBugzillaJSONComponentData &ComponentData : ProductData.components) + { + this->ComponentsList.Add(ComponentData.name); + } + for (const FBugzillaJSONVersionData &VersionData : ProductData.versions) + { + this->VersionsList.Add(VersionData.name); + } + } + + this->CheckIfAllFormResponsesAreIn(); + } + else + { + FStringFormatOrderedArguments Args; + Args.Add(FStringFormatArg(GetDefault()->ProductName)); + //this->ShowProcessingOverlayMessage(FString::Format(TEXT("Could not find data for a product called {0}"), Args), true); + this->CreateError(FString::Format(TEXT("Could not find data for a product called {0}"), Args)); + } + } + } + else + { + this->ServerConnectionError(Request->GetStatus()); + } +} + +void UServerAPI::ServerSeverityInfoResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool Success) +{ + if (Success) + { + FBugzillaJSONFieldResponse ResponseData; + FString JSONResponse = Response->GetContentAsString(); + FJsonObjectConverter::JsonObjectStringToUStruct(JSONResponse, &ResponseData); + + if (ResponseData.error) + { + //this->ShowProcessingOverlayMessage(ResponseData.message); + this->CreateError(EErrorVerb::GET, ResponseData); + } + else + { + if (!ResponseData.fields.IsEmpty() && ResponseData.fields[0].name == "bug_severity") + { + for (const FBugzillaJSONFieldValueData &FieldValue : ResponseData.fields[0].values) + { + this->SeverityList.Add(FieldValue.name); + } + } + + this->CheckIfAllFormResponsesAreIn(); + } + } + else + { + this->ServerConnectionError(Request->GetStatus()); + } +} + +void UServerAPI::ServerPlatformInfoResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool Success) +{ + if (Success) + { + FBugzillaJSONFieldResponse ResponseData; + FString JSONResponse = Response->GetContentAsString(); + FJsonObjectConverter::JsonObjectStringToUStruct(JSONResponse, &ResponseData); + + if (ResponseData.error) + { + //this->ShowProcessingOverlayMessage(ResponseData.message); + this->CreateError(EErrorVerb::GET, ResponseData); + } + else + { + if (!ResponseData.fields.IsEmpty() && ResponseData.fields[0].name == "rep_platform") + { + for (const FBugzillaJSONFieldValueData &FieldValue : ResponseData.fields[0].values) + { + this->PlatformsList.Add(FieldValue.name); + } + } + + this->CheckIfAllFormResponsesAreIn(); + } + } + else + { + this->ServerConnectionError(Request->GetStatus()); + } +} + +void UServerAPI::ServerOSInfoResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool Success) +{ + if (Success) + { + FBugzillaJSONFieldResponse ResponseData; + FString JSONResponse = Response->GetContentAsString(); + FJsonObjectConverter::JsonObjectStringToUStruct(JSONResponse, &ResponseData); + + if (ResponseData.error) + { + //this->ShowProcessingOverlayMessage(ResponseData.message); + this->CreateError(EErrorVerb::GET, ResponseData); + } + else + { + if (!ResponseData.fields.IsEmpty() && ResponseData.fields[0].name == "op_sys") + { + for (const FBugzillaJSONFieldValueData &FieldValue : ResponseData.fields[0].values) + { + this->OSList.Add(FieldValue.name); + } + } + + this->CheckIfAllFormResponsesAreIn(); + } + } + else + { + this->ServerConnectionError(Request->GetStatus()); + } +} + +void UServerAPI::CheckIfAllFormResponsesAreIn() +{ + if (!this->ComponentsList.IsEmpty() && !this->VersionsList.IsEmpty() && !this->SeverityList.IsEmpty() && + !this->PlatformsList.IsEmpty() && !this->OSList.IsEmpty()) + { + FUnrealzillaFormPrepData Data; + + Data.ComponentsList = this->ComponentsList; + Data.SeverityList = this->SeverityList; + Data.VersionsList = this->VersionsList; + Data.PlatformsList = this->PlatformsList; + Data.OSList = this->OSList; + + // Find a default version number to use if possible + if (this->VersionsList.Contains(GetGameVersion())) + { + Data.DetectedVersion = GetGameVersion(); + } + else if (this->VersionsList.Contains("unspecified")) + { + Data.DetectedVersion = "unspecified"; + } + else if (this->VersionsList.Contains("Latest")) + { + Data.DetectedVersion = "Latest"; + } + else if (!this->VersionsList.IsEmpty()) + { + Data.DetectedVersion = this->VersionsList[0]; + } + + // Set these as defaults in case nothing below changes this setting + Data.DetectedHardware = "All"; + Data.DetectedOS = "All"; + + if (this->PlatformsList.Contains("PC")) + { + // Try our best to auto-detect PC hardware + if (UGameplayStatics::GetPlatformName() == "Windows" && this->OSList.Contains("Windows")) + { + Data.DetectedHardware = "PC"; + Data.DetectedOS = "Windows"; + } + else if (UGameplayStatics::GetPlatformName() == "Linux" && this->OSList.Contains("Linux")) + { + Data.DetectedHardware = "PC"; + Data.DetectedOS = "Linux"; + } + else if (UGameplayStatics::GetPlatformName() == "Mac" && this->OSList.Contains("Mac OS")) + { + Data.DetectedHardware = "All"; + Data.DetectedOS = "Mac OS"; + } + } + if (UGameplayStatics::GetPlatformName() == "Mac") + { + // Try our best to auto-detect Macintosh hardware + if (this->PlatformsList.Contains("Macintosh")) + { + if (this->OSList.Contains("Mac OS")) + { + Data.DetectedHardware = "Macintosh"; + Data.DetectedOS = "Mac OS"; + } + } + } + + this->FormDataResponse.Execute(Data); + + this->ComponentsList.Empty(); + this->VersionsList.Empty(); + this->SeverityList.Empty(); + this->PlatformsList.Empty(); + this->OSList.Empty(); + } +} + +void UServerAPI::ServerConnectionError(const EHttpRequestStatus::Type Status) +{ + switch (Status) { + case EHttpRequestStatus::Failed_ConnectionError: + this->CreateError("Unable to connect to the server"); + //this->ShowProcessingOverlayMessage("Unable to connect to the server", true); + break; + case EHttpRequestStatus::NotStarted: + this->CreateError("Connection could not start"); + //this->ShowProcessingOverlayMessage("Connection could not start", true); + break; + case EHttpRequestStatus::Failed: + this->CreateError("Connection failed"); + //this->ShowProcessingOverlayMessage("Connection failed", true); + break; + default: + this->CreateError("Request failed for unknown reasons"); + //this->ShowProcessingOverlayMessage("Request failed for unknown reasons", true); + } +} + +void UServerAPI::CreateError(const EErrorVerb &Verb, const FBugzillaJSONPostResponse &Data) +{ + FUnrealzillaErrorData Error; + Error.ErrorVerb = Verb; + Error.ErrorCode = Data.code; + Error.ErrorMessage = Data.message; + Error.DocumentationLink = Data.documentation; + this->ErrorResponse.Execute(Error); +} +void UServerAPI::CreateError(const EErrorVerb &Verb, const FBugzillaJSONProductResponse &Data) +{ + FUnrealzillaErrorData Error; + Error.ErrorVerb = Verb; + Error.ErrorCode = Data.code; + Error.ErrorMessage = Data.message; + Error.DocumentationLink = Data.documentation; + this->ErrorResponse.Execute(Error); +} +void UServerAPI::CreateError(const EErrorVerb &Verb, const FBugzillaJSONFieldResponse &Data) +{ + FUnrealzillaErrorData Error; + Error.ErrorVerb = Verb; + Error.ErrorCode = Data.code; + Error.ErrorMessage = Data.message; + Error.DocumentationLink = Data.documentation; + this->ErrorResponse.Execute(Error); +} +void UServerAPI::CreateError(const EErrorVerb &Verb, const FBugzillaJSONBugResponse &Data) +{ + FUnrealzillaErrorData Error; + Error.ErrorVerb = Verb; + Error.ErrorCode = Data.code; + Error.ErrorMessage = Data.message; + Error.DocumentationLink = Data.documentation; + this->ErrorResponse.Execute(Error); +} +void UServerAPI::CreateError(const FString &ErrorMessage) +{ + FUnrealzillaErrorData Error; + Error.ErrorVerb = EErrorVerb::None; + Error.ErrorMessage = ErrorMessage; + this->ErrorResponse.Execute(Error); +} + + +const FString UServerAPI::FormatQueryString(const TMap &QueryData) +{ + TArray AssembledKeyValuePairs; + TArray QueryKeys; + QueryData.GenerateKeyArray(QueryKeys); + for (const FString &QueryKey : QueryKeys) + { + AssembledKeyValuePairs.Add(QueryKey + "=" + QueryData[QueryKey]); + } + + return FString::Join(AssembledKeyValuePairs, TEXT("&")); +} diff --git a/Source/Unrealzilla/Private/ServerREST.cpp b/Source/Unrealzilla/Private/ServerREST.cpp deleted file mode 100644 index 1fd5294..0000000 Binary files a/Source/Unrealzilla/Private/ServerREST.cpp and /dev/null differ diff --git a/Source/Unrealzilla/Private/UnrealzillaGlobalSettings.cpp b/Source/Unrealzilla/Private/UnrealzillaGlobalSettings.cpp index c831d0c..9272e80 100644 --- a/Source/Unrealzilla/Private/UnrealzillaGlobalSettings.cpp +++ b/Source/Unrealzilla/Private/UnrealzillaGlobalSettings.cpp @@ -1,4 +1,4 @@ -// ©2022 Batty Bovine Productions, LLC. All Rights Reserved. +// ©2022 Batty Bovine Productions, LLC. All Rights Reserved. #include "UnrealzillaGlobalSettings.h" diff --git a/Source/Unrealzilla/Public/JSON/BugzillaJSONStructs.h b/Source/Unrealzilla/Public/API/BugzillaJSONStructs.h similarity index 98% rename from Source/Unrealzilla/Public/JSON/BugzillaJSONStructs.h rename to Source/Unrealzilla/Public/API/BugzillaJSONStructs.h index 1736be5..f8128b2 100644 --- a/Source/Unrealzilla/Public/JSON/BugzillaJSONStructs.h +++ b/Source/Unrealzilla/Public/API/BugzillaJSONStructs.h @@ -1,4 +1,4 @@ -// ©2022 Batty Bovine Productions, LLC. All Rights Reserved. +// ©2022 Batty Bovine Productions, LLC. All Rights Reserved. #pragma once diff --git a/Source/Unrealzilla/Public/JSON/JiraJSONStructs.h b/Source/Unrealzilla/Public/API/JiraJSONStructs.h similarity index 55% rename from Source/Unrealzilla/Public/JSON/JiraJSONStructs.h rename to Source/Unrealzilla/Public/API/JiraJSONStructs.h index 73ae81e..5f97de1 100644 --- a/Source/Unrealzilla/Public/JSON/JiraJSONStructs.h +++ b/Source/Unrealzilla/Public/API/JiraJSONStructs.h @@ -1,4 +1,4 @@ -// ©2022 Batty Bovine Productions, LLC. All Rights Reserved. +// ©2022 Batty Bovine Productions, LLC. All Rights Reserved. #pragma once diff --git a/Source/Unrealzilla/Public/API/UnrealzillaBugDataStructs.h b/Source/Unrealzilla/Public/API/UnrealzillaBugDataStructs.h new file mode 100644 index 0000000..48868d0 --- /dev/null +++ b/Source/Unrealzilla/Public/API/UnrealzillaBugDataStructs.h @@ -0,0 +1,113 @@ +// ©2022 Batty Bovine Productions, LLC. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" + +#include "UnrealzillaBugDataStructs.generated.h" + + +UENUM(Blueprintable) +enum class EErrorVerb : uint8 +{ + None UMETA(DisplayName="None"), + GET UMETA(DisplayName="GET"), + POST UMETA(DisplayName="POST"), + MAX UMETA(Hidden) +}; + +USTRUCT(Blueprintable) +struct FUnrealzillaErrorData +{ + GENERATED_BODY() +public: + UPROPERTY(BlueprintReadOnly) + EErrorVerb ErrorVerb = EErrorVerb::None; + UPROPERTY(BlueprintReadOnly) + int32 ErrorCode = -1; + UPROPERTY(BlueprintReadOnly) + FString ErrorMessage; + UPROPERTY(BlueprintReadOnly) + FString DocumentationLink; +}; + +USTRUCT(Blueprintable) +struct FUnrealzillaBugData +{ + GENERATED_BODY() +public: + UPROPERTY(BlueprintReadOnly) + int32 ID = -1; + UPROPERTY(BlueprintReadOnly) + FString Summary; + UPROPERTY(BlueprintReadOnly) + FString Component; + UPROPERTY(BlueprintReadOnly) + FString MapName; + UPROPERTY(BlueprintReadOnly) + FString MapLocation; + UPROPERTY(BlueprintReadOnly) + FString Platform; + UPROPERTY(BlueprintReadOnly) + FString OperatingSystem; + UPROPERTY(BlueprintReadOnly) + bool bIsOpen = true; + UPROPERTY(BlueprintReadOnly) + FString Severity; + UPROPERTY(BlueprintReadOnly) + FString Status; + UPROPERTY(BlueprintReadOnly) + FString Resolution; + UPROPERTY(BlueprintReadOnly) + int32 DuplicateOf = -1; +}; + +USTRUCT(Blueprintable) +struct FUnrealzillaFormPrepData +{ + GENERATED_BODY() +public: + UPROPERTY(BlueprintReadOnly) + TArray ComponentsList; + UPROPERTY(BlueprintReadOnly) + TArray SeverityList; + UPROPERTY(BlueprintReadOnly) + TArray VersionsList; + UPROPERTY(BlueprintReadOnly) + TArray PlatformsList; + UPROPERTY(BlueprintReadOnly) + TArray OSList; + + UPROPERTY(BlueprintReadOnly) + FString DetectedVersion; + UPROPERTY(BlueprintReadOnly) + FString DetectedHardware; + UPROPERTY(BlueprintReadOnly) + FString DetectedOS; +}; + + +USTRUCT(Blueprintable) +struct FUnrealzillaPostData +{ + GENERATED_BODY() +public: + UPROPERTY(BlueprintReadOnly) + FString Version; + UPROPERTY(BlueprintReadOnly) + FString Platform; + UPROPERTY(BlueprintReadOnly) + FString OS; + UPROPERTY(BlueprintReadOnly) + FString Component; + UPROPERTY(BlueprintReadOnly) + FString Severity; + UPROPERTY(BlueprintReadOnly) + FString MapName; + UPROPERTY(BlueprintReadOnly) + FString MapLocation; + UPROPERTY(BlueprintReadOnly) + FString Summary; + UPROPERTY(BlueprintReadOnly) + FString Comment; +}; diff --git a/Source/Unrealzilla/Public/BugMarkerActor.h b/Source/Unrealzilla/Public/BugMarkerActor.h index f3ee144..5950496 100644 --- a/Source/Unrealzilla/Public/BugMarkerActor.h +++ b/Source/Unrealzilla/Public/BugMarkerActor.h @@ -4,7 +4,7 @@ #include "CoreMinimal.h" -#include "ServerREST.h" +#include "ServerAPI.h" #include "BugMarkerActor.generated.h" diff --git a/Source/Unrealzilla/Public/BugMarkerSubsystem.h b/Source/Unrealzilla/Public/BugMarkerSubsystem.h index 294cc86..c728b09 100644 Binary files a/Source/Unrealzilla/Public/BugMarkerSubsystem.h and b/Source/Unrealzilla/Public/BugMarkerSubsystem.h differ diff --git a/Source/Unrealzilla/Public/ServerAPI.h b/Source/Unrealzilla/Public/ServerAPI.h new file mode 100644 index 0000000..982e865 --- /dev/null +++ b/Source/Unrealzilla/Public/ServerAPI.h @@ -0,0 +1,68 @@ +// ©2022 Batty Bovine Productions, LLC. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" + +#include "API/BugzillaJSONStructs.h" +#include "API/UnrealzillaBugDataStructs.h" +#include "Interfaces/IHttpRequest.h" +#include "Interfaces/IHttpResponse.h" + +#include "ServerAPI.generated.h" + + +/** + * Class for communicating with REST API on bug tracking software + */ +UCLASS() +class UNREALZILLA_API UServerAPI : public UObject +{ + GENERATED_BODY() + +public: + void ReturnListOfBugs(); + void PrepareForm(); + void SendFormData(const FUnrealzillaPostData &PostData); + + DECLARE_DELEGATE_OneParam(FBugListResponseDelegate, const TArray&); + FBugListResponseDelegate BugDataResponse; + + DECLARE_DELEGATE_OneParam(FFormResponseDelegate, const FUnrealzillaFormPrepData&); + FFormResponseDelegate FormDataResponse; + + DECLARE_DELEGATE_OneParam(FServerErrorResponseDelegate, const FUnrealzillaErrorData &) + FServerErrorResponseDelegate ErrorResponse; + + TArray GetComponentsList() const { return this->ComponentsList; } + TArray GetSeverityList() const { return this->SeverityList; } + TArray GetVersionsList() const { return this->VersionsList; } + TArray GetPlatformsList() const { return this->PlatformsList; } + TArray GetOSList() const { return this->OSList; } + +private: + void ListOfBugsResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool Success); + + void ServerPOSTResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool Success); + void ServerPOSTUpdateMarkerResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool Success); + void ServerProductInfoResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool Success); + void ServerSeverityInfoResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool Success); + void ServerPlatformInfoResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool Success); + void ServerOSInfoResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool Success); + void CheckIfAllFormResponsesAreIn(); + void ServerConnectionError(const EHttpRequestStatus::Type Status); + + void CreateError(const EErrorVerb &Verb, const FBugzillaJSONPostResponse &Data); + void CreateError(const EErrorVerb &Verb, const FBugzillaJSONProductResponse &Data); + void CreateError(const EErrorVerb &Verb, const FBugzillaJSONFieldResponse &Data); + void CreateError(const EErrorVerb &Verb, const FBugzillaJSONBugResponse &Data); + void CreateError(const FString &ErrorMessage); + + static const FString FormatQueryString(const TMap &QueryData); + + TArray ComponentsList; + TArray SeverityList; + TArray VersionsList; + TArray PlatformsList; + TArray OSList; +}; diff --git a/Source/Unrealzilla/Public/ServerREST.h b/Source/Unrealzilla/Public/ServerREST.h deleted file mode 100644 index a8b14fc..0000000 Binary files a/Source/Unrealzilla/Public/ServerREST.h and /dev/null differ