drop support for polls created with Croodle <= 0.3.x (#709)

This commit is contained in:
Jeldrik Hanschke 2023-10-27 20:40:18 +02:00 committed by GitHub
parent 83c994c363
commit 8a4954f4e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 1 additions and 438 deletions

View file

@ -177,11 +177,6 @@ class Model {
}
$data = self::convertFromStorage($storageObject);
if(method_exists($model, 'restoreLegacySupportHook')) {
$model->restoreLegacySupportHook($data);
}
$properties = array_merge(
static::ENCRYPTED_PROPERTIES,
static::PLAIN_PROPERTIES,

View file

@ -125,20 +125,4 @@ class Poll extends model {
return false;
}
}
protected function restoreLegacySupportHook(&$data) {
if (!isset($data->version) || $data->version === 'v0.3-0') {
if (isset($data->poll) && is_object($data->poll)) {
$data = $data->poll;
}
foreach($data as $key => $value) {
if (strpos($key, 'encrypted') === 0) {
$newKey = lcfirst(substr($key, 9));
$data->$newKey = $data->$key;
unset($data->$key);
}
}
}
}
}

View file

@ -74,20 +74,4 @@ class User extends Model {
Poll::isValidId($parts[0]) &&
intval($parts[1]) == $parts[1];
}
protected function restoreLegacySupportHook(&$data) {
if (!isset($data->version) || $data->version === 'v0.3-0') {
if (isset($data->user) && is_object($data->user)) {
$data = $data->user;
}
foreach($data as $key => $value) {
if (strpos($key, 'encrypted') === 0) {
$newKey = lcfirst(substr($key, 9));
$data->$newKey = $data->$key;
unset($data->$key);
}
}
}
}
}

View file

@ -1,126 +0,0 @@
<?php
$pollId = substr(md5(__FILE__), 0, 10);
$pollJson = <<<EOD
{
"poll": {
"encryptedTitle": "{\"iv\":\"G1QGS+OHz5Z6Y4Og/3UFRQ==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"sWHHRuInJDY=\",\"ct\":\"rgMRyJep4e0+Jj+K0ZTqbJS1j/gaouoTCoSHgXFdccn5L9gHBo1JO7Sl\"}",
"encryptedDescription": "{\"iv\":\"StcBqdGghIip/N3gLFmTMQ==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"sWHHRuInJDY=\",\"ct\":\"5fgh7XABR7OifXoqHxE+c89mnVwkKUAG+x7D+BOGzoZK8dGT\"}",
"encryptedPollType": "{\"iv\":\"JYFdfUTb6xLWja302/bAKQ==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"sWHHRuInJDY=\",\"ct\":\"wW+J3cGGF1tQUNfxt4gENDcZXQ==\"}",
"encryptedAnswerType": "{\"iv\":\"i0lDlvIVg2Le8pBSb47CIA==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"sWHHRuInJDY=\",\"ct\":\"+LNTLmILvxsN1X6E+vWa\"}",
"encryptedAnswers": "{\"iv\":\"xQV29b/F+gvlLl0zDCB7yw==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"sWHHRuInJDY=\",\"ct\":\"n5CwLLhSE5d28NU2/rOB7o6tXXWdDE7/uPr951Rr2ZQsmhsadmVwYE0K3Cxt+Hif4Am1jliS+PFjgVralrsSB00vlIH53wvDqQmNdk1Q/2zIebsVhHueamL4REyXn+18uVrjRarioojwOPYJLxNJHh0kPHATd0TgJxTb87RXgqUvAr1xc6DL7hY+fIbGoa6Otzt+OqIPhRTpaL+My1TYFXWQSlJxpPVSOILe1G/y6wg3Cp1lx4aFdHmGOGmrW+EF5pW9XrIz4A+3kNapSyUsDyuMk8wejrJpRHNcFpIlyRkxgUU=\"}",
"encryptedOptions": "{\"iv\":\"ruAw1xvAVLh9D19ngrEDgw==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"sWHHRuInJDY=\",\"ct\":\"pl1JeMRamWBuScBb1QOT9eqheJG2KD3y8RjtoPhNVid90wmoOQDm6WGtwt+gz6QXQEWUmIIXt8lyAJTH7updSnceW1SihfDi7xMmPTOf/338uSt3RdA2q+F+skiT14gheXHMtSFQaeVGvS8QfDXQfJBY9zJYp+On\"}",
"encryptedCreationDate": "{\"iv\":\"H/eApLF+Ja7ebX/1tPg7+w==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"sWHHRuInJDY=\",\"ct\":\"8BhpHOrgM3L7XftckMdkXSFzXi2evkfheanKfcjMFxzYsg==\"}",
"encryptedForceAnswer": "{\"iv\":\"DapF8f4GhKPORoIrDPiRXg==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"sWHHRuInJDY=\",\"ct\":\"WfPqwu5yBkhrHJWR\"}",
"encryptedAnonymousUser": "{\"iv\":\"sIclbapCBCxkHi0QrlCqOA==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"sWHHRuInJDY=\",\"ct\":\"SXyhfk7DVgfVKfp7Kw==\"}",
"encryptedIsDateTime": "{\"iv\":\"CbB/QEzDlENL3qRK2ZjWxA==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"sWHHRuInJDY=\",\"ct\":\"TD0rnzzHaawAWyUP\"}",
"encryptedTimezone": "{\"iv\":\"wQQXNefWW5QC9VZ1KkQQmA==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"sWHHRuInJDY=\",\"ct\":\"5Zkx8f0WQAgBBG1s0DcxoHeA5Dc/fEI=\"}",
"version": "v0.3-0"
}
}
EOD;
$user1Json = <<<EOD
{
"user": {
"encryptedName": "{\"iv\":\"wibexCADUTTMP8vjmegTwA==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"sWHHRuInJDY=\",\"ct\":\"r6Vu5fzAgvXctXaCx70/Pr1ldaOE\"}",
"encryptedSelections": "{\"iv\":\"gCMgC5Rie++L3s42RGzQJg==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"sWHHRuInJDY=\",\"ct\":\"jTmkMEkFTUiy8vGJinXAUmi7u8RNQ/FnLgnd+CMKL2XtqjeZuXgfMMDAdTEZnzNQTK7p/IhHBZrcrksUTnWkv68+f76msMs3rOqnYi7jhVL7O7NZMVNXysAgzalrQ+78Zz8TqoJ1qIARksTTCOi7Md07XKkYptCr3QUu0r8kfgk3KbGDuIE3tS4gGuB5CLKuPfFcbE0DjWAcr9IIEXpSPgjzJyEAx3bDd89ZfbRE0RaMoAR7Vqx+L3Hs6pXoUSbtnBJOQypNQYqUYycWA/kxCcuQEBlHwIR5qq7c9VsXNBG9SfGSA62scmbg6pxVXd3jEyTaxw3+B5r705mpMgAEY6NiJykob34x8LThdJP7XZKfe/tyczcKAlcQtJ7ocQsac0l1gRLK6eKHcNs8I3Zzi5iBzyqZtg0OVHzI8NiYpjwvg7piTHawsujAZIYkw/S4Pt29wkbb/heWpUsdJOF2xlfYYkTHnrPbX5jwZbNIgA==\"}",
"encryptedCreationDate": "{\"iv\":\"NGuUKkuLbabetQG5co01ZA==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"sWHHRuInJDY=\",\"ct\":\"ratk7+pQ14nax+slSf7ttOk2IIbQx7W2iu3I5VuUIR8RGg==\"}",
"version": "v0.3-0",
"poll": "gpwW7uZhbP"
}
}
EOD;
$user2Json = <<<EOD
{
"user": {
"encryptedName": "{\"iv\":\"GsRvWloC3GYi+MoOCUQ1vg==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"sWHHRuInJDY=\",\"ct\":\"0upVYhihQhWZcWpXcx5xKGHOTKTcVptz\"}",
"encryptedSelections": "{\"iv\":\"1FQ0Bf91k3JQbr23AhTszg==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"sWHHRuInJDY=\",\"ct\":\"u6qAugU7o/gTUvjaBrSjlNsU1AJ5oIPiSqrXs7iC7117ss2iX0aENcwsGG09XUk+K1llyrGAI7Fp2uBqn6fyujpacJrJG5oO7SR7F8xwc5TpMlWp/CHN2C9VPdOnm8KhdDtt6IUbNV+McjBxa3FtNVttkF4FAtUGYSurrrEscRad7bvSVbYzYkMs+83xS/ui+pJ3NLuNPntfErRIJw3EKacaUfm2eHCftBVvPHTy3AQbJ9mSKy3tMch+qu1nLnyFSMKjRieCFOgkT3LkQcvfpSteV3V/UNfm82ERy7AYOB8KZ0hW1R/vDp2R+EjFS3/0cw+a8luW6HGcyY0fs18uIbsSUaLOiThKTjp9pYhupXEa9gz1DeZMC51M79Ha4YC9uy3AyG5hH29DYF5yhBPD1Z0iYcgosJ8TweiYN0AvlCYsy939VRSzFGeiI/ZFN76DF0YP1LAOK9bTXHN9n8oyDoQbBMKcY48/uWZZpCAvBw==\"}",
"encryptedCreationDate": "{\"iv\":\"gLvf5OObVV10vRrQbMcrDw==\",\"v\":1,\"iter\":1000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"sWHHRuInJDY=\",\"ct\":\"2S5gjZmZ8QQRPfovPpLTbvQLsurgNIHXhkG0Ze8OpTScCw==\"}",
"version": "v0.3-0",
"poll": "gpwW7uZhbP"
}
}
EOD;
$pollDir = 'tests/_tmp/data/' . $pollId . '/';
$userDir = $pollDir . 'user/';
mkdir($pollDir);
file_put_contents($pollDir . 'poll_data', $pollJson);
mkdir($userDir);
file_put_contents($userDir . '0', $user1Json);
file_put_contents($userDir . '1', $user2Json);
$I = new ApiTester($scenario);
$I->wantTo('get an existing legacy (v0.3.0) poll with users');
$I->sendGET('/polls/' . $pollId);
$I->seeResponseCodeIs(200);
$I->seeHttpHeader('Content-Type', 'application/json');
$I->seeHttpHeader('Expires', '-1');
$I->seeResponseIsJson();
$pollData = json_decode($pollJson, true)["poll"];
unset($pollData["serverExpirationDate"]);
unset($pollData["encryptedIsDateTime"]);
unset($pollData["encryptedAnswers"]);
foreach($pollData as $key => $value) {
if (strpos($key, 'encrypted') === 0) {
$key = lcfirst(substr($key, 9));
}
else {
$key = $key;
}
$I->seeResponseContainsJson(
array(
'poll' => array(
$key => $value
)
)
);
}
$I->seeResponseContainsJson(["poll" => ["id" => $pollId]]);
$I->dontSeeResponseJsonMatchesJsonPath('poll.serverExpirationDate');
$I->seeResponseJsonMatchesJsonPath('poll.users');
$users = $I->grabDataFromResponseByJsonPath('poll.users')[0];
\PHPUnit_Framework_Assert::assertTrue(
is_array($users),
'user should be an array'
);
\PHPUnit_Framework_Assert::assertEquals(
count($users),
2,
'user array should contain 2 users'
);
function wellformUser($user) {
$return = $user["user"];
foreach ($return as $key => $value) {
if(strpos($key, 'encrypted') === 0) {
$return[lcfirst(substr($key, 9))] = $value;
unset($return[$key]);
}
}
return $return;
}
$I->seeResponseContainsJson([
"poll" => [
"users" => [
wellformUser(json_decode($user1Json, true)),
wellformUser(json_decode($user2Json, true))
]
]
]);
$I->seeResponseJsonMatchesJsonPath('poll.users.0.id');
$I->seeResponseJsonMatchesJsonPath('poll.users.1.id');
$user1Id = $I->grabDataFromResponseByJsonPath('poll.users.0.id')[0];
$user2Id = $I->grabDataFromResponseByJsonPath('poll.users.1.id')[0];
\PHPUnit_Framework_Assert::assertTrue(
$user1Id !== $user2Id,
'user ids are unique'
);
\PHPUnit_Framework_Assert::assertEquals(
explode('_', $user1Id)[0],
$pollId,
'user id starts by poll id'
);

View file

@ -39,11 +39,6 @@ export default class ApplicationSerializer extends RESTSerializer {
}
}, this);
// run legacy support transformation specified in model serializer
if (typeof this.legacySupport === 'function') {
resourceHash = this.legacySupport(resourceHash);
}
return super.normalize(modelClass, resourceHash, prop);
}

View file

@ -1,35 +1,3 @@
import classic from 'ember-classic-decorator';
import { isEmpty } from '@ember/utils';
import ApplicationSerializer from './application';
@classic
export default class UserSerializer extends ApplicationSerializer {
legacySupport(resourceHash) {
/*
* Croodle <= 0.3.0:
* * for answer type "freetext":
* selections where a string containing label
* * all other answer types ("YesNo", "YesNoMaybe"):
* selections where stored as child object of "value" property
* and selection property "type" where named "id"
*/
if (!isEmpty(resourceHash.selections[0].value)) {
resourceHash.selections.forEach(function (selection, index) {
if (typeof selection.value === 'string') {
resourceHash.selections[index] = {
label: selection.value,
};
} else {
resourceHash.selections[index] = {
icon: selection.value.icon,
label: selection.value.label,
labelTranslation: selection.value.labelTranslation,
type: selection.value.id,
};
}
});
}
return resourceHash;
}
}
export default class UserSerializer extends ApplicationSerializer {}

View file

@ -1,237 +0,0 @@
import { currentRouteName, find, findAll, visit } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { setupIntl, t } from 'ember-intl/test-support';
import switchTab from 'croodle/tests/helpers/switch-tab';
import pollParticipate from 'croodle/tests/helpers/poll-participate';
import PollEvaluationPage from 'croodle/tests/pages/poll/evaluation';
module('Acceptance | legacy support', function (hooks) {
let yesLabel;
let maybeLabel;
let noLabel;
hooks.beforeEach(function () {
window.localStorage.setItem('locale', 'en');
});
setupApplicationTest(hooks);
setupIntl(hooks);
setupMirage(hooks);
hooks.beforeEach(function () {
yesLabel = t('answerTypes.yes.label').toString();
maybeLabel = t('answerTypes.maybe.label').toString();
noLabel = t('answerTypes.no.label').toString();
});
test('show a default poll created with v0.3.0', async function (assert) {
const encryptionKey = '5MKFuNTKILUXw6RuqkAw6ooZw4k3mWWx98ZQw8vH';
let poll = this.server.create('poll', {
encryptionKey,
answerType: 'YesNoMaybe',
// property 'id' of answers has been renamed to 'type' in v0.4.0
answers: [
{
id: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Ja',
},
{
id: 'maybe',
labelTranslation: 'answerTypes.maybe.label',
icon: 'glyphicon glyphicon-hand-right',
label: 'Vielleicht',
},
{
id: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'Nein',
},
],
options: [
{ title: new Date('2015-12-24T17:00').toISOString() },
{ title: new Date('2015-12-24T19:00').toISOString() },
{ title: new Date('2015-12-31T22:59').toISOString() },
],
users: [
this.server.create('user', {
encryptionKey,
name: 'Fritz Bauer',
// selections.value was renamed to selections.label
// selections.id was renamed to selections.type
selections: [
{
value: {
id: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Ja',
},
},
{
value: {
id: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'Nein',
},
},
{
value: {
id: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'Nein',
},
},
],
// version tag had have wrong format
version: 'v0.3-0',
}),
],
// version tag had have wrong format
version: 'v0.3-0',
});
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
assert.equal(currentRouteName(), 'poll.participation');
assert.deepEqual(
findAll(
`[data-test-form-element^="option"] label:not(.custom-control-label)`,
).map((el) => el.textContent.trim()),
[
Intl.DateTimeFormat('en-US', {
dateStyle: 'full',
timeStyle: 'short',
}).format(new Date('2015-12-24T17:00')),
Intl.DateTimeFormat('en-US', { timeStyle: 'short' }).format(
new Date('2015-12-24T19:00'),
),
Intl.DateTimeFormat('en-US', {
dateStyle: 'full',
timeStyle: 'short',
}).format(new Date('2015-12-31T22:59')),
],
);
assert.deepEqual(
Array.from(
find('[data-test-form-element^="option"]').querySelectorAll(
'.radio label',
),
).map((el) => el.textContent.trim()),
[yesLabel, maybeLabel, noLabel],
);
await switchTab('evaluation');
assert.equal(currentRouteName(), 'poll.evaluation');
let participant = PollEvaluationPage.participants.filterBy(
'name',
'Fritz Bauer',
)[0];
assert.ok(participant, 'user exists in participants table');
assert.deepEqual(
participant.selections.map((_) => _.answer),
[yesLabel, noLabel, noLabel],
'participants table shows correct answers for new participant',
);
await switchTab('participation');
assert.equal(currentRouteName(), 'poll.participation');
await pollParticipate('Hermann Langbein', ['yes', 'maybe', 'yes']);
assert.equal(currentRouteName(), 'poll.evaluation');
participant = PollEvaluationPage.participants.filterBy(
'name',
'Hermann Langbein',
)[0];
assert.ok(participant, 'user exists in participants table');
assert.deepEqual(
participant.selections.map((_) => _.answer),
[yesLabel, maybeLabel, yesLabel],
'participants table shows correct answers for new participant',
);
});
test('show a poll using free text created with v0.3.0', async function (assert) {
let encryptionKey = 'Rre6dAGOYLW9gYKOP4LhX7Qwfhe5Th3je0uKDtyy';
let poll = this.server.create('poll', {
encryptionKey,
answerType: 'FreeText',
answers: [],
options: [
{ title: 'apple pie' },
{ title: 'pecan pie' },
{ title: 'plum pie' },
],
pollType: 'MakeAPoll',
users: [
this.server.create('user', {
encryptionKey,
name: 'Paul Levi',
// selections.value was renamed to selections.label
// selections.id was renamed to selections.type
selections: [
{ value: 'would be great!' },
{ value: 'no way' },
{ value: 'if I had to' },
],
// version tag had have wrong format
version: 'v0.3-0',
}),
],
// version tag had have wrong format
version: 'v0.3-0',
});
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
assert.equal(currentRouteName(), 'poll.participation');
assert.deepEqual(
findAll(
`[data-test-form-element^="option"] label:not(.custom-control-label)`,
).map((el) => el.textContent.trim()),
['apple pie', 'pecan pie', 'plum pie'],
);
await switchTab('evaluation');
assert.equal(currentRouteName(), 'poll.evaluation');
let participant = PollEvaluationPage.participants.filterBy(
'name',
'Paul Levi',
)[0];
assert.ok(participant, 'user exists in participants table');
assert.deepEqual(
participant.selections.map((_) => _.answer),
['would be great!', 'no way', 'if I had to'],
'participants table shows correct answers for new participant',
);
await switchTab('participation');
assert.equal(currentRouteName(), 'poll.participation');
await pollParticipate('Hermann Langbein', [
"I don't care",
'would be awesome',
"can't imagine anything better",
]);
assert.equal(currentRouteName(), 'poll.evaluation');
participant = PollEvaluationPage.participants.filterBy(
'name',
'Hermann Langbein',
)[0];
assert.ok(participant, 'user exists in participants table');
assert.deepEqual(
participant.selections.map((_) => _.answer),
["I don't care", 'would be awesome', "can't imagine anything better"],
'participants table shows correct answers for new participant',
);
});
});