first commit

This commit is contained in:
lethanhsonvsp
2025-11-17 15:16:36 +07:00
commit a40d0921eb
17012 changed files with 2652386 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
using System;
using UnityEngine;
using Codice.CM.Common;
using Codice.LogWrapper;
using PlasticGui;
using Unity.PlasticSCM.Editor.WebApi;
namespace Unity.PlasticSCM.Editor.Configuration
{
internal static class AutoConfig
{
internal static TokenExchangeResponse PlasticCredentials(
string unityAccessToken,
string serverName)
{
var startTick = Environment.TickCount;
var tokenExchangeResponse = WebRestApiClient.PlasticScm.TokenExchange(unityAccessToken);
mLog.DebugFormat("TokenExchange time {0} ms", Environment.TickCount - startTick);
if (tokenExchangeResponse == null)
{
var warning = PlasticLocalization.GetString(PlasticLocalization.Name.TokenExchangeResponseNull);
mLog.Warn(warning);
Debug.LogWarning(warning);
return null;
}
if (tokenExchangeResponse.Error != null)
{
var warning = string.Format(
PlasticLocalization.GetString(PlasticLocalization.Name.TokenExchangeResponseError),
tokenExchangeResponse.Error.Message, tokenExchangeResponse.Error.ErrorCode);
mLog.ErrorFormat(warning);
Debug.LogWarning(warning);
return tokenExchangeResponse;
}
if (string.IsNullOrEmpty(tokenExchangeResponse.AccessToken))
{
var warning = string.Format(
PlasticLocalization.GetString(PlasticLocalization.Name.TokenExchangeAccessEmpty),
tokenExchangeResponse.User);
mLog.InfoFormat(warning);
Debug.LogWarning(warning);
return tokenExchangeResponse;
}
ClientConfiguration.Save(
serverName,
SEIDWorkingMode.SSOWorkingMode,
tokenExchangeResponse.User,
tokenExchangeResponse.AccessToken);
return tokenExchangeResponse;
}
static readonly ILog mLog = PlasticApp.GetLogger("AutoConfig");
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7c21251ff4b7d844292a388e81e47e59
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,93 @@
using Codice.Client.Common;
using Codice.CM.Common;
using PlasticGui;
using PlasticPipe.Certificates;
using Unity.PlasticSCM.Editor.UI;
using UnityEditor;
namespace Unity.PlasticSCM.Editor.Configuration
{
internal class ChannelCertificateUiImpl : IChannelCertificateUI
{
internal ChannelCertificateUiImpl()
{
}
CertOperationResult IChannelCertificateUI.AcceptNewServerCertificate(PlasticCertInfo serverCertificate)
{
return GetUserResponse(
PlasticLocalization.GetString(
PlasticLocalization.Name.NewCertificateTitle),
PlasticLocalization.GetString(
PlasticLocalization.Name.NewCertificateMessageUnityVCS),
serverCertificate);
}
CertOperationResult IChannelCertificateUI.AcceptChangedServerCertificate(PlasticCertInfo serverCertificate)
{
return GetUserResponse(
PlasticLocalization.GetString(
PlasticLocalization.Name.ExistingCertificateChangedTitle),
PlasticLocalization.GetString(
PlasticLocalization.Name.ExistingCertificateChangedMessageUnityVCS),
serverCertificate);
}
bool IChannelCertificateUI.AcceptInvalidHostname(string certHostname, string serverHostname)
{
bool result = false;
GUIActionRunner.RunGUIAction(delegate {
result = EditorUtility.DisplayDialog(
PlasticLocalization.GetString(
PlasticLocalization.Name.InvalidCertificateHostnameTitle),
PlasticLocalization.GetString(
PlasticLocalization.Name.InvalidCertificateHostnameMessage,
certHostname, serverHostname),
PlasticLocalization.GetString(PlasticLocalization.Name.YesButton),
PlasticLocalization.GetString(PlasticLocalization.Name.NoButton));
});
return result;
}
CertOperationResult GetUserResponse(
string title, string message, PlasticCertInfo serverCertificate)
{
GuiMessage.GuiMessageResponseButton result =
GuiMessage.GuiMessageResponseButton.Neutral;
GUIActionRunner.RunGUIAction(delegate {
result = GuiMessage.ShowQuestion(
title,
GetCertificateMessageString(message, serverCertificate),
PlasticLocalization.GetString(PlasticLocalization.Name.YesButton),
PlasticLocalization.GetString(PlasticLocalization.Name.CancelButton),
PlasticLocalization.GetString(PlasticLocalization.Name.NoButton));
});
switch (result)
{
case GuiMessage.GuiMessageResponseButton.Positive:
return CertOperationResult.AddToStore;
case GuiMessage.GuiMessageResponseButton.Negative:
return CertOperationResult.DoNotAddToStore;
case GuiMessage.GuiMessageResponseButton.Neutral:
return CertOperationResult.Cancel;
default:
return CertOperationResult.Cancel;
}
}
string GetCertificateMessageString(string message, PlasticCertInfo serverCertificate)
{
return string.Format(message,
CertificateUi.GetCnField(serverCertificate.Subject),
CertificateUi.GetCnField(serverCertificate.Issuer),
serverCertificate.Format,
serverCertificate.ExpirationDateString,
serverCertificate.KeyAlgorithm,
serverCertificate.CertHashString);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 628bc1ed591aa164ab9124ac22e02d9a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,82 @@
using Codice.Client.Common;
using Codice.Client.Common.Servers;
using Codice.CM.Common;
using Codice.Utils;
using PlasticGui;
using PlasticGui.Configuration.TeamEdition;
using PlasticGui.WorkspaceWindow.Home;
namespace Unity.PlasticSCM.Editor.Configuration
{
internal static class ClientConfiguration
{
internal static void Save(
string server,
SEIDWorkingMode workingMode,
string user,
string accessToken
)
{
SetupUnityEditionToken.CreateCloudEditionTokenIfNeeded();
// We observed that UserAccounts.SaveAccount skips the client.conf update when there is auth info saved.
// However, we want to make sure the configuration is always updated, so we add the skipped saving.
if (ClientConfig.HasAuthInfoConfigured())
{
ConfigurationActions.SaveClientConfig(
server,
workingMode,
user,
accessToken,
null);
}
// This creates the client.conf if needed but doesn't overwrite it if it exists already,
// and it also updates the profiles.conf and tokens.conf with the new AccessToken
UserAccounts.SaveAccount(
server,
user,
accessToken,
workingMode,
null,
null,
null);
SaveDefaultCloudServer(server);
}
// Save the Default Server in the config files of all clients, so they are already configured.
// Avoids having the Desktop application asking the user again later.
static void SaveDefaultCloudServer(string cloudServer)
{
SaveCloudServer.ToPlasticGuiConfig(cloudServer);
SaveCloudServer.ToPlasticGuiConfigFile(
cloudServer, GetPlasticConfigFileToSaveOrganization());
SaveCloudServer.ToPlasticGuiConfigFile(
cloudServer, GetGluonConfigFileToSaveOrganization());
KnownServers.ServersFromCloud.InitializeForWindows(
PlasticGuiConfig.Get().Configuration.DefaultCloudServer);
}
static string GetPlasticConfigFileToSaveOrganization()
{
if (PlatformIdentifier.IsMac())
{
return "macgui.conf";
}
return "plasticgui.conf";
}
static string GetGluonConfigFileToSaveOrganization()
{
if (PlatformIdentifier.IsMac())
{
return "gluon.conf";
}
return "gameui.conf";
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: edf8d7a4bab748b4a77c198d33394e58
timeCreated: 1726212017

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0b593e05bcd27824eb229f8c6b20e13b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 86d9084a265d35f4db65c4e31e0b6769
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,146 @@
using System;
using UnityEditor;
using UnityEngine;
using Codice.Client.Common.Threading;
using Codice.CM.Common;
using Codice.LogWrapper;
using PlasticGui;
using Unity.PlasticSCM.Editor.UI;
using Unity.PlasticSCM.Editor.WebApi;
namespace Unity.PlasticSCM.Editor.Configuration.CloudEdition.Welcome
{
internal class AutoLogin
{
internal enum State : byte
{
Off = 0,
Started = 1,
Running = 2,
ResponseInit = 3,
ResponseEnd = 4,
ResponseSuccess = 5,
ErrorNoToken = 20,
ErrorTokenException = 21,
ErrorResponseNull = 22,
ErrorResponseError = 23,
ErrorTokenEmpty = 24,
}
internal void Run()
{
mPlasticWindow = GetPlasticWindow();
if (!string.IsNullOrEmpty(CloudProjectSettings.accessToken))
{
mLog.Debug("Run");
ExchangeTokensAndJoinOrganizationInThreadWaiter(CloudProjectSettings.accessToken);
return;
}
mPlasticWindow.GetWelcomeView().autoLoginState = AutoLogin.State.ErrorNoToken;
}
void ExchangeTokensAndJoinOrganizationInThreadWaiter(string unityAccessToken)
{
int ini = Environment.TickCount;
TokenExchangeResponse tokenExchangeResponse = null;
IThreadWaiter waiter = ThreadWaiter.GetWaiter(10);
waiter.Execute(
/*threadOperationDelegate*/ delegate
{
mPlasticWindow.GetWelcomeView().autoLoginState = AutoLogin.State.ResponseInit;
tokenExchangeResponse = WebRestApiClient.PlasticScm.TokenExchange(unityAccessToken);
},
/*afterOperationDelegate*/ delegate
{
mLog.DebugFormat(
"TokenExchange time {0} ms",
Environment.TickCount - ini);
if (waiter.Exception != null)
{
mPlasticWindow.GetWelcomeView().autoLoginState = AutoLogin.State.ErrorTokenException;
ExceptionsHandler.LogException(
"TokenExchangeSetting",
waiter.Exception);
Debug.LogWarning(waiter.Exception.Message);
return;
}
if (tokenExchangeResponse == null)
{
mPlasticWindow.GetWelcomeView().autoLoginState = AutoLogin.State.ErrorResponseNull;
var warning = PlasticLocalization.GetString(PlasticLocalization.Name.TokenExchangeResponseNull);
mLog.Warn(warning);
Debug.LogWarning(warning);
return;
}
if (tokenExchangeResponse.Error != null)
{
mPlasticWindow.GetWelcomeView().autoLoginState = AutoLogin.State.ErrorResponseError;
var warning = string.Format(
PlasticLocalization.GetString(PlasticLocalization.Name.TokenExchangeResponseError),
tokenExchangeResponse.Error.Message, tokenExchangeResponse.Error.ErrorCode);
mLog.ErrorFormat(warning);
Debug.LogWarning(warning);
return;
}
if (string.IsNullOrEmpty(tokenExchangeResponse.AccessToken))
{
mPlasticWindow.GetWelcomeView().autoLoginState = AutoLogin.State.ErrorTokenEmpty;
var warning = string.Format(
PlasticLocalization.GetString(PlasticLocalization.Name.TokenExchangeAccessEmpty),
tokenExchangeResponse.User);
mLog.InfoFormat(warning);
Debug.LogWarning(warning);
return;
}
mPlasticWindow.GetWelcomeView().autoLoginState = AutoLogin.State.ResponseEnd;
Credentials credentials = new Credentials(
new SEID(tokenExchangeResponse.User, false, tokenExchangeResponse.AccessToken),
SEIDWorkingMode.SSOWorkingMode);
ShowOrganizationsPanel(credentials);
});
}
void ShowOrganizationsPanel(Credentials credentials)
{
mPlasticWindow = GetPlasticWindow();
mPlasticWindow.GetWelcomeView().autoLoginState = AutoLogin.State.ResponseSuccess;
CloudEditionWelcomeWindow.ShowWindow(
PlasticGui.Plastic.WebRestAPI, null, true);
mCloudEditionWelcomeWindow = CloudEditionWelcomeWindow.GetWelcomeWindow();
mCloudEditionWelcomeWindow.GetOrganizations(credentials);
mCloudEditionWelcomeWindow.Focus();
}
static PlasticWindow GetPlasticWindow()
{
var windows = Resources.FindObjectsOfTypeAll<PlasticWindow>();
PlasticWindow plasticWindow = windows.Length > 0 ? windows[0] : null;
if (plasticWindow == null)
plasticWindow = ShowWindow.Plastic();
return plasticWindow;
}
PlasticWindow mPlasticWindow;
CloudEditionWelcomeWindow mCloudEditionWelcomeWindow;
static readonly ILog mLog = PlasticApp.GetLogger("AutoLogin");
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 806bdb4f911275c4ca1ee81fde4b4d4f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,212 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using Codice.Client.Common;
using Codice.Client.Common.Authentication;
using Codice.Client.Common.Connection;
using Codice.Client.Common.WebApi;
using Codice.Client.Common.WebApi.Responses;
using Codice.CM.Common;
using Codice.LogWrapper;
using PlasticGui;
using Unity.PlasticSCM.Editor.UI.Progress;
using Unity.PlasticSCM.Editor.Views.Welcome;
namespace Unity.PlasticSCM.Editor.Configuration.CloudEdition.Welcome
{
internal interface IWelcomeWindowNotify
{
void ProcessLoginResponseWithOrganizations(Credentials credentials, List<string> cloudServers);
void Back();
}
internal class CloudEditionWelcomeWindow :
EditorWindow, IWelcomeWindowNotify, OAuthSignIn.INotify, GetCloudOrganizations.INotify
{
internal static void ShowWindow(
IPlasticWebRestApi restApi,
WelcomeView welcomeView,
bool autoLogin = false)
{
sRestApi = restApi;
sAutoLogin = autoLogin;
CloudEditionWelcomeWindow window = GetWindow<CloudEditionWelcomeWindow>();
window.titleContent = new GUIContent(
PlasticLocalization.GetString(PlasticLocalization.Name.SignInToUnityVCS));
window.minSize = window.maxSize = new Vector2(450, 300);
window.mWelcomeView = welcomeView;
window.Show();
}
internal static CloudEditionWelcomeWindow GetWelcomeWindow()
{
return GetWindow<CloudEditionWelcomeWindow>();
}
internal void CancelJoinOrganization()
{
if (sAutoLogin)
{
mLog.Debug("CancelJoinOrganization");
GetWindow<PlasticWindow>().GetWelcomeView().autoLoginState = AutoLogin.State.Started;
}
}
internal void ReplaceRootPanel(VisualElement panel)
{
rootVisualElement.Clear();
rootVisualElement.Add(panel);
}
internal SignInPanel GetSignInPanel()
{
return mSignInPanel;
}
internal void GetOrganizations(Credentials credentials)
{
mCredentials = credentials;
GetCloudOrganizations.GetOrganizationsInThreadWaiter(
mCredentials.User.Data,
mCredentials.User.Password,
new ProgressControlsForDialogs(),
this,
sRestApi,
CmConnection.Get());
}
void ShowOrganizationsPanel(
Credentials credentials, List<string> cloudServers, string errorMessage)
{
mLog.DebugFormat("ShowOrganizationsPanel({0}, {1} orgs) {2}",
credentials.Mode, cloudServers.Count, errorMessage);
mOrganizationPanel = new OrganizationPanel(
this,
cloudServers,
errorMessage,
GetWindowTitle(),
joinedOrganization =>
{
mLog.DebugFormat("JoinedOrganization: {0}", joinedOrganization);
ClientConfiguration.Save(
joinedOrganization,
credentials.Mode,
credentials.User.Data,
credentials.User.Password);
});
ReplaceRootPanel(mOrganizationPanel);
}
string GetWindowTitle()
{
return PlasticLocalization.Name.SignInToUnityVCS.GetString();
}
void OnEnable()
{
BuildComponents();
}
void OnDestroy()
{
Dispose();
if (mWelcomeView != null)
mWelcomeView.OnUserClosedConfigurationWindow();
}
void Dispose()
{
if (mSignInPanel != null)
mSignInPanel.Dispose();
if (mOrganizationPanel != null)
mOrganizationPanel.Dispose();
}
// Used by WaitingSignInPanel
void OAuthSignIn.INotify.SignedInForCloud(
string chosenProviderName, Credentials credentials)
{
mLog.Debug("SignedInForCloud");
GetOrganizations(credentials);
}
void OAuthSignIn.INotify.SignedInForOnPremise(
string server, string proxy, Credentials credentials)
{
// Won't run
}
void OAuthSignIn.INotify.Cancel(string message)
{
mLog.Debug("Cancel");
Focus();
}
void GetCloudOrganizations.INotify.CloudOrganizationsRetrieved(List<string> cloudServers)
{
ShowOrganizationsPanel(mCredentials, cloudServers, errorMessage: null);
}
void GetCloudOrganizations.INotify.Error(ErrorResponse.ErrorFields error)
{
ShowOrganizationsPanel(mCredentials, cloudServers: null, errorMessage: error.Message);
}
void IWelcomeWindowNotify.ProcessLoginResponseWithOrganizations(
Credentials credentials, List<string> cloudServers)
{
mLog.DebugFormat("ProcessLoginResponseWithOrganizations: {0} orgs", cloudServers.Count);
mCredentials = credentials;
ShowOrganizationsPanel(mCredentials, cloudServers, errorMessage: null);
}
void IWelcomeWindowNotify.Back()
{
rootVisualElement.Clear();
rootVisualElement.Add(mSignInPanel);
}
void BuildComponents()
{
VisualElement root = rootVisualElement;
root.Clear();
mSignInPanel = new SignInPanel(this, sRestApi);
titleContent = new GUIContent(GetWindowTitle());
root.Add(mSignInPanel);
if (sAutoLogin)
{
mSignInPanel.SignInWithUnityIdButtonAutoLogin();
}
}
string mUserName;
Credentials mCredentials;
OrganizationPanel mOrganizationPanel;
SignInPanel mSignInPanel;
WelcomeView mWelcomeView;
static IPlasticWebRestApi sRestApi;
static bool sAutoLogin = false;
static readonly ILog mLog = PlasticApp.GetLogger("CloudEditionWelcomeWindow");
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0ad54f9e1bb701142b116d0d1ed98437
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,220 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
using PlasticGui;
using PlasticGui.WorkspaceWindow.Home;
using Unity.PlasticSCM.Editor.UI;
using Unity.PlasticSCM.Editor.UI.UIElements;
namespace Unity.PlasticSCM.Editor.Configuration.CloudEdition.Welcome
{
internal class OrganizationPanel : VisualElement
{
internal OrganizationPanel(
CloudEditionWelcomeWindow parentWindow,
List<string> cloudServers,
string errorMessage,
string title,
Action<string> organizationJoinedAction)
{
mParentWindow = parentWindow;
mPrefetchedCloudServers = cloudServers;
mPrefetchedErrorMessage = errorMessage;
mOnOrganizationJoined = organizationJoinedAction;
InitializeLayoutAndStyles();
BuildComponents(title);
OnEditorActivated();
}
internal void Dispose()
{
if (!mOrganizationJoined)
mParentWindow.CancelJoinOrganization();
if (mJoinSingleOrganizationButton != null)
mJoinSingleOrganizationButton.clicked -= JoinOrganizationButton_clicked;
if (mJoinMultipleOrganizationsButton != null)
mJoinMultipleOrganizationsButton.clicked -= JoinOrganizationButton_clicked;
if (mOpenUnityDashboardButton != null)
mOpenUnityDashboardButton.clicked -= OpenUnityDashboardButton_clicked;
}
void OnEditorActivated()
{
if (!string.IsNullOrEmpty(mPrefetchedErrorMessage))
{
mProgressControls.ShowError(mPrefetchedErrorMessage);
return;
}
if (mPrefetchedCloudServers == null || mPrefetchedCloudServers.Count == 0)
{
mProgressControls.ShowError("Could not find cloud organizations");
return;
}
List<OrganizationInfo> organizationsInfo =
OrganizationsInformation.FromServersOrdered(mPrefetchedCloudServers);
ProcessOrganizations(organizationsInfo);
}
void ProcessOrganizations(List<OrganizationInfo> organizations)
{
this.Query<VisualElement>("noOrganization").Collapse();
this.Query<VisualElement>("joinSingleOrganization").Collapse();
this.Query<VisualElement>("joinMultipleOrganizations").Collapse();
if (organizations.Count == 0)
{
BuildNoOrganizationSection();
mOpenUnityDashboardButton = this.Q<Button>("openUnityDashboardButton");
mOpenUnityDashboardButton.clicked += OpenUnityDashboardButton_clicked;
return;
}
if (organizations.Count == 1)
{
BuildSingleOrganizationSection(organizations.First());
mJoinSingleOrganizationButton = this.Q<Button>("joinSingleOrganizationButton");
mJoinSingleOrganizationButton.clicked += JoinOrganizationButton_clicked;
return;
}
BuildMultipleOrganizationsSection(organizations);
mJoinMultipleOrganizationsButton = this.Q<Button>("joinMultipleOrganizationsButton");
mJoinMultipleOrganizationsButton.clicked += JoinOrganizationButton_clicked;
mOrganizationToJoin = organizations.First().Server;
}
void InitializeLayoutAndStyles()
{
this.LoadLayout(typeof(OrganizationPanel).Name);
this.LoadStyle(typeof(OrganizationPanel).Name);
}
void JoinOrganizationButton_clicked()
{
mOnOrganizationJoined(mOrganizationToJoin);
mOrganizationJoined = true;
// TODO: Closing the window for now. Need to connect this event to the main on boarding workflow.
mParentWindow.Close();
}
void OpenUnityDashboardButton_clicked()
{
Application.OpenURL(UnityUrl.UnityDashboard.Plastic.Get());
}
void BuildComponents(string title)
{
mParentWindow.titleContent = new UnityEngine.GUIContent(title);
mProgressControls = new ProgressControlsForDialogs(null);
mProgressContainer = this.Q<VisualElement>("progressContainer");
mProgressContainer.Add((VisualElement)mProgressControls);
}
void BuildSingleOrganizationSection(OrganizationInfo organizationInfo)
{
this.SetControlText<Label>("confirmationMessage",
PlasticLocalization.Name.JoinOrganizationTitle);
mOrganizationToJoin = organizationInfo.Server;
this.Query<VisualElement>("joinSingleOrganization").Show();
this.SetControlText<Label>("joinSingleOrganizationLabel",
PlasticLocalization.Name.YouBelongToOrganization, organizationInfo.DisplayName);
this.SetControlText<Button>("joinSingleOrganizationButton",
PlasticLocalization.Name.JoinButton);
}
void BuildMultipleOrganizationsSection(List<OrganizationInfo> organizations)
{
organizations.Sort((x, y) =>
string.Compare(x.DisplayName, y.DisplayName, StringComparison.CurrentCulture));
this.SetControlText<Label>("confirmationMessage",
PlasticLocalization.Name.JoinOrganizationTitle);
this.Query<VisualElement>("joinMultipleOrganizations").Show();
this.SetControlText<Label>("joinMultipleOrganizationsLabel",
PlasticLocalization.Name.YouBelongToSeveralOrganizations);
VisualElement organizationDropdown = this.Query<VisualElement>("organizationDropdown");
ToolbarMenu toolbarMenu = new ToolbarMenu
{
text = organizations.First().DisplayName,
};
foreach (OrganizationInfo organization in organizations)
{
string organizationDisplayName = organization.DisplayName;
toolbarMenu.menu.AppendAction(organizationDisplayName, x =>
{
toolbarMenu.text = organizationDisplayName;
mOrganizationToJoin = organization.Server;
}, DropdownMenuAction.AlwaysEnabled);
organizationDropdown.Add(toolbarMenu);
}
this.SetControlText<Button>("joinMultipleOrganizationsButton",
PlasticLocalization.Name.JoinButton);
}
void BuildNoOrganizationSection()
{
this.SetControlText<Label>("confirmationMessage",
PlasticLocalization.Name.CreateOrganizationTitle);
this.Query<VisualElement>("noOrganization").Show();
this.SetControlImage("iconUnity",
Images.Name.ButtonSsoSignInUnity);
this.SetControlText<Label>("noOrganizationLabel",
PlasticLocalization.Name.ClickButtonBelowToCreateOrg);
this.SetControlText<Button>("openUnityDashboardButton",
PlasticLocalization.Name.MainSidebarOpenUnityDashboardItem);
}
string mOrganizationToJoin = "";
bool mOrganizationJoined;
Button mJoinSingleOrganizationButton;
Button mJoinMultipleOrganizationsButton;
Button mOpenUnityDashboardButton;
VisualElement mProgressContainer;
IProgressControls mProgressControls;
readonly CloudEditionWelcomeWindow mParentWindow;
readonly List<string> mPrefetchedCloudServers;
readonly string mPrefetchedErrorMessage;
readonly Action<string> mOnOrganizationJoined;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 615ff93ab52eb8242a9194d4f711676f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,156 @@
using System;
using UnityEngine;
using UnityEngine.UIElements;
using Codice.Client.Common;
using Codice.Client.Common.Authentication;
using Codice.Client.Common.WebApi;
using Codice.CM.Common;
using PlasticGui;
using Unity.PlasticSCM.Editor.UI;
using Unity.PlasticSCM.Editor.UI.UIElements;
using PlasticGui.Configuration.CloudEdition.Welcome;
namespace Unity.PlasticSCM.Editor.Configuration.CloudEdition.Welcome
{
internal class SignInPanel : VisualElement
{
internal SignInPanel(
CloudEditionWelcomeWindow parentWindow, IPlasticWebRestApi restApi)
{
mParentWindow = parentWindow;
mRestApi = restApi;
InitializeLayoutAndStyles();
BuildComponents();
}
internal void Dispose()
{
mSignInWithUnityIdButton.clicked -= SignInWithUnityIdButton_Clicked;
mSignInWithEmailButton.clicked -= SignInWithEmailButton_Clicked;
mPrivacyPolicyStatementButton.clicked -= PrivacyPolicyStatementButton_Clicked;
mSignUpButton.clicked -= SignUpButton_Clicked;
if (mSignInWithEmailPanel != null)
mSignInWithEmailPanel.Dispose();
if (mWaitingSignInPanel != null)
mWaitingSignInPanel.Dispose();
}
void SignInWithEmailButton_Clicked()
{
mSignInWithEmailPanel = new SignInWithEmailPanel(mParentWindow, mRestApi);
mParentWindow.ReplaceRootPanel(mSignInWithEmailPanel);
}
void SignUpButton_Clicked()
{
Application.OpenURL(UnityUrl.DevOps.GetSignUp());
}
internal void SignInWithUnityIdButton_Clicked()
{
mWaitingSignInPanel = new WaitingSignInPanel(
mParentWindow, mParentWindow, mRestApi);
mParentWindow.ReplaceRootPanel(mWaitingSignInPanel);
Guid state = Guid.NewGuid();
mWaitingSignInPanel.OAuthSignIn(
GetAuthProviders.GetUnityIdAuthProvider(string.Empty, state),
GetCredentialsFromState.Build(
string.Empty, state, SEIDWorkingMode.SSOWorkingMode, mRestApi));
}
internal void SignInWithUnityIdButtonAutoLogin()
{
mWaitingSignInPanel = new WaitingSignInPanel(
mParentWindow, mParentWindow, mRestApi);
mWaitingSignInPanel.OnAutoLogin();
mParentWindow.ReplaceRootPanel(mWaitingSignInPanel);
}
void PrivacyPolicyStatementButton_Clicked()
{
Application.OpenURL(UnityUrl.DevOps.GetPrivacyPolicy());
}
void BuildComponents()
{
BuildSignUpArea();
BuildSignInUnityIdArea();
BuildSignInEmailArea();
BuildPrivatePolicyArea();
}
void BuildPrivatePolicyArea()
{
this.SetControlText<Label>(
"privacyStatementText",
PlasticLocalization.Name.PrivacyStatementText,
PlasticLocalization.GetString(PlasticLocalization.Name.PrivacyStatement));
mPrivacyPolicyStatementButton = this.Query<Button>("privacyStatement");
mPrivacyPolicyStatementButton.text = PlasticLocalization.Name.PrivacyStatement.GetString();
mPrivacyPolicyStatementButton.clicked += PrivacyPolicyStatementButton_Clicked;
}
void BuildSignInEmailArea()
{
this.SetControlImage(
"iconEmail",
Images.Name.ButtonSsoSignInEmail);
mSignInWithEmailButton = this.Query<Button>("emailButton");
mSignInWithEmailButton.text = PlasticLocalization.Name.SignInWithEmail.GetString();
mSignInWithEmailButton.clicked += SignInWithEmailButton_Clicked;
}
void BuildSignInUnityIdArea()
{
this.SetControlImage(
"iconUnity",
Images.Name.ButtonSsoSignInUnity);
mSignInWithUnityIdButton = this.Query<Button>("unityIDButton");
mSignInWithUnityIdButton.text = PlasticLocalization.Name.SignInWithUnityID.GetString();
mSignInWithUnityIdButton.clicked += SignInWithUnityIdButton_Clicked;
}
void BuildSignUpArea()
{
Label signUpLabel = this.Query<Label>("signUpLabel");
signUpLabel.text = PlasticLocalization.Name.LoginOrSignUp.GetString();
mSignUpButton = this.Query<Button>("signUpButton");
mSignUpButton.text = PlasticLocalization.Name.SignUpButton.GetString();
mSignUpButton.clicked += SignUpButton_Clicked;
}
void InitializeLayoutAndStyles()
{
AddToClassList("grow");
this.LoadLayout(typeof(SignInPanel).Name);
this.LoadStyle(typeof(SignInPanel).Name);
}
SignInWithEmailPanel mSignInWithEmailPanel;
WaitingSignInPanel mWaitingSignInPanel;
Button mSignInWithUnityIdButton;
Button mSignInWithEmailButton;
Button mPrivacyPolicyStatementButton;
Button mSignUpButton;
readonly CloudEditionWelcomeWindow mParentWindow;
readonly IPlasticWebRestApi mRestApi;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bba806fdb20eb5a4da6cc856323d6273
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,184 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
using Codice.Client.Common;
using Codice.Client.Common.Authentication;
using Codice.Client.Common.WebApi;
using Codice.Client.Common.WebApi.Responses;
using Codice.CM.Common;
using PlasticGui;
using PlasticGui.Configuration.CloudEdition.Welcome;
using PlasticGui.Configuration.CloudEdition;
using Unity.PlasticSCM.Editor.UI.UIElements;
namespace Unity.PlasticSCM.Editor.Configuration.CloudEdition.Welcome
{
internal class SignInWithEmailPanel : VisualElement, GetCloudOrganizations.INotify
{
internal SignInWithEmailPanel(
IWelcomeWindowNotify notify,
IPlasticWebRestApi restApi)
{
mNotify = notify;
mRestApi = restApi;
InitializeLayoutAndStyles();
BuildComponents();
}
internal void Dispose()
{
mSignInButton.clicked -= SignInButton_Clicked;
mBackButton.clicked -= BackButton_Clicked;
mSignUpButton.clicked -= SignUpButton_Clicked;
}
void ShowSignUpNeeded()
{
mSignUpNeededNotificationContainer.Show();
}
void HideSignUpNeeded()
{
mSignUpNeededNotificationContainer.Collapse();
}
void GetCloudOrganizations.INotify.CloudOrganizationsRetrieved(
List<string> cloudServers)
{
mNotify.ProcessLoginResponseWithOrganizations(mCredentials, cloudServers);
}
void GetCloudOrganizations.INotify.Error(
ErrorResponse.ErrorFields error)
{
if (error.ErrorCode == ErrorCodes.UserNotFound)
{
ShowSignUpNeeded();
return;
}
HideSignUpNeeded();
((IProgressControls)mProgressControls).ShowError(error.Message);
}
void CleanNotificationLabels()
{
mEmailNotificationLabel.text = string.Empty;
mPasswordNotificationLabel.text = string.Empty;
HideSignUpNeeded();
}
void SignInButton_Clicked()
{
CleanNotificationLabels();
ValidateEmailAndPassword.ValidationResult validationResult;
if (!ValidateEmailAndPassword.IsValid(mEmailField.text, mPasswordField.text, out validationResult))
{
ShowValidationResult(validationResult);
return;
}
mCredentials = new Credentials(
new SEID(mEmailField.text, false, mPasswordField.text),
SEIDWorkingMode.LDAPWorkingMode);
GetCloudOrganizations.GetOrganizationsInThreadWaiter(
mCredentials.User.Data,
mCredentials.User.Password,
mProgressControls,
this,
mRestApi,
CmConnection.Get());
}
void ShowValidationResult(
ValidateEmailAndPassword.ValidationResult validationResult)
{
if (validationResult.UserError != null)
{
mEmailNotificationLabel.text = validationResult.UserError;
}
if (validationResult.PasswordError != null)
{
mPasswordNotificationLabel.text = validationResult.PasswordError;
}
}
void BackButton_Clicked()
{
mNotify.Back();
}
void InitializeLayoutAndStyles()
{
this.LoadLayout(typeof(SignInWithEmailPanel).Name);
this.LoadStyle(typeof(SignInWithEmailPanel).Name);
}
void SignUpButton_Clicked()
{
Application.OpenURL(UnityUrl.DevOps.GetSignUp());
}
void BuildComponents()
{
mEmailField = this.Q<TextField>("email");
mPasswordField = this.Q<TextField>("password");
mEmailNotificationLabel = this.Q<Label>("emailNotification");
mPasswordNotificationLabel = this.Q<Label>("passwordNotification");
mSignInButton = this.Q<Button>("signIn");
mBackButton = this.Q<Button>("back");
mSignUpButton = this.Q<Button>("signUpButton");
mProgressContainer = this.Q<VisualElement>("progressContainer");
mSignUpNeededNotificationContainer = this.Q<VisualElement>("signUpNeededNotificationContainer");
mSignInButton.clicked += SignInButton_Clicked;
mBackButton.clicked += BackButton_Clicked;
mSignUpButton.clicked += SignUpButton_Clicked;
mEmailField.FocusOnceLoaded();
mProgressControls = new ProgressControlsForDialogs(new VisualElement[] { mSignInButton });
mProgressContainer.Add((VisualElement)mProgressControls);
this.SetControlText<Label>("signInLabel",
PlasticLocalization.Name.SignInWithEmail);
this.SetControlLabel<TextField>("email",
PlasticLocalization.Name.Email);
this.SetControlLabel<TextField>("password",
PlasticLocalization.Name.Password);
this.SetControlText<Button>("signIn",
PlasticLocalization.Name.SignIn);
this.SetControlText<Button>("back",
PlasticLocalization.Name.BackButton);
this.SetControlText<Label>("signUpNeededNotificationLabel",
PlasticLocalization.Name.SignUpNeededNoArgs);
this.SetControlText<Button>("signUpButton",
PlasticLocalization.Name.SignUp);
}
TextField mEmailField;
TextField mPasswordField;
Label mEmailNotificationLabel;
Label mPasswordNotificationLabel;
Button mSignInButton;
Button mBackButton;
Button mSignUpButton;
VisualElement mProgressContainer;
VisualElement mSignUpNeededNotificationContainer;
Credentials mCredentials;
ProgressControlsForDialogs mProgressControls;
readonly IWelcomeWindowNotify mNotify;
readonly IPlasticWebRestApi mRestApi;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 85f4628ae66f0eb439e59db66adbc696
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,118 @@
using System;
using Codice.Client.Common;
using Codice.Client.Common.Authentication;
using Codice.Client.Common.WebApi;
using Codice.CM.Common;
using PlasticGui;
using Unity.PlasticSCM.Editor.UI.UIElements;
using UnityEngine.UIElements;
namespace Unity.PlasticSCM.Editor.Configuration.CloudEdition.Welcome
{
internal class WaitingSignInPanel : VisualElement
{
internal WaitingSignInPanel(
IWelcomeWindowNotify parentNotify,
OAuthSignIn.INotify notify,
IPlasticWebRestApi restApi)
{
mParentNotify = parentNotify;
mNotify = notify;
mRestApi = restApi;
InitializeLayoutAndStyles();
BuildComponents();
}
internal void OAuthSignIn(
AuthProvider provider,
IGetCredentialsFromState getCredentialsFromState)
{
mSignIn = new OAuthSignIn();
mSignIn.SignInForProviderInThreadWaiter(
provider,
string.Empty,
mProgressControls,
mNotify,
new OAuthSignIn.Browser(),
getCredentialsFromState);
ShowWaitingSpinner();
}
internal void OnAutoLogin()
{
mCompleteOnBrowserLabel.visible = false;
mCancelButton.visible = false;
mProgressControls.ProgressData.ProgressMessage =
PlasticLocalization.Name.SigningIn.GetString();
ShowWaitingSpinner();
}
internal void Dispose()
{
mCancelButton.clicked -= CancelButton_Clicked;
}
void InitializeLayoutAndStyles()
{
this.LoadLayout(typeof(WaitingSignInPanel).Name);
this.LoadStyle(typeof(WaitingSignInPanel).Name);
}
void ShowWaitingSpinner()
{
var spinner = new LoadingSpinner();
mProgressContainer.Add(spinner);
spinner.Start();
var checkinMessageLabel = new Label(mProgressControls.ProgressData.ProgressMessage);
checkinMessageLabel.style.paddingLeft = 20;
mProgressContainer.Add(checkinMessageLabel);
}
void CancelButton_Clicked()
{
mSignIn.Cancel();
mParentNotify.Back();
}
void BuildComponents()
{
this.SetControlText<Label>("signInToPlasticSCM",
PlasticLocalization.Name.SignInToUnityVCS);
mCompleteOnBrowserLabel = this.Q<Label>("completeSignInOnBrowser");
mCompleteOnBrowserLabel.text = PlasticLocalization.Name.CompleteSignInOnBrowser.GetString();
mProgressContainer = this.Q<VisualElement>("progressContainer");
mProgressControls = new UI.Progress.ProgressControlsForDialogs();
mCancelButton = this.Query<Button>("cancelButton");
mCancelButton.text = PlasticLocalization.GetString(
PlasticLocalization.Name.CancelButton);
mCancelButton.visible = true;
mCancelButton.clicked += CancelButton_Clicked;
}
Button mCancelButton;
VisualElement mProgressContainer;
Label mCompleteOnBrowserLabel;
OAuthSignIn mSignIn;
UI.Progress.ProgressControlsForDialogs mProgressControls;
readonly IPlasticWebRestApi mRestApi;
readonly OAuthSignIn.INotify mNotify;
readonly IWelcomeWindowNotify mParentNotify;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 077387e98bf29fb4a97bccfb592cfaf7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
using System.Collections.Generic;
using System.IO;
using Codice.Client.Commands.WkTree;
using Codice.Client.Common;
using Codice.Client.Common.GameUI;
using Codice.CM.Common;
using Codice.CM.Common.Mount;
using Codice.CM.Common.Partial;
using Codice.CM.WorkspaceServer.DataStore.Configuration;
namespace Unity.PlasticSCM.Editor.Configuration
{
internal static class ConfigurePartialWorkspace
{
internal static void AsFullyChecked(WorkspaceInfo wkInfo)
{
string rootPath = WorkspacePath.GetWorkspacePathFromCmPath(
wkInfo.ClientPath, "/", Path.DirectorySeparatorChar);
WorkspaceTreeNode rootWkNode = CmConnection.Get().GetWorkspaceTreeHandler().
WkGetWorkspaceTreeNode(rootPath);
FullyCheckedDirectory rootDirectory = new FullyCheckedDirectory(
MountPointId.WORKSPACE_ROOT, rootWkNode.RevInfo.ItemId);
List<FullyCheckedDirectory> directoryList = new List<FullyCheckedDirectory>();
directoryList.Add(rootDirectory);
FullyCheckedDirectoriesStorage.Save(wkInfo, directoryList);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2b3223ee740687445a7e4bc793fa2aae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,156 @@
using UnityEngine;
using UnityEditor;
using PlasticGui;
using Unity.PlasticSCM.Editor.UI;
using Unity.PlasticSCM.Editor.UI.Progress;
using Codice.Client.Common.Authentication;
using Codice.Client.Common.Connection;
using Codice.CM.Common;
using PlasticGui.WorkspaceWindow.Home;
namespace Unity.PlasticSCM.Editor.Configuration
{
internal class CredentialsDialog : PlasticDialog
{
protected override Rect DefaultRect
{
get
{
var baseRect = base.DefaultRect;
return new Rect(baseRect.x, baseRect.y, 525, 250);
}
}
internal static AskCredentialsToUser.DialogData RequestCredentials(
string server,
SEIDWorkingMode seidWorkingMode,
EditorWindow parentWindow)
{
CredentialsDialog dialog = Create(
server, seidWorkingMode, new ProgressControlsForDialogs());
ResponseType dialogResult = dialog.RunModal(parentWindow);
return dialog.BuildCredentialsDialogData(dialogResult);
}
protected override void OnModalGUI()
{
Title(PlasticLocalization.Name.CredentialsDialogTitle.GetString());
Paragraph(PlasticLocalization.Name.CredentialsDialogExplanation.GetString(mOrganizationInfo.DisplayName));
GUILayout.Space(5);
DoEntriesArea();
GUILayout.Space(10);
DrawProgressForDialogs.For(
mProgressControls.ProgressData);
GUILayout.Space(10);
DoButtonsArea();
}
protected override string GetTitle()
{
return PlasticLocalization.Name.CredentialsDialogTitle.GetString();
}
AskCredentialsToUser.DialogData BuildCredentialsDialogData(
ResponseType dialogResult)
{
return dialogResult == ResponseType.Ok
? AskCredentialsToUser.DialogData.Success(
new Credentials(
new SEID(mUser, false, mPassword),
mSeidWorkingMode))
: AskCredentialsToUser.DialogData.Failure(mSeidWorkingMode);
}
void DoEntriesArea()
{
mUser = TextEntry(PlasticLocalization.Name.UserName.GetString(),
mUser, ENTRY_WIDTH, ENTRY_X);
GUILayout.Space(5);
mPassword = PasswordEntry(PlasticLocalization.Name.Password.GetString(),
mPassword, ENTRY_WIDTH, ENTRY_X);
GUILayout.Space(5);
mSaveProfile = ToggleEntry(PlasticLocalization.Name.RememberCredentialsAsProfile.GetString(),
mSaveProfile, ENTRY_WIDTH, ENTRY_X);
}
void DoButtonsArea()
{
using (new EditorGUILayout.HorizontalScope())
{
GUILayout.FlexibleSpace();
if (Application.platform == RuntimePlatform.WindowsEditor)
{
DoOkButton();
DoCancelButton();
return;
}
DoCancelButton();
DoOkButton();
}
}
void DoOkButton()
{
if (!AcceptButton(PlasticLocalization.Name.OkButton.GetString()))
return;
OkButtonWithValidationAction();
}
void DoCancelButton()
{
if (!NormalButton(PlasticLocalization.Name.CancelButton.GetString()))
return;
CancelButtonAction();
}
void OkButtonWithValidationAction()
{
CredentialsDialogValidation.Validate(mUser, mPassword, this, mProgressControls);
}
static CredentialsDialog Create(
string server,
SEIDWorkingMode seidWorkingMode,
ProgressControlsForDialogs progressControls)
{
var instance = CreateInstance<CredentialsDialog>();
instance.mOrganizationInfo = OrganizationsInformation.FromServer(server);
instance.mSeidWorkingMode = seidWorkingMode;
instance.mProgressControls = progressControls;
instance.mEnterKeyAction = instance.OkButtonWithValidationAction;
instance.mEscapeKeyAction = instance.CancelButtonAction;
return instance;
}
string mUser;
string mPassword = string.Empty;
ProgressControlsForDialogs mProgressControls;
bool mSaveProfile;
OrganizationInfo mOrganizationInfo;
SEIDWorkingMode mSeidWorkingMode;
const float ENTRY_WIDTH = 345f;
const float ENTRY_X = 150f;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c46424c57c6462945b14ac0c95281406
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,102 @@
using System;
using System.Threading.Tasks;
using UnityEditor;
using Codice.CM.Common;
using Codice.Client.Common;
using Codice.Client.Common.Connection;
using Codice.Client.Common.Threading;
using PlasticGui;
using Unity.PlasticSCM.Editor.UI;
using Unity.PlasticSCM.Editor.WebApi;
namespace Unity.PlasticSCM.Editor.Configuration
{
internal class CredentialsUiImpl : AskCredentialsToUser.IGui
{
AskCredentialsToUser.DialogData AskCredentialsToUser.IGui.AskUserForCredentials(
string servername, SEIDWorkingMode seidWorkingMode)
{
if (!PlasticPlugin.ConnectionMonitor.IsConnected)
return AskCredentialsToUser.DialogData.Failure(seidWorkingMode);
if (seidWorkingMode == SEIDWorkingMode.OIDCWorkingMode
|| seidWorkingMode == SEIDWorkingMode.SAMLWorkingMode)
{
throw new NotImplementedException(
string.Format("Authentication for {0} not supported yet.", seidWorkingMode));
}
AskCredentialsToUser.DialogData result = null;
GUIActionRunner.RunGUIAction(delegate
{
result = seidWorkingMode == SEIDWorkingMode.SSOWorkingMode
? RunSSOCredentialsRequest(
servername, CloudProjectSettings.accessToken)
: CredentialsDialog.RequestCredentials(
servername, seidWorkingMode, ParentWindow.Get());
});
return result;
}
AskCredentialsToUser.DialogData RunSSOCredentialsRequest(
string cloudServer,
string unityAccessToken)
{
if (string.IsNullOrEmpty(unityAccessToken))
{
return SSOCredentialsDialog.RequestCredentials(
cloudServer, ParentWindow.Get());
}
TokenExchangeResponse tokenExchangeResponse =
WaitUntilTokenExchange(unityAccessToken);
// There is no internet connection, so no way to get credentials
if (tokenExchangeResponse == null)
{
return AskCredentialsToUser.DialogData.Failure(SEIDWorkingMode.SSOWorkingMode);
}
if (tokenExchangeResponse.Error == null)
{
return AskCredentialsToUser.DialogData.Success(
new Credentials(
new SEID(
tokenExchangeResponse.User,
false,
tokenExchangeResponse.AccessToken),
SEIDWorkingMode.SSOWorkingMode));
}
return SSOCredentialsDialog.RequestCredentials(
cloudServer, ParentWindow.Get());
}
static TokenExchangeResponse WaitUntilTokenExchange(
string unityAccessToken)
{
TokenExchangeResponse result = null;
Task.Run(() =>
{
try
{
result = WebRestApiClient
.PlasticScm
.TokenExchange(unityAccessToken);
}
catch (Exception ex)
{
ExceptionsHandler.LogException(
"CredentialsUiImpl", ex);
}
}).Wait();
return result;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 50d82b3e371b7cc42abc2999039b19cb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,186 @@
using UnityEditor;
using UnityEngine;
using Codice.Utils;
using PlasticGui;
using PlasticGui.WorkspaceWindow.Home;
using Unity.PlasticSCM.Editor.UI;
namespace Unity.PlasticSCM.Editor.Configuration
{
internal class EncryptionConfigurationDialog : PlasticDialog
{
protected override Rect DefaultRect
{
get
{
var baseRect = base.DefaultRect;
return new Rect(baseRect.x, baseRect.y, 650, 425);
}
}
internal static EncryptionConfigurationDialogData RequestEncryptionPassword(
string server,
EditorWindow parentWindow)
{
EncryptionConfigurationDialog dialog = Create(server);
ResponseType dialogResult = dialog.RunModal(parentWindow);
EncryptionConfigurationDialogData result =
dialog.BuildEncryptionConfigurationData();
result.Result = dialogResult == ResponseType.Ok;
return result;
}
protected override void OnModalGUI()
{
Title(PlasticLocalization.Name.EncryptionConfiguration.GetString());
GUILayout.Space(20);
Paragraph(PlasticLocalization.Name.EncryptionConfigurationExplanation.GetString(mOrganizationInfo.DisplayName));
DoPasswordArea();
Paragraph(PlasticLocalization.Name.EncryptionConfigurationRemarks.GetString(mOrganizationInfo.DisplayName));
GUILayout.Space(10);
DoNotificationArea();
GUILayout.Space(10);
DoButtonsArea();
}
protected override string GetTitle()
{
return PlasticLocalization.Name.EncryptionConfiguration.GetString();
}
EncryptionConfigurationDialogData BuildEncryptionConfigurationData()
{
return new EncryptionConfigurationDialogData(
CryptoServices.GetEncryptedPassword(mPassword.Trim()));
}
void DoPasswordArea()
{
Paragraph(PlasticLocalization.Name.EncryptionConfigurationEnterPassword.GetString());
GUILayout.Space(5);
mPassword = PasswordEntry(PlasticLocalization.Name.Password.GetString(),
mPassword, PASSWORD_TEXT_WIDTH, PASSWORD_TEXT_X);
GUILayout.Space(5);
mRetypePassword = PasswordEntry(PlasticLocalization.Name.RetypePassword.GetString(),
mRetypePassword, PASSWORD_TEXT_WIDTH, PASSWORD_TEXT_X);
GUILayout.Space(18f);
}
void DoNotificationArea()
{
if (string.IsNullOrEmpty(mErrorMessage))
return;
var rect = GUILayoutUtility.GetRect(
GUILayoutUtility.GetLastRect().width, 30);
EditorGUI.HelpBox(rect, mErrorMessage, MessageType.Error);
}
void DoButtonsArea()
{
using (new EditorGUILayout.HorizontalScope())
{
GUILayout.FlexibleSpace();
if (Application.platform == RuntimePlatform.WindowsEditor)
{
DoOkButton();
DoCancelButton();
return;
}
DoCancelButton();
DoOkButton();
}
}
void DoOkButton()
{
if (!AcceptButton(PlasticLocalization.Name.OkButton.GetString()))
return;
OkButtonWithValidationAction();
}
void DoCancelButton()
{
if (!NormalButton(PlasticLocalization.Name.CancelButton.GetString()))
return;
CancelButtonAction();
}
void OkButtonWithValidationAction()
{
if (IsValidPassword(
mPassword.Trim(), mRetypePassword.Trim(),
out mErrorMessage))
{
mErrorMessage = string.Empty;
OkButtonAction();
return;
}
mPassword = string.Empty;
mRetypePassword = string.Empty;
}
static bool IsValidPassword(
string password, string retypePassword,
out string errorMessage)
{
errorMessage = string.Empty;
if (string.IsNullOrEmpty(password))
{
errorMessage = PlasticLocalization.Name.InvalidEmptyPassword.GetString();
return false;
}
if (!password.Equals(retypePassword))
{
errorMessage = PlasticLocalization.Name.PasswordDoesntMatch.GetString();
return false;
}
return true;
}
static EncryptionConfigurationDialog Create(string server)
{
var instance = CreateInstance<EncryptionConfigurationDialog>();
instance.mOrganizationInfo = OrganizationsInformation.FromServer(server);
instance.mEnterKeyAction = instance.OkButtonWithValidationAction;
instance.mEscapeKeyAction = instance.CancelButtonAction;
return instance;
}
string mPassword = string.Empty;
string mRetypePassword = string.Empty;
string mErrorMessage = string.Empty;
OrganizationInfo mOrganizationInfo;
const float PASSWORD_TEXT_WIDTH = 250f;
const float PASSWORD_TEXT_X = 200f;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 68d5bb402c52edc48b494a59b8971758
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,36 @@
using UnityEditor;
using Codice.Client.Common.Encryption;
using PlasticGui;
using Unity.PlasticSCM.Editor.UI;
namespace Unity.PlasticSCM.Editor.Configuration
{
internal class MissingEncryptionPasswordPromptHandler :
ClientEncryptionServiceProvider.IEncryptioPasswordProvider
{
string ClientEncryptionServiceProvider.IEncryptioPasswordProvider
.GetEncryptionEncryptedPassword(string server)
{
string result = null;
GUIActionRunner.RunGUIAction(delegate
{
result = AskForEncryptionPassword(server);
});
return result;
}
string AskForEncryptionPassword(string server)
{
EncryptionConfigurationDialogData dialogData =
EncryptionConfigurationDialog.RequestEncryptionPassword(server, ParentWindow.Get());
if (!dialogData.Result)
return null;
return dialogData.EncryptedPassword;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4f6e4f3809c687045b21461609e2f78b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,255 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using Codice.CM.Common;
using Codice.Client.Common;
using Codice.Client.Common.Authentication;
using Codice.Client.Common.Connection;
using Codice.Client.Common.WebApi.Responses;
using PlasticGui;
using PlasticGui.Configuration.CloudEdition;
using PlasticGui.Configuration.CloudEdition.Welcome;
using PlasticGui.WorkspaceWindow.Home;
using Unity.PlasticSCM.Editor.UI;
using Unity.PlasticSCM.Editor.UI.Progress;
namespace Unity.PlasticSCM.Editor.Configuration
{
internal class SSOCredentialsDialog :
PlasticDialog,
OAuthSignIn.INotify,
GetCloudOrganizations.INotify
{
protected override Rect DefaultRect
{
get
{
var baseRect = base.DefaultRect;
return new Rect(baseRect.x, baseRect.y, 525, 450);
}
}
internal static AskCredentialsToUser.DialogData RequestCredentials(
string cloudServer,
EditorWindow parentWindow)
{
SSOCredentialsDialog dialog = Create(
cloudServer, new ProgressControlsForDialogs());
ResponseType dialogResult = dialog.RunModal(parentWindow);
return dialog.BuildCredentialsDialogData(dialogResult);
}
protected override string GetTitle()
{
return PlasticLocalization.Name.CredentialsDialogTitle.GetString();
}
protected override void OnModalGUI()
{
Title(PlasticLocalization.Name.CredentialsDialogTitle.GetString());
Paragraph(
PlasticLocalization.Name.CredentialsDialogExplanation.GetString(
mOrganizationInfo.DisplayName));
GUILayout.Space(20);
DoEntriesArea();
GUILayout.Space(10);
DrawProgressForDialogs.For(
mProgressControls.ProgressData);
GUILayout.Space(10);
DoButtonsArea();
}
void DoEntriesArea()
{
Paragraph("Sign in with Unity ID");
GUILayout.Space(5);
DoUnityIDButton();
GUILayout.Space(25);
Paragraph(" --or-- ");
Paragraph("Sign in with email");
mEmail = TextEntry(
PlasticLocalization.Name.Email.GetString(),
mEmail, ENTRY_WIDTH, ENTRY_X);
GUILayout.Space(5);
mPassword = PasswordEntry(
PlasticLocalization.Name.Password.GetString(),
mPassword, ENTRY_WIDTH, ENTRY_X);
}
void DoUnityIDButton()
{
if (NormalButton("Sign in with Unity ID"))
{
Guid state = Guid.NewGuid();
OAuthSignInForUnityPackage(
GetAuthProviders.GetUnityIdAuthProvider(string.Empty, state),
GetCredentialsFromState.Build(
string.Empty,
state,
SEIDWorkingMode.SSOWorkingMode,
PlasticGui.Plastic.WebRestAPI));
}
}
void DoButtonsArea()
{
using (new EditorGUILayout.HorizontalScope())
{
GUILayout.FlexibleSpace();
if (Application.platform == RuntimePlatform.WindowsEditor)
{
DoOkButton();
DoCancelButton();
return;
}
DoCancelButton();
DoOkButton();
}
}
void DoOkButton()
{
if (!AcceptButton(PlasticLocalization.Name.OkButton.GetString()))
return;
OkButtonWithValidationAction();
}
void DoCancelButton()
{
if (!NormalButton(PlasticLocalization.Name.CancelButton.GetString()))
return;
CancelButtonAction();
}
void OkButtonWithValidationAction()
{
mCredentials = new Credentials(
new SEID(mEmail, false, mPassword),
SEIDWorkingMode.LDAPWorkingMode);
GetCloudOrganizations.GetOrganizationsInThreadWaiter(
mCredentials.User.Data,
mCredentials.User.Password,
mProgressControls,
this,
PlasticGui.Plastic.WebRestAPI,
CmConnection.Get());
}
void OAuthSignInForUnityPackage(
AuthProvider authProvider, IGetCredentialsFromState getCredentialsFromState)
{
OAuthSignIn oAuthSignIn = new OAuthSignIn();
oAuthSignIn.SignInForProviderInThreadWaiter(
authProvider,
string.Empty,
mProgressControls,
this,
new OAuthSignIn.Browser(),
getCredentialsFromState);
}
void OAuthSignIn.INotify.SignedInForCloud(
string chosenProviderName, Credentials credentials)
{
mCredentials = credentials;
GetCloudOrganizations.GetOrganizationsInThreadWaiter(
mCredentials.User.Data,
mCredentials.User.Password,
mProgressControls,
this,
PlasticGui.Plastic.WebRestAPI,
CmConnection.Get());
}
void OAuthSignIn.INotify.SignedInForOnPremise(
string server, string proxy, Credentials credentials)
{
// The Plugin does not support SSO for on-premise (OIDCWorkingMode / SAMLWorkingMode)
// as it is not prepared to show the necessary UI
}
void OAuthSignIn.INotify.Cancel(string errorMessage)
{
CancelButtonAction();
}
void GetCloudOrganizations.INotify.CloudOrganizationsRetrieved(
List<string> cloudOrganizations)
{
if (!cloudOrganizations.Contains(mOrganizationInfo.Server))
{
CancelButtonAction();
return;
}
ClientConfiguration.Save(
mOrganizationInfo.Server,
mCredentials.Mode,
mCredentials.User.Data,
mCredentials.User.Password);
GetWindow<PlasticWindow>().InitializePlastic();
OkButtonAction();
}
void GetCloudOrganizations.INotify.Error(ErrorResponse.ErrorFields error)
{
CancelButtonAction();
}
AskCredentialsToUser.DialogData BuildCredentialsDialogData(ResponseType dialogResult)
{
return dialogResult == ResponseType.Ok
? AskCredentialsToUser.DialogData.Success(mCredentials)
: AskCredentialsToUser.DialogData.Failure(SEIDWorkingMode.SSOWorkingMode);
}
static SSOCredentialsDialog Create(
string server,
ProgressControlsForDialogs progressControls)
{
var instance = CreateInstance<SSOCredentialsDialog>();
instance.mOrganizationInfo = OrganizationsInformation.FromServer(server);
instance.mProgressControls = progressControls;
instance.mEnterKeyAction = instance.OkButtonWithValidationAction;
instance.mEscapeKeyAction = instance.CancelButtonAction;
return instance;
}
string mEmail;
string mPassword = string.Empty;
Credentials mCredentials;
ProgressControlsForDialogs mProgressControls;
OrganizationInfo mOrganizationInfo;
const float ENTRY_WIDTH = 345f;
const float ENTRY_X = 150f;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f1969c6a4a44a474983058896f48d9f5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e9d092d8c9e8ffe48882f0c22e0e880d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,315 @@
using System;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using PlasticGui;
using Codice.CM.Common;
using Codice.Client.Common;
using Codice.Client.Common.WebApi;
using Unity.PlasticSCM.Editor.UI.UIElements;
using PlasticGui.Configuration.TeamEdition;
using PlasticGui.Configuration;
using Unity.PlasticSCM.Editor.Views.Welcome;
namespace Unity.PlasticSCM.Editor.Configuration.TeamEdition
{
internal class TeamEditionConfigurationWindow : EditorWindow
{
internal static void ShowWindow(IPlasticWebRestApi restApi, WelcomeView welcomeView)
{
TeamEditionConfigurationWindow window = GetWindow<TeamEditionConfigurationWindow>();
window.mRestApi = restApi;
window.mWelcomeView = welcomeView;
window.titleContent = new GUIContent(
PlasticLocalization.GetString(PlasticLocalization.Name.WelcomeToUnityVCS));
window.minSize = window.maxSize = new Vector2(650, 300);
window.Show();
}
void OnEnable()
{
InitializeLayoutAndStyles();
BuildComponents();
}
void Dispose()
{
mConnectButton.clicked -= ConnectButton_Clicked;
mCheckConnectionButton.clicked -= CheckConnectionButton_Clicked;
mOkButton.clicked -= OkButton_Clicked;
mCancelButton.clicked -= CancelButton_Clicked;
mServerTextField.UnregisterValueChangedCallback(OnServerTextFieldChanged);
mUseSslToggle.UnregisterValueChangedCallback(OnUseSslToggleChanged);
mLoadingSpinner.Dispose();
}
void ConnectButton_Clicked()
{
ConfigurationConnectServerButtonClickEvent.ClickInThreadWaiter(
server: mUserAssistant.GetProposedServer(),
HideValidation: HideValidation,
ShowError: ShowServerValidationError,
ShowProgress: ShowProgress,
HideProgress: HideProgress,
ShowNotification: ShowServerNotificationMessage,
DisableButtons: () => { mConnectButton.SetEnabled(false); },
EnableButtons: () => { mConnectButton.SetEnabled(true); },
UpdatePasswordEntries: (seidWorkingMode) =>
{
UpdatePasswordEntries(seidWorkingMode);
},
NotifyWorkingMode: (mode) => { mSEIDWorkingMode = mode; },
NotifyConnectedStatus: (b) => { });
mUserTextField.SetEnabled(true);
}
void OnDestroy()
{
Dispose();
if (mWelcomeView != null)
mWelcomeView.OnUserClosedConfigurationWindow();
}
void CheckConnectionButton_Clicked()
{
ConfigurationCheckCredentialsButtonClickEvent.ClickInThreadWaiter(
mSEIDWorkingMode,
mUserTextField.value,
mPasswordTextField.value,
Edition.Team,
mUserAssistant,
HideCredentialsValidationError,
ShowCheckCredentialsError,
ShowProgress,
HideProgress,
ShowNotification: ShowCredentialsNotificationMessage,
DisableButtons: () => { mCheckConnectionButton.SetEnabled(false); mConnectButton.SetEnabled(false); },
EnableButtons: () => { mCheckConnectionButton.SetEnabled(true); mConnectButton.SetEnabled(true); },
NotifyWorkingMode: (mode) => { mSEIDWorkingMode = mode; },
NotifyConnectedStatus: (status) => { },
restApi: mRestApi);
}
void CancelButton_Clicked()
{
Close();
}
void OkButton_Clicked()
{
if (!ValidateServerAndCreds.IsValidInput(
mUserAssistant.GetProposedServer(),
mUserTextField.value,
mSEIDWorkingMode,
mPasswordTextField.value,
ShowCheckCredentialsError))
{
return;
}
ConfigurationActions.SaveClientConfig(
mServerTextField.value,
mSEIDWorkingMode,
mUserTextField.value,
mPasswordTextField.value);
Close();
}
void HideCredentialsValidationError()
{
mCredentialsLabel.RemoveFromClassList("error");
mCredentialsLabel.Hide();
}
void BuildComponents()
{
VisualElement root = rootVisualElement;
root.Query<Label>("plasticConfigurationTitle").First().text =
PlasticLocalization.GetString(PlasticLocalization.Name.PlasticConfigurationTitleUnityVCS);
root.SetControlText<Label>(
"plasticConfigurationExplanation",
PlasticLocalization.Name.PlasticConfigurationExplanation);
root.SetControlText<Label>("configurationServerInfo",
PlasticLocalization.Name.PlasticSCMServerLabel);
root.SetControlText<Button>(
"connect",
PlasticLocalization.Name.Connect);
root.SetControlText<Label>("useSsl",
PlasticLocalization.Name.UseSsl);
root.SetControlText<Label>("configurationUserNameInfo",
PlasticLocalization.Name.ConfigurationUserNameInfo);
root.SetControlText<Label>("configurationCredentialsInfo",
PlasticLocalization.Name.ConfigurationCredentialsInfo);
root.SetControlText<Button>("check",
PlasticLocalization.Name.Check);
root.SetControlText<Label>("credentialsOk",
PlasticLocalization.Name.CredentialsOK);
root.SetControlText<Button>("okButton",
PlasticLocalization.Name.OkButton);
root.SetControlText<Button>("cancelButton",
PlasticLocalization.Name.CancelButton);
mSpinnerContainer = root.Query<VisualElement>("spinnerContainer").First();
mSpinnerLabel = root.Query<Label>("spinnerLabel").First();
mLoadingSpinner = new LoadingSpinner();
mSpinnerContainer.Add(mLoadingSpinner);
mSpinnerContainer.Hide();
mCheckConnectionButton = root.Query<Button>("check").First();
mCheckConnectionButton.clicked += CheckConnectionButton_Clicked;
mConnectButton = root.Query<Button>("connect").First();
mConnectButton.clicked += ConnectButton_Clicked;
mServerTextField = root.Query<TextField>("serverTextField").First();
mServerTextField.RegisterValueChangedCallback(OnServerTextFieldChanged);
mUseSslToggle = root.Query<Toggle>("useSslToogle").First();
mUseSslToggle.RegisterValueChangedCallback(OnUseSslToggleChanged);
mUserTextField = root.Query<TextField>("userTextField").First();
mUserTextField.SetEnabled(false);
mPasswordTextField = root.Query<TextField>("passwordTextField").First();
mPasswordTextField.isPasswordField = true;
mConnectedLabel = root.Query<Label>("connectedLabel").First();
mCredentialsLabel = root.Query<Label>("credentialsOk").First();
mOkButton = root.Query<Button>("okButton").First();
mOkButton.clicked += OkButton_Clicked;
mCancelButton = root.Query<Button>("cancelButton").First();
mCancelButton.clicked += CancelButton_Clicked;
}
void OnUseSslToggleChanged(ChangeEvent<bool> evt)
{
mUserAssistant.OnSslChanged(mServerTextField.value, evt.newValue);
mServerTextField.value = mUserAssistant.GetProposedServer();
}
void InitializeLayoutAndStyles()
{
VisualElement root = rootVisualElement;
root.LoadLayout(typeof(TeamEditionConfigurationWindow).Name);
root.LoadStyle(typeof(TeamEditionConfigurationWindow).Name);
}
void OnServerTextFieldChanged(ChangeEvent<string> evt)
{
mUserAssistant.OnServerChanged(evt.newValue);
mUseSslToggle.value = mUserAssistant.IsSslServer(evt.newValue);
}
void ShowServerNotificationMessage(string message)
{
mConnectedLabel.text = message;
mConnectedLabel.Show();
}
void ShowServerValidationError(string message)
{
mConnectedLabel.text = message;
mConnectedLabel.AddToClassList("error");
mConnectedLabel.Show();
}
void ShowCredentialsNotificationMessage(string message)
{
mCredentialsLabel.text = message;
mCredentialsLabel.Show();
}
void ShowCheckCredentialsError(string message)
{
mCredentialsLabel.text = message;
mCredentialsLabel.AddToClassList("error");
mCredentialsLabel.Show();
}
void HideValidation()
{
mConnectedLabel.RemoveFromClassList("error");
mConnectedLabel.Hide();
}
void ShowProgress(string text)
{
mSpinnerLabel.text = text;
mSpinnerContainer.Show();
mSpinnerLabel.Show();
mLoadingSpinner.Start();
}
void HideProgress()
{
mLoadingSpinner.Stop();
mSpinnerContainer.Hide();
mSpinnerLabel.Hide();
}
void UpdatePasswordEntries(SEIDWorkingMode workingMode)
{
bool bIsPasswordRequired =
ValidateServerAndCreds.IsPasswordRequired(workingMode);
if (!bIsPasswordRequired)
{
mPasswordTextField.Collapse();
mUserTextField.SetEnabled(false);
mUserTextField.value = Environment.UserName;
return;
}
mUserTextField.SetEnabled(true);
mPasswordTextField.Show();
mUserTextField.SelectAll();
mUserTextField.FocusWorkaround();
}
Button mConnectButton;
Label mConnectedLabel;
TextField mServerTextField;
TextField mPasswordTextField;
Toggle mUseSslToggle;
LoadingSpinner mLoadingSpinner;
Label mSpinnerLabel;
VisualElement mSpinnerContainer;
Button mCheckConnectionButton;
Label mCredentialsLabel;
Button mOkButton;
Button mCancelButton;
SEIDWorkingMode mSEIDWorkingMode = SEIDWorkingMode.UPWorkingMode;
ConfigurationDialogUserAssistant mUserAssistant =
new ConfigurationDialogUserAssistant();
IPlasticWebRestApi mRestApi;
WelcomeView mWelcomeView;
TextField mUserTextField;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c95121e1e2d89e648b9d0aed259caad9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,42 @@
using System.IO;
using Codice.Utils;
namespace Unity.PlasticSCM.Editor.Configuration
{
internal static class ToolConfig
{
internal static string GetUnityPlasticLogConfigFile()
{
if (!string.IsNullOrEmpty(mLogConfigFolder))
return Path.Combine(mLogConfigFolder, LOG_CONFIG_FILE);
return GetConfigFilePath(LOG_CONFIG_FILE);
}
internal static void InitializeLogConfigFolderForTesting(string logConfigFolder)
{
mLogConfigFolder = logConfigFolder;
}
internal static void Reset()
{
mLogConfigFolder = null;
}
static string GetConfigFilePath(string configfile)
{
string file = Path.Combine(
ApplicationLocation.GetAppPath(), configfile);
if (File.Exists(file))
return file;
return UserConfigFolder.GetConfigFile(configfile);
}
static string mLogConfigFolder;
const string LOG_CONFIG_FILE = "unityplastic.log.conf";
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ee776820547bd654980004e8471df8e3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,66 @@
using System.IO;
namespace Unity.PlasticSCM.Editor.Configuration
{
internal class WriteLogConfiguration
{
internal static void For(string logConfigPath)
{
string logDirectoryPath = GetPlasticLogDirectoryPath(logConfigPath);
string relevantLogFile = Path.Combine(logDirectoryPath, RELEVANT_LOG_FILE_NAME);
string debugLogFile = Path.Combine(logDirectoryPath, DEBUG_LOG_FILE_NAME);
using (StreamWriter sw = File.CreateText(logConfigPath))
{
sw.Write(string.Format(
LOG_CONFIGURATION,
relevantLogFile,
debugLogFile));
}
}
static string GetPlasticLogDirectoryPath(string logConfigPath)
{
return Path.Combine(
Directory.GetParent(logConfigPath).FullName,
LOGS_DIRECTORY);
}
const string LOGS_DIRECTORY = "logs";
const string RELEVANT_LOG_FILE_NAME = "unityplastic.relevant.log.txt";
const string DEBUG_LOG_FILE_NAME = "unityplastic.debug.log.txt";
const string LOG_CONFIGURATION =
@"<log4net>
<appender name=""RelevantInfoAppender"" type=""log4net.Appender.RollingFileAppender"">
<file value=""{0}"" />
<appendToFile value=""true"" />
<rollingStyle value=""Size"" />
<maxSizeRollBackups value=""10"" />
<maximumFileSize value=""2MB"" />
<layout type=""log4net.Layout.PatternLayout"">
<conversionPattern value=""%date %username %-5level %logger - %message%newline"" />
</layout>
<filter type=""log4net.Filter.LevelRangeFilter""><levelMin value=""INFO"" /><levelMax value=""FATAL"" /></filter>
</appender>
<appender name=""DebugAppender"" type=""log4net.Appender.RollingFileAppender"">
<file value=""{1}"" />
<appendToFile value=""true"" />
<rollingStyle value=""Size"" />
<maxSizeRollBackups value=""10"" />
<maximumFileSize value=""10MB"" />
<staticLogFileName value=""true"" />
<layout type=""log4net.Layout.PatternLayout"">
<conversionPattern value=""%date %username %-5level %logger - %message%newline"" />
</layout>
</appender>
<root>
<level value=""DEBUG"" />
<appender-ref ref=""RelevantInfoAppender"" />
<appender-ref ref=""DebugAppender"" />
</root>
</log4net>
";
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 332442c8f4f7b1943bb9e12fc97356e4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: