Allow edit/delete/multiple answers without a drive and fix race condition
This commit is contained in:
parent
f0bc1ef07a
commit
600771682a
7 changed files with 73 additions and 33 deletions
|
@ -210,7 +210,7 @@ Channel.trimHistory = function (Env, safeKey, data, cb) {
|
|||
|
||||
// Delete a signed mailbox message. This is used when users want
|
||||
// to delete their form reponses.
|
||||
Channel.deleteMailboxMessage = function (Env, safeKey, data, cb) {
|
||||
Channel.deleteMailboxMessage = function (Env, data, cb) {
|
||||
const channelId = data.channel;
|
||||
const hash = data.hash;
|
||||
const proof = data.proof;
|
||||
|
@ -355,10 +355,11 @@ Channel.writePrivateMessage = function (Env, args, _cb, Server, netfluxId) {
|
|||
Server.getChannelUserList(channelId).forEach(function (userId) {
|
||||
Server.send(userId, fullMessage);
|
||||
});
|
||||
|
||||
cb();
|
||||
});
|
||||
|
||||
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ const UNAUTHENTICATED_CALLS = {
|
|||
IS_CHANNEL_PINNED: Pinning.isChannelPinned, // FIXME drop this RPC
|
||||
IS_NEW_CHANNEL: Channel.isNewChannel,
|
||||
WRITE_PRIVATE_MESSAGE: Channel.writePrivateMessage,
|
||||
DELETE_MAILBOX_MESSAGE: Channel.deleteMailboxMessage,
|
||||
GET_METADATA: Metadata.getMetadata,
|
||||
};
|
||||
|
||||
|
@ -47,7 +48,6 @@ const AUTHENTICATED_USER_TARGETED = {
|
|||
CLEAR_OWNED_CHANNEL: Channel.clearOwnedChannel,
|
||||
REMOVE_OWNED_CHANNEL: Channel.removeOwnedChannel,
|
||||
TRIM_HISTORY: Channel.trimHistory,
|
||||
DELETE_MAILBOX_MESSAGE: Channel.deleteMailboxMessage,
|
||||
UPLOAD_STATUS: Upload.status,
|
||||
UPLOAD: Upload.upload,
|
||||
UPLOAD_COMPLETE: Upload.complete,
|
||||
|
|
|
@ -125,6 +125,12 @@ define([
|
|||
formSeed = obj;
|
||||
}));
|
||||
}).nThen(function () {
|
||||
if (!formSeed) { // no drive mode
|
||||
formSeed = localStorage.CP_formSeed || Hash.createChannelId();
|
||||
localStorage.CP_formSeed = formSeed;
|
||||
} else {
|
||||
delete localStorage.CP_formSeed;
|
||||
}
|
||||
cb({
|
||||
curvePrivate: curvePrivate,
|
||||
curvePublic: curvePrivate && Hash.getCurvePublicFromPrivate(curvePrivate),
|
||||
|
@ -132,16 +138,39 @@ define([
|
|||
});
|
||||
});
|
||||
};
|
||||
common.getFormAnswer = function (data, onlyLast, cb) {
|
||||
common.getFormAnswer = function (data, cb) {
|
||||
postMessage("GET", {
|
||||
key: ['forms', data.channel],
|
||||
}, function (obj) {
|
||||
if (!obj || obj.error) { return void cb(obj); }
|
||||
if (!Array.isArray(obj)) { obj = [obj]; }
|
||||
if (obj && obj.error === "ENODRIVE") {
|
||||
var all = Util.tryParse(localStorage.CP_formAnswers || "{}");
|
||||
return void cb(all[data.channel]);
|
||||
}
|
||||
if (obj && obj.error) { return void cb(obj); }
|
||||
|
||||
var last = obj[obj.length - 1];
|
||||
if (onlyLast) { return void cb(last); }
|
||||
return void cb(obj);
|
||||
if (obj) {
|
||||
if (!Array.isArray(obj)) { obj = [obj]; }
|
||||
return void cb(obj);
|
||||
}
|
||||
|
||||
// We have a drive and no answer but maybe we had
|
||||
// previous "nodrive" answers: migrate
|
||||
var old = Util.tryParse(localStorage.CP_formAnswers || "{}");
|
||||
if (Array.isArray(old[data.channel])) {
|
||||
var d = old[data.channel];
|
||||
return void postMessage("SET", {
|
||||
key: ['forms', data.channel],
|
||||
value: d
|
||||
}, function (obj) {
|
||||
// Delete old data if it was correctly stored in the drive
|
||||
if (obj && obj.error) { return void cb(d); }
|
||||
delete old[data.channel];
|
||||
localStorage.CP_formAnswers = JSON.stringify(old);
|
||||
cb(d);
|
||||
});
|
||||
}
|
||||
|
||||
cb();
|
||||
});
|
||||
};
|
||||
common.storeFormAnswer = function (data, cb) {
|
||||
|
@ -153,7 +182,7 @@ define([
|
|||
};
|
||||
var answers = [];
|
||||
Nthen(function (waitFor) {
|
||||
common.getFormAnswer(data, false, waitFor(function (obj) {
|
||||
common.getFormAnswer(data, waitFor(function (obj) {
|
||||
if (!obj || obj.error) { return; }
|
||||
answers = obj;
|
||||
}));
|
||||
|
@ -165,9 +194,15 @@ define([
|
|||
}, function (obj) {
|
||||
if (obj && obj.error) {
|
||||
if (obj.error === "ENODRIVE") {
|
||||
var all = Util.tryParse(localStorage.CP_formAnswers || "{}");
|
||||
all[data.channel] = answers;
|
||||
localStorage.CP_formAnswers = JSON.stringify(all);
|
||||
/*
|
||||
|
||||
var answered = JSON.parse(localStorage.CP_formAnswered || "[]");
|
||||
if (answered.indexOf(data.channel) === -1) { answered.push(data.channel); }
|
||||
localStorage.CP_formAnswered = JSON.stringify(answered);
|
||||
*/
|
||||
return void cb();
|
||||
}
|
||||
console.error(obj.error);
|
||||
|
@ -178,7 +213,7 @@ define([
|
|||
};
|
||||
common.deleteFormAnswers = function (data, _cb) {
|
||||
var cb = Util.once(_cb);
|
||||
common.getFormAnswer(data, false, function (obj) {
|
||||
common.getFormAnswer(data, function (obj) {
|
||||
if (!obj || obj.error) { return void cb(); }
|
||||
if (!obj.length) { return void cb(); }
|
||||
var n = Nthen;
|
||||
|
@ -224,7 +259,16 @@ define([
|
|||
postMessage("SET", {
|
||||
key: ['forms', data.channel],
|
||||
value: obj
|
||||
}, cb);
|
||||
}, function (_obj) {
|
||||
if (_obj && _obj.error === "ENODRIVE") {
|
||||
var all = Util.tryParse(localStorage.CP_formAnswers || "{}");
|
||||
if (obj) { all[data.channel] = obj; }
|
||||
else { delete all[data.channel]; }
|
||||
localStorage.CP_formAnswers = JSON.stringify(all);
|
||||
return void cb();
|
||||
}
|
||||
return void cb(_obj);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -2480,6 +2524,7 @@ define([
|
|||
anonHash: LocalStore.getFSHash(),
|
||||
localToken: tryParsing(localStorage.getItem(Constants.tokenKey)), // TODO move this to LocalStore ?
|
||||
language: common.getLanguage(),
|
||||
form_seed: localStorage.CP_formSeed,
|
||||
cache: rdyCfg.cache,
|
||||
noDrive: rdyCfg.noDrive,
|
||||
disableCache: localStorage['CRYPTPAD_STORE|disableCache'],
|
||||
|
|
|
@ -2162,8 +2162,8 @@ define([
|
|||
};
|
||||
|
||||
Store.deleteMailboxMessage = function (clientId, data, cb) {
|
||||
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
|
||||
store.rpc.deleteMailboxMessage(data, function (e) {
|
||||
if (!store.anon_rpc) { return void cb({error: 'RPC_NOT_READY'}); }
|
||||
store.anon_rpc.send('DELETE_MAILBOX_MESSAGE', data, function (e) {
|
||||
cb({error:e});
|
||||
});
|
||||
};
|
||||
|
@ -2962,6 +2962,9 @@ define([
|
|||
if (!rt.proxy.uid && store.noDriveUid) {
|
||||
rt.proxy.uid = store.noDriveUid;
|
||||
}
|
||||
if (!rt.proxy.form_seed && data.form_seed) {
|
||||
rt.proxy.form_seed = data.form_seed;
|
||||
}
|
||||
/*
|
||||
// deprecating localStorage migration as of 4.2.0
|
||||
var drive = rt.proxy.drive;
|
||||
|
|
|
@ -249,16 +249,6 @@ var factory = function (Util, Rpc) {
|
|||
}, cb);
|
||||
};
|
||||
|
||||
exp.deleteMailboxMessage = function (obj, cb) {
|
||||
rpc.send('DELETE_MAILBOX_MESSAGE', {
|
||||
channel: obj.channel,
|
||||
hash: obj.hash,
|
||||
proof: obj.proof
|
||||
}, cb);
|
||||
};
|
||||
|
||||
|
||||
|
||||
cb(e, exp);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -3218,7 +3218,8 @@ define([
|
|||
$(anonOffContent).append(h('span.cp-form-anon-answer-input', [
|
||||
Messages.form_answerAs,
|
||||
h('input', {
|
||||
value: user.name || '',
|
||||
value: (typeof(APP.cantAnon) === "string" && APP.cantAnon)
|
||||
|| user.name || '',
|
||||
placeholder: Messages.form_anonName
|
||||
})
|
||||
]));
|
||||
|
@ -3227,7 +3228,8 @@ define([
|
|||
$anonName.on('click input', function () {
|
||||
if (!Util.isChecked($off)) { $off.prop('checked', true); }
|
||||
});
|
||||
} else if (APP.cantAnon) {
|
||||
}
|
||||
if (APP.cantAnon) {
|
||||
// You've already answered with your credentials
|
||||
$(anonRadioOn).find('input').attr('disabled', 'disabled');
|
||||
$(anonRadioOff).find('input[type="radio"]').prop('checked', true);
|
||||
|
@ -4143,13 +4145,17 @@ define([
|
|||
});
|
||||
}
|
||||
|
||||
var loggedIn = framework._.sfCommon.isLoggedIn();
|
||||
|
||||
// In view mode, add "Submit" and "reset" buttons
|
||||
APP.cantAnon = Object.keys(answers || {}).length && !answers._isAnon;
|
||||
if (!loggedIn && answers && answers._userdata && answers._userdata.name) {
|
||||
APP.cantAnon = answers._userdata.name;
|
||||
}
|
||||
$container.append(makeFormControls(framework, content, evOnChange));
|
||||
|
||||
// In view mode, tell the user if answers are forced to be anonymous or authenticated
|
||||
var infoTxt;
|
||||
var loggedIn = framework._.sfCommon.isLoggedIn();
|
||||
if (content.answers.makeAnonymous) {
|
||||
infoTxt = Messages.form_anonAnswer;
|
||||
} else if (!content.answers.anonymous && loggedIn && !content.answers.cantEdit) {
|
||||
|
|
|
@ -265,7 +265,7 @@ define([
|
|||
Cryptpad.getFormKeys(w(function (keys) {
|
||||
myKeys = keys;
|
||||
}));
|
||||
Cryptpad.getFormAnswer({channel: data.channel}, false, w(function (obj) {
|
||||
Cryptpad.getFormAnswer({channel: data.channel}, w(function (obj) {
|
||||
if (!obj || obj.error) {
|
||||
if (obj && obj.error === "ENODRIVE") {
|
||||
var answered = JSON.parse(localStorage.CP_formAnswered || "[]");
|
||||
|
@ -354,11 +354,6 @@ define([
|
|||
// We can create a seed in localStorage.
|
||||
if (!keys.formSeed) {
|
||||
// No drive mode
|
||||
var answered = JSON.parse(localStorage.CP_formAnswered || "[]");
|
||||
if(answered.indexOf(data.channel) !== -1) {
|
||||
// Already answered: abort
|
||||
return void cb({ error: "EANSWERED" });
|
||||
}
|
||||
keys = { formSeed: noDriveSeed };
|
||||
}
|
||||
myKeys = keys;
|
||||
|
|
Loading…
Reference in a new issue