public BoxUtils.FileFolderInfo GetMiscellaneousFolder()
        {
            var bfc = (BoxFolderCache)FoldersByScreen.Select(MiscellaneousFolderScreenId);

            if (bfc == null)
            {
                throw new PXException(Messages.MiscFolderNotFoundRunSynchAgain);
            }
            else
            {
                try
                {
                    // Folder was found in BoxFolderCache, retrieve it by ID
                    var tokenHandler = PXGraph.CreateInstance <UserTokenHandler>();
                    BoxUtils.FileFolderInfo folderInfo = BoxUtils.GetFolderInfo(tokenHandler, bfc.FolderID).Result;
                    return(folderInfo);
                }
                catch (AggregateException ae)
                {
                    ScreenUtils.HandleAggregateException(ae, HttpStatusCode.NotFound, (exception) =>
                    {
                        using (new PXConnectionScope())
                        {
                            // Delete entry from BoxFolderCache so that it gets created again.
                            FoldersByScreen.Delete(bfc);
                            Actions.PressSave();
                        }

                        throw new PXException(Messages.MiscFolderNotFoundRunSynchAgain, bfc.FolderID, exception);
                    });

                    return(null);
                }
            }
        }
        public string GetEditUrl(Guid fileID)
        {
            FileHandler graph = PXGraph.CreateInstance <FileHandler>();

            BoxUtils.FileFolderInfo file = graph.GetBoxFileInfoForFileID(fileID);
            return("https://boxenterprise.net/embed_widget/000000000000/files/0/f/" + file.ParentFolderID + "/1/f_" + file.ID);
        }
        public void SynchronizeScreen(Screen screen, BoxUtils.FileFolderInfo rootFolder, bool forceSync)
        {
            string folderName = string.Format("{0} ({1})", (object)BoxUtils.CleanFileOrFolderName(screen.Name), (object)screen.ScreenID);

            BoxFolderCache screenFolderInfo = FoldersByScreen.Select(screen.ScreenID);

            BoxUtils.FileFolderInfo folderInfo = null;
            var tokenHandler = PXGraph.CreateInstance <UserTokenHandler>();

            if (screenFolderInfo != null)
            {
                try
                {
                    folderInfo = BoxUtils.GetFolderInfo(tokenHandler, screenFolderInfo.FolderID).Result;
                }
                catch (AggregateException ae)
                {
                    ScreenUtils.HandleAggregateException(ae, HttpStatusCode.NotFound, (exception) =>
                    {
                        // Folder no longer exist on Box - it may have been deleted on purpose by the user. Remove it from cache so it is recreated on the next run.
                        screenFolderInfo = FoldersByScreen.Delete(screenFolderInfo);
                        Actions.PressSave();
                        throw new PXException(Messages.BoxFolderNotFoundRunSynchAgain, screenFolderInfo.ScreenID, exception);
                    });
                }
            }

            if (folderInfo == null)
            {
                // Folder wasn't found, try finding it by name in the root folder.
                folderInfo = BoxUtils.FindFolder(tokenHandler, rootFolder.ID, folderName).Result;
            }

            if (folderInfo == null)
            {
                // Folder doesn't exist at all - create it
                folderInfo = BoxUtils.CreateFolder(tokenHandler, folderName, rootFolder.ID).Result;
            }

            if (screenFolderInfo == null)
            {
                screenFolderInfo                      = (BoxFolderCache)FoldersByScreen.Cache.CreateInstance();
                screenFolderInfo.FolderID             = folderInfo.ID;
                screenFolderInfo.ParentFolderID       = folderInfo.ParentFolderID;
                screenFolderInfo.ScreenID             = screen.ScreenID;
                screenFolderInfo.LastModifiedDateTime = null; //To force initial sync
                screenFolderInfo                      = FoldersByScreen.Insert(screenFolderInfo);
                Actions.PressSave();
            }

            // We don't synchronize the miscellaneous files folder, since we can't easily identify the corresponding NoteID from folder
            if (screen.ScreenID != FileHandler.MiscellaneousFolderScreenId && (forceSync || screenFolderInfo.LastModifiedDateTime != folderInfo.ModifiedAt))
            {
                SynchronizeFolderContentsWithScreen(screenFolderInfo.ScreenID, screenFolderInfo.FolderID, forceSync);
                screenFolderInfo.LastModifiedDateTime = folderInfo.ModifiedAt;
                FoldersByScreen.Update(screenFolderInfo);
                Actions.PressSave();
            }
        }
        public BoxUtils.FileFolderInfo GetBoxFileInfoForFileID(Guid fileID)
        {
            Guid         blobHandler  = GetBlobHandlerForFileID(fileID);
            BoxFileCache bfc          = GetFileInfoFromCache(blobHandler);
            var          tokenHandler = PXGraph.CreateInstance <UserTokenHandler>();

            BoxUtils.FileFolderInfo fileInfo = BoxUtils.GetFileInfo(tokenHandler, bfc.FileID).Result;
            if (fileInfo == null)
            {
                throw new PXException(Messages.FileNotFoundInBox, bfc.FileID);
            }

            return(fileInfo);
        }
        private BoxUtils.FileFolderInfo GetOrCreateActivityFolder(Guid?refNoteID, UserTokenHandler tokenHandler, object entityRow, object activityRefNoteID)
        {
            //Save an activity related file into the record's activity folder
            var activityRefNoteGuid = Guid.Parse(activityRefNoteID.ToString());

            //Get or create record folder
            string         folderID          = GetOrCreateBoxFolderForNoteID(activityRefNoteGuid);
            BoxFolderCache recordFolderCache = FoldersByFolderID.Select(folderID);

            //Get or create Activities folder
            BoxUtils.FileFolderInfo activityFolderInfo = null;
            if (string.IsNullOrEmpty(recordFolderCache.ActivityFolderID))
            {
                // Create Activities folder and update cache for future reference.
                activityFolderInfo = GetOrCreateFolder(tokenHandler, recordFolderCache.FolderID, null, null, Messages.ActivitiesFolderName);
                recordFolderCache.ActivityFolderID = activityFolderInfo.ID;
                FoldersByFolderID.Update(recordFolderCache);
                Actions.PressSave();
            }
            else
            {
                try
                {
                    // Folder was found in BoxFolderCache, retrieve it by ID
                    activityFolderInfo = BoxUtils.GetFolderInfo(tokenHandler, recordFolderCache.ActivityFolderID).Result;
                }
                catch (AggregateException ae)
                {
                    ScreenUtils.HandleAggregateException(ae, HttpStatusCode.NotFound, (exception) =>
                    {
                        using (new PXConnectionScope())
                        {
                            // Delete entry from BoxFolderCache so that it gets created again.
                            recordFolderCache.ActivityFolderID = null;
                            FoldersByNote.Update(recordFolderCache);
                            Actions.PressSave();
                        }

                        throw new PXException(Messages.BoxFolderNotFoundTryAgain, recordFolderCache.FolderID, exception);
                    });
                }
            }

            //Get/Create activityRecord folder
            string folderName = GetFolderNameForActivityRow(entityRow);

            return(GetOrCreateFolder(tokenHandler, activityFolderInfo.ID, entityRow, refNoteID, folderName));
        }
        private BoxUtils.FileFolderInfo GetOrCreateFolder(UserTokenHandler tokenHandler, string parentFolderID, object entityRow, Guid?refNoteID, string folderName)
        {
            try
            {
                BoxUtils.FileFolderInfo folderInfo = BoxUtils.FindFolder(tokenHandler, parentFolderID, folderName).Result;

                if (folderInfo == null)
                {
                    // Folder doesn't exist on Box, create it.
                    var description = entityRow != null?GetFolderDescriptionForEntityRow(entityRow) : string.Empty;

                    folderInfo = BoxUtils.CreateFolder(tokenHandler, folderName, parentFolderID, description).Result;
                }

                if (!FoldersByFolderID.Select(folderInfo.ID).Any())
                {
                    // Store the folder info in our local cache for future reference
                    BoxFolderCache bfc = (BoxFolderCache)FoldersByFolderID.Cache.CreateInstance();
                    bfc.FolderID             = folderInfo.ID;
                    bfc.ParentFolderID       = folderInfo.ParentFolderID;
                    bfc.RefNoteID            = refNoteID;
                    bfc.LastModifiedDateTime = null; // To force initial sync of Box file list with record file ilst
                    bfc = FoldersByFolderID.Insert(bfc);
                }

                return(folderInfo);
            }
            catch (AggregateException ae)
            {
                ScreenUtils.HandleAggregateException(ae, HttpStatusCode.NotFound, (exception) =>
                {
                    using (new PXConnectionScope())
                    {
                        var bfc      = FoldersByFolderID.Cache.CreateInstance() as BoxFolderCache;
                        bfc.FolderID = parentFolderID;
                        FoldersByFolderID.Delete(bfc);
                        Actions.PressSave();
                    }

                    throw (new PXException(string.Format(Messages.BoxFolderNotFoundTryAgain, parentFolderID), exception));
                });

                return(null);
            }
        }
        public BoxUtils.FileFolderInfo GetRootFolder()
        {
            string rootFolderName = GetRootFolderName();

            if (string.IsNullOrEmpty(rootFolderName))
            {
                throw new PXException(Messages.RootFolderNotSetup);
            }

            var tokenHandler = PXGraph.CreateInstance <UserTokenHandler>();

            BoxUtils.FileFolderInfo rootFolder = BoxUtils.FindFolder(tokenHandler, "0", rootFolderName).Result;
            if (rootFolder == null)
            {
                throw new PXException(Messages.RootFolderNotFound, rootFolderName);
            }

            return(rootFolder);
        }
        public void RefreshRecordFileList(string screenID, string folderName, string folderID, Guid?refNoteID, bool isForcingSync)
        {
            var tokenHandler = PXGraph.CreateInstance <UserTokenHandler>();

            //Get list of files contained in the record folder. RecurseDepth=0 will retrieve all subfolders
            List <BoxUtils.FileFolderInfo> boxFileList = BoxUtils.GetFileList(tokenHandler, folderID, (int)BoxUtils.RecursiveDepth.Unlimited).Result;

            // Remove files from cache if they don't exist on Box server
            foreach (PXResult <BoxFileCache, UploadFileRevisionNoData, UploadFile, NoteDoc> result in FilesByNoteID.Select(refNoteID))
            {
                BoxUtils.FileFolderInfo boxFile = boxFileList.FirstOrDefault(f => f.ID == ((BoxFileCache)result).FileID);
                if (boxFile == null)
                {
                    //File was deleted
                    FilesByNoteID.Delete(result);
                    UploadFiles.Delete(result);
                    UploadFileRevisions.Delete(result);
                    NoteDocs.Delete(result);
                }
                else
                {
                    // File still exists, remove it from in-memory list
                    // so we don't process it as a new file in the next loop
                    boxFileList.Remove(boxFile);
                }
            }

            // Remove any files/folders coming from activities stored beneath the current record, they've been processed above
            var filesFoundOnlyOnServer = boxFileList.Where(x => !x.Name.StartsWith(Messages.ActivitiesFolderName)).ToList();

            //Check for underlying activities records
            BoxFolderCache currentFolder = FoldersByFolderID.Select(folderID);

            if (currentFolder != null && boxFileList.Any(x => x.Name.StartsWith(Messages.ActivitiesFolderName)))
            {
                // If nullOrEmpty, Folder may have been created manually
                if (string.IsNullOrEmpty(currentFolder.ActivityFolderID))
                {
                    //Find actual folder ID and save in BoxFolderCache's ActivityFolderID field
                    BoxUtils.FileFolderInfo activityFolderinfo = BoxUtils.FindFolder(tokenHandler, folderID, Messages.ActivitiesFolderName).Result;
                    if (activityFolderinfo != null)
                    {
                        currentFolder.ActivityFolderID = activityFolderinfo?.ID;
                        FoldersByFolderID.Update(currentFolder);
                    }
                }

                if (currentFolder.ActivityFolderID != null)
                {
                    SynchronizeFolderContentsWithScreen(ActivityMaintScreenId, currentFolder.ActivityFolderID, isForcingSync);
                }
            }

            //Remaining files aren't found in cache but are in Box server.
            if (filesFoundOnlyOnServer.Any())
            {
                if (refNoteID == null)
                {
                    // User may have created some folder manually with a name not matching to any record, or record
                    // may have been deleted in Acumatica. We can safely ignore it, but let's write to trace.
                    PXTrace.WriteWarning(string.Format("No record found for folder {0} (screen {1}, ID {2})", folderName, screenID, folderID));
                    return;
                }

                UploadFileMaintenance ufm = PXGraph.CreateInstance <UploadFileMaintenance>();
                ufm.IgnoreFileRestrictions = true;

                ufm.RowInserting.AddHandler <UploadFileRevision>(delegate(PXCache sender, PXRowInsertingEventArgs e)
                {
                    ((UploadFileRevision)e.Row).BlobHandler = Guid.NewGuid();
                });
                //Add files to the caches
                foreach (BoxUtils.FileFolderInfo boxFile in filesFoundOnlyOnServer)
                {
                    ufm.Clear();
                    string   fileName = string.Format("{0}\\{1}", folderName, boxFile.Name.Replace(Path.GetInvalidPathChars(), ' '));
                    FileInfo fileInfo = ufm.GetFileWithNoData(fileName);
                    Guid?    blobHandlerGuid;
                    if (fileInfo == null)
                    {
                        fileInfo = new FileInfo(fileName, null, new byte[0]);
                        //The SaveFile call will trigger a Load() on the BoxBlobStorageProvider which can be skipped
                        PXContext.SetSlot <bool>("BoxDisableLoad", true);
                        try
                        {
                            if (!ufm.SaveFile(fileInfo))
                            {
                                throw new PXException(Messages.ErrorAddingFileSaveFileFailed, fileName);
                            }
                        }
                        finally
                        {
                            PXContext.SetSlot <bool>("BoxDisableLoad", false);
                        }

                        if (!fileInfo.UID.HasValue)
                        {
                            throw new PXException(Messages.ErrorAddingFileUIDNull, fileName);
                        }

                        UploadFileMaintenance.SetAccessSource(fileInfo.UID.Value, null, screenID);
                        NoteDoc noteDoc = (NoteDoc)NoteDocs.Cache.CreateInstance();
                        noteDoc.NoteID = refNoteID;
                        noteDoc.FileID = fileInfo.UID;
                        NoteDocs.Insert(noteDoc);

                        blobHandlerGuid = ufm.Revisions.Current.BlobHandler;
                    }
                    else
                    {
                        //File already exists in the database, retrieve BlobHandler
                        if (!fileInfo.UID.HasValue)
                        {
                            throw new PXException(Messages.GetFileWithNoDataReturnedUIDNull, fileName);
                        }
                        blobHandlerGuid = GetBlobHandlerForFileID(fileInfo.UID.Value);

                        //Clear old references of this blob handler from cache; it will be reinserted with up-to-date info
                        var bfcOrphan = (BoxFileCache)FilesByBlobHandler.Select(blobHandlerGuid);
                        if (bfcOrphan != null)
                        {
                            FilesByBlobHandler.Delete(bfcOrphan);
                        }

                        //Update NoteDoc entry if existing file was moved to new NoteID or create it if not there
                        NoteDoc nd = (NoteDoc)NoteDocsByFileID.Select(fileInfo.UID);
                        if (nd == null)
                        {
                            nd        = (NoteDoc)NoteDocs.Cache.CreateInstance();
                            nd.NoteID = refNoteID;
                            nd.FileID = fileInfo.UID;
                            NoteDocs.Insert(nd);
                        }
                        else if (nd.NoteID != refNoteID)
                        {
                            nd.NoteID = refNoteID;
                            NoteDocs.Update(nd);
                        }
                    }

                    var bfc = (BoxFileCache)FilesByBlobHandler.Cache.CreateInstance();
                    bfc.BlobHandler    = blobHandlerGuid;
                    bfc.FileID         = boxFile.ID;
                    bfc.ParentFolderID = boxFile.ParentFolderID;
                    bfc = FilesByBlobHandler.Insert(bfc);
                }
            }
        }
        public Guid SaveFileToBoxAndUpdateFileCache(byte[] data, PXBlobStorageContext saveContext)
        {
            BoxUtils.FileFolderInfo boxFile = null;
            Guid blobHandlerGuid            = Guid.NewGuid();

            var tokenHandler = PXGraph.CreateInstance <UserTokenHandler>();

            if (saveContext == null || saveContext.FileInfo == null || !saveContext.NoteID.HasValue)
            {
                var fileName = string.Empty;
                if (saveContext?.FileInfo?.Name == null)
                {
                    fileName = blobHandlerGuid.ToString();
                }
                else
                {
                    fileName = BoxUtils.CleanFileOrFolderName(saveContext.FileInfo.Name);
                    fileName = $"{Path.GetFileNameWithoutExtension(fileName)} ({blobHandlerGuid.ToString()}){Path.GetExtension(fileName)}";
                }

                //We don't know on which screen this file belongs. We'll have to save it in miscellaneous files folder.
                BoxUtils.FileFolderInfo boxFolder = GetMiscellaneousFolder();
                boxFile = BoxUtils.UploadFile(tokenHandler, boxFolder.ID, fileName, data).Result;
            }
            else
            {
                CheckForMissingNoteRecord(saveContext);
                var    fileName    = BoxUtils.CleanFileOrFolderName(Path.GetFileName(saveContext.FileInfo.Name));
                string boxFolderID = GetOrCreateBoxFolderForNoteID(saveContext.NoteID.Value);
                try
                {
                    boxFile = BoxUtils.UploadFile(tokenHandler, boxFolderID, fileName, data).Result;
                }
                catch (AggregateException ae)
                {
                    ScreenUtils.HandleAggregateException(ae, HttpStatusCode.NotFound, exception =>
                    {
                        using (new PXConnectionScope())
                        {
                            BoxFolderCache folderCacheToDelete = FoldersByFolderID.Cache.CreateInstance() as BoxFolderCache;
                            folderCacheToDelete.FolderID       = boxFolderID;
                            var deletedFolderInfo = FoldersByFolderID.Delete(folderCacheToDelete);
                            Actions.PressSave();
                        }

                        ScreenUtils.TraceAndThrowException(Messages.BoxFolderNotFoundRunSynchAgain, boxFolderID);
                    });
                }

                if (!string.IsNullOrEmpty(saveContext.FileInfo.Comment))
                {
                    BoxUtils.SetFileDescription(tokenHandler, boxFile.ID, saveContext.FileInfo.Comment).Wait();
                }
            }

            var bfc = (BoxFileCache)FilesByBlobHandler.Cache.CreateInstance();

            bfc.BlobHandler    = blobHandlerGuid;
            bfc.FileID         = boxFile.ID;
            bfc.ParentFolderID = boxFile.ParentFolderID;
            bfc = FilesByBlobHandler.Insert(bfc);
            Actions.PressSave();

            return(blobHandlerGuid);
        }