wix-file-sharing-client
v1.0.309
Published
File Sharing Server API JS Client
Downloads
42
Maintainers
Keywords
Readme
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.