@girder/core 5.0.0-beta.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/Girder_Favicon.png +0 -0
- package/dist-lib/Girder_Mark.png +0 -0
- package/dist-lib/girder-core.css +2 -0
- package/dist-lib/girder-core.js +60421 -0
- package/dist-lib/girder-core.js.map +1 -0
- package/dist-lib/girder-core.umd.cjs +1484 -0
- package/dist-lib/girder-core.umd.cjs.map +1 -0
- package/dist-lib/index.d.ts +1 -0
- package/dist-lib/src/auth.js +112 -0
- package/dist-lib/src/collections/ApiKeyCollection.js +9 -0
- package/dist-lib/src/collections/AssetstoreCollection.js +10 -0
- package/dist-lib/src/collections/Collection.js +295 -0
- package/dist-lib/src/collections/CollectionCollection.js +9 -0
- package/dist-lib/src/collections/FileCollection.js +11 -0
- package/dist-lib/src/collections/FolderCollection.js +11 -0
- package/dist-lib/src/collections/GroupCollection.js +9 -0
- package/dist-lib/src/collections/ItemCollection.js +11 -0
- package/dist-lib/src/collections/UserCollection.js +24 -0
- package/dist-lib/src/collections/index.js +21 -0
- package/dist-lib/src/constants.js +32 -0
- package/dist-lib/src/dialog.js +128 -0
- package/dist-lib/src/events.js +6 -0
- package/dist-lib/src/index.ts +80 -0
- package/dist-lib/src/main.ts +61 -0
- package/dist-lib/src/misc.js +260 -0
- package/dist-lib/src/models/AccessControlledModel.js +76 -0
- package/dist-lib/src/models/ApiKeyModel.js +31 -0
- package/dist-lib/src/models/AssetstoreModel.js +43 -0
- package/dist-lib/src/models/CollectionCreationPolicyModel.js +20 -0
- package/dist-lib/src/models/CollectionModel.js +12 -0
- package/dist-lib/src/models/FileModel.js +310 -0
- package/dist-lib/src/models/FolderModel.js +33 -0
- package/dist-lib/src/models/GroupModel.js +197 -0
- package/dist-lib/src/models/ItemModel.js +72 -0
- package/dist-lib/src/models/MetadataMixin.js +88 -0
- package/dist-lib/src/models/Model.js +187 -0
- package/dist-lib/src/models/UserModel.js +189 -0
- package/dist-lib/src/models/index.js +25 -0
- package/dist-lib/src/pluginUtils.js +11 -0
- package/dist-lib/src/rest.js +221 -0
- package/dist-lib/src/router.js +58 -0
- package/dist-lib/src/routes.js +229 -0
- package/dist-lib/src/stylesheets/apidocs/apidocs.styl +50 -0
- package/dist-lib/src/stylesheets/body/adminConsole.styl +21 -0
- package/dist-lib/src/stylesheets/body/assetstores.styl +46 -0
- package/dist-lib/src/stylesheets/body/collectionList.styl +39 -0
- package/dist-lib/src/stylesheets/body/collectionPage.styl +6 -0
- package/dist-lib/src/stylesheets/body/frontPage.styl +48 -0
- package/dist-lib/src/stylesheets/body/groupList.styl +43 -0
- package/dist-lib/src/stylesheets/body/groupPage.styl +116 -0
- package/dist-lib/src/stylesheets/body/itemPage.styl +81 -0
- package/dist-lib/src/stylesheets/body/plugins.styl +61 -0
- package/dist-lib/src/stylesheets/body/searchResultsList.styl +51 -0
- package/dist-lib/src/stylesheets/body/systemConfig.styl +56 -0
- package/dist-lib/src/stylesheets/body/userAccount.styl +57 -0
- package/dist-lib/src/stylesheets/body/userList.styl +79 -0
- package/dist-lib/src/stylesheets/body/userPage.styl +6 -0
- package/dist-lib/src/stylesheets/layout/footer.styl +19 -0
- package/dist-lib/src/stylesheets/layout/global.styl +154 -0
- package/dist-lib/src/stylesheets/layout/globalNav.styl +89 -0
- package/dist-lib/src/stylesheets/layout/header.styl +29 -0
- package/dist-lib/src/stylesheets/layout/headerUser.styl +33 -0
- package/dist-lib/src/stylesheets/layout/layout.styl +75 -0
- package/dist-lib/src/stylesheets/layout/layoutVars.styl +9 -0
- package/dist-lib/src/stylesheets/layout/loading.styl +37 -0
- package/dist-lib/src/stylesheets/layout/progressArea.styl +17 -0
- package/dist-lib/src/stylesheets/widgets/accessWidget.styl +106 -0
- package/dist-lib/src/stylesheets/widgets/browserWidget.styl +9 -0
- package/dist-lib/src/stylesheets/widgets/hierarchyWidget.styl +188 -0
- package/dist-lib/src/stylesheets/widgets/markdownWidget.styl +92 -0
- package/dist-lib/src/stylesheets/widgets/metadataWidget.styl +92 -0
- package/dist-lib/src/stylesheets/widgets/searchFieldWidget.styl +70 -0
- package/dist-lib/src/stylesheets/widgets/taskProgress.styl +41 -0
- package/dist-lib/src/stylesheets/widgets/timelineWidget.styl +41 -0
- package/dist-lib/src/stylesheets/widgets/uploadWidget.styl +43 -0
- package/dist-lib/src/stylesheets/widgets/userOtpManagementWidget.styl +159 -0
- package/dist-lib/src/templates/body/adminConsole.pug +13 -0
- package/dist-lib/src/templates/body/assetstores.pug +83 -0
- package/dist-lib/src/templates/body/collectionList.pug +40 -0
- package/dist-lib/src/templates/body/collectionPage.pug +36 -0
- package/dist-lib/src/templates/body/filesystemImport.pug +41 -0
- package/dist-lib/src/templates/body/frontPage.pug +83 -0
- package/dist-lib/src/templates/body/groupList.pug +30 -0
- package/dist-lib/src/templates/body/groupPage.pug +116 -0
- package/dist-lib/src/templates/body/itemPage.pug +61 -0
- package/dist-lib/src/templates/body/plugins.pug +20 -0
- package/dist-lib/src/templates/body/s3Import.pug +35 -0
- package/dist-lib/src/templates/body/searchResults.pug +15 -0
- package/dist-lib/src/templates/body/searchResultsType.pug +13 -0
- package/dist-lib/src/templates/body/systemConfiguration.pug +215 -0
- package/dist-lib/src/templates/body/userAccount.pug +83 -0
- package/dist-lib/src/templates/body/userList.pug +43 -0
- package/dist-lib/src/templates/body/userPage.pug +40 -0
- package/dist-lib/src/templates/layout/alert.pug +5 -0
- package/dist-lib/src/templates/layout/layout.pug +12 -0
- package/dist-lib/src/templates/layout/layoutFooter.pug +11 -0
- package/dist-lib/src/templates/layout/layoutGlobalNav.pug +7 -0
- package/dist-lib/src/templates/layout/layoutHeader.pug +8 -0
- package/dist-lib/src/templates/layout/layoutHeaderUser.pug +26 -0
- package/dist-lib/src/templates/layout/layoutProgressArea.pug +1 -0
- package/dist-lib/src/templates/layout/loginDialog.pug +30 -0
- package/dist-lib/src/templates/layout/registerDialog.pug +35 -0
- package/dist-lib/src/templates/layout/resetPasswordDialog.pug +25 -0
- package/dist-lib/src/templates/widgets/accessEditor.pug +23 -0
- package/dist-lib/src/templates/widgets/accessEditorMixins.pug +57 -0
- package/dist-lib/src/templates/widgets/accessEditorNonModal.pug +11 -0
- package/dist-lib/src/templates/widgets/accessEntry.pug +32 -0
- package/dist-lib/src/templates/widgets/apiKeyList.pug +50 -0
- package/dist-lib/src/templates/widgets/browserWidget.pug +32 -0
- package/dist-lib/src/templates/widgets/checkedActionsMenu.pug +46 -0
- package/dist-lib/src/templates/widgets/collectionInfoDialog.pug +37 -0
- package/dist-lib/src/templates/widgets/confirmDialog.pug +14 -0
- package/dist-lib/src/templates/widgets/dateTimeRangeWidget.pug +20 -0
- package/dist-lib/src/templates/widgets/dateTimeWidget.pug +8 -0
- package/dist-lib/src/templates/widgets/editApiKeyWidget.pug +43 -0
- package/dist-lib/src/templates/widgets/editAssetstoreWidget.pug +70 -0
- package/dist-lib/src/templates/widgets/editCollectionWidget.pug +27 -0
- package/dist-lib/src/templates/widgets/editFileWidget.pug +21 -0
- package/dist-lib/src/templates/widgets/editFolderWidget.pug +27 -0
- package/dist-lib/src/templates/widgets/editGroupWidget.pug +54 -0
- package/dist-lib/src/templates/widgets/editItemWidget.pug +27 -0
- package/dist-lib/src/templates/widgets/fileInfoDialog.pug +33 -0
- package/dist-lib/src/templates/widgets/fileList.pug +33 -0
- package/dist-lib/src/templates/widgets/folderInfoDialog.pug +42 -0
- package/dist-lib/src/templates/widgets/folderList.pug +21 -0
- package/dist-lib/src/templates/widgets/groupAdminList.pug +33 -0
- package/dist-lib/src/templates/widgets/groupInviteDialog.pug +76 -0
- package/dist-lib/src/templates/widgets/groupInviteList.pug +14 -0
- package/dist-lib/src/templates/widgets/groupMemberList.pug +39 -0
- package/dist-lib/src/templates/widgets/groupModList.pug +23 -0
- package/dist-lib/src/templates/widgets/hierarchyBreadcrumb.pug +37 -0
- package/dist-lib/src/templates/widgets/hierarchyPaginated.pug +19 -0
- package/dist-lib/src/templates/widgets/hierarchyWidget.pug +96 -0
- package/dist-lib/src/templates/widgets/itemBreadcrumb.pug +16 -0
- package/dist-lib/src/templates/widgets/itemList.pug +27 -0
- package/dist-lib/src/templates/widgets/jsonMetadatumEditWidget.pug +13 -0
- package/dist-lib/src/templates/widgets/jsonMetadatumView.pug +6 -0
- package/dist-lib/src/templates/widgets/loadingAnimation.pug +4 -0
- package/dist-lib/src/templates/widgets/markdownWidget.pug +34 -0
- package/dist-lib/src/templates/widgets/metadataWidget.pug +16 -0
- package/dist-lib/src/templates/widgets/metadatumEditWidget.pug +15 -0
- package/dist-lib/src/templates/widgets/metadatumView.pug +5 -0
- package/dist-lib/src/templates/widgets/newAssetstore.pug +87 -0
- package/dist-lib/src/templates/widgets/paginateWidget.pug +7 -0
- package/dist-lib/src/templates/widgets/pluginConfigBreadcrumb.pug +13 -0
- package/dist-lib/src/templates/widgets/rootSelectorWidget.pug +13 -0
- package/dist-lib/src/templates/widgets/searchField.pug +10 -0
- package/dist-lib/src/templates/widgets/searchHelp.pug +12 -0
- package/dist-lib/src/templates/widgets/searchModeSelect.pug +9 -0
- package/dist-lib/src/templates/widgets/searchResults.pug +14 -0
- package/dist-lib/src/templates/widgets/sortCollectionWidget.pug +14 -0
- package/dist-lib/src/templates/widgets/taskProgress.pug +16 -0
- package/dist-lib/src/templates/widgets/timeline.pug +15 -0
- package/dist-lib/src/templates/widgets/uploadWidget.pug +15 -0
- package/dist-lib/src/templates/widgets/uploadWidgetMixins.pug +31 -0
- package/dist-lib/src/templates/widgets/uploadWidgetNonModal.pug +10 -0
- package/dist-lib/src/templates/widgets/userOtpBegin.pug +4 -0
- package/dist-lib/src/templates/widgets/userOtpDisable.pug +6 -0
- package/dist-lib/src/templates/widgets/userOtpEnable.pug +44 -0
- package/dist-lib/src/utilities/EventStream.js +119 -0
- package/dist-lib/src/utilities/PluginUtils.js +36 -0
- package/dist-lib/src/utilities/S3UploadHandler.js +263 -0
- package/dist-lib/src/utilities/index.js +9 -0
- package/dist-lib/src/utilities/jquery/girderEnable.js +19 -0
- package/dist-lib/src/utilities/jquery/girderModal.js +48 -0
- package/dist-lib/src/version.js +6 -0
- package/dist-lib/src/views/App.js +359 -0
- package/dist-lib/src/views/View.js +79 -0
- package/dist-lib/src/views/body/AdminView.js +29 -0
- package/dist-lib/src/views/body/AssetstoresView.js +233 -0
- package/dist-lib/src/views/body/CollectionView.js +188 -0
- package/dist-lib/src/views/body/CollectionsView.js +120 -0
- package/dist-lib/src/views/body/FilesystemImportView.js +83 -0
- package/dist-lib/src/views/body/FolderView.js +54 -0
- package/dist-lib/src/views/body/FrontPageView.js +47 -0
- package/dist-lib/src/views/body/GroupView.js +336 -0
- package/dist-lib/src/views/body/GroupsView.js +106 -0
- package/dist-lib/src/views/body/ItemView.js +177 -0
- package/dist-lib/src/views/body/PluginsView.js +73 -0
- package/dist-lib/src/views/body/S3ImportView.js +80 -0
- package/dist-lib/src/views/body/SearchResultsView.js +162 -0
- package/dist-lib/src/views/body/SystemConfigurationView.js +177 -0
- package/dist-lib/src/views/body/UserAccountView.js +179 -0
- package/dist-lib/src/views/body/UserView.js +165 -0
- package/dist-lib/src/views/body/UsersView.js +124 -0
- package/dist-lib/src/views/body/index.js +38 -0
- package/dist-lib/src/views/index.js +13 -0
- package/dist-lib/src/views/layout/FooterView.js +29 -0
- package/dist-lib/src/views/layout/GlobalNavView.js +103 -0
- package/dist-lib/src/views/layout/HeaderUserView.js +45 -0
- package/dist-lib/src/views/layout/HeaderView.js +83 -0
- package/dist-lib/src/views/layout/LoginView.js +100 -0
- package/dist-lib/src/views/layout/ProgressListView.js +70 -0
- package/dist-lib/src/views/layout/RegisterView.js +101 -0
- package/dist-lib/src/views/layout/ResetPasswordView.js +70 -0
- package/dist-lib/src/views/layout/index.js +19 -0
- package/dist-lib/src/views/widgets/AccessWidget.js +427 -0
- package/dist-lib/src/views/widgets/ApiKeyListWidget.js +140 -0
- package/dist-lib/src/views/widgets/BrowserWidget.js +317 -0
- package/dist-lib/src/views/widgets/CheckedMenuWidget.js +68 -0
- package/dist-lib/src/views/widgets/CollectionInfoWidget.js +40 -0
- package/dist-lib/src/views/widgets/DateTimeRangeWidget.js +180 -0
- package/dist-lib/src/views/widgets/DateTimeWidget.js +110 -0
- package/dist-lib/src/views/widgets/EditApiKeyWidget.js +124 -0
- package/dist-lib/src/views/widgets/EditAssetstoreWidget.js +136 -0
- package/dist-lib/src/views/widgets/EditCollectionWidget.js +93 -0
- package/dist-lib/src/views/widgets/EditFileWidget.js +56 -0
- package/dist-lib/src/views/widgets/EditFolderWidget.js +116 -0
- package/dist-lib/src/views/widgets/EditGroupWidget.js +125 -0
- package/dist-lib/src/views/widgets/EditItemWidget.js +110 -0
- package/dist-lib/src/views/widgets/FileInfoWidget.js +26 -0
- package/dist-lib/src/views/widgets/FileListWidget.js +151 -0
- package/dist-lib/src/views/widgets/FolderInfoWidget.js +39 -0
- package/dist-lib/src/views/widgets/FolderListWidget.js +106 -0
- package/dist-lib/src/views/widgets/GroupAdminsWidget.js +88 -0
- package/dist-lib/src/views/widgets/GroupInvitesWidget.js +56 -0
- package/dist-lib/src/views/widgets/GroupMembersWidget.js +185 -0
- package/dist-lib/src/views/widgets/GroupModsWidget.js +77 -0
- package/dist-lib/src/views/widgets/HierarchyWidget.js +1097 -0
- package/dist-lib/src/views/widgets/ItemBreadcrumbWidget.js +38 -0
- package/dist-lib/src/views/widgets/ItemListWidget.js +345 -0
- package/dist-lib/src/views/widgets/LoadingAnimation.js +17 -0
- package/dist-lib/src/views/widgets/MarkdownWidget.js +217 -0
- package/dist-lib/src/views/widgets/MetadataWidget.js +508 -0
- package/dist-lib/src/views/widgets/NewAssetstoreWidget.js +72 -0
- package/dist-lib/src/views/widgets/PaginateWidget.js +37 -0
- package/dist-lib/src/views/widgets/PluginConfigBreadcrumbWidget.js +33 -0
- package/dist-lib/src/views/widgets/RootSelectorWidget.js +192 -0
- package/dist-lib/src/views/widgets/SearchFieldWidget.js +365 -0
- package/dist-lib/src/views/widgets/SearchPaginateWidget.js +149 -0
- package/dist-lib/src/views/widgets/SortCollectionWidget.js +53 -0
- package/dist-lib/src/views/widgets/TaskProgressWidget.js +91 -0
- package/dist-lib/src/views/widgets/TimelineWidget.js +155 -0
- package/dist-lib/src/views/widgets/UploadWidget.js +340 -0
- package/dist-lib/src/views/widgets/UserOtpManagementWidget.js +105 -0
- package/dist-lib/src/views/widgets/index.js +81 -0
- package/dist-lib/src/vite-env.d.ts +5 -0
- package/package.json +17 -15
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import AccessControlledModel from '@girder/core/models/AccessControlledModel';
|
|
2
|
+
import { restRequest } from '@girder/core/rest';
|
|
3
|
+
|
|
4
|
+
var CollectionCreationPolicyModel = AccessControlledModel.extend({
|
|
5
|
+
resourceName: 'system/setting/collection_creation_policy',
|
|
6
|
+
fetchAccess: function () {
|
|
7
|
+
return restRequest({
|
|
8
|
+
url: `${this.resourceName}/access`,
|
|
9
|
+
method: 'GET'
|
|
10
|
+
}).done((resp) => {
|
|
11
|
+
this.set('access', resp);
|
|
12
|
+
this.trigger('g:accessFetched');
|
|
13
|
+
return resp;
|
|
14
|
+
}).fail((err) => {
|
|
15
|
+
this.trigger('g:error', err);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export default CollectionCreationPolicyModel;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import _ from 'underscore';
|
|
2
|
+
|
|
3
|
+
import AccessControlledModel from '@girder/core/models/AccessControlledModel';
|
|
4
|
+
import MetadataMixin from '@girder/core/models/MetadataMixin';
|
|
5
|
+
|
|
6
|
+
var CollectionModel = AccessControlledModel.extend({
|
|
7
|
+
resourceName: 'collection'
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
_.extend(CollectionModel.prototype, MetadataMixin);
|
|
11
|
+
|
|
12
|
+
export default CollectionModel;
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import _ from 'underscore';
|
|
2
|
+
|
|
3
|
+
import FolderModel from '@girder/core/models/FolderModel';
|
|
4
|
+
import ItemModel from '@girder/core/models/ItemModel';
|
|
5
|
+
import Model from '@girder/core/models/Model';
|
|
6
|
+
import { restRequest, uploadHandlers, getUploadChunkSize } from '@girder/core/rest';
|
|
7
|
+
import '@girder/core/utilities/S3UploadHandler'; // imported for side effect
|
|
8
|
+
|
|
9
|
+
var FileModel = Model.extend({
|
|
10
|
+
resourceName: 'file',
|
|
11
|
+
resumeInfo: null,
|
|
12
|
+
|
|
13
|
+
_wrapData: function (data, type) {
|
|
14
|
+
var wrapped = data;
|
|
15
|
+
|
|
16
|
+
if (!(data instanceof Blob)) {
|
|
17
|
+
if (!_.isArray(data)) {
|
|
18
|
+
wrapped = [data];
|
|
19
|
+
}
|
|
20
|
+
wrapped = new Blob(wrapped, {
|
|
21
|
+
type: type
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return wrapped;
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Upload into an existing file object (i.e. this model) to change its
|
|
30
|
+
* contents. This does not change the name or MIME type of the existing
|
|
31
|
+
* file.
|
|
32
|
+
* @param data A browser File object, browser Blob object, or raw data to be uploaded.
|
|
33
|
+
*/
|
|
34
|
+
updateContents: function (data) {
|
|
35
|
+
data = this._wrapData(data);
|
|
36
|
+
|
|
37
|
+
this.upload(null, data, {
|
|
38
|
+
url: `file/${this.id}/contents`,
|
|
39
|
+
method: 'PUT',
|
|
40
|
+
data: {
|
|
41
|
+
size: data.size
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Upload data to a new file in a given container
|
|
48
|
+
* @param Model A constructor for the parent model (either FolderModel or ItemModel).
|
|
49
|
+
* @param model The parent model to upload to, or a string containing the id thereof.
|
|
50
|
+
* @param data The data to upload - either a string, File object, or Blob object.
|
|
51
|
+
* @param name The name of the file to create (optional if data is a File).
|
|
52
|
+
* @param type The mime type of the file (optional).
|
|
53
|
+
*/
|
|
54
|
+
_uploadToContainer: function (Model, model, data, name, type) {
|
|
55
|
+
if (_.isString(model)) {
|
|
56
|
+
model = new Model({
|
|
57
|
+
_id: model
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
data = this._wrapData(data, type);
|
|
62
|
+
data.name = name;
|
|
63
|
+
|
|
64
|
+
this.upload(model, data);
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Upload data to a new file in a given folder
|
|
69
|
+
* @param parentFolder The parent folder to upload to, or a string containing the id thereof.
|
|
70
|
+
* @param data The data to upload - either a string, File object, or Blob object.
|
|
71
|
+
* @param name The name of the file to create (optional if data is a File).
|
|
72
|
+
* @param type The mime type of the file (optional).
|
|
73
|
+
*/
|
|
74
|
+
uploadToFolder: function (parentFolder, data, name, type) {
|
|
75
|
+
this._uploadToContainer(FolderModel, parentFolder, data, name, type);
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Upload data to a new file in a given folder
|
|
80
|
+
* @param parentItem The parent item to upload to, or a string containing the id thereof.
|
|
81
|
+
* @param data The data to upload - either a string, File object, or Blob object.
|
|
82
|
+
* @param name The name of the file to create (optional if data is a File).
|
|
83
|
+
* @param type The mime type of the file (optional).
|
|
84
|
+
*/
|
|
85
|
+
uploadToItem: function (parentItem, data, name, type) {
|
|
86
|
+
this._uploadToContainer(ItemModel, parentItem, data, name, type);
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Upload a file. Handles uploading into all of the core assetstore types.
|
|
91
|
+
* @param parentModel The parent folder or item to upload into.
|
|
92
|
+
* @param file The browser File object to be uploaded.
|
|
93
|
+
* @param [_restParams] Override the rest request parameters. This is meant
|
|
94
|
+
* for internal use; do not pass this parameter.
|
|
95
|
+
* @param [otherParams] Optional Object containing other parameters for the
|
|
96
|
+
* initUpload request.
|
|
97
|
+
*/
|
|
98
|
+
upload: function (parentModel, file, _restParams, otherParams) {
|
|
99
|
+
this.startByte = 0;
|
|
100
|
+
this.resumeInfo = null;
|
|
101
|
+
this.uploadHandler = null;
|
|
102
|
+
_restParams = _restParams || {
|
|
103
|
+
url: 'file',
|
|
104
|
+
method: 'POST',
|
|
105
|
+
data: _.extend({
|
|
106
|
+
parentType: parentModel.resourceName,
|
|
107
|
+
parentId: parentModel.get('_id'),
|
|
108
|
+
name: file.name,
|
|
109
|
+
size: file.size,
|
|
110
|
+
mimeType: file.type
|
|
111
|
+
}, otherParams)
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// Authenticate and generate the upload token for this file
|
|
115
|
+
restRequest(_restParams).done((upload) => {
|
|
116
|
+
var behavior = upload.behavior;
|
|
117
|
+
if (behavior && uploadHandlers[behavior]) {
|
|
118
|
+
this.uploadHandler = new uploadHandlers[behavior]({
|
|
119
|
+
upload: upload,
|
|
120
|
+
parentModel: parentModel,
|
|
121
|
+
file: file
|
|
122
|
+
});
|
|
123
|
+
this.uploadHandler.on({
|
|
124
|
+
'g:upload.complete': function (params) {
|
|
125
|
+
this.set(params);
|
|
126
|
+
this.trigger('g:upload.complete', params);
|
|
127
|
+
this.uploadHandler = null;
|
|
128
|
+
},
|
|
129
|
+
'g:upload.chunkSent': function (params) {
|
|
130
|
+
this.trigger('g:upload.chunkSent', params);
|
|
131
|
+
},
|
|
132
|
+
'g:upload.error': function (params) {
|
|
133
|
+
this.trigger('g:upload.error', params);
|
|
134
|
+
},
|
|
135
|
+
'g:upload.errorStarting': function (params) {
|
|
136
|
+
this.trigger('g:upload.errorStarting', params);
|
|
137
|
+
},
|
|
138
|
+
'g:upload.progress': function (params) {
|
|
139
|
+
this.trigger('g:upload.progress', {
|
|
140
|
+
startByte: params.startByte,
|
|
141
|
+
loaded: params.loaded,
|
|
142
|
+
total: params.file.size,
|
|
143
|
+
file: params.file
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}, this);
|
|
147
|
+
return this.uploadHandler.execute();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (file.size > 0) {
|
|
151
|
+
// Begin uploading chunks of this file
|
|
152
|
+
this._uploadChunk(file, upload._id);
|
|
153
|
+
} else {
|
|
154
|
+
// Empty file, so we are done
|
|
155
|
+
this.set(upload);
|
|
156
|
+
this.trigger('g:upload.complete');
|
|
157
|
+
}
|
|
158
|
+
}).fail((resp) => {
|
|
159
|
+
var text = 'Error: ', identifier;
|
|
160
|
+
|
|
161
|
+
if (resp.status === 0) {
|
|
162
|
+
text += 'Connection to the server interrupted.';
|
|
163
|
+
} else {
|
|
164
|
+
text += resp.responseJSON.message;
|
|
165
|
+
identifier = resp.responseJSON.identifier;
|
|
166
|
+
}
|
|
167
|
+
this.trigger('g:upload.errorStarting', {
|
|
168
|
+
message: text,
|
|
169
|
+
identifier: identifier,
|
|
170
|
+
response: resp
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* If an error was triggered during the upload of this file, call this
|
|
177
|
+
* in order to attempt to resume it.
|
|
178
|
+
*/
|
|
179
|
+
resumeUpload: function () {
|
|
180
|
+
if (this.uploadHandler !== null && this.uploadHandler.resume) {
|
|
181
|
+
return this.uploadHandler.resume();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Request the actual offset we need to resume at
|
|
185
|
+
restRequest({
|
|
186
|
+
url: 'file/offset',
|
|
187
|
+
method: 'GET',
|
|
188
|
+
data: {
|
|
189
|
+
uploadId: this.resumeInfo.uploadId
|
|
190
|
+
},
|
|
191
|
+
error: null
|
|
192
|
+
}).done((resp) => {
|
|
193
|
+
this.startByte = resp.offset;
|
|
194
|
+
this._uploadChunk(this.resumeInfo.file, this.resumeInfo.uploadId);
|
|
195
|
+
}).fail((resp) => {
|
|
196
|
+
var msg;
|
|
197
|
+
|
|
198
|
+
if (resp.status === 0) {
|
|
199
|
+
msg = 'Could not connect to the server.';
|
|
200
|
+
} else {
|
|
201
|
+
msg = 'An error occurred when resuming upload, check console.';
|
|
202
|
+
}
|
|
203
|
+
this.trigger('g:upload.error', {
|
|
204
|
+
message: msg,
|
|
205
|
+
response: resp
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
abortUpload: function () {
|
|
211
|
+
if (!this.resumeInfo || !this.resumeInfo.uploadId) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
restRequest({
|
|
215
|
+
url: 'system/uploads',
|
|
216
|
+
method: 'DELETE',
|
|
217
|
+
data: {
|
|
218
|
+
uploadId: this.resumeInfo.uploadId
|
|
219
|
+
},
|
|
220
|
+
error: null,
|
|
221
|
+
done: null
|
|
222
|
+
});
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
_uploadChunk: function (file, uploadId) {
|
|
226
|
+
var endByte = Math.min(this.startByte + getUploadChunkSize(), file.size);
|
|
227
|
+
|
|
228
|
+
this.chunkLength = endByte - this.startByte;
|
|
229
|
+
var sliceFn = file.webkitSlice ? 'webkitSlice' : 'slice';
|
|
230
|
+
var blob = file[sliceFn](this.startByte, endByte);
|
|
231
|
+
|
|
232
|
+
restRequest({
|
|
233
|
+
url: `file/chunk?offset=${this.startByte}&uploadId=${uploadId}`,
|
|
234
|
+
method: 'POST',
|
|
235
|
+
data: blob,
|
|
236
|
+
contentType: false,
|
|
237
|
+
processData: false,
|
|
238
|
+
success: (resp) => {
|
|
239
|
+
this.trigger('g:upload.chunkSent', {
|
|
240
|
+
bytes: endByte - this.startByte
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
if (endByte === file.size) {
|
|
244
|
+
this.startByte = 0;
|
|
245
|
+
this.resumeInfo = null;
|
|
246
|
+
this.set(resp);
|
|
247
|
+
this.trigger('g:upload.complete');
|
|
248
|
+
} else {
|
|
249
|
+
this.startByte = endByte;
|
|
250
|
+
this._uploadChunk(file, uploadId);
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
error: (resp) => {
|
|
254
|
+
var text = 'Error: ', identifier;
|
|
255
|
+
|
|
256
|
+
if (resp.status === 0) {
|
|
257
|
+
text += 'Connection to the server interrupted.';
|
|
258
|
+
} else {
|
|
259
|
+
text += resp.responseJSON.message;
|
|
260
|
+
identifier = resp.responseJSON.identifier;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
this.resumeInfo = {
|
|
264
|
+
uploadId: uploadId,
|
|
265
|
+
file: file
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
this.trigger('g:upload.error', {
|
|
269
|
+
message: text,
|
|
270
|
+
identifier: identifier,
|
|
271
|
+
response: resp
|
|
272
|
+
});
|
|
273
|
+
},
|
|
274
|
+
xhr: () => {
|
|
275
|
+
// Custom XHR so we can register a progress handler
|
|
276
|
+
var xhr = new window.XMLHttpRequest();
|
|
277
|
+
xhr.upload.addEventListener('progress', (e) => {
|
|
278
|
+
this._uploadProgress(file, e);
|
|
279
|
+
});
|
|
280
|
+
return xhr;
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Progress callback from XHR during upload. This will trigger useful
|
|
287
|
+
* progress events under the 'upload.progress' tag.
|
|
288
|
+
*/
|
|
289
|
+
_uploadProgress: function (file, event) {
|
|
290
|
+
if (!event.lengthComputable) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// We only want to count bytes of the actual file, not the bytes of
|
|
295
|
+
// the request body corresponding to the other form parameters model
|
|
296
|
+
// we are also sending.
|
|
297
|
+
var loaded = this.chunkLength + event.loaded - event.total;
|
|
298
|
+
|
|
299
|
+
if (loaded >= 0) {
|
|
300
|
+
this.trigger('g:upload.progress', {
|
|
301
|
+
startByte: this.startByte,
|
|
302
|
+
loaded: loaded,
|
|
303
|
+
total: file.size,
|
|
304
|
+
file: file
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
export default FileModel;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import _ from 'underscore';
|
|
2
|
+
|
|
3
|
+
import AccessControlledModel from '@girder/core/models/AccessControlledModel';
|
|
4
|
+
import MetadataMixin from '@girder/core/models/MetadataMixin';
|
|
5
|
+
import { restRequest } from '@girder/core/rest';
|
|
6
|
+
|
|
7
|
+
var FolderModel = AccessControlledModel.extend({
|
|
8
|
+
resourceName: 'folder',
|
|
9
|
+
|
|
10
|
+
getRootPath: function () {
|
|
11
|
+
return restRequest({
|
|
12
|
+
url: `${this.resourceName}/${this.id}/rootpath`
|
|
13
|
+
});
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Remove the contents of the folder.
|
|
18
|
+
*/
|
|
19
|
+
removeContents: function () {
|
|
20
|
+
return restRequest({
|
|
21
|
+
url: `${this.resourceName}/${this.id}/contents`,
|
|
22
|
+
method: 'DELETE'
|
|
23
|
+
}).done(() => {
|
|
24
|
+
this.trigger('g:success');
|
|
25
|
+
}).fail((err) => {
|
|
26
|
+
this.trigger('g:error', err);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
_.extend(FolderModel.prototype, MetadataMixin);
|
|
32
|
+
|
|
33
|
+
export default FolderModel;
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import _ from 'underscore';
|
|
2
|
+
|
|
3
|
+
import AccessControlledModel from '@girder/core/models/AccessControlledModel';
|
|
4
|
+
import { AccessType } from '@girder/core/constants';
|
|
5
|
+
import { getCurrentUser } from '@girder/core/auth';
|
|
6
|
+
import { restRequest } from '@girder/core/rest';
|
|
7
|
+
|
|
8
|
+
var GroupModel = AccessControlledModel.extend({
|
|
9
|
+
resourceName: 'group',
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Send an invitation to this group to the user identified by userId.
|
|
13
|
+
* Requires moderator (write) access on the group.
|
|
14
|
+
* @param userId The ID of the user to invite.
|
|
15
|
+
* @param accessType The access level to invite them as.
|
|
16
|
+
* @param request Set to true if this is accepting a user's request to join.
|
|
17
|
+
* @param [params] Additional parameters to pass with the request.
|
|
18
|
+
*/
|
|
19
|
+
sendInvitation: function (userId, accessType, request, params) {
|
|
20
|
+
params = params || {};
|
|
21
|
+
return restRequest({
|
|
22
|
+
url: `${this.resourceName}/${this.id}/invitation`,
|
|
23
|
+
data: _.extend({
|
|
24
|
+
userId: userId,
|
|
25
|
+
level: accessType
|
|
26
|
+
}, params),
|
|
27
|
+
method: 'POST',
|
|
28
|
+
error: null
|
|
29
|
+
}).done((resp) => {
|
|
30
|
+
this.set(resp);
|
|
31
|
+
|
|
32
|
+
if (!request && userId === getCurrentUser().get('_id')) {
|
|
33
|
+
if (params.force) {
|
|
34
|
+
getCurrentUser().addToGroup(this.get('_id'));
|
|
35
|
+
} else {
|
|
36
|
+
getCurrentUser().addInvitation(this.get('_id'), accessType);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
this.trigger('g:invited');
|
|
40
|
+
}).fail((err) => {
|
|
41
|
+
this.trigger('g:error', err);
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Accept an invitation to join a group. Only call this if the user has
|
|
47
|
+
* already been invited to the group.
|
|
48
|
+
*/
|
|
49
|
+
joinGroup: function () {
|
|
50
|
+
return restRequest({
|
|
51
|
+
url: `${this.resourceName}/${this.id}/member`,
|
|
52
|
+
method: 'POST'
|
|
53
|
+
}).done((resp) => {
|
|
54
|
+
getCurrentUser().addToGroup(this.get('_id'));
|
|
55
|
+
getCurrentUser().removeInvitation(this.get('_id'));
|
|
56
|
+
|
|
57
|
+
this.set(resp);
|
|
58
|
+
|
|
59
|
+
this.trigger('g:joined');
|
|
60
|
+
}).fail((err) => {
|
|
61
|
+
this.trigger('g:error', err);
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* This will create an invitation request on this group for the current
|
|
67
|
+
* user. Requires read access on the group. If the user already has an
|
|
68
|
+
* outstanding invitation to this group, call joinGroup instead.
|
|
69
|
+
*/
|
|
70
|
+
requestInvitation: function () {
|
|
71
|
+
return restRequest({
|
|
72
|
+
url: `${this.resourceName}/${this.id}/member`,
|
|
73
|
+
method: 'POST'
|
|
74
|
+
}).done((resp) => {
|
|
75
|
+
this.set(resp);
|
|
76
|
+
|
|
77
|
+
this.trigger('g:inviteRequested');
|
|
78
|
+
}).fail((err) => {
|
|
79
|
+
this.trigger('g:error', err);
|
|
80
|
+
});
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Promote a user to moderator or administrator. Requires admin access
|
|
85
|
+
* on the group.
|
|
86
|
+
* @param user The user model of the user being promoted
|
|
87
|
+
* @param level The AccessLevel (WRITE or ADMIN) to promote to
|
|
88
|
+
*/
|
|
89
|
+
promoteUser: function (user, level) {
|
|
90
|
+
var role;
|
|
91
|
+
if (level === AccessType.WRITE) {
|
|
92
|
+
role = 'moderator';
|
|
93
|
+
} else if (level === AccessType.ADMIN) {
|
|
94
|
+
role = 'admin';
|
|
95
|
+
}
|
|
96
|
+
return restRequest({
|
|
97
|
+
url: `${this.resourceName}/${this.id}/${role}`,
|
|
98
|
+
data: {
|
|
99
|
+
userId: user.get('_id')
|
|
100
|
+
},
|
|
101
|
+
method: 'POST'
|
|
102
|
+
}).done((resp) => {
|
|
103
|
+
this.set(resp);
|
|
104
|
+
|
|
105
|
+
this.trigger('g:promoted');
|
|
106
|
+
}).fail((err) => {
|
|
107
|
+
this.trigger('g:error', err);
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Demote a user to ordinary member status. Requires admin access on the
|
|
113
|
+
* group.
|
|
114
|
+
* @param userId The id of the user to demote.
|
|
115
|
+
* @param level The current access level of the user.
|
|
116
|
+
*/
|
|
117
|
+
demoteUser: function (userId, level) {
|
|
118
|
+
var role;
|
|
119
|
+
if (level === AccessType.WRITE) {
|
|
120
|
+
role = 'moderator';
|
|
121
|
+
} else if (level === AccessType.ADMIN) {
|
|
122
|
+
role = 'admin';
|
|
123
|
+
}
|
|
124
|
+
return restRequest({
|
|
125
|
+
url: `${this.resourceName}/${this.id}/${role}?userId=${userId}`,
|
|
126
|
+
method: 'DELETE'
|
|
127
|
+
}).done((resp) => {
|
|
128
|
+
this.set(resp);
|
|
129
|
+
|
|
130
|
+
this.trigger('g:demoted');
|
|
131
|
+
}).fail((err) => {
|
|
132
|
+
this.trigger('g:error', err);
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Remove a member of a group, or if the user is not already a member,
|
|
138
|
+
* this will simply delete any outstanding membership request or
|
|
139
|
+
* invitation for this user.
|
|
140
|
+
* @param userId The ID of the user to remove.
|
|
141
|
+
*/
|
|
142
|
+
removeMember: function (userId) {
|
|
143
|
+
return restRequest({
|
|
144
|
+
url: `${this.resourceName}/${this.id}/member?userId=${userId}`,
|
|
145
|
+
method: 'DELETE'
|
|
146
|
+
}).done((resp) => {
|
|
147
|
+
if (userId === getCurrentUser().get('_id')) {
|
|
148
|
+
getCurrentUser().removeFromGroup(this.get('_id'));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
this.set(resp);
|
|
152
|
+
|
|
153
|
+
this.trigger('g:removed');
|
|
154
|
+
}).fail((err) => {
|
|
155
|
+
this.trigger('g:error', err);
|
|
156
|
+
});
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
/* Check if the current user has the authority in this group to directly
|
|
160
|
+
* add members.
|
|
161
|
+
*
|
|
162
|
+
* @returns: true if adding members is allowed.
|
|
163
|
+
*/
|
|
164
|
+
mayAddMembers: function () {
|
|
165
|
+
if (getCurrentUser().get('admin')) {
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
var groupAddAllowed;
|
|
169
|
+
var addToGroupPolicy = this.get('_addToGroupPolicy');
|
|
170
|
+
if (addToGroupPolicy === 'nomod' || addToGroupPolicy === 'yesmod') {
|
|
171
|
+
groupAddAllowed = 'mod';
|
|
172
|
+
} else if (addToGroupPolicy === 'noadmin' || addToGroupPolicy === 'yesadmin') {
|
|
173
|
+
groupAddAllowed = 'admin';
|
|
174
|
+
} else {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
var addAllowed = this.get('addAllowed') || '';
|
|
178
|
+
if (addAllowed === 'no' || (addToGroupPolicy.substr(0, 3) !== 'yes' &&
|
|
179
|
+
addAllowed.substr(0, 3) !== 'yes')) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
if (addAllowed === 'yesadmin') {
|
|
183
|
+
groupAddAllowed = 'admin';
|
|
184
|
+
}
|
|
185
|
+
if (groupAddAllowed === 'admin' &&
|
|
186
|
+
this.get('_accessLevel') >= AccessType.ADMIN) {
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
if (groupAddAllowed === 'mod' &&
|
|
190
|
+
this.get('_accessLevel') >= AccessType.WRITE) {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
export default GroupModel;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import $ from 'jquery';
|
|
2
|
+
import _ from 'underscore';
|
|
3
|
+
|
|
4
|
+
import FileCollection from '@girder/core/collections/FileCollection';
|
|
5
|
+
import FolderModel from '@girder/core/models/FolderModel';
|
|
6
|
+
import MetadataMixin from '@girder/core/models/MetadataMixin';
|
|
7
|
+
import Model from '@girder/core/models/Model';
|
|
8
|
+
import { restRequest } from '@girder/core/rest';
|
|
9
|
+
|
|
10
|
+
var ItemModel = Model.extend({
|
|
11
|
+
resourceName: 'item',
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Get the access level of the item if it is set. Takes an optional callback
|
|
15
|
+
* to be called once the access level is fetched (or immediately if it has
|
|
16
|
+
* already been fetched).
|
|
17
|
+
*/
|
|
18
|
+
getAccessLevel: function (callback) {
|
|
19
|
+
callback = callback || $.noop;
|
|
20
|
+
|
|
21
|
+
if (this.has('_accessLevel')) {
|
|
22
|
+
callback(this.get('_accessLevel'));
|
|
23
|
+
return this.get('_accessLevel');
|
|
24
|
+
}
|
|
25
|
+
if (this.parent && this.parent.getAccessLevel()) {
|
|
26
|
+
this.set('_accessLevel', this.parent.getAccessLevel());
|
|
27
|
+
callback(this.get('_accessLevel'));
|
|
28
|
+
return this.get('_accessLevel');
|
|
29
|
+
} else {
|
|
30
|
+
var parent = new FolderModel();
|
|
31
|
+
parent.set({
|
|
32
|
+
_id: this.get('folderId')
|
|
33
|
+
}).once('g:fetched', function () {
|
|
34
|
+
this.parent = parent;
|
|
35
|
+
this.set('_accessLevel', this.parent.getAccessLevel());
|
|
36
|
+
callback(this.get('_accessLevel'));
|
|
37
|
+
}, this).fetch();
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get the path to the root of the hierarchy
|
|
43
|
+
*/
|
|
44
|
+
getRootPath: function (callback) {
|
|
45
|
+
return restRequest({
|
|
46
|
+
url: `${this.resourceName}/${this.id}/rootpath`
|
|
47
|
+
}).done((resp) => {
|
|
48
|
+
callback(resp);
|
|
49
|
+
}).fail((err) => {
|
|
50
|
+
this.trigger('g:error', err);
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get the files within the item.
|
|
56
|
+
*/
|
|
57
|
+
getFiles: function () {
|
|
58
|
+
return restRequest({
|
|
59
|
+
url: `${this.resourceName}/${this.id}/files`
|
|
60
|
+
}).then((resp) => {
|
|
61
|
+
const fileCollection = new FileCollection(resp);
|
|
62
|
+
this.trigger('g:files', fileCollection);
|
|
63
|
+
return fileCollection;
|
|
64
|
+
}).fail((err) => {
|
|
65
|
+
this.trigger('g:error', err);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
_.extend(ItemModel.prototype, MetadataMixin);
|
|
71
|
+
|
|
72
|
+
export default ItemModel;
|