wix-file-sharing-client
TypeScript icon, indicating that this package has built-in type declarations

1.0.309 • Public • Published

About

Client library for File Sharing Server based on fetch.

Usage

import {FileSharingClient, FileSharingClientOptions} from 'file-sharing-client-js';

const fetch = window.fetch //in web or node-fetch in nodejs
const clientOptions: FileSharingClientOptions = {
  authorization: 'value-of-signed-instance',
  fetch
};
const fileSharingClient = FileSharingClient.create(clientOptions);

// Interacting with server
try {
  const appSettings = await fileSharingClient.getAppSettings();
} catch (e) {
  console.log('Error with code: ', e.errorCode);
}

Errors

Server errors are mapped to error object:

it('invalid request', async () => {
  try {
    await fileSharingClient.viewFile({actions: [{libraryItemId: 'test'}]});
  } catch (e) {
    expect(e.errorCode).to.be.equal('InvalidRequest');
    expect(e.message).to.contain('is invalid');
  }
});

e.errorCode can be one of InvalidRequest, TooManyRequests, InternalError. e.message holds explanation of the error that was sent by server.

Enums

For Enum fields you can import Enum constants or use strings that match constant name.

Constants:

import {wix} from 'file-sharing-client-js';

displaySettings: {
  layoutOptions: wix.filesharing.api.v1.settings.LayoutOptions.LIST,
  textAlignment: wix.filesharing.api.v1.settings.TextAlignment.LEFT
}

Strings:

import {wix} from 'file-sharing-client-js';

displaySettings: {
  layoutOptions: 'LIST',
  textAlignment: 'LEFT'
}

Longs

Big integers are represented as https://github.com/dcodeIO/long.js longs. Example is file size in bytes.

Root Folder Id

Root folder is a special folder. It is not physicaly stored anywhere. Root folder's parent is root folder itself. Each instance of file sharing can have different root folder id. Root folder id is provided in getAppSettings response.

App Settings

App settings entity contains all settings for site's or group's File Sharing TPA.

{
  "uploadSettings":{
    "allowVideoUploads": true
  },
  "downloadSettings":{
    "whoCanDownload":"ANYONE|MEMBERS_ONLY"
  },
  "favoriteSettings":{
    "isMembersAllowedToFavorite":true
  },
  "displaySettings":{
    "showFileOwnerName":true,
    "showSizeOfFiles":true,
    "showViewsCounter":true,
    "layoutOptions":"LIST|THUMBNAIL",
    "textAlignment":"LEFT|RIGHT",
    "showFileUploadDate":true,
    "showFavoritesCounter":true,
    "showNumberOfItems":true,
    "showLastModified":true,
    "defaultSort": "CREATED_AT|NAME|TYPE|TIMES_FAVORITED|UNIQUE_VIEWS|LAST_MODIFIED",
    "defaultOrientation": "ASC|DESC"
  },
  "designSettings":{
    "fileIcon": "EXTENSION|CLASSIC|LINE",
    "buttonCornerRadius": 42,
    "dividerWidth": 42,
    "memberProfileDividerWidth": 42
  }
}

Updates existing or default app settings. Only keys present in json are updated (Object.keys).

const settings = {
  uploadSettings: {
    allowVideoUploads: true,
  }
};
const {settings} = await fileSharingClient.updateAppSettings(settings);

Get default or existing settings:

const {settings, rootFolderId} = await fileSharingClient.getAppSettings();
Library Items

Main domain entity is Library Item. Library Item can be either Folder or File.

Library Item Entity
{
  id: "uuid",
  name: "string",
  createdByProfile: "IdentityProfile object",
  createdAt: "Date object",
  parentFolderId: "uuid",
  path: [{
    id: "uuid",
    name: "folder name"
  }],
  isFavorited: true,
  timesFavorited: 42,
  uniqueViews: 42,
  isViewed: true,
  // When file item is a file
  fileFields: {
    extension: "string", //lowercase without dot "pdf", "jpg", etc.
    sizeInBytes: "int"
  },

  // When file item is a folder
  folderFields: {
    childrenCount: "int",
    lastModified: "Date object",
    recentContributors: ["IdentityProfile object"]
  }
}
Folder creation

Creates new folder if it doesn't exist with same name.

const {folderId} = await fileSharingClient.createFolder({
  action: {
    name: "string",
    parentFolderId: "uuid", //Optional. To create under root folder send null or undefined
    actionId: "unique_for_this_request"
  }
});
Query library items

When no filters specified all files sorted by its ID is returned until the limit is reached.

const {libraryItems, metaData} = await fileSharingClient.queryLibraryItems({
  // Each filtering field is connected using logical AND.
  filter: {
    // Gets items with direct parent from this list.
    parentLibraryItemIds: [],
    // Gets all items that are descendants of given folder
    descendantsOfFolderId: "string",
    // Gets all items where name contains given string or is uploaded by matching user
    search: "string",
    // Gets all favorited items by current user
    filterFavoritedByCallingUser: "boolean",
    // Gets all items created by specified users
    createdBy: [],
    // Gets only files or folders. Empty means both.
    libraryItemTypes: [FILE, FOLDER]
  },
  sort: {
    sortBy: "NATURAL|CREATED_AT|NAME|TYPE|TIMES_FAVORITED|UNIQUE_VIEWS|LAST_MODIFIED",
    orientation: "DESC|ASC"
  },
  paging: {
    cursor: "string" //Optional. When unspecified will return first page until limit.
    limit: "number" //Optional. Limited to max 100.
  };
});

// Use next_cursor to fetch additional page. null means no more pages.
// Filtering and sorting is encoded inside cursor.
// Cursor takes precedence over given `filter` and `sorting` parameters
const { nextCursor } = metaData;
Query folder library items

Get library items for given folders. Defaults to root folder when filter is unspecified.

Response is identical to queryLibraryItems.

const {libraryItems, metadata} = await fileSharingClient.queryLibraryFolderItems({
  filter: {
    parentLibraryItemIds: [] // Defaults to Root folder when empty or unspecified
  },
  sort: {}, // Same as in queryLibraryItems
  paging: {} // Same as in queryLibraryItems
});
Get Library items by id

If it is not found it is ommited from response.

const response = await fileSharingClient.getLibraryItemsById({libraryItemIds: [folderId]});
expect(response.libraryItems).to.not.be.empty;
Get Folder Tree

rootLibraryItemId is optional. When given only tree from given folder will be returned.

const response = await fileSharingClient.getFolderTree({rootLibraryItemId: '00000000-0000-0000-0000-000000000000'});
expect(response).to.deep.equal({
  folderTree: {
    folderId: '00000000-0000-0000-0000-000000000000',
    name: '/',
    subfolders: []
  }
});
Upload file

File upload consits of 3 phases:

  • start upload by getting upload url
  • upload to upload url
  • callback with upload response

You can initiate multiple file uploads with single request:

const response = await fileSharingClient.startFileUpload({
  actions: [{
    name: 'test.png',
    sizeInBytes: 123,
    parentFolderId: '00000000-0000-0000-0000-000000000000',
    actionId: 'unique_for_this_request'
  }]
});
expect(response).to.be.deep.equal({
  urls: [{
    url: 'uploadUrl',
    requestParameters: {
      parent_folder_id: 'uploadParentFolderId',
      upload_token: 'uploadToken'
    },
    actionId: 'success1'
  }],
  failures: [{
    fileName: 'test.png',
    fileExtensionNotSupported: {
      extension: 'png'
    },
    fileTooBig: {
      size: 42,
      maxSize: 41
    },
    quotaExceeded: {
      quota: 1,
      limit: 2,
      type: "STORAGE|VIDEO_DURATION"
    }
    actionId: 'failure1'
  }]
});

You should not care what is in requestParameters. Just map it to FormData when performing upload.

Example of upload from browser:

<html>
  <body>
    <script>

      const uploadUrl = 'urlFrom_startFileUpload';
      const requestParameters = {}; // From startFileUpload

      async function uploadFile(e) {
        const file = e.elements[0].files[0];
        console.log('fileName', file.nane); //This name should be provided to startFileUpload, completeFileUpload

        //Populate form data with request parameters as is
        const formData = new FormData(e);
        Object.keys(requestParameters).forEach(key => formData.append(key, requestParameters[key]))

        const response = await fetch(uploadUrl, {
          method: 'POST',
          body: formData,
        });
        // this response must be provded to completeFileUpload
        console.log(await response.text());
      }
    </script>

    <form id="upload-form" enctype="multipart/form-data" action="" method="post" target="upload-result" onsubmit="uploadFile(this)">
        <input id="file" name="file" type="file" accept="image/*">
        <input id="submit" type="submit">
    </form>
  </body>
</html>

Complete upload by providing uploadResponse:

const response = await fileSharingClient.completeFileUpload({
  actions: [{
    parentFolderId: '00000000-0000-0000-0000-000000000000',
    uploadResponse: 'responseFromUploadUrl',
    actionId: 'unique_for_this_request'
  }]
});

expect(response).to.be.deep.equal({
  libraryItems: [{
    id: 'cfbeadb5-f75c-4046-a7a1-7b259f7ae382',
    name: 'file.png',
    createdBy: 'cfbeadb5-f75c-4046-a7a1-7b259f7ae382',
    createdByName: 'test',
    createdAt: new Date('1970-01-01T00:00:00.000Z'),
    parentFolderId: 'cfbeadb5-f75c-4046-a7a1-7b259f7ae382',
    path: [],
    isFavorited: true,
    timesFavorited: 42,
    uniqueViews: 42,
    isViewed: true,
    fileFields: {
      extension: 'png',
      sizeInBytes: 42
    }
  }],
  failures: [{
    fileName: 'test.png',
    fileTooBig: {
      size: 42,
      maxSize: 41
    },
    videoFilesForbidden: {},
    actionId: 'failure1'
  }]
});

Complete upload responds with newly created library items. You can complete upload of multiple files with single request.

Downloading

Same endpoint can be used to download:

  • single file: by probiding single id
  • multiple files: by providing multiple file ids
  • folder: by providing folder id

When download is invoked with single file id it would return url that would download that file. Browser will start file download because url respons with header Content-Disposition: attachment.

const response = await fileSharingClient.download({
  action: {
    libraryItemIds: ['cfbeadb5-f75c-4046-a7a1-7b259f7ae382']
  }
});
expect(response).to.be.deep.equal({url: 'http://testkit.download.com', isArchive: false});
View file

Returns url that responds with a file and Content-Disposition: inline

const response = await fileSharingClient.viewFile({
  actions: [{
    libraryItemId: 'cfbeadb5-f75c-4046-a7a1-7b259f7ae382'
  }]
});
expect(response).to.deep.equal({
  urls: [{
    libraryItemId: 'cfbeadb5-f75c-4046-a7a1-7b259f7ae382',
    url : 'view-url'
  }]
});

View folder

View folder increments folder view counts

const response = await fileSharingClient.viewFolder({
  actions: [{
    libraryItemId: 'cfbeadb5-f75c-4046-a7a1-7b259f7ae382'
  }]
});
expect(response).to.deep.equal({});
Favorite file or folder

Marks file or folder as favorite

const response = await fileSharingClient.favorite({
  actions: [{
    libraryItemId: 'cfbeadb5-f75c-4046-a7a1-7b259f7ae382',
    isFavorite: true,
    actionId: "unique_for_this_request"
  }]
});
expect(response).to.deep.equal({});
Rename file or folder

parentFolderId is optinal. Specifying zero UUID or undefined yields same behavior.

const response = await fileSharingClient.rename({
  actions: [{
    libraryItemId: 'cfbeadb5-f75c-4046-a7a1-7b259f7ae382', // File or Folder id
    newName: 'test',
    parentFolderId: '00000000-0000-0000-0000-000000000000',
    actionId: 'unique_for_this_request'
  }]
});
expect(response).to.deep.equal({});
Move file or folder

To move file or folder just specify its id and new parent. When currentParentFolderId is null Root is assumed.

const response = await fileSharingClient.move({
  actions: [{
    libraryItemId: 'cfbeadb5-f75c-4046-a7a1-7b259f7ae382',
    newParentFolderId: 'test',
    currentParentFolderId: '00000000-0000-0000-0000-000000000000',
    actionId: 'unique_for_this_request'
  }]
});
expect(response).to.deep.equal({});
Delete file or folder

Deletes file or folder

const response = await fileSharingClient.delete({
  actions: [{
    libraryItemIds: ['cfbeadb5-f75c-4046-a7a1-7b259f7ae382'],
    parentFolderId: '00000000-0000-0000-0000-000000000000',
    actionId: 'unique_for_this_request'
  }]
});
expect(response).to.deep.equal({});
Identity Profile

is an object that contains member information

const identityProfile = {
  id: "uuid",
  name: "string" // optional
  imageUrl: "string" //optional
}
Share file or folder

Currently share is implemented as url shortener without any file/folder context. It is responsible to prepend correct site domain to given path

const response = await fileSharingClient.share({
  urlPath: 'file-sharing-dev/file-sharing-dev/00000000-0000-0000-0000-000000000000'
});
expect(response).to.deep.equal({url: 'http://wix.to/testing'});
Roles and Permissions
Authorized actions

Provides actions that are available to user per item. Some actions like UPLOAD_FILE means that this action is available in the context of provided libraryItemId.

const response = await fileSharingClient.authorizeActions({
  libraryItemIds: ['00000000-0000-0000-0000-000000000000']
});
expect(response).to.deep.equal({
  authorizedActions: [
    {
      action: 'CREATE_FOLDER',
      isAllowedForAllMembers: true,
      itemId: '00000000-0000-0000-0000-000000000000',
      reason: 'MISSING_PERMISSION',
      status: 'FORBIDDEN'
    }
  ]
});

Currently supported rejection reasons

[    DEFAULT_REASON,
     NOT_ALLOWED_ON_ROOT,
     MISSING_PERMISSION,
     MUST_BE_A_MEMBER,
     MUST_BE_PUBLIC,
     OWNED_BY_ANOTHER_USER,
     FOLDER_NOT_EMPTY
]
Assign permissions
await fileSharingClient.assignPermissions({
  actions: [
    {
      permission: 'UPLOAD_FILE',
      roleId: '00000000-0000-0000-0000-000000000000'
    }
]});
Remove permissions
await fileSharingClient.removePermissions({
  actions: [
    {
      permission: 'CREATE_FOLDER',
      roleId: '00000000-0000-0000-0000-000000000000'
    }
]});
List roles with permission
const {roles} = await fileSharingClient.listRoles({
  permissions: ['CREATE_FOLDER', 'UPLOAD_FILE']
});

const {id, name, permissions, roleType} = roles[0];

When permissions array is empty then role has no file sharing permission assigned.

To fetch roles that have specific permission assigned use permissions filter.

To fetch all roles omit permissions filter (null or empty array).

List roles for current user

Lists current roles assigned to requesting user

const response = await fileSharingClient.listCurrentUserRoles();
expect(response).to.deep.equal([
  {
    id: '00000000-0000-0000-0000-000000000000',
    name: 'Admin',
    roleType: 'ADMINS'
  },
  {
    id: '00000000-0000-0000-0000-000000000001',
    name: 'All Members',
    roleType: 'ALL_MEMBERS'
  },
  {
    id: '548c837e-40b4-46b4-8436-27f5b12d5548',
    name: 'Some custom role',
    roleType: 'CUSTOM'
  }
]);

Role Entity
{
  id: "uuid",
  name: "user given name of a role",
  permissions: [
    'CREATE_FOLDER', 'UPLOAD_FILE', 'MODERATE'
  ],
  roleType: "ALL_MEMBERS|ADMINS|CUSTOM|PLAN"
}
Report item

Requires appDefId of reporting application. Response contains limitExceeded flag, indicating if user request was throttled

const appDefId = '00000000-0000-0000-0000-000000000000';
const response = await fileSharingClient.report({
  action: {
    itemId: '3a992b33-97b7-413b-be11-bdbd65197fb9',
    reason: 'UNWANTED_OR_SPAM|HARASSMENT_OR_BULLYING|INAPPROPRIATE_CONTENT|HATE_SPEECH_OR_GRAPHIC_VIOLENCE',
    actionId: 'clientgenerated'
  }
}, appDefId);
expect(response).to.deep.equal({'limitExceeded' false});

Don't forget to check if REPORT action is available in authorizeActions api.

Readme

Keywords

none

Package Sidebar

Install

npm i wix-file-sharing-client

Weekly Downloads

3

Version

1.0.309

License

MIT

Unpacked Size

2.58 MB

Total Files

24

Last publish

Collaborators

  • falconci
  • yurynix
  • itai.benda
  • wix-ci
  • wix-ambassador
  • shahata
  • netanelgilad
  • wix-ci-publisher
  • wix-bi-publisher