public IActionResult User_GetFolders(int id)
        {
            try
            {
                // verify that the user is either admin or is requesting their own data
                if (!HelperMethods.ValidateIsUserOrAdmin(_httpContextAccessor, _context, id))
                {
                    ErrorMessage error = new ErrorMessage("Invalid User", "Caller can only access their information.");
                    return(new UnauthorizedObjectResult(error));
                }

                // get and return all this user's accounts
                List <ReturnableFolder> folders = new List <ReturnableFolder>();
                foreach (Folder fold in _context.Users.Single(a => a.ID == id).Folders.ToArray())
                {
                    ReturnableFolder retFold = new ReturnableFolder(fold);
                    folders.Add(retFold);
                }

                return(new OkObjectResult(folders));
            }
            catch (Exception ex)
            {
                ErrorMessage error = new ErrorMessage("Error getting folders", ex.Message);
                return(new InternalServerErrorResult(error));
            }
        }
        public IActionResult User_SetFolderParent(int id, int folder_id, [FromBody] int?newParentID)
        {
            // verify that the user is either admin or is requesting their own data
            if (!HelperMethods.ValidateIsUserOrAdmin(_httpContextAccessor, _context, id, _keyAndIV))
            {
                ErrorMessage error = new ErrorMessage("Invalid User", "Caller can only access their information.");
                return(new UnauthorizedObjectResult(error));
            }

            // validate ownership of child
            if (!_context.Users.Single(a => a.ID == id).Folders.Exists(b => b.ID == folder_id))
            {
                ErrorMessage error = new ErrorMessage("Invalid folder", "User does not have a folder matching that ID.");
                return(new BadRequestObjectResult(error));
            }

            // use zero to mean null since body paramter must be present
            if (newParentID == 0)
            {
                newParentID = null;
            }

            // validate ownership of parent
            if (newParentID != null && !_context.Users.Single(a => a.ID == id).Folders.Exists(b => b.ID == newParentID))
            {
                ErrorMessage error = new ErrorMessage("Invalid folder", "User does not have a folder matching the ID of the new parent.");
                return(new BadRequestObjectResult(error));
            }

            /*
             * We need to be careful here that there are no issues when we move up the tree.
             * The new parent cannot be a child of the folder we wish to give a new parent.
             */
            if (CheckFolderForParentClash(id, folder_id, newParentID))
            {
                ErrorMessage error = new ErrorMessage("Invalid new parent folder", "Folder cannot be a child of itself or one of its children.");
                return(new BadRequestObjectResult(error));
            }

            // get reference to child old parent
            Folder child     = _context.Users.Single(a => a.ID == id).Folders.Single(b => b.ID == folder_id);
            Folder oldParent = child.ParentID != null?_context.Users.Single(a => a.ID == id).Folders.Single(b => b.ID == child.ParentID) : null;

            // set the childs new parentID, and set new parent to have a child
            child.ParentID = newParentID;
            if (newParentID != null)
            {
                _context.Users.Single(a => a.ID == id).Folders.Single(b => b.ID == newParentID).HasChild = true;
            }

            // Here we will want to check the old parent to make sure it still has children
            if (oldParent != null)
            {
                // if no other folder exists with their parent id the same as the old parent id, we update it to not have children
                if (!_context.Users.Single(a => a.ID == id).Folders.Exists(b => b.ParentID == oldParent.ID && b.ID != child.ID))
                {
                    oldParent.HasChild = false;
                }
            }

            _context.SaveChanges();

            // get and return all this user's folders...
            // this is helpful to have here because changin one folder could affect others and we dont
            // want to redo the parsing logic UI side
            List <ReturnableFolder> folders = new List <ReturnableFolder>();

            foreach (Folder fold in _context.Users.Single(a => a.ID == id).Folders.ToArray())
            {
                ReturnableFolder retFold = new ReturnableFolder(fold);
                folders.Add(retFold);
            }
            return(new OkObjectResult(folders));
        }
        public IActionResult User_DeleteFolder(int id, int folder_id)
        {
            // verify that the user is either admin or is requesting their own data
            if (!HelperMethods.ValidateIsUserOrAdmin(_httpContextAccessor, _context, id, _keyAndIV))
            {
                ErrorMessage error = new ErrorMessage("Invalid User", "Caller can only access their information.");
                return(new UnauthorizedObjectResult(error));
            }

            // validate ownership of said folder
            if (!_context.Users.Single(a => a.ID == id).Folders.Exists(b => b.ID == folder_id))
            {
                ErrorMessage error = new ErrorMessage("Invalid folder", "User does not have a folder matching that ID.");
                return(new BadRequestObjectResult(error));
            }

            Folder folderToDelete = _context.Users.Single(a => a.ID == id).Folders.Single(b => b.ID == folder_id);

            // if this folder has children, then we need to call DeleteFolder on all children
            if (folderToDelete.HasChild)
            {
                List <Folder> folders = _context.Users.Single(a => a.ID == id).Folders.ToList <Folder>();
                foreach (Folder folder in folders)
                {
                    if (folder.ParentID == folderToDelete.ID)
                    {
                        User_DeleteFolder(id, folder.ID); // recursive call to go down the tree and delete children
                    }
                }
            }

            // delete the accounts in the folder
            List <Account> accounts = _context.Users.Single(a => a.ID == id).Accounts.ToList <Account>();

            foreach (Account account in accounts)
            {
                if (account.FolderID == folderToDelete.ID)
                {
                    _context.Accounts.Remove(account); // no need to call User_DeleteAccount because identity and access token have already been verifies
                }
            }
            _context.SaveChanges();                  // save the accounts being deleted
            _context.Folders.Remove(folderToDelete); // remove the folder
            _context.SaveChanges();                  // save the folder being deleted.. must be done seperate because of foreign keys

            // if parent isnt root, then check if parent still has children
            if (folderToDelete.ParentID != null)
            {
                bool          parent_has_children = false;
                List <Folder> folders             = _context.Users.Single(a => a.ID == id).Folders.ToList <Folder>();
                foreach (Folder fold in folders)
                {
                    // if this folders parent is the same as the one we were just deleting than the original parent still has kids
                    if (fold.ParentID == folderToDelete.ParentID)
                    {
                        parent_has_children = true;
                    }
                }

                // update parent if needed
                if (!parent_has_children)
                {
                    _context.Users.Single(a => a.ID == id).Folders.Single(b => b.ID == folderToDelete.ParentID).HasChild = false;
                    _context.SaveChanges();
                }
            }

            // get and return all this user's folders...
            // this is helpful to have here because deleting one folder could affect others and we dont
            // want to redo the parsing logic UI side or make more api calls
            List <ReturnableFolder> updatedFolders = new List <ReturnableFolder>();

            foreach (Folder fold in _context.Users.Single(a => a.ID == id).Folders.ToArray())
            {
                ReturnableFolder retFold = new ReturnableFolder(fold);
                updatedFolders.Add(retFold);
            }

            // get and return all this user's accounts
            List <ReturnableAccount> safe = new List <ReturnableAccount>();

            foreach (Account acc in _context.Users.Single(a => a.ID == id).Accounts.ToArray())
            {
                ReturnableAccount retAcc = new ReturnableAccount(acc);
                safe.Add(retAcc);
            }

            // return both as an anonomous type
            var test = new { safe, updatedFolders };

            return(new OkObjectResult(test));
        }