Merge pull request #4659 from paulkaplan/external-project-save

Move project saving to server to helper, allow external save action
This commit is contained in:
Paul Kaplan authored and GitHub committed 2019-03-18 16:49:29 -04:00
commit e0db28d82b
2 files changed
+73 -48

No files matched your search

+11 -48
View File
@@ -1,15 +1,14 @@
import bindAll from 'lodash.bindall';
import React from 'react';
import PropTypes from 'prop-types';
import queryString from 'query-string';
import {connect} from 'react-redux';
import VM from 'scratch-vm';
import xhr from 'xhr';
import collectMetadata from '../lib/collect-metadata';
import log from '../lib/log';
import storage from '../lib/storage';
import dataURItoBlob from '../lib/data-uri-to-blob';
import saveProjectToServer from '../lib/save-project-to-server';
import {
showAlertWithTimeout,
@@ -176,8 +175,8 @@ const ProjectSaverHOC = function (WrappedComponent) {
createCopyToStorage () {
this.props.onShowCreatingCopyAlert();
return this.storeProject(null, {
original_id: this.props.reduxProjectId,
is_copy: 1,
originalId: this.props.reduxProjectId,
isCopy: 1,
title: this.props.reduxProjectTitle
})
.then(response => {
@@ -192,8 +191,8 @@ const ProjectSaverHOC = function (WrappedComponent) {
createRemixToStorage () {
this.props.onShowCreatingRemixAlert();
return this.storeProject(null, {
original_id: this.props.reduxProjectId,
is_remix: 1,
originalId: this.props.reduxProjectId,
isRemix: 1,
title: this.props.reduxProjectTitle
})
.then(response => {
@@ -233,47 +232,8 @@ const ProjectSaverHOC = function (WrappedComponent) {
() => (asset.clean = true)
)
)
).then(() => {
const opts = {
body: savedVMState,
// If we set json:true then the body is double-stringified, so don't
headers: {
'Content-Type': 'application/json'
},
withCredentials: true
};
const creatingProject = projectId === null || typeof projectId === 'undefined';
let qs = queryString.stringify(requestParams);
if (qs) qs = `?${qs}`;
if (creatingProject) {
Object.assign(opts, {
method: 'post',
url: `${storage.projectHost}/${qs}`
});
} else {
Object.assign(opts, {
method: 'put',
url: `${storage.projectHost}/${projectId}${qs}`
});
}
return new Promise((resolve, reject) => {
xhr(opts, (err, response) => {
if (err) return reject(err);
let body;
try {
// Since we didn't set json: true, we have to parse manually
body = JSON.parse(response.body);
} catch (e) {
return reject(e);
}
body.id = projectId;
if (creatingProject) {
body.id = body['content-name'];
}
resolve(body);
});
});
})
)
.then(() => this.props.onUpdateProjectData(projectId, savedVMState, requestParams))
.then(response => {
this.props.onSetProjectUnchanged();
const id = response.id.toString();
@@ -358,6 +318,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
onShowSaveSuccessAlert,
onShowSavingAlert,
onUpdatedProject,
onUpdateProjectData,
onUpdateProjectThumbnail,
reduxProjectId,
reduxProjectTitle,
@@ -403,6 +364,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
onShowRemixSuccessAlert: PropTypes.func,
onShowSaveSuccessAlert: PropTypes.func,
onShowSavingAlert: PropTypes.func,
onUpdateProjectData: PropTypes.func.isRequired,
onUpdateProjectThumbnail: PropTypes.func,
onUpdatedProject: PropTypes.func,
projectChanged: PropTypes.bool,
@@ -413,7 +375,8 @@ const ProjectSaverHOC = function (WrappedComponent) {
ProjectSaverComponent.defaultProps = {
autoSaveIntervalSecs: 120,
onRemixing: () => {},
onSetProjectThumbnailer: () => {}
onSetProjectThumbnailer: () => {},
onUpdateProjectData: saveProjectToServer
};
const mapStateToProps = (state, ownProps) => {
const loadingState = state.scratchGui.projectState.loadingState;
+62
View File
@@ -0,0 +1,62 @@
import queryString from 'query-string';
import xhr from 'xhr';
import storage from '../lib/storage';
/**
* Save a project JSON to the project server.
* This should eventually live in scratch-www.
* @param {number} projectId the ID of the project, null if a new project.
* @param {object} vmState the JSON project representation.
* @param {object} params the request params.
* @property {?number} params.originalId the original project ID if a copy/remix.
* @property {?boolean} params.isCopy a flag indicating if this save is creating a copy.
* @property {?boolean} params.isRemix a flag indicating if this save is creating a remix.
* @property {?string} params.title the title of the project.
* @return {Promise} A promise that resolves when the network request resolves.
*/
export default function (projectId, vmState, params) {
const opts = {
body: vmState,
// If we set json:true then the body is double-stringified, so don't
headers: {
'Content-Type': 'application/json'
},
withCredentials: true
};
const creatingProject = projectId === null || typeof projectId === 'undefined';
const queryParams = {};
if (params.hasOwnProperty('originalId')) queryParams.original_id = params.originalId;
if (params.hasOwnProperty('isCopy')) queryParams.is_copy = params.isCopy;
if (params.hasOwnProperty('isRemix')) queryParams.is_remix = params.isRemix;
if (params.hasOwnProperty('title')) queryParams.title = params.title;
let qs = queryString.stringify(queryParams);
if (qs) qs = `?${qs}`;
if (creatingProject) {
Object.assign(opts, {
method: 'post',
url: `${storage.projectHost}/${qs}`
});
} else {
Object.assign(opts, {
method: 'put',
url: `${storage.projectHost}/${projectId}${qs}`
});
}
return new Promise((resolve, reject) => {
xhr(opts, (err, response) => {
if (err) return reject(err);
let body;
try {
// Since we didn't set json: true, we have to parse manually
body = JSON.parse(response.body);
} catch (e) {
return reject(e);
}
body.id = projectId;
if (creatingProject) {
body.id = body['content-name'];
}
resolve(body);
});
});
}