1222 lines
45 KiB
C#
1222 lines
45 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Text.RegularExpressions;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
using C4IT.Logging;
|
|
using C4IT.MsGraph;
|
|
using static C4IT.Logging.cLogManager;
|
|
using C4IT.Matrix42.ServerInfo;
|
|
using static C4IT.MsGraph.cMsGraphSharepoint;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
namespace C4IT.LIAM
|
|
{
|
|
public static class LiamInitializer
|
|
{
|
|
public static Guid msTeamsModuleId = new Guid("2591832a-1b25-ec11-6985-00155d300101");
|
|
static public cLiamProviderBase CreateInstance(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData)
|
|
{
|
|
return new cLiamProviderMsTeams(LiamConfiguration, ProviderData);
|
|
}
|
|
}
|
|
|
|
public class cLiamProviderMsTeams : cLiamProviderBase
|
|
{
|
|
public readonly cMsGraphSharepoint MsSharepoint = new cMsGraphSharepoint(new cMsGraphBase());
|
|
public const string allowedMailNickNameCharacter = @"[^A-Za-z0-9!#$%&'*+\-/=?^_`{|}~]";
|
|
|
|
public readonly bool WithoutPrivateChannels = true;
|
|
|
|
private string lastErrorMessage = null;
|
|
|
|
private sealed class GraphPermissionRequirement
|
|
{
|
|
public string Description { get; private set; }
|
|
|
|
public string[] AcceptedPermissions { get; private set; }
|
|
|
|
public GraphPermissionRequirement(string description, params string[] acceptedPermissions)
|
|
{
|
|
Description = description;
|
|
AcceptedPermissions = acceptedPermissions ?? new string[0];
|
|
}
|
|
}
|
|
|
|
private static readonly GraphPermissionRequirement[] RequiredGraphPermissions = new[]
|
|
{
|
|
new GraphPermissionRequirement(
|
|
"Team lesen",
|
|
"Team.ReadBasic.All",
|
|
"Group.Read.All",
|
|
"Group.ReadWrite.All",
|
|
"Directory.Read.All",
|
|
"Directory.ReadWrite.All"),
|
|
new GraphPermissionRequirement(
|
|
"Channels lesen",
|
|
"Channel.ReadBasic.All",
|
|
"ChannelSettings.Read.All",
|
|
"ChannelSettings.ReadWrite.All",
|
|
"Group.Read.All",
|
|
"Group.ReadWrite.All",
|
|
"Directory.Read.All",
|
|
"Directory.ReadWrite.All"),
|
|
new GraphPermissionRequirement(
|
|
"Dateien lesen und schreiben",
|
|
"Files.ReadWrite.All",
|
|
"Sites.ReadWrite.All",
|
|
"Sites.FullControl.All"),
|
|
new GraphPermissionRequirement(
|
|
"Benutzer lesen",
|
|
"User.Read.All",
|
|
"User.ReadWrite.All",
|
|
"Directory.Read.All",
|
|
"Directory.ReadWrite.All"),
|
|
};
|
|
|
|
private static readonly GraphPermissionRequirement[] CloneBaseGraphPermissions = new[]
|
|
{
|
|
new GraphPermissionRequirement("Teams klonen", "Team.Create"),
|
|
};
|
|
|
|
private static readonly GraphPermissionRequirement[] CloneAppsGraphPermissions = new[]
|
|
{
|
|
new GraphPermissionRequirement("Apps mitklonen", "Application.Read.All", "Application.ReadWrite.All"),
|
|
};
|
|
|
|
private static readonly GraphPermissionRequirement[] CloneSettingsGraphPermissions = new[]
|
|
{
|
|
new GraphPermissionRequirement("Team-Einstellungen mitklonen", "TeamSettings.Read.All", "TeamSettings.ReadWrite.All"),
|
|
};
|
|
|
|
private static readonly GraphPermissionRequirement[] CloneMemberGraphPermissions = new[]
|
|
{
|
|
new GraphPermissionRequirement(
|
|
"Mitglieder mitklonen",
|
|
"GroupMember.Read.All",
|
|
"GroupMember.ReadWrite.All",
|
|
"Group.Read.All",
|
|
"Group.ReadWrite.All",
|
|
"Directory.Read.All",
|
|
"Directory.ReadWrite.All"),
|
|
};
|
|
|
|
private void SetLastError(string message)
|
|
{
|
|
lastErrorMessage = string.IsNullOrWhiteSpace(message) ? null : message;
|
|
}
|
|
|
|
public cLiamProviderMsTeams(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData) :
|
|
base(LiamConfiguration, ProviderData)
|
|
{
|
|
WithoutPrivateChannels = AdditionalConfiguration.ContainsKey("WithoutPrivateChannels") ? AdditionalConfiguration["WithoutPrivateChannels"].ToLower() == "true" || AdditionalConfiguration["WithoutPrivateChannels"] == "1" : false;
|
|
}
|
|
|
|
public override async Task<bool> LogonAsync()
|
|
{
|
|
return await LogonAsync(true);
|
|
}
|
|
|
|
public async Task<bool> LogonAsync(bool force = false)
|
|
{
|
|
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId))
|
|
{
|
|
LogEntry($"Error: License not valid", LogLevels.Error);
|
|
SetLastError("License not valid");
|
|
return false;
|
|
}
|
|
if (!force && this.MsSharepoint.Base.IsOnline)
|
|
{
|
|
if (!EnsureGraphPermissions(MsSharepoint.Base?.AccessToken))
|
|
return false;
|
|
SetLastError(null);
|
|
return true;
|
|
}
|
|
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
try
|
|
{
|
|
var LI = new cMsGraphLogonInfo() {
|
|
Tenant = this.Domain,
|
|
ClientID = this.Credential?.Identification,
|
|
ClientSecret = this.Credential?.Secret
|
|
};
|
|
var RetVal = await MsSharepoint.Base.LogonAsync(LI);
|
|
if (!RetVal)
|
|
{
|
|
SetLastError(MsSharepoint.Base?.LastErrorMessage ?? "MsTeams Logon fehlgeschlagen");
|
|
return false;
|
|
}
|
|
if (!EnsureGraphPermissions(MsSharepoint.Base?.AccessToken))
|
|
return false;
|
|
SetLastError(null);
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
SetLastError(E.Message);
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(lastErrorMessage))
|
|
SetLastError("MsTeams Logon fehlgeschlagen");
|
|
|
|
return false;
|
|
}
|
|
|
|
public override async Task<List<cLiamDataAreaBase>> getDataAreasAsync(int Depth = -1)
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
try
|
|
{
|
|
if (!await LogonAsync())
|
|
return null;
|
|
|
|
var DataAreas = new List<cLiamDataAreaBase>();
|
|
|
|
var DAL = await MsSharepoint.RequestTeamsListAsync();
|
|
if (DAL == null)
|
|
{
|
|
SetLastError(MsSharepoint.Base?.LastErrorMessage ?? "Konnte Teams-Liste nicht abrufen");
|
|
return null;
|
|
}
|
|
|
|
foreach (var Entry in DAL)
|
|
{
|
|
if (!string.IsNullOrEmpty(this.DataAreaRegEx) && !Regex.Match(Entry.Key, this.DataAreaRegEx).Success)
|
|
continue;
|
|
|
|
var MsTeam = await MsSharepoint.RequestGroupInfoAsync(Entry.Value);
|
|
if (MsTeam == null)
|
|
{
|
|
SetLastError(MsSharepoint.Base?.LastErrorMessage ?? $"Konnte Team-Informationen für '{Entry.Key}' nicht abrufen");
|
|
continue;
|
|
}
|
|
|
|
var Team = new cLiamMsTeamsTeam(this, MsTeam);
|
|
DataAreas.Add(Team);
|
|
}
|
|
|
|
if (Depth > 0)
|
|
{
|
|
var allChilds = new List<cLiamDataAreaBase>();
|
|
foreach (var Entry in DataAreas)
|
|
{
|
|
var entryChilds = await (Entry as cLiamMsTeamsTeam).getChannels(true);
|
|
if (entryChilds != null && entryChilds.Count > 0)
|
|
allChilds.AddRange(entryChilds);
|
|
}
|
|
DataAreas.AddRange(allChilds);
|
|
}
|
|
|
|
SetLastError(null);
|
|
return DataAreas;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
SetLastError(E.Message);
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private bool EnsureGraphPermissions(string accessToken)
|
|
{
|
|
return EnsureGraphPermissions(accessToken, RequiredGraphPermissions, null);
|
|
}
|
|
|
|
private bool EnsureClonePermissions(string accessToken, int partsToClone)
|
|
{
|
|
var requirements = new List<GraphPermissionRequirement>(CloneBaseGraphPermissions);
|
|
var cloneParts = (CloneTeamRequest.ClonableTeamParts)partsToClone;
|
|
|
|
if (cloneParts.HasFlag(CloneTeamRequest.ClonableTeamParts.Apps))
|
|
requirements.AddRange(CloneAppsGraphPermissions);
|
|
if (cloneParts.HasFlag(CloneTeamRequest.ClonableTeamParts.Settings))
|
|
requirements.AddRange(CloneSettingsGraphPermissions);
|
|
if (cloneParts.HasFlag(CloneTeamRequest.ClonableTeamParts.Members))
|
|
requirements.AddRange(CloneMemberGraphPermissions);
|
|
|
|
return EnsureGraphPermissions(accessToken, requirements, "Team-Klonen");
|
|
}
|
|
|
|
private bool EnsureGraphPermissions(string accessToken, IEnumerable<GraphPermissionRequirement> requirements, string operationName)
|
|
{
|
|
if (!TryGetGrantedGraphPermissions(accessToken, out var granted, out var errorMessage))
|
|
{
|
|
SetLastError(errorMessage);
|
|
return false;
|
|
}
|
|
|
|
var missing = requirements
|
|
.Where(requirement => requirement.AcceptedPermissions == null || !requirement.AcceptedPermissions.Any(granted.Contains))
|
|
.Select(requirement => $"{requirement.Description} ({string.Join(" / ", requirement.AcceptedPermissions)})")
|
|
.ToList();
|
|
|
|
if (missing.Count > 0)
|
|
{
|
|
var prefix = string.IsNullOrWhiteSpace(operationName)
|
|
? "Fehlende Graph-Berechtigungen: "
|
|
: $"Fehlende Graph-Berechtigungen für {operationName}: ";
|
|
SetLastError(prefix + string.Join(", ", missing));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool TryGetGrantedGraphPermissions(string accessToken, out HashSet<string> granted, out string errorMessage)
|
|
{
|
|
granted = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
errorMessage = null;
|
|
|
|
if (string.IsNullOrWhiteSpace(accessToken))
|
|
{
|
|
errorMessage = "Kein Access Token für Berechtigungsprüfung verfügbar";
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
var parts = accessToken.Split('.');
|
|
if (parts.Length < 2)
|
|
{
|
|
errorMessage = "Ungültiges Access Token";
|
|
return false;
|
|
}
|
|
|
|
var payload = parts[1].Replace('-', '+').Replace('_', '/');
|
|
switch (payload.Length % 4)
|
|
{
|
|
case 2: payload += "=="; break;
|
|
case 3: payload += "="; break;
|
|
}
|
|
|
|
var payloadBytes = Convert.FromBase64String(payload);
|
|
var payloadJson = Encoding.UTF8.GetString(payloadBytes);
|
|
var payloadObj = JsonConvert.DeserializeObject<JObject>(payloadJson);
|
|
if (payloadObj == null)
|
|
{
|
|
errorMessage = "Token-Payload konnte nicht gelesen werden";
|
|
return false;
|
|
}
|
|
|
|
if (payloadObj.TryGetValue("roles", out var rolesToken) && rolesToken is JArray roleArray)
|
|
{
|
|
foreach (var role in roleArray.Values<string>())
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(role))
|
|
granted.Add(role);
|
|
}
|
|
}
|
|
|
|
if (!granted.Any() && payloadObj.TryGetValue("scp", out var scopeToken))
|
|
{
|
|
var scopes = scopeToken.Value<string>() ?? string.Empty;
|
|
foreach (var scope in scopes.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
|
|
granted.Add(scope);
|
|
}
|
|
|
|
if (!granted.Any())
|
|
{
|
|
errorMessage = "Keine Graph-Berechtigungen im Access Token gefunden";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
errorMessage = "Berechtigungsprüfung fehlgeschlagen: " + ex.Message;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public override async Task<cLiamDataAreaBase> LoadDataArea(string UID)
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
try
|
|
{
|
|
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId))
|
|
{
|
|
LogEntry($"Error: License not valid", LogLevels.Error);
|
|
return null;
|
|
}
|
|
var lstIds = UID.Split('|');
|
|
|
|
switch (lstIds.Length)
|
|
{
|
|
case 4:
|
|
var FO = await cLiamMsTeamsFolder.Load(this, UID);
|
|
return FO;
|
|
case 2:
|
|
var CH = await cLiamMsTeamsChannel.Load(this, UID);
|
|
return CH;
|
|
case 1:
|
|
var TM = await cLiamMsTeamsTeam.Load(this, UID);
|
|
return TM;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return null;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
|
|
}
|
|
|
|
public static string getUidItem(ref string UID)
|
|
{
|
|
try
|
|
{
|
|
var p = UID.IndexOf('|');
|
|
if (p >= 0)
|
|
{
|
|
var Item = UID.Substring(0, p);
|
|
UID = UID.Remove(0, p + 1);
|
|
UID = UID.TrimStart();
|
|
return Item.Trim();
|
|
}
|
|
|
|
|
|
}
|
|
catch { };
|
|
|
|
var h2 = UID;
|
|
UID = "";
|
|
return h2;
|
|
}
|
|
|
|
public static cMsGraphResultPermission.ePermissionRole getMsGraphRole(eLiamAccessRoles LiamRole)
|
|
{
|
|
switch (LiamRole)
|
|
{
|
|
case eLiamAccessRoles.Owner:
|
|
return cMsGraphResultPermission.ePermissionRole.owner;
|
|
case eLiamAccessRoles.Write:
|
|
return cMsGraphResultPermission.ePermissionRole.write;
|
|
default:
|
|
return cMsGraphResultPermission.ePermissionRole.read;
|
|
}
|
|
}
|
|
|
|
public static eLiamAccessRoles getLiamRole(cMsGraphResultPermission.ePermissionRole MsGraphRole)
|
|
{
|
|
switch (MsGraphRole)
|
|
{
|
|
case cMsGraphResultPermission.ePermissionRole.owner:
|
|
return eLiamAccessRoles.Owner;
|
|
case cMsGraphResultPermission.ePermissionRole.write:
|
|
return eLiamAccessRoles.Write;
|
|
default:
|
|
return eLiamAccessRoles.Read;
|
|
}
|
|
}
|
|
|
|
public override Task<List<cLiamDataAreaBase>> getSecurityGroupsAsync(string groupFilter)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override string GetLastErrorMessage()
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(lastErrorMessage))
|
|
return lastErrorMessage;
|
|
return MsSharepoint?.Base?.LastErrorMessage ?? string.Empty;
|
|
}
|
|
|
|
public async Task<cMsGraphResultBase> cloneTeam(string teamId, string name, string description, int visibility, int partsToClone, string additionalMembers, string additionalOwners)
|
|
{
|
|
if (!await LogonAsync())
|
|
return null;
|
|
if (!EnsureClonePermissions(MsSharepoint.Base?.AccessToken, partsToClone))
|
|
return null;
|
|
|
|
var request = new CloneTeamRequest()
|
|
{
|
|
DisplayName = name,
|
|
Visibility = (CloneTeamRequest.TeamVisibilityType)visibility,
|
|
MailNickname = Regex.Replace(name, allowedMailNickNameCharacter, ""),
|
|
Description = description
|
|
};
|
|
request.SetClonableParts((CloneTeamRequest.ClonableTeamParts)partsToClone);
|
|
var res = await MsSharepoint.CloneTeam(teamId, request);
|
|
return res;
|
|
}
|
|
}
|
|
|
|
public class cLiamMsTeamsTeam : cLiamDataAreaBase
|
|
{
|
|
public new readonly cLiamProviderMsTeams Provider = null;
|
|
|
|
private readonly cMsGraphResultGroup MsTeam = null;
|
|
|
|
public cLiamMsTeamsTeam(cLiamProviderMsTeams Provider, cMsGraphResultGroup MsTeam) :
|
|
base(Provider)
|
|
{
|
|
this.Provider = Provider;
|
|
this.MsTeam = MsTeam;
|
|
|
|
this.TechnicalName = getUID(MsTeam.ID);
|
|
this.DisplayName = MsTeam.DisplayName;
|
|
this.Level = 0;
|
|
this.UID = getUID(MsTeam.ID);
|
|
this.ParentUID = "";
|
|
this.DataType = eLiamDataAreaTypes.MsTeamsTeam;
|
|
this.SupportsOwners = true;
|
|
this.SupportsPermissions = true;
|
|
}
|
|
|
|
internal static string getUID(string TeamID)
|
|
{
|
|
return $"{TeamID}";
|
|
}
|
|
|
|
internal async Task<List<cLiamDataAreaBase>> getChannels(bool OnlyPrivate)
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
try
|
|
{
|
|
if (MsTeam == null)
|
|
return null;
|
|
|
|
var RegExFilter = this.Provider?.DataAreaRegEx;
|
|
var SP = this.Provider?.MsSharepoint;
|
|
var WithoutPrivateChannels = this.Provider?.WithoutPrivateChannels ?? false;
|
|
|
|
if (MsTeam.Channels == null)
|
|
if (SP == null || !await MsTeam.ResolveChannels(SP, OnlyPrivate))
|
|
return null;
|
|
|
|
var RetVal = new List<cLiamDataAreaBase>(MsTeam.Channels.Count);
|
|
foreach (var Entry in MsTeam.Channels.Values)
|
|
{
|
|
if (!string.IsNullOrEmpty(RegExFilter) && !Regex.Match(Entry.DisplayName, RegExFilter).Success)
|
|
continue;
|
|
if (WithoutPrivateChannels && !string.IsNullOrEmpty(Entry.MembershipType) && Entry.MembershipType == "private")
|
|
continue;
|
|
|
|
var DA = new cLiamMsTeamsChannel(Provider, this, Entry);
|
|
RetVal.Add(DA);
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return null;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public override async Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
try
|
|
{
|
|
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId))
|
|
{
|
|
LogEntry($"Error: License not valid", LogLevels.Error);
|
|
return null;
|
|
}
|
|
var RetVal = await getChannels(false);
|
|
if (RetVal != null)
|
|
RetVal.AddRange(await getChildrenFromListAsync(RetVal, Depth));
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return null;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public static async Task<cLiamMsTeamsTeam> Load(cLiamProviderMsTeams Provider, string UID)
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
try
|
|
{
|
|
var arrIDs = UID.Split('|');
|
|
if (arrIDs.Length != 1)
|
|
return null;
|
|
|
|
var TeamID = cLiamProviderMsTeams.getUidItem(ref UID);
|
|
|
|
var T = await Provider.MsSharepoint.RequestGroupInfoAsync(TeamID);
|
|
if (T == null)
|
|
return null;
|
|
|
|
var RetVal = new cLiamMsTeamsTeam(Provider, T);
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return null;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
public override async Task<List<cLiamUserInfo>> GetOwnersAsync()
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
try
|
|
{
|
|
return await GetMembersAsync(true);
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return null;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
private async Task<List<cLiamUserInfo>> GetMembersAsync(bool owners)
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
try
|
|
{
|
|
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId))
|
|
{
|
|
LogEntry($"Error: License not valid", LogLevels.Error);
|
|
return null;
|
|
}
|
|
var SP = this.Provider?.MsSharepoint;
|
|
if (SP == null)
|
|
{
|
|
LogEntry($"Could not get Sharepoint class from Provider for Team '{this.TechnicalName}'", LogLevels.Warning);
|
|
return null;
|
|
}
|
|
|
|
cMsGraphCollectionUsers lstMembers;
|
|
if(owners)
|
|
lstMembers = await MsTeam.GetOwnersAsync(SP);
|
|
else
|
|
lstMembers = await MsTeam.GetMembersAsync(SP);
|
|
if (lstMembers == null)
|
|
{
|
|
LogEntry($"Could not get owner list for Team '{this.TechnicalName}'", LogLevels.Warning);
|
|
return null;
|
|
}
|
|
|
|
var RetVal = new List<cLiamUserInfo>(lstMembers.Count);
|
|
LogEntry($"Owners for Team found: {lstMembers.Count}", LogLevels.Debug);
|
|
foreach (var MemberEntry in lstMembers.Values)
|
|
{
|
|
var User = new cLiamUserInfo()
|
|
{
|
|
DisplayName = MemberEntry.DisplayName,
|
|
GivenName = MemberEntry.GivenName,
|
|
SurName = MemberEntry.SurName,
|
|
UserPrincipalName = MemberEntry.UserPrincipalName,
|
|
EMail = MemberEntry.EMail,
|
|
SID = null
|
|
};
|
|
RetVal.Add(User);
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return null;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public override async Task<List<cLiamPermissionInfo>> GetPermissionsAsync(bool force = false)
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
try
|
|
{
|
|
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId))
|
|
{
|
|
LogEntry($"Error: License not valid", LogLevels.Error);
|
|
return null;
|
|
}
|
|
var RetVal = new List<cLiamPermissionInfo>();
|
|
var owners = await GetOwnersAsync();
|
|
foreach ( var owner in owners)
|
|
{
|
|
var permission = new cLiamPermissionInfo()
|
|
{
|
|
User = owner,
|
|
AccessRole = eLiamAccessRoles.Owner
|
|
};
|
|
RetVal.Add(permission);
|
|
}
|
|
var members = await GetMembersAsync(false);
|
|
foreach (var member in members)
|
|
{
|
|
var permission = new cLiamPermissionInfo()
|
|
{
|
|
User = member,
|
|
AccessRole = eLiamAccessRoles.Write
|
|
};
|
|
RetVal.Add(permission);
|
|
}
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
public override async Task<cLiamPermissionResult> GrantPermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId))
|
|
{
|
|
LogEntry($"Error: License not valid", LogLevels.Error);
|
|
return null;
|
|
}
|
|
var result = new cLiamPermissionResult();
|
|
|
|
if (Role == eLiamAccessRoles.Read)
|
|
{
|
|
return result;
|
|
}
|
|
try
|
|
{
|
|
var Roles = new List<cMsGraphResultPermission.ePermissionRole>()
|
|
{
|
|
cLiamProviderMsTeams.getMsGraphRole(Role)
|
|
};
|
|
|
|
var UserInfo = await Provider.MsSharepoint.RequestUserInfoAsync(User.UserPrincipalName);
|
|
if(string.IsNullOrEmpty(UserInfo?.ID))
|
|
{
|
|
LogEntry($"Could not find user {User.UserPrincipalName}", LogLevels.Error);
|
|
return null;
|
|
}
|
|
var retVal = await Provider.MsSharepoint.AddGroupMembership(MsTeam, false, UserInfo);
|
|
if(Role == eLiamAccessRoles.Owner)
|
|
retVal = await Provider.MsSharepoint.AddGroupMembership(MsTeam, true, UserInfo);
|
|
result.Valid = retVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public override async Task<bool> RevokePermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId))
|
|
{
|
|
LogEntry($"Error: License not valid", LogLevels.Error);
|
|
return false;
|
|
}
|
|
if (Role == eLiamAccessRoles.Read)
|
|
{
|
|
return false;
|
|
}
|
|
try
|
|
{
|
|
var Roles = new List<cMsGraphResultPermission.ePermissionRole>()
|
|
{
|
|
cLiamProviderMsTeams.getMsGraphRole(Role)
|
|
};
|
|
|
|
var UserInfo = await Provider.MsSharepoint.RequestUserInfoAsync(User.UserPrincipalName);
|
|
if (string.IsNullOrEmpty(UserInfo?.ODataId))
|
|
{
|
|
LogEntry($"Could not find user {User.UserPrincipalName}", LogLevels.Error);
|
|
return false;
|
|
}
|
|
bool retVal = false;
|
|
if (Role == eLiamAccessRoles.Owner)
|
|
{
|
|
retVal = await Provider.MsSharepoint.DeleteGroupMembership(MsTeam, true, UserInfo);
|
|
retVal &= await Provider.MsSharepoint.DeleteGroupMembership(MsTeam, false, UserInfo);
|
|
}
|
|
if (Role == eLiamAccessRoles.Write)
|
|
{
|
|
var members = await Provider.MsSharepoint.RequestGroupOwnersAsync(MsTeam.ID, UserInfo.ID);
|
|
if(members == null || members.Count == 0)
|
|
{
|
|
retVal = await Provider.MsSharepoint.DeleteGroupMembership(MsTeam, false, UserInfo);
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
public class cLiamMsTeamsChannel : cLiamDataAreaBase
|
|
{
|
|
public new readonly cLiamProviderMsTeams Provider = null;
|
|
public readonly cMsGraphResultChannel MsChannel = null;
|
|
|
|
public cLiamMsTeamsChannel(cLiamProviderMsTeams Provider, cLiamMsTeamsTeam Team, cMsGraphResultChannel MsChannel, string TeamUID = null) : base(Provider)
|
|
{
|
|
this.Provider = Provider;
|
|
this.MsChannel = MsChannel;
|
|
|
|
this.TechnicalName = getUID(MsChannel.ID, TeamUID ?? Team?.UID ?? "*");
|
|
this.DisplayName = MsChannel.DisplayName;
|
|
this.Level = 1;
|
|
this.UID = getUID(MsChannel.ID, TeamUID ?? Team?.UID ?? "*");
|
|
if (Team != null)
|
|
this.ParentUID = Team.UID;
|
|
this.DataType = eLiamDataAreaTypes.MsTeamsChannel;
|
|
}
|
|
|
|
internal static string getUID(string ChannelID, string TeamUID)
|
|
{
|
|
return $"{ChannelID} | {TeamUID}";
|
|
}
|
|
|
|
public override async Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
try
|
|
{
|
|
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId))
|
|
{
|
|
LogEntry($"Error: License not valid", LogLevels.Error);
|
|
return null;
|
|
}
|
|
if (MsChannel == null)
|
|
return null;
|
|
|
|
var RegExFilter = this.Provider?.DataAreaRegEx;
|
|
var SP = this.Provider?.MsSharepoint;
|
|
|
|
if (MsChannel.RootFolder == null)
|
|
if (SP == null || !await MsChannel.ResolveRootFolder(SP))
|
|
return null;
|
|
|
|
if (MsChannel.RootFolder.Folders == null)
|
|
if (SP == null || !await MsChannel.RootFolder.ResolveFolders(SP))
|
|
return null;
|
|
|
|
var DataAreas = new List<cLiamDataAreaBase>();
|
|
foreach (var Entry in MsChannel.RootFolder.Folders.Values)
|
|
{
|
|
if (!string.IsNullOrEmpty(RegExFilter) && !Regex.Match(Entry.DisplayName, RegExFilter).Success)
|
|
continue;
|
|
|
|
var DA = new cLiamMsTeamsFolder(this, Entry);
|
|
DataAreas.Add(DA);
|
|
}
|
|
DataAreas.AddRange(await getChildrenFromListAsync(DataAreas, Depth));
|
|
|
|
return DataAreas;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return null;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public static async Task<cLiamMsTeamsChannel> Load(cLiamProviderMsTeams Provider, string UID)
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
try
|
|
{
|
|
var arrIDs = UID.Split('|');
|
|
if (arrIDs.Length != 2)
|
|
return null;
|
|
|
|
var ChannelID = cLiamProviderMsTeams.getUidItem(ref UID);
|
|
var TeamID = cLiamProviderMsTeams.getUidItem(ref UID);
|
|
|
|
var C = await Provider.MsSharepoint.RequestChannelInfo(TeamID, ChannelID);
|
|
if (C == null)
|
|
return null;
|
|
|
|
var RetVal = new cLiamMsTeamsChannel(Provider, null, C, TeamID);
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return null;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
public class cLiamMsTeamsFolder : cLiamDataAreaBase
|
|
{
|
|
public new readonly cLiamProviderMsTeams Provider = null;
|
|
public readonly cLiamMsTeamsChannel Channel = null;
|
|
public readonly string ChannelUID = null;
|
|
public readonly cMsGraphResultFileObject MsFolder = null;
|
|
|
|
|
|
public cLiamMsTeamsFolder(cLiamMsTeamsChannel Channel, cMsGraphResultFileObject MsFolder) : this(Channel.Provider, Channel, Channel, MsFolder) { }
|
|
|
|
public cLiamMsTeamsFolder(cLiamMsTeamsFolder ParentFolder, cMsGraphResultFileObject MsFolder) : this(ParentFolder.Channel.Provider, ParentFolder.Channel, ParentFolder, MsFolder) { }
|
|
|
|
private cLiamMsTeamsFolder(cLiamProviderMsTeams Provider, cLiamMsTeamsChannel Channel, cLiamDataAreaBase ParentFolder, cMsGraphResultFileObject MsFolder, string ChannelUID = null) : base(Provider)
|
|
{
|
|
this.Channel = Channel;
|
|
if (Channel == null)
|
|
this.ChannelUID = ChannelUID;
|
|
else
|
|
this.ChannelUID = Channel.UID;
|
|
this.Provider = Provider;
|
|
this.MsFolder = MsFolder;
|
|
|
|
this.TechnicalName = MsFolder.DisplayName;
|
|
this.DisplayName = MsFolder.DisplayName;
|
|
if (ParentFolder != null)
|
|
{
|
|
this.Level = ParentFolder.Level + 1;
|
|
this.ParentUID = ParentFolder.UID;
|
|
}
|
|
this.UID = getUID(MsFolder.ID, MsFolder.DriveID, ChannelUID ?? Channel?.UID ?? "*|*");
|
|
this.DataType = eLiamDataAreaTypes.MsTeamsFolder;
|
|
this.SupportsPermissions = true;
|
|
}
|
|
|
|
internal static string getUID(string FolderID, string DriveID, string ChannelUID)
|
|
{
|
|
return $"{FolderID} | {DriveID} | {ChannelUID}";
|
|
}
|
|
|
|
public override async Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
try
|
|
{
|
|
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId))
|
|
{
|
|
LogEntry($"Error: License not valid", LogLevels.Error);
|
|
return null;
|
|
}
|
|
if (MsFolder == null)
|
|
return null;
|
|
|
|
var RegExFilter = this.Provider?.DataAreaRegEx;
|
|
var SP = this.Provider?.MsSharepoint;
|
|
|
|
if (MsFolder.Folders == null)
|
|
if (SP == null || !await MsFolder.ResolveFolders(SP))
|
|
return null;
|
|
|
|
var DataAreas = new List<cLiamDataAreaBase>();
|
|
foreach (var Entry in MsFolder.Folders.Values)
|
|
{
|
|
if (!string.IsNullOrEmpty(RegExFilter) && !Regex.Match(Entry.DisplayName, RegExFilter).Success)
|
|
continue;
|
|
|
|
var DA = new cLiamMsTeamsFolder(this.Provider, this.Channel, this, Entry, this.ChannelUID);
|
|
DataAreas.Add(DA);
|
|
}
|
|
var CL = await getChildrenFromListAsync(DataAreas, Depth);
|
|
if (CL != null)
|
|
DataAreas.AddRange(CL);
|
|
|
|
return DataAreas;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return null;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public static async Task<cLiamMsTeamsFolder> Load(cLiamProviderMsTeams Provider, string UID)
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
try
|
|
{
|
|
var arrIDs = UID.Split('|');
|
|
if (arrIDs.Length != 4)
|
|
return null;
|
|
|
|
var FolderID = cLiamProviderMsTeams.getUidItem(ref UID);
|
|
var DriveID = cLiamProviderMsTeams.getUidItem(ref UID);
|
|
|
|
var F = await Provider.MsSharepoint.RequestFileObjectInfo(DriveID, FolderID);
|
|
if (F == null)
|
|
return null;
|
|
|
|
var RetVal = new cLiamMsTeamsFolder(Provider, null, null, F, UID);
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return null;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
public override async Task<List<cLiamPermissionInfo>> GetPermissionsAsync(bool force = false)
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
try
|
|
{
|
|
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId))
|
|
{
|
|
LogEntry($"Error: License not valid", LogLevels.Error);
|
|
return null;
|
|
}
|
|
var RetVal = new List<cLiamPermissionInfo>();
|
|
if (this.MsFolder.Permissions == null || force)
|
|
if (!await this.MsFolder.ResolvePermissions(Provider.MsSharepoint))
|
|
return null;
|
|
|
|
if (this.MsFolder.Permissions == null)
|
|
return null;
|
|
|
|
foreach (var Perm in this.MsFolder.Permissions)
|
|
{
|
|
if (!(Perm is cMsGraphResultPermission.PermissionDirect) && !(Perm is cMsGraphResultPermission.PermissionLink))
|
|
continue;
|
|
|
|
if (Perm.isInherited)
|
|
continue;
|
|
|
|
|
|
|
|
if (Perm.Identities != null)
|
|
{
|
|
foreach (var Role in Perm.Roles)
|
|
{
|
|
var AccessRole = cLiamProviderMsTeams.getLiamRole(Role);
|
|
|
|
foreach (var Ident in Perm.Identities)
|
|
{
|
|
if (Ident.IdentityType != cMsGraphResultPermission.cMsGraphPermissionIdentity.eIdentityType.user)
|
|
continue;
|
|
|
|
if (string.IsNullOrEmpty(Ident.EMail))
|
|
continue;
|
|
|
|
if (!string.IsNullOrEmpty(Ident.ID))
|
|
{
|
|
var GroupInfo = await Provider.MsSharepoint.RequestGroupInfoAsync(Ident.ID);
|
|
if (GroupInfo != null)
|
|
continue;
|
|
}
|
|
|
|
var Usr = Ident.EMail.ToLowerInvariant();
|
|
var alreadyFound = false;
|
|
foreach (var Entry in RetVal)
|
|
{
|
|
if (Usr == Entry.User.EMail.ToLowerInvariant())
|
|
if (AccessRole == Entry.AccessRole)
|
|
{
|
|
alreadyFound = true;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (!alreadyFound)
|
|
{
|
|
var UsrInfo = new cLiamUserInfo()
|
|
{
|
|
DisplayName = Ident.DisplayName,
|
|
EMail = Ident.EMail,
|
|
UserPrincipalName = Ident.EMail
|
|
};
|
|
var PermInfo = new cLiamPermissionInfo()
|
|
{
|
|
User = UsrInfo,
|
|
AccessRole = AccessRole
|
|
};
|
|
RetVal.Add(PermInfo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public override async Task<cLiamPermissionResult> GrantPermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
try
|
|
{
|
|
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId))
|
|
{
|
|
LogEntry($"Error: License not valid", LogLevels.Error);
|
|
return null;
|
|
}
|
|
var Roles = new List<cMsGraphResultPermission.ePermissionRole>()
|
|
{
|
|
cLiamProviderMsTeams.getMsGraphRole(Role)
|
|
};
|
|
var RetVal = await this.MsFolder.AddPermission(Provider.MsSharepoint, Roles, cMsGraphResultPermission.eDriveReceipientType.email, User.EMail);
|
|
if (RetVal == null)
|
|
return null;
|
|
|
|
var RetVal2 = new cLiamPermissionResult();
|
|
if (RetVal.Count>= 0)
|
|
{
|
|
RetVal2.Valid = true;
|
|
var Perm = RetVal[0];
|
|
if (Perm is cMsGraphResultPermission.PermissionLink Link)
|
|
{
|
|
RetVal2.UserReference = Link.WebUrl;
|
|
}
|
|
else
|
|
RetVal2.UserReference = this.MsFolder.WebUrl;
|
|
}
|
|
|
|
return RetVal2;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return null;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
|
|
}
|
|
|
|
public override async Task<bool> RevokePermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
try
|
|
{
|
|
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId))
|
|
{
|
|
LogEntry($"Error: License not valid", LogLevels.Error);
|
|
return false;
|
|
}
|
|
var myRole = cLiamProviderMsTeams.getMsGraphRole(Role);
|
|
var RetVal = await this.MsFolder.RemovePermission(Provider.MsSharepoint, myRole, User.EMail);
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|