using Microsoft.Graph; using Mps.Client.Mfp.SecureJobIndexerProxy.Interfaces; using Mps.Client.Mfp.Service.Commons.Interfaces; using Mps.Client.Mfp.Service.Commons.ScanToOneDrive.Implementation; using Mps.Client.Mfp.Service.Commons.ScanToOneDrive.Interfaces; using Mps.Client.Mfp.WebHost.Exceptions; using Mps.Client.Mfp.WebHost.Interfaces; using Mps.Client.Mfp.WebHost.Model.Scan; using Nancy; using Nancy.ModelBinding; using Pharos.Core.CustomerContext.Interfaces; using Pharos.Mfp.Services.Lib.Session.Interfaces; using PharosSystems.Mps.Client.Mfp.Constants; using PharosSystems.Mps.Client.Mfp.Interfaces; using PharosSystems.Mps.Client.Mfp.Types; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; namespace Mps.Client.Mfp.WebHost.Modules { class SharePointModule : NancyModule { private readonly ILogProvider _logger; private readonly HttpClientHandler _httpClientHandler; private readonly ISppAuthenticationService _authenticationService; private readonly INancyHeaderResolver _nancyHeaderResolver; private readonly ICustomerContextHelper _customerContextHelper; private readonly ISessionService _sessionService; private readonly ISppSettingsService _sppSettingsService; private readonly Func _scanToOneDriveServiceFactory; public SharePointModule( ILogProvider logger, ISppAuthenticationService authenticationService, INancyHeaderResolver nancyHeaderResolver, ICustomerContextHelper customerContextHelper, ISessionService sessionService, HttpClientHandler httpClientHandler, ISppSettingsService sppSettingsService, Func scanToOneDriveServiceFactory) { _logger = logger; _authenticationService = authenticationService; _nancyHeaderResolver = nancyHeaderResolver; _customerContextHelper = customerContextHelper; _sessionService = sessionService; _sppSettingsService = sppSettingsService; _httpClientHandler = httpClientHandler; _scanToOneDriveServiceFactory = scanToOneDriveServiceFactory; Get["api/sharepoint/sites", true] = async (parameters, ct) => { return await GetSharePointSites(); }; Get["api/sharepoint/site/{siteId}/folder/get-elements", true] = async (parameters, ct) => { return await GetSharePointSiteFolderElements(parameters.siteId, ""); }; Get["api/sharepoint/site/{siteId}/folder/get-elements/{folderId}", true] = async (parameters, ct) => { return await GetSharePointSiteFolderElements(parameters.siteId, parameters.folderId); }; Post["api/sharepoint/site/{siteId}/folder/create-folder/", true] = async (parameters, ct) => { return await CreateSharePointFolder(this.Bind()); }; } public async Task GetSharePointSites() { string methodName = $"[{nameof(OneDriveModule)}.{nameof(GetSharePointSites)}]"; IList folderItems; try { Guid assetId = _nancyHeaderResolver.GetAssetIdFromRequest(Request); Guid customerId = _nancyHeaderResolver.GetCustomerIdFromRequest(Request); using (ICustomerContext context = _customerContextHelper.BeginCustomerContext(customerId)) { var session = await _sessionService.GetSessionAsync(assetId); SppCredentials credentials = _authenticationService.GetCredentialsFromAccessTokenAsync(session.User.AccessToken, session.Device.AssetId).Result; string email = credentials.EmailAddress; // When AD is enabled sometime I was not getting email id in credentials.EmailAddress so // I am tring to fetech it from credentials.Username instead. if (email == "" || email == null) { if (credentials.Username.Contains("@")) { email = credentials.Username; } } IScanToOneDriveService service = _scanToOneDriveServiceFactory(customerId); IUserFollowedSitesCollectionWithReferencesPage childrenItems = await service.GetSharePointSites(email); folderItems = childrenItems.Select(childItem => new StorageItem { Id = childItem.Id, Name = childItem.DisplayName, Size = 0, IsFolder = true, ItemType = Office365StorageItemTypes.SharePointSite, }).ToList(); } } catch (CustomerNotAttachedToOfficeException e) { _logger.Runtime.LogError(Vendor.Common, e, $"{methodName} Error occured because email is not associated with office365."); return HandleError(HttpStatusCode.PreconditionFailed, e); } catch (Exception e) { _logger.Runtime.LogError(Vendor.Common, e, $"{methodName} Error occured while getting sharepoint sites."); return HandleError(HttpStatusCode.InternalServerError, e); } return Response.AsJson(folderItems); } public async Task GetSharePointSiteFolderElements(string siteId, string folderId) { string methodName = $"[{nameof(OneDriveModule)}.{nameof(GetSharePointSiteFolderElements)}]"; IList folderItems; try { Guid assetId = _nancyHeaderResolver.GetAssetIdFromRequest(Request); Guid customerId = _nancyHeaderResolver.GetCustomerIdFromRequest(Request); using (ICustomerContext context = _customerContextHelper.BeginCustomerContext(customerId)) { var session = await _sessionService.GetSessionAsync(assetId); SppCredentials credentials = _authenticationService.GetCredentialsFromAccessTokenAsync(session.User.AccessToken, session.Device.AssetId).Result; string email = credentials.EmailAddress; // When AD is enabled sometime I was not getting email id in credentials.EmailAddress so // I am tring to fetech it from credentials.Username instead. if (email == "" || email == null) { if (credentials.Username.Contains("@")) { email = credentials.Username; } } IScanToOneDriveService service = _scanToOneDriveServiceFactory(customerId); IDriveItemChildrenCollectionPage childrenItems = await service.GetSharePointSiteFolderElements(email, siteId, folderId); folderItems = childrenItems.Select(childItem => new StorageItem { Id = childItem.Id, Name = childItem.Name, Size = 0, IsFolder = true, ItemType = this.getOneDriveItemType(childItem), }).ToList(); } } catch (CustomerNotAttachedToOfficeException e) { _logger.Runtime.LogError(Vendor.Common, e, $"{methodName} Error occured because email is not associated with office365."); return HandleError(HttpStatusCode.PreconditionFailed, e); } catch (Exception e) { _logger.Runtime.LogError(Vendor.Common, e, $"{methodName} Error occured while getting sharepoint folder elements."); return HandleError(HttpStatusCode.InternalServerError, e); } return Response.AsJson(folderItems); } private async Task CreateSharePointFolder(Office365NewFolderRequest newFolderRequest) { string methodName = $"[{nameof(OneDriveModule)}.{nameof(CreateSharePointFolder)}]"; StorageItem sharePointFolderItem; try { Guid assetId = _nancyHeaderResolver.GetAssetIdFromRequest(Request); Guid customerId = _nancyHeaderResolver.GetCustomerIdFromRequest(Request); using (ICustomerContext context = _customerContextHelper.BeginCustomerContext(customerId)) { var session = await _sessionService.GetSessionAsync(assetId); SppCredentials credentials = _authenticationService.GetCredentialsFromAccessTokenAsync(session.User.AccessToken, session.Device.AssetId).Result; string emailId = credentials.EmailAddress; // When AD is enabled sometime I was not getting email id in credentials.EmailAddress so // I am tring to fetch it from credentials.Username instead. if (emailId == "" || emailId == null) { if (credentials.Username.Contains("@")) { emailId = credentials.Username; } } IScanToOneDriveService service = _scanToOneDriveServiceFactory(customerId); DriveItem driveItem = await service.CreateSharePointNewFolder(emailId, newFolderRequest.SharePointSiteId, newFolderRequest.FolderId, newFolderRequest.FolderName); sharePointFolderItem = new StorageItem { Id = driveItem.Id, Name = driveItem.Name, Size = driveItem.Size, IsFolder = driveItem.Folder != null ? true : false, }; } } catch (Exception e) { _logger.Runtime.LogError(Vendor.Common, e, $"{methodName} Error occured while creating new folder."); return HandleError(HttpStatusCode.InternalServerError, e); } return Response.AsJson(sharePointFolderItem); } private Office365StorageItemTypes getOneDriveItemType(DriveItem driveItem) { Office365StorageItemTypes type; if (driveItem.Folder != null) { type = Office365StorageItemTypes.OneDriveDirectory; } else if (driveItem.File != null) { type = Office365StorageItemTypes.OneDriveFile; } else { type = Office365StorageItemTypes.Unknown; } return type; } #region Helpers private Response HandleError(HttpStatusCode statusCode, Exception e) { string errorMessage = e.Message; // If a service does not respond, tell the client // a network connectivity error has occurred. if (!string.IsNullOrEmpty(errorMessage)) { string errorMessageLower = errorMessage.ToLower(); if (errorMessageLower.Contains(ErrorConstants.ErrorConnectingTo) || errorMessageLower.Contains(ErrorConstants.DidNotProperlyRespond) || errorMessageLower.Contains(ErrorConstants.FailedToRespond)) { errorMessage = ErrorConstants.ErrorNetwork; } } else if (e.InnerException != null) { if (e.InnerException.Message.ToLower().Contains(ErrorConstants.UnableToConnect)) { errorMessage = ErrorConstants.ErrorNetwork; } } if (errorMessage == ErrorConstants.ErrorNetwork) { statusCode = HttpStatusCode.ServiceUnavailable; } var resp = new Response { StatusCode = statusCode }; return resp; } #endregion } }