microsoft / WindowsDevicePortalWrapper

A client library that wraps the Windows Device Portal REST APIs.
MIT License
182 stars 87 forks source link

Will there ever be a CreateFolderAsync() method added to the core Device Portal API? #266

Open gjrgj opened 7 years ago

gjrgj commented 7 years ago

Not being able to generate folders remotely is a small hindrance that I keep running into. It would be really convenient to be able to create my own directory structure on a remote device for file storage. Alternatively, a way of renaming folders remotely would also suffice, as I could have my applications generate the necessary directory structure on the first startup.

hpsin commented 7 years ago

Hi George - please upvote here: https://wpdev.uservoice.com/forums/110705-universal-windows-platform/suggestions/16509844-folder-upload-creation-and-download We're investigating the work needed here and which platforms will support it.

austinbhale commented 4 months ago

If anyone ever runs into this, you can create a new folder name using the following:

public static class DevicePortalExt
{
    /// <summary>
    /// API to retrieve the list of files in a folder.
    /// </summary>
    public static readonly string GetFolderApi = "api/filesystem/apps/folder";

    /// <summary>
    /// Creates a folder inside a Known Folder (e.g. LocalAppData)
    /// </summary>
    /// <param name="knownFolderId">The known folder id for the root of the path.</param>
    /// <param name="folderName">The name of the folder we are creating.</param>
    /// <param name="subPath">An optional subpath to the folder.</param>
    /// <param name="packageFullName">The package full name if using LocalAppData.</param>
    /// <returns>Task tracking completion of the upload request.</returns>
    public static Task CreateFolderAsync(
        this DevicePortal portal,
        string knownFolderId,
        string folderName,
        string? subPath = null,
        string? packageFullName = null)
    {
        Dictionary<string, string> payload = BuildCommonFilePayload(knownFolderId, subPath, packageFullName);
        payload.Add("newfoldername", folderName);
        return portal.PostAsync(GetFolderApi, BuildQueryString(payload));
    }

    /// <summary>
    /// Builds a query string from key value pairs.
    /// </summary>
    /// <param name="payload">The key value pairs containing the query parameters.</param>
    /// <returns>Properly formatted query string.</returns>
    public static string BuildQueryString(Dictionary<string, string> payload)
    {
        string query = string.Empty;

        foreach (KeyValuePair<string, string> pair in payload)
        {
            query += pair.Key + "=" + pair.Value + "&";
        }

        // Trim off the final ampersand.
        query = query.Trim('&');

        return query;
    }

    /// <summary>
    /// Do some common parsing and validation of file explorer parameters.
    /// </summary>
    /// <param name="knownFolderId">The known folder id.</param>
    /// <param name="subPath">The optional subpath for the folder.</param>
    /// <param name="packageFullName">The packagefullname if using LocalAppData.</param>
    /// <returns>Dictionary of param name to value.</returns>
    private static Dictionary<string, string> BuildCommonFilePayload(string knownFolderId, string? subPath, string? packageFullName)
    {
        Dictionary<string, string> payload = [];
        payload.Add("knownfolderid", knownFolderId);

        if (!string.IsNullOrEmpty(subPath))
        {
            if (!subPath.StartsWith("/"))
            {
                subPath = subPath.Insert(0, "/");
            }

            payload.Add("path", subPath);
        }

        if (!string.IsNullOrEmpty(packageFullName))
        {
            payload.Add("packagefullname", packageFullName);
        }
        else if (string.Equals(knownFolderId, "LocalAppData", StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("LocalAppData requires a packageFullName be provided.");
        }

        return payload;
    }
}