Skip to content
This repository was archived by the owner on Feb 16, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/HealthyHabitat/App.config
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
<appSettings>
<add key="ApplicationId" value=""/>
<add key="ClientScopes" value="user.read https://storage.azure.com/user_impersonation"/>
<add key="localCache" value="C:\localCache"/>
<add key="storageAccountName" value="hhaiimgupdev"/>
<add key="containerName" value="images"/>
<add key="key" value=""/>
<add key="RetryLimit" value="3"/>
<add key="RetrySeconds" value="30"/>
</appSettings>
</configuration>
6 changes: 6 additions & 0 deletions app/HealthyHabitat/HealthyHabitat.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@
<Reference Include="Microsoft.Azure.Storage.Common, Version=11.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Azure.Storage.Common.11.1.0\lib\net452\Microsoft.Azure.Storage.Common.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Identity.Client, Version=4.4.0.0, Culture=neutral, PublicKeyToken=0a613f4dd989e8ae, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Identity.Client.4.4.0\lib\net45\Microsoft.Identity.Client.dll</HintPath>
</Reference>
<Reference Include="MvvmDialogs, Version=5.3.0.0, Culture=neutral, PublicKeyToken=3d3b9708589bc73e, processorArchitecture=MSIL">
<HintPath>..\packages\MvvmDialogs.5.3.0\lib\net45\MvvmDialogs.dll</HintPath>
</Reference>
Expand All @@ -69,6 +72,9 @@
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.IdentityModel" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\MvvmLightLibs.5.4.1.1\lib\net45\System.Windows.Interactivity.dll</HintPath>
</Reference>
Expand Down
313 changes: 311 additions & 2 deletions app/HealthyHabitat/ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using Microsoft.Identity.Client;
using Microsoft.Azure.Storage.Auth;

public class MainWindowViewModel : ViewModelBase
{
Expand Down Expand Up @@ -48,6 +50,18 @@ public RelayCommand<DragEventArgs> DropCommand
private set;
}

public RelayCommand SignInCommand
{
get;
private set;
}

public RelayCommand SignOutCommand
{
get;
private set;
}

public ICommand ShowMessageBoxWithMessageCommand { get; }
#endregion Commands

Expand Down Expand Up @@ -137,8 +151,75 @@ public bool LocationDialogVisible
}
}

private bool _signInButtonVisible;
public bool SignInButtonVisible
{
get { return _signInButtonVisible; }
set
{
_signInButtonVisible = value;
RaisePropertyChanged("SignInButtonVisible");
}
}

private bool _signOutButtonVisible;
public bool SignOutButtonVisible
{
get { return _signOutButtonVisible; }
set
{
_signOutButtonVisible = value;
RaisePropertyChanged("SignOutButtonVisible");
}
}

private string _signedInUserName;
public string SignedInUserName
{
get { return _signedInUserName; }
set
{
_signedInUserName = value;
RaisePropertyChanged("SignedInUserName");
}
}

private string _displayMessage;
public string DisplayMessage
{
get { return _displayMessage; }
set
{
_displayMessage = value;
RaisePropertyChanged("DisplayMessage");
}
}

// Auth definitions -------------------------------------------------------------------
private readonly string ClientId = ConfigurationManager.AppSettings["ApplicationId"].ToString();
private readonly string ClientScopes = ConfigurationManager.AppSettings["ClientScopes"].ToString();

private IPublicClientApplication PublicClientApp { get; set; }
private AuthenticationResult AuthResult { get; set; }

// End Auth definitions -------------------------------------------------------------------

public MainWindowViewModel(IDialogService dialogService)
{
// Auth init -------------------------------------------------------------------
SignInButtonVisible = true;
DisplayMessage = "Please sign in.";
SignedInUserName = "";
PublicClientApp = PublicClientApplicationBuilder.Create(ClientId)
.WithAuthority(AadAuthorityAudience.AzureAdMultipleOrgs)
.WithLogging((level, message, containsPii) =>
{
Debug.WriteLine($"MSAL: {level} {message} ");
}, Microsoft.Identity.Client.LogLevel.Warning, enablePiiLogging: false, enableDefaultPlatformLogging: true)
.Build();

// End Auth init -------------------------------------------------------------------

NameValueCollection locationSection = (NameValueCollection)ConfigurationManager.GetSection("locations");

Locations = new ObservableCollection<Location>();
Expand All @@ -152,6 +233,11 @@ public MainWindowViewModel(IDialogService dialogService)

UploadClickCommand = new RelayCommand(() =>
{
if (this.SelectedLocation == null)
{
return;
}

LocationDialogVisible = false;

ProgressVisible = true;
Expand All @@ -175,8 +261,97 @@ public MainWindowViewModel(IDialogService dialogService)

LocationDialogVisible = true;
});

SignInCommand = new RelayCommand(async () =>
{
await Authorize();
DisplayBasicTokenInfo();
});

SignOutCommand = new RelayCommand(async () =>
{
await DeAuthorize();
DisplayBasicTokenInfo();
});
}

// Auth -------------------------------------------------------------------
private async Task Authorize()
{
AuthResult = null;

// It's good practice to not do work on the UI thread, so use ConfigureAwait(false) whenever possible.
IEnumerable<IAccount> accounts = await PublicClientApp.GetAccountsAsync().ConfigureAwait(true);
IAccount firstAccount = accounts.FirstOrDefault();

try
{
AuthResult = await PublicClientApp.AcquireTokenSilent(ClientScopes.Split(), firstAccount)
.ExecuteAsync();
}
catch (MsalUiRequiredException ex)
{
// A MsalUiRequiredException happened on AcquireTokenSilentAsync. This indicates you need to call AcquireTokenAsync to acquire a token
System.Diagnostics.Debug.WriteLine($"MsalUiRequiredException: {ex.Message}");

try
{
AuthResult = await PublicClientApp.AcquireTokenInteractive(ClientScopes.Split())
.ExecuteAsync()
.ConfigureAwait(false);
}
catch (MsalException msalex)
{
DisplayMessage = $"Error Acquiring Token:{System.Environment.NewLine}{msalex}";
}
}
catch (Exception ex)
{
DisplayMessage = $"Error Acquiring Token Silently:{System.Environment.NewLine}{ex}";
return;
}

if (AuthResult != null)
{
SignedInUserName = $"Signed in as: {AuthResult.Account.Username}";
SignInButtonVisible = false;
SignOutButtonVisible = true;
}
}

private async Task DeAuthorize()
{
IEnumerable<IAccount> accounts = await PublicClientApp.GetAccountsAsync().ConfigureAwait(false);
IAccount firstAccount = accounts.FirstOrDefault();

try
{
await PublicClientApp.RemoveAsync(firstAccount).ConfigureAwait(false);
AuthResult = null;
SignedInUserName = "";
SignOutButtonVisible = false;
SignInButtonVisible = true;
}
catch (MsalException ex)
{
DisplayMessage = $"Error signing-out user: {ex.Message}";
}
}

public void DisplayBasicTokenInfo()
{
if (AuthResult != null)
{
DisplayMessage = $"User Name: {AuthResult.Account.Username}" + Environment.NewLine + $"Token Expires: {AuthResult.ExpiresOn.ToLocalTime()}" + Environment.NewLine;
}
else
{
DisplayMessage = "You have been signed out.";
}
}

// End Auth -------------------------------------------------------------------

private async void CopyFilesToLocalCache(string[] files, string location, string season)
{

Expand Down Expand Up @@ -228,11 +403,145 @@ private async void CopyFilesToLocalCache(string[] files, string location, string

string[] subFolders = Directory.GetDirectories(cacheLocation);

await CreateStorageContainer();
foreach (string folder in subFolders)
{
await InitiateAzCopy(folder, cacheLocation);
//await InitiateAzCopy(folder, cacheLocation);
await CreateStorageBlobs(folder, cacheLocation);
}
}

private async Task CreateStorageContainer()
{
if (AuthResult == null)
{
await Authorize();
}

if (AuthResult == null)
{
return;
}

int retryLimit = System.Convert.ToInt32(ConfigurationManager.AppSettings["RetryLimit"].ToString());
int retrySeconds = System.Convert.ToInt32(ConfigurationManager.AppSettings["RetrySeconds"].ToString());
string storageAccountName = ConfigurationManager.AppSettings["StorageAccountName"].ToString();
string storageContainerName = ConfigurationManager.AppSettings["ContainerName"].ToString();

TokenCredential tokenCredential = new TokenCredential(AuthResult.AccessToken);
StorageCredentials storageCredentials = new StorageCredentials(tokenCredential);

CloudBlobContainer container = new CloudBlobContainer(
new Uri($"https://{storageAccountName}.blob.core.windows.net/{storageContainerName}"),
storageCredentials);

DisplayMessage = $"Creating storage container {container.Uri.ToString()}" + Environment.NewLine;

int createContainerOK = 0;
while (createContainerOK < retryLimit)
{
try
{
container.CreateIfNotExists();
createContainerOK = retryLimit + 1;
}
catch
{
createContainerOK++;
DisplayMessage += $"...Retry {createContainerOK} of {retryLimit} will start in {retrySeconds} seconds." + Environment.NewLine;
await Task.Delay(retrySeconds * 1000);
}

if (createContainerOK == retryLimit)
{
DisplayMessage += $"Error creating container, check that you have the correct permissions for this storage account." + Environment.NewLine;
}
}
}

private async Task CreateStorageBlobs(string sourceDirectory, string cacheDirectory)
{
if (AuthResult == null)
{
return;
}

int retryLimit = System.Convert.ToInt32(ConfigurationManager.AppSettings["RetryLimit"].ToString());
int retrySeconds = System.Convert.ToInt32(ConfigurationManager.AppSettings["RetrySeconds"].ToString());
string storageAccountName = ConfigurationManager.AppSettings["StorageAccountName"].ToString();
string storageContainerName = ConfigurationManager.AppSettings["ContainerName"].ToString();

TokenCredential tokenCredential = new TokenCredential(AuthResult.AccessToken);
StorageCredentials storageCredentials = new StorageCredentials(tokenCredential);

string sourceDirName = new DirectoryInfo(sourceDirectory).Name;

foreach (string dir in Directory.GetDirectories(sourceDirectory))
{
string dirName = new DirectoryInfo(dir).Name;
DisplayMessage += $"Uploading {dir}" + Environment.NewLine;

int uploadDirectoryOK = 0;
foreach (string file in Directory.GetFiles(dir))
{
string fileName = new FileInfo(file).Name;

CloudBlockBlob blob = new CloudBlockBlob(
new Uri($"https://{storageAccountName}.blob.core.windows.net/{storageContainerName}/{sourceDirName}/{dirName}/{fileName}"),
storageCredentials);

DisplayMessage += $"Creating storage blob {blob.Uri.ToString()}" + Environment.NewLine;

int createBlobOK = 0;
while (createBlobOK < retryLimit)
{
try
{
await blob.UploadFromFileAsync(file);
createBlobOK = retryLimit + 1;
File.Delete(file);
}
catch
{
createBlobOK++;
DisplayMessage += $"...Retry {createBlobOK} of {retryLimit} will start in {retrySeconds} seconds." + Environment.NewLine;
await Task.Delay(retrySeconds * 1000);
}

if (createBlobOK == retryLimit)
{
DisplayMessage += $"Error creating blob, check that you have the correct permissions for this storage account." + Environment.NewLine;
}
}

if (createBlobOK != retryLimit + 1)
{
uploadDirectoryOK++;
}

if (uploadDirectoryOK == retryLimit)
{
DisplayMessage += $"Failed upload, too many consecutive errors." + Environment.NewLine;
break;
}
}

if (Directory.GetFiles(dir).Length == 0)
{
DisplayMessage += "Upload successful.";
Directory.Delete(dir, true);
}
}

if (Directory.GetDirectories(sourceDirectory).Length == 0)
{
Directory.Delete(sourceDirectory, true);
}

if (Directory.GetDirectories(cacheDirectory).Length == 0)
{
Directory.Delete(cacheDirectory, true);
}

}

private async Task InitiateAzCopy(string sourceDir, string parentDir)
Expand Down
Loading