diff --git a/deploy/create-aadapp-cli.ps1 b/deploy/create-aadapp-cli.ps1 new file mode 100644 index 0000000..b83fc95 --- /dev/null +++ b/deploy/create-aadapp-cli.ps1 @@ -0,0 +1,33 @@ +# Azure CLI must be installed +# https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-windows?tabs=azure-cli +# User must be able to create apps and consent (Global Admin, ...) + +$appName = "dev-GKMM-msteamsbackup-app"; #Change for example GKMM to your tenant +$servicePrincipalName = "Microsoft Graph"; +$servicePrincipalNameOauth2Permissions = @("Channel.ReadBasic.All", "ChannelMember.Read.All", "ChannelMessage.Read.All", "ChannelSettings.Read.All", "Group.Read.All", "GroupMember.Read.All", "Team.ReadBasic.All", "TeamMember.Read.All", "TeamSettings.Read.All", "TeamsTab.Read.All"); + +az login --use-device-code --allow-no-subscriptions + +$servicePrincipalId = az ad sp list --filter "displayname eq '$servicePrincipalName'" --query '[0].appId' | ConvertFrom-Json + +$reqGraph = @{ + resourceAppId = $servicePrincipalId + resourceAccess = @() +} + +(az ad sp show --id $servicePrincipalId --query oauth2Permissions | ConvertFrom-Json) | ? { $_.value -in $servicePrincipalNameOauth2Permissions} | % { + $permission = $_ + + $delPermission = @{ + id = $permission.Id + type = "Scope" + } + $reqGraph.resourceAccess += $delPermission +} + +Set-Content ./required_resource_accesses.json -Value ("[" + ($reqGraph | ConvertTo-Json) + "]") +$newapp = az ad app create --display-name $appName --available-to-other-tenants false --native-app true --required-resource-accesses `@required_resource_accesses.json | ConvertFrom-Json +az ad app permission admin-consent --id $newapp.appId + +"ClientId: " + $newapp.appId; +"TenantId: " + (az account show | ConvertFrom-Json).tenantId; \ No newline at end of file diff --git a/deploy/create-aadapp.ps1 b/deploy/create-aadapp.ps1 new file mode 100644 index 0000000..a59e9f9 --- /dev/null +++ b/deploy/create-aadapp.ps1 @@ -0,0 +1,31 @@ +# Requires AzureADPreview Module; +# Install-Module AzureADPreview +# User must be able to create apps and consent (Global Admin, ...) + +$appName = "dev-GKMM-msteamsbackup-app"; #Change for example GKMM to your tenant +$servicePrincipalName = "Microsoft Graph"; +$servicePrincipalNameOauth2Permissions = @("Channel.ReadBasic.All", "ChannelMember.Read.All", "ChannelMessage.Read.All", "ChannelSettings.Read.All", "Group.Read.All", "GroupMember.Read.All", "Team.ReadBasic.All", "TeamMember.Read.All", "TeamSettings.Read.All", "TeamsTab.Read.All"); + +# login +Connect-AzureAD; + +# Get MS Graph +$servicePrincipal = Get-AzureADServicePrincipal -All $true | ? { $_.DisplayName -eq $servicePrincipalName }; + +# Thanks http://blog.octavie.nl/index.php/2017/09/19/create-azure-ad-app-registration-with-powershell-part-2 +$reqGraph = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"; +$reqGraph.ResourceAppId = $servicePrincipal.AppId; + +$servicePrincipal.Oauth2Permissions | ? { $_.Value -in $servicePrincipalNameOauth2Permissions} | % { + $permission = $_ + $delPermission = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList $permission.Id,"Scope" #delegate permission (oauth) are always "Scope" + $reqGraph.ResourceAccess += $delPermission +} + +New-AzureADApplication -DisplayName $appName -AvailableToOtherTenants:$false -PublicClient:$true -RequiredResourceAccess $reqGraph; +$newapp = Get-AzureADApplication -SearchString $appName; +"ClientId: " + $newapp.AppId; +"TenantId: " + (Get-AzureADTenantDetail).ObjectId; + +"TODO: Consent in portal"; +"Check AAD app: https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/CallAnAPI/appId/" + $newapp.AppId + "/objectId/" + $newapp.ObjectId + "/isMSAApp/"; \ No newline at end of file diff --git a/deploy/publish-BackupConsole.ps1 b/deploy/publish-BackupConsole.ps1 new file mode 100644 index 0000000..aa32ea8 --- /dev/null +++ b/deploy/publish-BackupConsole.ps1 @@ -0,0 +1,29 @@ +#Build release +$corePathToProject = "..\src\BackupConsole"; +$configNames = @("Release"); + +foreach($configName in $configNames){ + $configName; + $publishLocation = ".\$configName-output"; + $publishLocationApp = $publishLocation + "\M365.TeamsBackup.BackupConsole.exe"; + + + dotnet publish $corePathToProject --configuration $configName --output $publishLocation; + + Remove-Item "$publishLocation/appsettings.Development.json"; + Remove-Item "$publishLocation/appsettings.Production.json"; + + if (Test-Path $publishLocationApp){ + + if ((Test-Path $configName) -eq $false){ + mkdir $configName; + } + + $version2publish = [System.Diagnostics.FileVersionInfo]::GetVersionInfo((Get-Location).ToString() + $publishLocationApp).FileVersion.ToString().Replace(".", "-"); + + $thisZipVersion = ".\" + $configName + "\M365.TeamsBackup.BackupConsole-V-" + $version2publish + "-" + $configName + ".zip"; + + Compress-Archive ($publishLocation + "\*") $thisZipVersion -CompressionLevel Fastest; + Remove-Item $publishLocation -Recurse:$true + } +} \ No newline at end of file diff --git a/deploy/publish-BackupToHtmlConsole.ps1 b/deploy/publish-BackupToHtmlConsole.ps1 new file mode 100644 index 0000000..ff94bfb --- /dev/null +++ b/deploy/publish-BackupToHtmlConsole.ps1 @@ -0,0 +1,29 @@ +#Build release +$corePathToProject = "..\src\BackupToHtmlConsole"; +$configNames = @("Release"); + +foreach($configName in $configNames){ + $configName; + $publishLocation = ".\$configName-output"; + $publishLocationApp = $publishLocation + "\M365.TeamsBackup.BackupToHtmlConsole.exe"; + + + dotnet publish $corePathToProject --configuration $configName --output $publishLocation; + + Remove-Item "$publishLocation/appsettings.Development.json"; + Remove-Item "$publishLocation/appsettings.Production.json"; + + if (Test-Path $publishLocationApp){ + + if ((Test-Path $configName) -eq $false){ + mkdir $configName; + } + + $version2publish = [System.Diagnostics.FileVersionInfo]::GetVersionInfo((Get-Location).ToString() + $publishLocationApp).FileVersion.ToString().Replace(".", "-"); + + $thisZipVersion = ".\" + $configName + "\M365.TeamsBackup.BackupToHtmlConsole-V-" + $version2publish + "-" + $configName + ".zip"; + + Compress-Archive ($publishLocation + "\*") $thisZipVersion -CompressionLevel Fastest; + Remove-Item $publishLocation -Recurse:$true + } +} \ No newline at end of file diff --git a/src/BackupConsole/BackupConsole.csproj b/src/BackupConsole/BackupConsole.csproj index 443483d..3fca044 100644 --- a/src/BackupConsole/BackupConsole.csproj +++ b/src/BackupConsole/BackupConsole.csproj @@ -6,7 +6,7 @@ M365.TeamsBackup.BackupConsole M365.TeamsBackup.BackupConsole Marco Scheel - 0.1.3 + 0.1.4 M365.TeamsBackup Backup from MS Graph Beta to Local JSON @@ -33,4 +33,10 @@ + + + PreserveNewest + + + diff --git a/src/BackupConsole/Properties/launchSettings.json b/src/BackupConsole/Properties/launchSettings.json index a68c905..2182415 100644 --- a/src/BackupConsole/Properties/launchSettings.json +++ b/src/BackupConsole/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "BackupConsole": { "commandName": "Project", - "commandLineArgs": "--environment Production" + "commandLineArgs": "--environment Development" } } } \ No newline at end of file diff --git a/src/BackupConsole/appsettings.Development.json b/src/BackupConsole/appsettings.Development.json index 7d12e85..9c84738 100644 --- a/src/BackupConsole/appsettings.Development.json +++ b/src/BackupConsole/appsettings.Development.json @@ -8,14 +8,14 @@ }, "AzureAd": { "Instance": "https://login.microsoftonline.com", - "ClientId": "12c9d807-90dd-42d8-abb3-b5f15a03d492", + "ClientId": "fdc12731-7742-4c3d-a3ab-f3b358ba2e09", "TenantId": "052c8489-1e3c-450e-9b79-233d8604e40a", - "ReplyUri": "msal12c9d807-90dd-42d8-abb3-b5f15a03d492://auth", "Scope": [ "https://graph.microsoft.com/.default" ] }, "M365": { "Backup": { "Path": "C:\\Code\\M365.TeamsBackup\\data\\development", + "ShouldZip": true, "JsonWriteIndented": true, "TeamId": "872265e1-0c5a-48ea-9355-0710869db8cb" } diff --git a/src/BackupConsole/appsettings.Production.json b/src/BackupConsole/appsettings.Production.json index 77bd790..073c422 100644 --- a/src/BackupConsole/appsettings.Production.json +++ b/src/BackupConsole/appsettings.Production.json @@ -10,13 +10,13 @@ "Instance": "https://login.microsoftonline.com", "ClientId": "4c50ca04-1ecf-4a02-8ac0-c8698a818701", "TenantId": "cb9543bb-9168-4dc6-b17f-766487518a6a", - "ReplyUri": "msal4c50ca04-1ecf-4a02-8ac0-c8698a818701://auth", "Scope": [ "https://graph.microsoft.com/.default" ] }, "M365": { "Backup": { "Path": "C:\\Code\\M365.TeamsBackup\\data\\production", "JsonWriteIndented": false, + "ShouldZip": true, "TeamId": "8b04f653-e2ba-4b57-92b7-3d1247073927" } } diff --git a/src/BackupConsole/appsettings.json b/src/BackupConsole/appsettings.json index 5166e3d..272a3d3 100644 --- a/src/BackupConsole/appsettings.json +++ b/src/BackupConsole/appsettings.json @@ -9,13 +9,13 @@ "Instance": "https://login.microsoftonline.com", "ClientId": "YOUR AAD CLIENT ID", "TenantId": "YOUR AAD TENANT ID", - "ReplyUri": "YOUR AAD APP REPLY URI", "Scope": [ "https://graph.microsoft.com/.default" ] }, "M365": { "Backup": { "Path": "C:\\M365.TeamsBackup\\data", "JsonWriteIndented": false, + "ShouldZip": false, "TeamId": "YOUR TEAM ID TO BACKUP" } } diff --git a/src/BackupToHtmlConsole/BackupToHtmlConsole.csproj b/src/BackupToHtmlConsole/BackupToHtmlConsole.csproj index 301ad62..a807937 100644 --- a/src/BackupToHtmlConsole/BackupToHtmlConsole.csproj +++ b/src/BackupToHtmlConsole/BackupToHtmlConsole.csproj @@ -5,7 +5,7 @@ net5.0 M365.TeamsBackup.BackupToHtmlConsole M365.TeamsBackup.BackupToHtmlConsole - 0.1.3 + 0.1.4 Marco Scheel M365.TeamsBackup Convert an existing JSON based backup to HTML @@ -33,4 +33,10 @@ + + + PreserveNewest + + + diff --git a/src/BackupToHtmlConsole/Properties/launchSettings.json b/src/BackupToHtmlConsole/Properties/launchSettings.json index d515a22..d85d5db 100644 --- a/src/BackupToHtmlConsole/Properties/launchSettings.json +++ b/src/BackupToHtmlConsole/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "BackupToHtmlConsole": { "commandName": "Project", - "commandLineArgs": "--environment Production" + "commandLineArgs": "--environment Development" } } } \ No newline at end of file diff --git a/src/BackupToHtmlConsole/appsettings.Development.json b/src/BackupToHtmlConsole/appsettings.Development.json index f7f68c8..805b3cb 100644 --- a/src/BackupToHtmlConsole/appsettings.Development.json +++ b/src/BackupToHtmlConsole/appsettings.Development.json @@ -11,7 +11,7 @@ "SourcePath": "C:\\Code\\M365.TeamsBackup\\data\\development", "TargetPath": "C:\\Code\\M365.TeamsBackup\\data\\development-html", "TemplateFile": "C:\\Code\\M365.TeamsBackup\\template\\template.html", - "UseInlineImages": true, + "UseInlineImages": false, "CreateSingleHtmlForMessage": true } } diff --git a/src/Core/Config/AzureAD.cs b/src/Core/Config/AzureAD.cs index 9e946fe..629c737 100644 --- a/src/Core/Config/AzureAD.cs +++ b/src/Core/Config/AzureAD.cs @@ -11,7 +11,6 @@ public class AzureAd public string Instance { get; set; } public string ClientId { get; set; } public string TenantId { get; set; } - public string ReplyUri { get; set; } public string[] Scope { get; set; } } } diff --git a/src/Core/Config/Backup.cs b/src/Core/Config/Backup.cs index aab5858..673089b 100644 --- a/src/Core/Config/Backup.cs +++ b/src/Core/Config/Backup.cs @@ -1,4 +1,5 @@ -using System; +using Microsoft.Graph; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -11,6 +12,7 @@ namespace M365.TeamsBackup.Core.Config public class Backup { public string Path { get; set; } + public bool ShouldZip { get; set; } public string TeamId { get; set; } public bool JsonWriteIndented { get; set; } diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj index 04f290d..3b7a516 100644 --- a/src/Core/Core.csproj +++ b/src/Core/Core.csproj @@ -4,18 +4,18 @@ net5.0 M365.TeamsBackup.Core M365.TeamsBackup.Core - 0.1.3 + 0.1.4 Marco Scheel M365.TeamsBackup - + - + diff --git a/src/Core/Data/HtmlTeamChannelMessage.cs b/src/Core/Data/HtmlTeamChannelMessage.cs index 6f96101..051c57d 100644 --- a/src/Core/Data/HtmlTeamChannelMessage.cs +++ b/src/Core/Data/HtmlTeamChannelMessage.cs @@ -192,6 +192,8 @@ private void GetHtmlForPost(HtmlNode threadNode, ChatMessage message) } System.IO.File.Copy(blobFileName, outFilename, true); + System.IO.File.SetCreationTime(outFilename, message.CreatedDateTime.Value.DateTime); + System.IO.File.SetLastWriteTime(outFilename, message.CreatedDateTime.Value.DateTime); imgNode.SetAttributeValue("src", $"./img/{System.IO.Path.GetFileName(outFilename)}"); } diff --git a/src/Core/Data/MgTeam.cs b/src/Core/Data/MgTeam.cs index e79ff46..a8f487d 100644 --- a/src/Core/Data/MgTeam.cs +++ b/src/Core/Data/MgTeam.cs @@ -111,11 +111,18 @@ public static string GetBackupPath(string root, string teamId) System.IO.Directory.CreateDirectory(fullpath); return fullpath; } + public static string GetBackupTeamFile(string root, string teamId) { var fullpath = System.IO.Path.Combine(GetBackupPath(root, teamId), "team.json"); return fullpath; } + public static string GetBackupTeamZipFile(string root, string teamId) + { + var fullpath = System.IO.Path.Combine(root, $"{teamId}.zip"); + return fullpath; + } + public static string GetBackupTeamMembersFile(string root, string teamId) { var fullpath = System.IO.Path.Combine(GetBackupPath(root, teamId), "team.members.json"); diff --git a/src/Core/Services/BackupFromGraphService.cs b/src/Core/Services/BackupFromGraphService.cs index 6923360..efb1d22 100644 --- a/src/Core/Services/BackupFromGraphService.cs +++ b/src/Core/Services/BackupFromGraphService.cs @@ -34,8 +34,10 @@ public BackupFromGraphService(ILogger logger, ILogger