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