kopia lustrzana https://github.com/backface/turtlestitch
commit
1601dffddc
85
src/cloud.js
85
src/cloud.js
|
@ -28,10 +28,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Global settings /////////////////////////////////////////////////////
|
// Global settings /////////////////////////////////////////////////////
|
||||||
|
// cloud.js should be able to exist indepent of Snap!
|
||||||
|
// (The module date is included for simplicity, but is not needed elsewhere.)
|
||||||
|
|
||||||
/*global modules, SnapSerializer, nop, hex_sha512, DialogBoxMorph, Color,
|
/*global modules, hex_sha512*/
|
||||||
normalizeCanvas*/
|
|
||||||
|
|
||||||
|
modules = modules || {};
|
||||||
modules.cloud = '2019-January-17';
|
modules.cloud = '2019-January-17';
|
||||||
|
|
||||||
// Global stuff
|
// Global stuff
|
||||||
|
@ -45,10 +47,14 @@ function Cloud() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Cloud.prototype.init = function () {
|
Cloud.prototype.init = function () {
|
||||||
this.url = this.determineCloudDomain();
|
this.urlBasePath = '/api/v1';
|
||||||
|
this.url = this.determineCloudDomain() + this.urlBasePath;
|
||||||
this.username = null;
|
this.username = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Projects larger than this are rejected.
|
||||||
|
Cloud.MAX_FILE_SIZE = 10 * 1024 * 1024;
|
||||||
|
|
||||||
Cloud.prototype.knownDomains = {
|
Cloud.prototype.knownDomains = {
|
||||||
'Snap!Cloud' : 'https://cloud.snap.berkeley.edu',
|
'Snap!Cloud' : 'https://cloud.snap.berkeley.edu',
|
||||||
'Snap!Cloud (cs10)' : 'https://snap-cloud.cs10.org',
|
'Snap!Cloud (cs10)' : 'https://snap-cloud.cs10.org',
|
||||||
|
@ -144,6 +150,8 @@ Cloud.prototype.genericError = function () {
|
||||||
throw new Error(Cloud.genericErrorMessage);
|
throw new Error(Cloud.genericErrorMessage);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Low level functionality
|
// Low level functionality
|
||||||
|
|
||||||
Cloud.prototype.request = function (
|
Cloud.prototype.request = function (
|
||||||
|
@ -249,7 +257,7 @@ Cloud.prototype.initSession = function (onSuccess) {
|
||||||
'POST',
|
'POST',
|
||||||
'/init',
|
'/init',
|
||||||
function () { myself.checkCredentials(onSuccess); },
|
function () { myself.checkCredentials(onSuccess); },
|
||||||
nop,
|
function () {},
|
||||||
null,
|
null,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
@ -369,7 +377,6 @@ Cloud.prototype.changePassword = function (
|
||||||
onError,
|
onError,
|
||||||
'Could not change password'
|
'Could not change password'
|
||||||
);
|
);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Cloud.prototype.resetPassword = function (username, onSuccess, onError) {
|
Cloud.prototype.resetPassword = function (username, onSuccess, onError) {
|
||||||
|
@ -395,79 +402,19 @@ Cloud.prototype.resendVerification = function (username, onSuccess, onError) {
|
||||||
|
|
||||||
// Projects
|
// Projects
|
||||||
|
|
||||||
Cloud.prototype.saveProject = function (ide, onSuccess, onError) {
|
Cloud.prototype.saveProject = function (projectName, body, onSuccess, onError) {
|
||||||
|
// Expects a body object with the following paramters:
|
||||||
|
// xml, media, thumbnail, remixID (optional), notes (optional)
|
||||||
var myself = this;
|
var myself = this;
|
||||||
this.checkCredentials(
|
this.checkCredentials(
|
||||||
function (username) {
|
function (username) {
|
||||||
if (username) {
|
if (username) {
|
||||||
var xml = ide.serializer.serialize(ide.stage),
|
|
||||||
thumbnail = normalizeCanvas(
|
|
||||||
ide.stage.thumbnail(
|
|
||||||
SnapSerializer.prototype.thumbnailSize
|
|
||||||
)).toDataURL(),
|
|
||||||
body, mediaSize, size;
|
|
||||||
|
|
||||||
ide.serializer.isCollectingMedia = true;
|
|
||||||
body = {
|
|
||||||
notes: ide.projectNotes,
|
|
||||||
xml: xml,
|
|
||||||
media: ide.hasChangedMedia ?
|
|
||||||
ide.serializer.mediaXML(ide.projectName) : null,
|
|
||||||
thumbnail: thumbnail,
|
|
||||||
remixID: ide.stage.remixID
|
|
||||||
};
|
|
||||||
ide.serializer.isCollectingMedia = false;
|
|
||||||
ide.serializer.flushMedia();
|
|
||||||
|
|
||||||
mediaSize = body.media ? body.media.length : 0;
|
|
||||||
size = body.xml.length + mediaSize;
|
|
||||||
if (mediaSize > 10485760) {
|
|
||||||
new DialogBoxMorph().inform(
|
|
||||||
'Snap!Cloud - Cannot Save Project',
|
|
||||||
'The media inside this project exceeds 10 MB.\n' +
|
|
||||||
'Please reduce the size of costumes or sounds.\n',
|
|
||||||
ide.world(),
|
|
||||||
ide.cloudIcon(null, new Color(180, 0, 0))
|
|
||||||
);
|
|
||||||
throw new Error('Project media exceeds 10 MB size limit');
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if serialized data can be parsed back again
|
|
||||||
try {
|
|
||||||
ide.serializer.parse(body.xml);
|
|
||||||
} catch (err) {
|
|
||||||
ide.showMessage(
|
|
||||||
'Serialization of program data failed:\n' + err
|
|
||||||
);
|
|
||||||
throw new Error(
|
|
||||||
'Serialization of program data failed:\n' + err
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (body.media !== null) {
|
|
||||||
try {
|
|
||||||
ide.serializer.parse(body.media);
|
|
||||||
} catch (err) {
|
|
||||||
ide.showMessage(
|
|
||||||
'Serialization of media failed:\n' + err
|
|
||||||
);
|
|
||||||
throw new Error(
|
|
||||||
'Serialization of media failed:\n' + err
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ide.serializer.isCollectingMedia = false;
|
|
||||||
ide.serializer.flushMedia();
|
|
||||||
|
|
||||||
ide.showMessage(
|
|
||||||
'Uploading ' + Math.round(size / 1024) + ' KB...'
|
|
||||||
);
|
|
||||||
|
|
||||||
myself.request(
|
myself.request(
|
||||||
'POST',
|
'POST',
|
||||||
'/projects/' +
|
'/projects/' +
|
||||||
encodeURIComponent(username) +
|
encodeURIComponent(username) +
|
||||||
'/' +
|
'/' +
|
||||||
encodeURIComponent(ide.projectName),
|
encodeURIComponent(projectName),
|
||||||
onSuccess,
|
onSuccess,
|
||||||
onError,
|
onError,
|
||||||
'Project could not be saved',
|
'Project could not be saved',
|
||||||
|
|
104
src/gui.js
104
src/gui.js
|
@ -5583,17 +5583,85 @@ IDE_Morph.prototype.logout = function () {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
IDE_Morph.prototype.saveProjectToCloud = function (name) {
|
IDE_Morph.prototype.buildProjectRequest = function () {
|
||||||
var myself = this;
|
var xml = this.serializer.serialize(this.stage),
|
||||||
if (name) {
|
thumbnail = normalizeCanvas(
|
||||||
this.showMessage('Saving project\nto the cloud...');
|
this.stage.thumbnail(
|
||||||
this.setProjectName(name);
|
SnapSerializer.prototype.thumbnailSize
|
||||||
this.cloud.saveProject(
|
)).toDataURL(),
|
||||||
this,
|
body;
|
||||||
function () {myself.showMessage('saved.', 2); },
|
|
||||||
this.cloudError()
|
this.serializer.isCollectingMedia = true;
|
||||||
|
body = {
|
||||||
|
notes: this.projectNotes,
|
||||||
|
xml: xml,
|
||||||
|
media: this.hasChangedMedia ?
|
||||||
|
this.serializer.mediaXML(this.projectName) : null,
|
||||||
|
thumbnail: thumbnail,
|
||||||
|
remixID: this.stage.remixID
|
||||||
|
};
|
||||||
|
this.serializer.isCollectingMedia = false;
|
||||||
|
this.serializer.flushMedia();
|
||||||
|
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDE_Morph.prototype.verifyProject = function (body) {
|
||||||
|
// Ensure the project is less than 10MB and serializes correctly.
|
||||||
|
var encodedBody = JSON.stringify(body);
|
||||||
|
if (encodedBody.length > Cloud.MAX_FILE_SIZE) {
|
||||||
|
new DialogBoxMorph().inform(
|
||||||
|
'Snap!Cloud - Cannot Save Project',
|
||||||
|
'The media inside this project exceeds 10 MB.\n' +
|
||||||
|
'Please reduce the size of costumes or sounds.\n',
|
||||||
|
this.world(),
|
||||||
|
this.cloudIcon(null, new Color(180, 0, 0))
|
||||||
);
|
);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(encodedBody.length)
|
||||||
|
// check if serialized data can be parsed back again
|
||||||
|
try {
|
||||||
|
this.serializer.parse(body.xml);
|
||||||
|
} catch (err) {
|
||||||
|
this.showMessage('Serialization of program data failed:\n' + err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (body.media !== null) {
|
||||||
|
try {
|
||||||
|
this.serializer.parse(body.media);
|
||||||
|
} catch (err) {
|
||||||
|
this.showMessage('Serialization of media failed:\n' + err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.serializer.isCollectingMedia = false;
|
||||||
|
this.serializer.flushMedia();
|
||||||
|
|
||||||
|
return encodedBody.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDE_Morph.prototype.saveProjectToCloud = function (name) {
|
||||||
|
var myself = this, projectBody, projectSize;
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
this.setProjectName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.showMessage('Saving project\nto the cloud...');
|
||||||
|
projectBody = this.buildProjectRequest();
|
||||||
|
projectSize = this.verifyProject(projectBody);
|
||||||
|
if (!projectSize) {return; } // Invalid Projects don't return anything.
|
||||||
|
this.showMessage(
|
||||||
|
'Uploading ' + Math.round(projectSize / 1024) + ' KB...'
|
||||||
|
);
|
||||||
|
this.cloud.saveProject(
|
||||||
|
this.projectName,
|
||||||
|
projectBody,
|
||||||
|
function () {myself.showMessage('saved.', 2); },
|
||||||
|
this.cloudError()
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
IDE_Morph.prototype.exportProjectMedia = function (name) {
|
IDE_Morph.prototype.exportProjectMedia = function (name) {
|
||||||
|
@ -5804,11 +5872,11 @@ IDE_Morph.prototype.getURL = function (url, callback, responseType) {
|
||||||
async = callback instanceof Function,
|
async = callback instanceof Function,
|
||||||
myself = this,
|
myself = this,
|
||||||
rsp;
|
rsp;
|
||||||
if (async) {
|
if (async) {
|
||||||
request.responseType = responseType || 'text';
|
request.responseType = responseType || 'text';
|
||||||
}
|
}
|
||||||
rsp = (!async || request.responseType === 'text') ? 'responseText'
|
rsp = (!async || request.responseType === 'text') ? 'responseText'
|
||||||
: 'response';
|
: 'response';
|
||||||
try {
|
try {
|
||||||
request.open('GET', url, async);
|
request.open('GET', url, async);
|
||||||
if (async) {
|
if (async) {
|
||||||
|
@ -6627,16 +6695,8 @@ ProjectDialogMorph.prototype.saveProject = function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
ProjectDialogMorph.prototype.saveCloudProject = function () {
|
ProjectDialogMorph.prototype.saveCloudProject = function () {
|
||||||
var myself = this;
|
this.ide.source = 'cloud';
|
||||||
this.ide.showMessage('Saving project\nto the cloud...');
|
this.ide.saveProjectToCloud();
|
||||||
this.ide.cloud.saveProject(
|
|
||||||
this.ide,
|
|
||||||
function () {
|
|
||||||
myself.ide.source = 'cloud';
|
|
||||||
myself.ide.showMessage('saved.', 2);
|
|
||||||
},
|
|
||||||
this.ide.cloudError()
|
|
||||||
);
|
|
||||||
this.destroy();
|
this.destroy();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue