Merge pull request #2315 from jmoenig/cloud-enhancements

Updates to cloud.js
pull/89/head
Jens Mönig 2019-01-25 12:04:09 +01:00 zatwierdzone przez GitHub
commit 1601dffddc
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
2 zmienionych plików z 98 dodań i 91 usunięć

Wyświetl plik

@ -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',

Wyświetl plik

@ -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();
}; };