590 lines
20 KiB
C++
590 lines
20 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "JiraService.h"
|
|
#include "GenericPlatform/GenericPlatformProcess.h"
|
|
#include "Logic/DialogFactory.h"
|
|
#include "Logging/SubmitToolLog.h"
|
|
#include "SubmitToolUtils.h"
|
|
#include "Logic/TagService.h"
|
|
#include "Logic/PreflightService.h"
|
|
#include "Logic/Services/SubmitToolServiceProvider.h"
|
|
#include "Logic/Services/Interfaces/ISTSourceControlService.h"
|
|
#include "Logic/CredentialsService.h"
|
|
|
|
#include "HttpModule.h"
|
|
#include "Interfaces/IHttpResponse.h"
|
|
#include "Json.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "Parameters/SubmitToolParameters.h"
|
|
#include "JsonObjectConverter.h"
|
|
#include "Configuration/Configuration.h"
|
|
|
|
|
|
FJiraService::FJiraService(const FJiraParameters& InJiraSettings, const int32 InMaxResults, TWeakPtr<FSubmitToolServiceProvider> InServiceProvider) :
|
|
Definition(InJiraSettings),
|
|
MaxResults(InMaxResults),
|
|
ServiceProvider(InServiceProvider)
|
|
{
|
|
if(!Definition.ServerAddress.IsEmpty())
|
|
{
|
|
FetchJiraTickets(false);
|
|
LoadJiraIssues();
|
|
}
|
|
}
|
|
|
|
FJiraService::~FJiraService()
|
|
{
|
|
if(JiraRequest.IsValid())
|
|
{
|
|
JiraRequest->CancelRequest();
|
|
}
|
|
OnJiraIssuesRetrievedCallback.Unbind();
|
|
}
|
|
|
|
bool FJiraService::FetchJiraTickets(bool InForce)
|
|
{
|
|
TSharedPtr<FCredentialsService> CredentialsService = ServiceProvider.Pin()->GetService<FCredentialsService>();
|
|
if(CredentialsService->HasCredentials() && !Definition.ServerAddress.IsEmpty())
|
|
{
|
|
if (InForce || (JiraIssues.Num() == 0 && CredentialsService->AreCredentialsValid()))
|
|
{
|
|
QueryIssues();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void FJiraService::Reset()
|
|
{
|
|
JiraIssues.Reset();
|
|
}
|
|
|
|
void FJiraService::QueryIssues()
|
|
{
|
|
if(JiraRequest.IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
FHttpModule& HttpModule = FModuleManager::LoadModuleChecked<FHttpModule>("HTTP");
|
|
JiraRequest = HttpModule.Get().CreateRequest();
|
|
|
|
JiraRequest->OnProcessRequestComplete().BindRaw(this, &FJiraService::QueryIssues_HttpRequestComplete);
|
|
|
|
TSharedPtr<FCredentialsService> CredentialsService = ServiceProvider.Pin()->GetService<FCredentialsService>();
|
|
FString Url = FString::Format(TEXT("https://{0}/rest/api/2/search?maxResults={1}&jql=assignee={2}"), { Definition.ServerAddress, this->MaxResults, CredentialsService->GetUsername()});
|
|
|
|
JiraRequest->SetURL(Url);
|
|
JiraRequest->SetHeader(TEXT("Authorization"), TEXT("Basic ") + CredentialsService->GetEncodedLoginString());
|
|
JiraRequest->SetVerb(TEXT("GET"));
|
|
bOngoingRequest = true;
|
|
UE_LOG(LogSubmitToolDebug, Log, TEXT("Sending Jira request for tickets assigned to %s"), *CredentialsService->GetUsername())
|
|
JiraRequest->ProcessRequest();
|
|
}
|
|
|
|
void FJiraService::QueryIssues_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded)
|
|
{
|
|
JiraRequest = nullptr;
|
|
bOngoingRequest = false;
|
|
TSharedPtr<FCredentialsService> CredentialsService = ServiceProvider.Pin()->GetService<FCredentialsService>();
|
|
|
|
if (!bSucceeded)
|
|
{
|
|
UE_LOG(LogSubmitToolDebug, Error, TEXT("Unable to retrieve JIRA issues at the moment."))
|
|
return;
|
|
}
|
|
|
|
if (HttpResponse.IsValid())
|
|
{
|
|
if (EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode()))
|
|
{
|
|
CredentialsService->SetCredentialsValid(true);
|
|
UE_LOG(LogSubmitToolDebug, Log, TEXT("Successfully connected to Jira"));
|
|
|
|
FString ResponseStr = HttpResponse->GetContentAsString();
|
|
|
|
TSharedPtr<FJsonObject> RootJsonObject;
|
|
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(ResponseStr);
|
|
FJsonSerializer::Deserialize(Reader, RootJsonObject);
|
|
|
|
if (RootJsonObject.IsValid())
|
|
{
|
|
int32 Total;
|
|
if (RootJsonObject->TryGetNumberField(TEXT("total"), Total))
|
|
{
|
|
this->TotalIssues = Total;
|
|
}
|
|
|
|
const TArray<TSharedPtr<FJsonValue>>* Issues;
|
|
if (RootJsonObject->TryGetArrayField(TEXT("issues"), Issues))
|
|
{
|
|
UE_LOG(LogSubmitToolDebug, Log, TEXT("Retrieved %d issues for username %s"), Issues->Num(), *CredentialsService->GetUsername());
|
|
|
|
JiraIssues.Reset();
|
|
|
|
for (const TSharedPtr<FJsonValue>& ArrVal : *Issues)
|
|
{
|
|
if (!ArrVal.IsValid())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const TSharedPtr<FJsonObject>* IssueObject;
|
|
if (ArrVal->TryGetObject(IssueObject))
|
|
{
|
|
FJiraIssue Issue;
|
|
if(ParseJsonObject(IssueObject, Issue))
|
|
{
|
|
JiraIssues.Add(Issue.Key, Issue);
|
|
}
|
|
}
|
|
}
|
|
|
|
this->SaveJiraIssues();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogSubmitTool, Error, TEXT("Jira Request failed with error code %d, please make sure you're logging with the right credentials. if your Okta password expired recently, make sure you log into JIRA via browser at least once."), HttpResponse->GetResponseCode());
|
|
CredentialsService->SetCredentialsValid(false);
|
|
}
|
|
}
|
|
|
|
OnJiraIssuesRetrievedCallback.ExecuteIfBound(EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode()));
|
|
}
|
|
|
|
bool FJiraService::ParseJsonObject(const TSharedPtr<FJsonObject>* InJsonObject, FJiraIssue& OutJiraIssue) const
|
|
{
|
|
if(InJsonObject->IsValid())
|
|
{
|
|
FString Key{ "" };
|
|
FString Summary{ "" };
|
|
FString Description{ "" };
|
|
FString PriorityName{ "" };
|
|
FString StatusName{ "" };
|
|
FString IssueTypeName{ "" };
|
|
|
|
InJsonObject->Get()->TryGetStringField(TEXT("key"), Key);
|
|
|
|
const TSharedPtr<FJsonObject>* FieldsObject;
|
|
if(InJsonObject->Get()->TryGetObjectField(TEXT("fields"), FieldsObject))
|
|
{
|
|
if(FieldsObject->IsValid())
|
|
{
|
|
FieldsObject->Get()->TryGetStringField(TEXT("description"), Description);
|
|
FieldsObject->Get()->TryGetStringField(TEXT("summary"), Summary);
|
|
|
|
const TSharedPtr<FJsonObject>* PriorityObject;
|
|
if(FieldsObject->Get()->TryGetObjectField(TEXT("priority"), PriorityObject))
|
|
{
|
|
if(PriorityObject->IsValid())
|
|
{
|
|
PriorityObject->Get()->TryGetStringField(TEXT("name"), PriorityName);
|
|
}
|
|
}
|
|
|
|
const TSharedPtr<FJsonObject>* StatusObject;
|
|
if(FieldsObject->Get()->TryGetObjectField(TEXT("status"), StatusObject))
|
|
{
|
|
if(StatusObject->IsValid())
|
|
{
|
|
StatusObject->Get()->TryGetStringField(TEXT("name"), StatusName);
|
|
}
|
|
}
|
|
|
|
const TSharedPtr<FJsonObject>* IssueTypeObject;
|
|
if(FieldsObject->Get()->TryGetObjectField(TEXT("issuetype"), IssueTypeObject))
|
|
{
|
|
if(IssueTypeObject->IsValid())
|
|
{
|
|
IssueTypeObject->Get()->TryGetStringField(TEXT("name"), IssueTypeName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!Key.IsEmpty() && !this->JiraIssues.Contains(Key))
|
|
{
|
|
FString Link = Definition.ServerAddress + TEXT("/browse/") + Key;
|
|
OutJiraIssue = FJiraIssue(Key, Summary, Link, Description, PriorityName, StatusName, IssueTypeName);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
constexpr int JiraIssuesDatVersion = 1;
|
|
void FJiraService::SaveJiraIssues() const
|
|
{
|
|
FArchive* File = IFileManager::Get().CreateFileWriter(*GetJiraIssuesFilepath(), EFileWrite::FILEWRITE_EvenIfReadOnly);
|
|
|
|
if (File != nullptr)
|
|
{
|
|
int32 Version = JiraIssuesDatVersion;
|
|
*File << Version;
|
|
|
|
int32 Size = this->JiraIssues.Num();
|
|
*File << Size;
|
|
|
|
for (TPair<FString, FJiraIssue> Issue : this->JiraIssues)
|
|
{
|
|
FJiraIssue::StaticStruct()->SerializeBin(*File, &Issue.Value);
|
|
}
|
|
|
|
File->Close();
|
|
delete File;
|
|
File = nullptr;
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogSubmitTool, Warning, TEXT("Could not create file '%s'."), *GetJiraIssuesFilepath());
|
|
}
|
|
}
|
|
|
|
void FJiraService::LoadJiraIssues()
|
|
{
|
|
// do not load the issues if there is no credentials
|
|
if (!ServiceProvider.Pin()->GetService<FCredentialsService>()->HasCredentials())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (IFileManager::Get().FileExists(*GetJiraIssuesFilepath()))
|
|
{
|
|
FArchive* File = IFileManager::Get().CreateFileReader(*GetJiraIssuesFilepath());
|
|
|
|
if (File != nullptr)
|
|
{
|
|
this->JiraIssues.Reset();
|
|
|
|
int32 Version;
|
|
*File << Version;
|
|
|
|
// Check Versions here
|
|
if (Version != JiraIssuesDatVersion)
|
|
{
|
|
UE_LOG(LogSubmitToolDebug, Warning, TEXT("Unexpected Jira Issues Version, aborting issues loading."));
|
|
File->Close();
|
|
delete File;
|
|
File = nullptr;
|
|
return;
|
|
}
|
|
|
|
int32 Size = 0;
|
|
*File << Size;
|
|
|
|
for (int32 Idx = 0; Idx < Size; Idx++)
|
|
{
|
|
FJiraIssue Issue;
|
|
FJiraIssue::StaticStruct()->SerializeBin(*File, &Issue);
|
|
|
|
if (!this->JiraIssues.Contains(Issue.Key))
|
|
{
|
|
this->JiraIssues.Add(Issue.Key, Issue);
|
|
}
|
|
}
|
|
|
|
File->Close();
|
|
delete File;
|
|
File = nullptr;
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogSubmitTool, Warning, TEXT("Could not read file '%s'."), *GetJiraIssuesFilepath());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogSubmitToolDebug, Log, TEXT("File %s does not exists, no issues loaded"), *GetJiraIssuesFilepath())
|
|
}
|
|
}
|
|
|
|
const FString FJiraService::GetJiraIssuesFilepath() const
|
|
{
|
|
return FPaths::Combine(FSubmitToolUtils::GetLocalAppDataPath(), TEXT("SubmitTool"), TEXT("jira.issues.dat"));
|
|
}
|
|
|
|
void FJiraService::GetuserInfo()
|
|
{
|
|
FHttpModule& HttpModule = FModuleManager::LoadModuleChecked<FHttpModule>("HTTP");
|
|
FHttpRequestRef HttpRequest = HttpModule.Get().CreateRequest();
|
|
|
|
HttpRequest->OnProcessRequestComplete().BindRaw(this, &FJiraService::GetuserInfo_HttpRequestComplete);
|
|
|
|
FString Url = FString::Format(TEXT("https://{0}/rest/api/2/myself}"), { Definition.ServerAddress });
|
|
|
|
HttpRequest->SetURL(Url);
|
|
|
|
HttpRequest->SetHeader(TEXT("Authorization"), TEXT("Basic ") + ServiceProvider.Pin()->GetService<FCredentialsService>()->GetEncodedLoginString());
|
|
HttpRequest->SetVerb(TEXT("GET"));
|
|
HttpRequest->ProcessRequest();
|
|
}
|
|
|
|
void FJiraService::GetuserInfo_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded)
|
|
{
|
|
if (!bSucceeded)
|
|
{
|
|
UE_LOG(LogSubmitToolDebug, Error, TEXT("Unable to retrieve JIRA issues at the moment."))
|
|
return;
|
|
}
|
|
|
|
if (HttpResponse.IsValid())
|
|
{
|
|
if (EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode()))
|
|
{
|
|
ServiceProvider.Pin()->GetService<FCredentialsService>()->SetCredentialsValid(true);
|
|
FString ResponseStr = HttpResponse->GetContentAsString();
|
|
|
|
TSharedPtr<FJsonObject> RootJsonObject;
|
|
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(ResponseStr);
|
|
FJsonSerializer::Deserialize(Reader, RootJsonObject);
|
|
|
|
if (RootJsonObject.IsValid())
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FJiraService::GetIssueAndCreateServiceDeskRequest(const FString& Key, const FString& Description, const FString& SwarmURL, const FString& InCurrentStream, const TMap<FString, TSharedPtr<FIntegrationOptionBase>>& InIntegrationOptions, const FOnBooleanValueChanged OnComplete)
|
|
{
|
|
if(Key.IsEmpty() || Key.Equals(TEXT("none"), ESearchCase::IgnoreCase))
|
|
{
|
|
CreateServiceDeskRequest(TSharedPtr<FJsonObject>(), Description, SwarmURL, InCurrentStream, InIntegrationOptions, OnComplete);
|
|
return;
|
|
}
|
|
|
|
UE_LOG(LogSubmitTool, Log, TEXT("Requesting Information for linked Jira issue %s"), *Key);
|
|
// I set this up so that it gets information from the linked jira, but I think they changed their minds on what information is taken from the jira
|
|
FHttpModule& HttpModule = FModuleManager::LoadModuleChecked<FHttpModule>("HTTP");
|
|
FHttpRequestRef HttpRequest = HttpModule.Get().CreateRequest();
|
|
|
|
HttpRequest->OnProcessRequestComplete().BindLambda([=, this](FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded) {FJiraService::GetIssueAndCreateServiceDeskRequest_HttpRequestComplete(HttpRequest, HttpResponse, bSucceeded, Description, SwarmURL, InCurrentStream, InIntegrationOptions, OnComplete); });
|
|
|
|
FString Url = FString::Format(TEXT("https://{0}/rest/api/2/issue/{1}"), { Definition.ServerAddress, Key });
|
|
HttpRequest->SetURL(Url);
|
|
HttpRequest->SetHeader(TEXT("Authorization"), TEXT("Basic ") + ServiceProvider.Pin()->GetService<FCredentialsService>()->GetEncodedLoginString());
|
|
HttpRequest->SetVerb(TEXT("GET"));
|
|
|
|
HttpRequest->ProcessRequest();
|
|
}
|
|
|
|
void FJiraService::GetIssueAndCreateServiceDeskRequest_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded, const FString& Description, const FString& SwarmURL, const FString& InCurrentStream, const TMap<FString, TSharedPtr<FIntegrationOptionBase>>& InIntegrationOptions, const FOnBooleanValueChanged OnComplete)
|
|
{
|
|
TSharedPtr<FJsonObject> RootJsonObject;
|
|
if (!bSucceeded)
|
|
{
|
|
if(HttpResponse.IsValid())
|
|
{
|
|
UE_LOG(LogSubmitTool, Log, TEXT("Unable to retrieve Base JIRA issue information. Summary will be created with the current CL description instead. Failed with code %d"), HttpResponse->GetResponseCode());
|
|
UE_LOG(LogSubmitToolDebug, Log, TEXT("Unable to retrieve JIRA issue information. Summary will be created with the current CL description instead. Failed with code %d\nResponse: %s"), HttpResponse->GetResponseCode(), *HttpResponse->GetContentAsString());
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogSubmitTool, Warning, TEXT("Unable to retrieve Base JIRA issue information. Unknown failure"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(HttpResponse.IsValid())
|
|
{
|
|
if(EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode()))
|
|
{
|
|
FString ResponseStr = HttpResponse->GetContentAsString();
|
|
UE_LOG(LogSubmitToolDebug, Log, TEXT("Obtained information from Jira Issue %s"), *ResponseStr);
|
|
|
|
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(ResponseStr);
|
|
FJsonSerializer::Deserialize(Reader, RootJsonObject);
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogSubmitTool, Warning, TEXT("Unable to retrieve Base JIRA issue information."));
|
|
UE_LOG(LogSubmitToolDebug, Warning, TEXT("Unable to retrieve Base JIRA issue information. Failed with code %d\nResponse: %s"), HttpResponse->GetResponseCode(), *HttpResponse->GetContentAsString());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Call the function to actually create the service desk request with the required information
|
|
CreateServiceDeskRequest(RootJsonObject, Description, SwarmURL, InCurrentStream, InIntegrationOptions, OnComplete);
|
|
}
|
|
|
|
void FJiraService::CreateServiceDeskRequest(TSharedPtr<FJsonObject> InBaseJiraJsonObject, const FString& Description, const FString& SwarmURL, const FString& InCurrentStream, const TMap<FString, TSharedPtr<FIntegrationOptionBase>>& InIntegrationOptions, const FOnBooleanValueChanged OnComplete)
|
|
{
|
|
UE_LOG(LogSubmitTool, Log, TEXT("Requesting creation of Jira ServiceDesk ticket..."));
|
|
FHttpModule& HttpModule = FModuleManager::LoadModuleChecked<FHttpModule>("HTTP");
|
|
ServiceDeskRequest = HttpModule.Get().CreateRequest();
|
|
|
|
ServiceDeskRequest->OnProcessRequestComplete().BindLambda([this, OnComplete](FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded) { CreateServiceDeskRequest_HttpRequestComplete(HttpRequest, HttpResponse, bSucceeded, OnComplete); });
|
|
FString Url = FString::Format(TEXT("https://{0}/rest/servicedeskapi/request"), { Definition.ServerAddress });
|
|
|
|
ServiceDeskRequest->SetURL(Url);
|
|
ServiceDeskRequest->SetHeader(TEXT("Authorization"), FString::Format(TEXT("Basic {0}"), { Definition.ServiceDeskToken }));
|
|
ServiceDeskRequest->SetHeader(TEXT("Content-Type"), TEXT("application/json"));
|
|
ServiceDeskRequest->SetVerb(TEXT("POST"));
|
|
|
|
TSharedPtr<FJsonObject> RequestJson = MakeShared<FJsonObject>();
|
|
|
|
// These values should probably be put inside the .ini file
|
|
RequestJson->SetNumberField(TEXT("serviceDeskId"), Definition.ServiceDeskID);
|
|
RequestJson->SetNumberField(TEXT("requestTypeId"), Definition.RequestFormID);
|
|
|
|
|
|
TSharedPtr<FJsonObject> RequestFieldValuesJson = MakeShared<FJsonObject>();
|
|
|
|
if(InBaseJiraJsonObject.IsValid())
|
|
{
|
|
TSharedPtr<FJsonObject> BaseJiraFields = InBaseJiraJsonObject->GetObjectField(TEXT("fields"));
|
|
RequestFieldValuesJson->SetStringField(TEXT("summary"), BaseJiraFields->GetStringField(TEXT("summary")));
|
|
}
|
|
else
|
|
{
|
|
FString Summary = Description.Left(50).Replace(TEXT("\n"), TEXT(" ")).Replace(TEXT("\r"), TEXT(""));
|
|
RequestFieldValuesJson->SetStringField(TEXT("summary"), Summary);
|
|
|
|
}
|
|
|
|
RequestFieldValuesJson->SetStringField(TEXT("description"), Description);
|
|
|
|
if(!SwarmURL.IsEmpty() && !Definition.SwarmUrlField.IsEmpty())
|
|
{
|
|
RequestFieldValuesJson->SetStringField(Definition.SwarmUrlField, SwarmURL);
|
|
}
|
|
|
|
if(!InCurrentStream.IsEmpty() && !Definition.StreamField.IsEmpty())
|
|
{
|
|
RequestFieldValuesJson->SetStringField(Definition.StreamField, InCurrentStream);
|
|
}
|
|
|
|
if(!Definition.PreflightField.IsEmpty())
|
|
{
|
|
const FTag* PreflightTag = ServiceProvider.Pin()->GetService<FTagService>()->GetTagOfSubtype(TEXT("preflight"));
|
|
if (PreflightTag != nullptr && PreflightTag->GetValues().Num() > 0)
|
|
{
|
|
FString PreflightTagValue = PreflightTag->GetValues()[0];
|
|
|
|
if(!PreflightTagValue.IsEmpty())
|
|
{
|
|
if(!PreflightTagValue.Contains(TEXT("/job/")))
|
|
{
|
|
RequestFieldValuesJson->SetStringField(Definition.PreflightField, FString::Format(TEXT("{0}job/{1}"), { ServiceProvider.Pin()->GetService<FPreflightService>()->GetHordeServerAddress(), PreflightTagValue }));
|
|
}
|
|
else
|
|
{
|
|
RequestFieldValuesJson->SetStringField(Definition.PreflightField, PreflightTagValue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FString Requestor = FConfiguration::Substitute(TEXT("$(USER)"));
|
|
TSharedPtr<FUserData> LocalUserData = ServiceProvider.Pin()->GetService<ISTSourceControlService>()->GetUserDataFromCache(Requestor);
|
|
if (LocalUserData.IsValid())
|
|
{
|
|
Requestor = LocalUserData.Get()->Email;
|
|
}
|
|
|
|
RequestFieldValuesJson->SetStringField(Definition.RequestorField, Requestor);
|
|
|
|
for(const TPair<FString, TSharedPtr<FIntegrationOptionBase>>& Pair : InIntegrationOptions)
|
|
{
|
|
FString Value;
|
|
if(!Pair.Value->GetJiraValue(Value))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
TSharedPtr<FJsonObject> JiraObject = MakeShared<FJsonObject>();
|
|
TArray<TSharedPtr<FJsonValue>> JiraArrayObject;
|
|
JiraObject->SetStringField(TEXT("value"), Value);
|
|
|
|
switch(Pair.Value->FieldDefinition.JiraType)
|
|
{
|
|
case EJiraFieldType::Object:
|
|
RequestFieldValuesJson->SetObjectField(Pair.Value->FieldDefinition.Id, JiraObject);
|
|
break;
|
|
|
|
case EJiraFieldType::Array:
|
|
const TArray<TSharedPtr<FJsonValue>>* ExistingJiraArrayObjectPtr;
|
|
if(RequestFieldValuesJson->TryGetArrayField(Pair.Value->FieldDefinition.Id, ExistingJiraArrayObjectPtr))
|
|
{
|
|
JiraArrayObject = *ExistingJiraArrayObjectPtr;
|
|
}
|
|
|
|
JiraArrayObject.Add(MakeShared<FJsonValueObject>(JiraObject));
|
|
RequestFieldValuesJson->SetArrayField(Pair.Value->FieldDefinition.Id, JiraArrayObject);
|
|
break;
|
|
|
|
case EJiraFieldType::String:
|
|
RequestFieldValuesJson->SetStringField(Pair.Value->FieldDefinition.Id, Value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// JW: I think they decided that any jira tickets referenced in the changelist should be added as additional URLs
|
|
RequestJson->SetObjectField(TEXT("requestFieldValues"), RequestFieldValuesJson);
|
|
|
|
FString BodyString;
|
|
TSharedRef<TJsonWriter<TCHAR>> JsonWriter = TJsonWriterFactory<>::Create(&BodyString);
|
|
FJsonSerializer::Serialize(RequestJson.ToSharedRef(), JsonWriter);
|
|
|
|
UE_LOG(LogSubmitToolDebug, Log, TEXT("Create Jira request body:\n%s"), *BodyString);
|
|
|
|
ServiceDeskRequest->SetContentAsString(BodyString);
|
|
|
|
ServiceDeskRequest->ProcessRequest();
|
|
}
|
|
|
|
void FJiraService::CreateServiceDeskRequest_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded, const FOnBooleanValueChanged OnComplete)
|
|
{
|
|
if(!bSucceeded)
|
|
{
|
|
if(HttpResponse.IsValid())
|
|
{
|
|
UE_LOG(LogSubmitTool, Error, TEXT("Unable to create JIRA service desk. Failed with code %d\nResponse: %s"), HttpResponse->GetResponseCode(), *HttpResponse->GetContentAsString());
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogSubmitTool, Error, TEXT("Unable to create JIRA service desk. Unknown failure"));
|
|
}
|
|
OnComplete.ExecuteIfBound(false);
|
|
return;
|
|
}
|
|
|
|
if (HttpResponse.IsValid())
|
|
{
|
|
if (EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode()))
|
|
{
|
|
TSharedRef<TJsonReader<TCHAR>> Reader = TJsonReaderFactory<TCHAR>::Create(HttpResponse->GetContentAsString());
|
|
TSharedPtr<FJsonObject> JsonObj;
|
|
if(!FJsonSerializer::Deserialize(Reader, JsonObj))
|
|
{
|
|
UE_LOG(LogSubmitTool, Error, TEXT("Unable to deserialize swarm create response"));
|
|
return;
|
|
}
|
|
|
|
FString CreatedTicketId = JsonObj->GetStringField(TEXT("issueKey"));
|
|
FString WebLink;
|
|
const TSharedPtr<FJsonObject>* Links;
|
|
if(JsonObj->TryGetObjectField(TEXT("_links"), Links))
|
|
{
|
|
WebLink = Links->Get()->GetStringField(TEXT("web"));
|
|
}
|
|
|
|
// If the service desk request was created successfully
|
|
UE_LOG(LogSubmitTool, Log, TEXT("Jira service desk ticket creation was successful: %s %s"), *CreatedTicketId, *WebLink);
|
|
UE_LOG(LogSubmitToolDebug, Log, TEXT("Jira service desk ticket creation was successful\n%s"), *HttpResponse->GetContentAsString());
|
|
FDialogFactory::ShowInformationDialog(FText::FromString(TEXT("Integration Request Successful")), FText::FromString(TEXT("The Integration has sucessfully been requested!")));
|
|
OnComplete.ExecuteIfBound(true);
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogSubmitTool, Error, TEXT("Unable to create JIRA service desk. Failed with code %d\nResponse: %s"), HttpResponse->GetResponseCode(), *HttpResponse->GetContentAsString());
|
|
FDialogFactory::ShowInformationDialog(FText::FromString(TEXT("Integration Request FAILED")), FText::FromString(TEXT("Unable to create JIRA service desk ticket.\nPlease check the logs for more info.")));
|
|
OnComplete.ExecuteIfBound(false);
|
|
}
|
|
}
|
|
}
|