Issue accessing files with cfs upload via API

I'm using the CFS temporary endpoint community.telligent.com/.../upload-cfs-rest-endpoint to upload a file and then passing the url of the file to the create media post endpoint.

I've used some of the code from here as a basis; https://community.telligent.com/community/9/w/developer-training/53237/uploading-files#Embed_a_File_in_a_Post

However I'm having issues when trying to view the files as other users.

I have tried to upload the files as the admin user and create the posts as an admin user and also via impersonation using other user accounts and unless I create and upload the files under my account I can't view/download them. I get an 'you do not have permissions to view the directory or page' error message.

I can see the post in the media gallery fine, just not the file.

There is something simliar mentioned here: https://community.telligent.com/community/10/f/ask-the-community/1145434/issue-using-files-uploaded-to-cfs-via-rest/1600829#1600829 but I've tried everything I can think of and I still can't get the files to be viewable/downloadable by group members of the gallery. I've checked the gallery permissions too and they seem fine.

Can someone help me out with this?

Parents
  • Can you verify the embedded files are not pointing to the CFS temporary endpoint?

  • I've just checked the path when I edit the post and one example is: mysite.com/.../test.pdf

    That looks fine to me I think?

    I pass the fileurl from the temp cfs endpoint when I create the post as per the example. Doesn't that create a copy of the file in the real location?

  • Can you share your code for creating the media gallery post with the embedded file?

  • Don't pass the url to the media endpoint, use the FileUploadContext parameter, it should be set the uploadContextId used when you uploaded the file.  Then it should get located and moved

  • Hi Brian & Patrick,

    Thanks for you help but I can't get this to work for me.

    Here is my code for creating the media gallery post:

     public string CreateMediaPost(string restUserToken, string url, Guid contextId, string filePath, string fileUrl, int galleryId, string impersonateUser = null)
            {
                // Create request
                var request = (HttpWebRequest)WebRequest.Create(url + $"/api.ashx/v2/media/{galleryId}/files.json");
                request.Headers.Add("Rest-User-Token", restUserToken);
                if (!string.IsNullOrEmpty(impersonateUser))
                {
                    request.Headers.Add("Rest-Impersonate-User", impersonateUser);
                }
                request.ContentType = "application/x-www-form-urlencoded";
    
                FileInfo file = new FileInfo(filePath);
                var fileName = file.Name;
                var fileNameWithoutExtension = System.IO.Path.GetFileNameWithoutExtension(fileName);
                var uploadedFileName = System.IO.Path.GetFileName(fileUrl);
                var friendlyFileName = fileNameWithoutExtension != null ? fileNameWithoutExtension.Replace("-", " ").Replace("_", " ") : Guid.NewGuid().ToString();
    
                var fileContentType = MimeMapping.GetMimeMapping(file.FullName);
    
                // Collect necessary request information
                var values = new Dictionary<string, string>
                {
                    {"Name", friendlyFileName},
                    {"FileName", uploadedFileName},
                    {"ContentType", fileContentType },
                    {"FileUploadContext", contextId.ToString()},
    	            {"Description", friendlyFileName}
    	        };
    
                try
                {
                    // Add data to request
                    var queryString = string.Join("&", values.Select(v => $"{v.Key}={v.Value}"));
                    var bytesToSend = Encoding.UTF8.GetBytes(queryString);
    
                    // Send request and check response
                    var response = SendPostRequest(request, bytesToSend);
                    return response?["Media"]?["Url"];
                }
                catch (Exception ex)
                {
                    return InvestigateError(ex);
                }
            }

    An example here is context id: 201ecac6-705e-40fd-a3f8-8f5738965ab3

    The temp file path returned from the upload to cfs is: "http://mysite.com/cfs-file/__key/CommunityServer-Components-MultipleUploadFileManager/201ecac6_2D00_705e_2D00_40fd_2D00_a3f8_2D00_8f5738965ab3-2100-complete/test_2D00_9_2D00_update1_2D00_logo.png"

    This is passed into my function as fileUrl. 

    From this and the filePath I can get the file name etc to pass to the create media gallery post API call.

    But I get this error back: The File with identifier 'test_2D00_9_2D00_update1_2D00_logo.png' could not be found.

    Also the docs say only a filename is needed if adding filedata - and I'm not, I'm passing my context id yet it still requests a name and filename from me.

    https://community.telligent.com/community/10/w/api-documentation/61605/create-media-rest-endpoint

    I don't know why this won't work for me.

  • Can you share the code where you are uploading the file to the api.ashx/v2/cfs/temporary.xml endpoint as well?

  • Hi, no problem. here is is (it's all based on the sample code provided in the links above and that code uses the url, not the contexid I think).

     public string UploadFile(string restUserToken, string url, Guid uploadContextId, string filePath, string impersonateUser = null)
            {
                string fileUrl = null;
    
                try
                {    
                    FileInfo file = new FileInfo(filePath);
                    // Name file variables
                    var fileName = file.Name;
                    var fileContentType = MimeMapping.GetMimeMapping(file.FullName);
                    var fileDataStream = file.OpenRead();
    
                    // Calculate chunk information
                    int totalChunks = (int) Math.Ceiling((double) fileDataStream.Length / MAX_CHUNK_SIZE_BYTES);
    
                    // Open the file reader to read chunks
                    using (var rdr = new BinaryReader(fileDataStream))
                    {
                        // Send each chunk in succession
                        for (var currentChunk = 0; currentChunk < totalChunks; currentChunk++)
                        {
     
                            var boundary = Guid.NewGuid().ToString("N");
    
                            // Create request
                            var request = (HttpWebRequest) WebRequest.Create(url + "/api.ashx/v2/cfs/temporary.json");
                            request.Headers.Add("Rest-User-Token", restUserToken);
                            if (!string.IsNullOrEmpty(impersonateUser))
                            {
                                request.Headers.Add("Rest-Impersonate-User", impersonateUser);
                            }
                            request.ContentType = "multipart/form-data; boundary=" + boundary;
    
                            // Collect necessary request information
                            var formData = new Dictionary<string, string>
                            {
                                {"UploadContextId", uploadContextId.ToString()},
                                {"FileName", fileName},
                                {"CurrentChunk", currentChunk.ToString()},
                                {"TotalChunks", totalChunks.ToString()},
                            };
    
                            // Add data to the multi-part form
                            var requestData = new StringBuilder();
                            foreach (var item in formData)
                            {
                                requestData.Append(
                                    $"--{boundary}\r\nContent-Disposition: form-data; name=\"{item.Key}\"\r\n\r\n{item.Value}\r\n");
                            }
    
                            // Add the file itself
                            requestData.Append(
                                $"--{boundary}\r\nContent-Disposition: form-data; name=\"file\"; filename=\"{fileName}\"\r\nContent-Type: {fileContentType}\r\n\r\n");
    
                            // Prepare data chunk
                            var startDataBytes = Encoding.UTF8.GetBytes(requestData.ToString());
                            var chunk = rdr.ReadBytes(MAX_CHUNK_SIZE_BYTES);
                            var endDataBytes = Encoding.UTF8.GetBytes($"\r\n--{boundary}--\r\n");
    
                            // Combine all the request data into one array
                            var bytesToSend = new byte[startDataBytes.Length + chunk.Length + endDataBytes.Length];
                            startDataBytes.CopyTo(bytesToSend, 0);
                            chunk.CopyTo(bytesToSend, startDataBytes.Length);
                            endDataBytes.CopyTo(bytesToSend, startDataBytes.Length + chunk.Length);
    
                            try
                            {
                                // Make request and read results
                                var response = SendPostRequest(request, bytesToSend);
    
                                if (response?["Errors"] != null)
                                {
                                    return string.Join("\r\n", response["Errors"]);
                                }
    
                                fileUrl = response?["UploadedFile"]?["DownloadUrl"];
                            }
                            catch (WebException ex)
                            {
                                using (var stream = ex.Response.GetResponseStream())
                                using (var reader = new StreamReader(stream))
                                {
                                    return "Error: " + reader.ReadToEnd();
                                }
                            }
                            catch (Exception ex)
                            {
                                return InvestigateError(ex);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    return "Error: " ex.Message;
                }
    
                return fileUrl;
            }

    Thanks for your help with this.

Reply
  • Hi, no problem. here is is (it's all based on the sample code provided in the links above and that code uses the url, not the contexid I think).

     public string UploadFile(string restUserToken, string url, Guid uploadContextId, string filePath, string impersonateUser = null)
            {
                string fileUrl = null;
    
                try
                {    
                    FileInfo file = new FileInfo(filePath);
                    // Name file variables
                    var fileName = file.Name;
                    var fileContentType = MimeMapping.GetMimeMapping(file.FullName);
                    var fileDataStream = file.OpenRead();
    
                    // Calculate chunk information
                    int totalChunks = (int) Math.Ceiling((double) fileDataStream.Length / MAX_CHUNK_SIZE_BYTES);
    
                    // Open the file reader to read chunks
                    using (var rdr = new BinaryReader(fileDataStream))
                    {
                        // Send each chunk in succession
                        for (var currentChunk = 0; currentChunk < totalChunks; currentChunk++)
                        {
     
                            var boundary = Guid.NewGuid().ToString("N");
    
                            // Create request
                            var request = (HttpWebRequest) WebRequest.Create(url + "/api.ashx/v2/cfs/temporary.json");
                            request.Headers.Add("Rest-User-Token", restUserToken);
                            if (!string.IsNullOrEmpty(impersonateUser))
                            {
                                request.Headers.Add("Rest-Impersonate-User", impersonateUser);
                            }
                            request.ContentType = "multipart/form-data; boundary=" + boundary;
    
                            // Collect necessary request information
                            var formData = new Dictionary<string, string>
                            {
                                {"UploadContextId", uploadContextId.ToString()},
                                {"FileName", fileName},
                                {"CurrentChunk", currentChunk.ToString()},
                                {"TotalChunks", totalChunks.ToString()},
                            };
    
                            // Add data to the multi-part form
                            var requestData = new StringBuilder();
                            foreach (var item in formData)
                            {
                                requestData.Append(
                                    $"--{boundary}\r\nContent-Disposition: form-data; name=\"{item.Key}\"\r\n\r\n{item.Value}\r\n");
                            }
    
                            // Add the file itself
                            requestData.Append(
                                $"--{boundary}\r\nContent-Disposition: form-data; name=\"file\"; filename=\"{fileName}\"\r\nContent-Type: {fileContentType}\r\n\r\n");
    
                            // Prepare data chunk
                            var startDataBytes = Encoding.UTF8.GetBytes(requestData.ToString());
                            var chunk = rdr.ReadBytes(MAX_CHUNK_SIZE_BYTES);
                            var endDataBytes = Encoding.UTF8.GetBytes($"\r\n--{boundary}--\r\n");
    
                            // Combine all the request data into one array
                            var bytesToSend = new byte[startDataBytes.Length + chunk.Length + endDataBytes.Length];
                            startDataBytes.CopyTo(bytesToSend, 0);
                            chunk.CopyTo(bytesToSend, startDataBytes.Length);
                            endDataBytes.CopyTo(bytesToSend, startDataBytes.Length + chunk.Length);
    
                            try
                            {
                                // Make request and read results
                                var response = SendPostRequest(request, bytesToSend);
    
                                if (response?["Errors"] != null)
                                {
                                    return string.Join("\r\n", response["Errors"]);
                                }
    
                                fileUrl = response?["UploadedFile"]?["DownloadUrl"];
                            }
                            catch (WebException ex)
                            {
                                using (var stream = ex.Response.GetResponseStream())
                                using (var reader = new StreamReader(stream))
                                {
                                    return "Error: " + reader.ReadToEnd();
                                }
                            }
                            catch (Exception ex)
                            {
                                return InvestigateError(ex);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    return "Error: " ex.Message;
                }
    
                return fileUrl;
            }

    Thanks for your help with this.

Children