Merge branch 'master' into 476-interface-fur-klausurkorrekturen-dev

This commit is contained in:
Sarah Vaupel 2020-02-07 22:47:51 +01:00
commit 9aca3405f3
13 changed files with 251 additions and 52 deletions

View File

@ -2,6 +2,127 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [11.0.0](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/compare/v10.6.0...v11.0.0) (2020-02-07)
### Bug Fixes
* merge ([a9636af](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/a9636af))
* **exam-correct:** add XSRF token to post header ([2fd996b](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/2fd996b))
* **exam-correct:** add XSRF token to post header ([2b30461](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/2b30461))
* **exam-correct:** also persist local time on non-success ([41a9539](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/41a9539))
* **exam-correct:** also persist local time on non-success ([dcb79d4](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/dcb79d4))
* **exam-correct:** cut off at maxPoints for now (TODO) ([af8d77c](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/af8d77c))
* **exam-correct:** fix addRow rowInfo ([88768eb](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/88768eb))
* **storage-manager:** correctly use encryption key in decrypt call ([2667aac](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/2667aac))
* **storage-manager:** post salt and timestamp only when fetching key ([6340509](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/6340509))
* fix webpack config ([50e4212](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/50e4212))
* **exam-correct:** correctly htmlify user on failure ([ef34755](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/ef34755))
* **exam-correct:** correctly htmlify user on failure ([595f46d](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/595f46d))
* **exam-correct:** fix addRow rowInfo ([792da22](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/792da22))
* **exam-correct:** fix attributes in template ([62bf73a](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/62bf73a))
* **exam-correct:** fix attributes in template ([000f97c](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/000f97c))
* **exam-correct:** fix hlint ([630194c](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/630194c))
* **exam-correct:** fix hlint ([c520918](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/c520918))
* **exam-correct:** fix returning null if old and new results are equal ([968c6de](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/968c6de))
* **exam-correct:** fix returning null if old and new results are equal ([2e7bca6](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/2e7bca6))
* **exam-correct:** temporarily disable exam results (WIP) ([533e748](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/533e748))
* **storage-key:** fix types ([a0d067f](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/a0d067f))
* **storage-key:** fix types ([a23a473](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/a23a473))
* **storage-manager:** remove and clear SessionStorage ([e42452e](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/e42452e))
* **storage-manager:** save salt and timestamp ([0282918](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/0282918))
* better translation for "exam office" ([edbdceb](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/edbdceb))
* design tweaks ([18ae758](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/18ae758))
* design tweaks ([68eb448](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/68eb448))
* fix hlint ([e60aef4](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/e60aef4))
* **exam-correct:** id on td instead of select ([1d0be2d](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/1d0be2d))
* **storage-manager:** remove and clear SessionStorage ([38b0a8e](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/38b0a8e))
* **storage-manager:** save salt and timestamp ([8bee033](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/8bee033))
* **style:** breadcrumb bar width ([7340fc1](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/7340fc1))
* do not apply target link height fix on targets in tables ([e7ff384](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/e7ff384))
* fix hlint ([9ecffc8](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/9ecffc8))
* fix merge ([d19cca6](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/d19cca6))
* fix webpack config ([5393a55](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/5393a55))
* typo ([4c58699](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/4c58699))
* **storage-manager:** correctly use encryption key in decrypt call ([9e9726e](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/9e9726e))
* **storage-manager:** post salt and timestamp only when fetching key ([301c88f](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/301c88f))
### Features
* **correction-interface:** wire up ECorrectR ([d8801a3](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/d8801a3))
* **exam-correct:** add basic interface stub ([623becf](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/623becf))
* **exam-correct:** add sortable style and date column ([87bda16](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/87bda16))
* **exam-correct:** display backend error messages ([6fc0262](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/6fc0262))
* **exam-correct:** general improvement ([23044b2](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/23044b2))
* **exam-correct:** more on frontend name resolving ([905d445](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/905d445))
* **exam-correct:** more stub ([cbe6495](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/cbe6495))
* **exam-correct:** overwrite request cells from response ([c8edbb3](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/c8edbb3))
* **exam-correct:** postECorrectR stub ([5f9a176](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/5f9a176))
* **exam-correct:** return user lookup result even for failure ([8e41820](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/8e41820))
* **exam-correct:** submit on enter ([10de1a7](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/10de1a7))
* **exam-correct:** work on delete ([014036e](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/014036e))
* **hide-columns:** don't break on dom changes ([c519792](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/c519792))
* pageactions for exam correct interface ([0d4dcf8](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/0d4dcf8))
* refine presentation of exam-correct ([95c1755](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/95c1755))
* **exam-correct:** persist results and more ([a7cc24b](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/a7cc24b))
* **exam-correct:** request refactor and handling of sent uuids ([f06ca00](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/f06ca00))
* **exam-correct:** resend option on ambiguous entries (TODO refactor) ([512f4d9](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/512f4d9))
* **exam-correct:** server date handling in frontend and refactor ([77e39be](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/77e39be))
* **exam-correct:** setup basic session storage manager, add util stub ([9cb64f2](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/9cb64f2))
* **exam-correct:** single runDB in POST handler; more response handling ([4cb62f8](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/4cb62f8))
* **exam-correct:** status icons (wip) ([3cc6814](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/3cc6814))
* **exam-correct:** stub ([90359c8](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/90359c8))
* **exam-correct:** upsert exam part results (TODO) ([c0f91bc](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/c0f91bc))
* **exam-correct:** use examId instead as uw-exam-correct value ([2d9a877](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/2d9a877))
* **exam-correct:** validate user input stub ([7f04862](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/7f04862))
* **pageactions:** finish restoration ([e1cac76](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/e1cac76))
* **pageactions:** restore pageactions ([4bc48a5](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/4bc48a5))
* **pageactions:** restore pageactions ([926bd44](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/926bd44))
* **sort-table:** add basic SortTable util stub ([53131e2](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/53131e2))
* **storage-key:** add breadcrumb and import ([8cf5d63](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/8cf5d63))
* **storage-key:** add StorageKeyR to routes; minor Handler refactor ([2d1d58f](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/2d1d58f))
* **storage-key:** postStorageKeyR ([059efe5](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/059efe5))
* **storage-manager:** add en-/decryption stub (WIP) and restructure ([54d852f](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/54d852f))
* improve navigation ([95ffda2](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/95ffda2))
* navbar header containers ([1348c91](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/1348c91))
* restore & improve navbar contents ([51fc6dc](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/51fc6dc))
* **exam-correct:** examResult interface, no styling or functionality ([970076e](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/970076e))
* rename "Start" to "Beginn" in error messages ([66bd10e](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/66bd10e))
* renamed "Bewertung abgeschlossen ab" to "Ergebnisse sichtbar ab" ([6b610e1](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/6b610e1))
* **correction-interface:** wire up ECorrectR ([df66c9b](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/df66c9b))
* **exam-correct:** accept grades besides exam part results ([be187ae](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/be187ae))
* **exam-correct:** add basic interface stub ([cb7c9ac](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/cb7c9ac))
* **exam-correct:** add sortable style and date column ([9fa4245](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/9fa4245))
* **exam-correct:** more on frontend name resolving ([daf9eee](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/daf9eee))
* **exam-correct:** more stub ([6727dff](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/6727dff))
* **exam-correct:** persist results and more ([53ff629](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/53ff629))
* **exam-correct:** postECorrectR stub ([a525cab](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/a525cab))
* **exam-correct:** request refactor and handling of sent uuids ([4a36a01](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/4a36a01))
* **exam-correct:** resend option on ambiguous entries (TODO refactor) ([e252be2](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/e252be2))
* **exam-correct:** server date handling in frontend and refactor ([d8a080d](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/d8a080d))
* **exam-correct:** setup basic session storage manager, add util stub ([9a79156](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/9a79156))
* **exam-correct:** single runDB in POST handler; more response handling ([6837c44](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/6837c44))
* **exam-correct:** status icons (wip) ([eefff9f](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/eefff9f))
* **exam-correct:** stub ([0467194](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/0467194))
* **exam-correct:** upsert exam part results (TODO) ([650598f](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/650598f))
* **exam-correct:** use examId instead as uw-exam-correct value ([5d7427a](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/5d7427a))
* **exam-correct:** validate user input stub ([431d004](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/431d004))
* **sort-table:** add basic SortTable util stub ([11c0bd0](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/11c0bd0))
* **storage-key:** add breadcrumb and import ([1580d3f](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/1580d3f))
* **storage-key:** add StorageKeyR to routes; minor Handler refactor ([4d4dc8f](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/4d4dc8f))
* **storage-key:** postStorageKeyR ([b51c466](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/b51c466))
* **storage-manager:** add en-/decryption stub (WIP) and restructure ([0016145](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/0016145))
* **storage-manager:** store encryption info per location ([25a7c34](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/25a7c34))
* **storage-manager:** store encryption info per location ([8122ab1](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/commit/8122ab1))
### BREAKING CHANGES
* major navigation refactor
## [10.6.0](https://gitlab2.rz.ifi.lmu.de/uni2work/uni2work/compare/v10.5.0...v10.6.0) (2020-01-30)

View File

@ -381,8 +381,9 @@ export class StorageManager {
}).catch(console.error);
}
_debugLog(fName, ...args) {
console.log(`[DEBUGLOG] StorageManager.${fName}`, { args: args, instance: this });
_debugLog() {
// _debugLog(fName, ...args) {
// console.log(`[DEBUGLOG] StorageManager.${fName}`, { args: args, instance: this });
}
}

View File

@ -49,6 +49,7 @@ export class ExamCorrect {
_partInputs;
_resultSelect;
_resultGradeSelect;
_partDeleteBoxes;
_dateFormat;
_cIndices;
@ -79,6 +80,7 @@ export class ExamCorrect {
this._partInputs = [...this._element.querySelectorAll(`input[${EXAM_CORRECT_PART_INPUT_ATTR}]`)];
this._resultSelect = document.getElementById('uw-exam-correct__result').querySelector('select');
this._resultGradeSelect = document.getElementById('uw-exam-correct__result__grade').querySelector('select');
this._partDeleteBoxes = [...this._element.querySelectorAll('input.uw-exam-correct--delete-exam-part')];
if (this._sendBtn)
this._sendBtn.addEventListener('click', this._sendCorrectionHandler.bind(this));
@ -88,6 +90,14 @@ export class ExamCorrect {
this._userInput.addEventListener('focusout', this._validateUserInput.bind(this));
else throw new Error('ExamCorrect utility could not detect user input!');
for (let deleteBox of this._partDeleteBoxes) {
deleteBox.addEventListener('change', (() => { this._updatePartDeleteDisabled(deleteBox); }).bind(this));
}
for (let input of [this._userInput, ...this._partInputs]) {
input.addEventListener('keypress', this._inputKeypress.bind(this));
}
if (!this._userInputStatus) {
throw new Error('ExamCorrect utility could not detect user input status element!');
}
@ -97,7 +107,7 @@ export class ExamCorrect {
}
// TODO get date format by post request
this._dateFormat = 'YYYY-MM-DD HH:mm:ss';
this._dateFormat = 'DD.MM.YYYY HH:mm:ss';
this._cIndices = new Map(
[...this._element.querySelectorAll('[uw-exam-correct-header]')]
@ -130,6 +140,22 @@ export class ExamCorrect {
// TODO destroy handlers on user input candidate elements
}
_updatePartDeleteDisabled(deleteBox) {
const partInput = deleteBox.parentElement.querySelector(`input[${EXAM_CORRECT_PART_INPUT_ATTR}]`);
if (!partInput)
return;
partInput.disabled = deleteBox.checked;
}
_inputKeypress() {
if (event.keyCode !== 13) {
return false;
}
this._sendCorrectionHandler();
}
_validateUserInput() {
(!this._userInput.value) ? this._userInput.classList.add('no-value') : this._userInput.classList.remove('no-value');
@ -188,11 +214,17 @@ export class ExamCorrect {
const results = {};
for (const input of this._partInputs) {
if (input.reportValidity && !input.reportValidity()) {
if (input.disabled) {
const partKey = input.getAttribute(EXAM_CORRECT_PART_INPUT_ATTR);
if (!partKey) {
console.error('Error while parsing results: Could not detect exam part key attribute');
return;
}
results[partKey] = null;
} else if (input.reportValidity && !input.reportValidity()) {
input.focus();
return;
}
if (input.value) {
} else if (input.value) {
const partKey = input.getAttribute(EXAM_CORRECT_PART_INPUT_ATTR);
if (!partKey) {
console.error('Error while parsing results: Could not detect exam part key attribute');
@ -201,11 +233,12 @@ export class ExamCorrect {
results[partKey] = parseFloat(input.value);
}
}
// console.log('results', results);
const result = this._resultSelect.value !== 'none' && this._resultSelect.value;
const result = this._resultSelect && this._resultSelect.value !== 'none' && this._resultSelect.value;
// abort send if there are neither part-results nor an exam-result (after validation)
if (Object.keys(results).length <= 0 && result === 'none') return;
if (Object.keys(results).length <= 0 && (!result || result === 'none')) return;
const rowInfo = {
users: [user],
@ -218,6 +251,7 @@ export class ExamCorrect {
// clear inputs on validation success
this._clearUserInput();
this._partInputs.forEach(clearInput);
this._partDeleteBoxes.forEach(box => { box.checked = false; this._updatePartDeleteDisabled(box); });
const body = this._toRequestBody(userId || user, results, result);
@ -307,39 +341,38 @@ export class ExamCorrect {
case 'success':
status = STATUS.SUCCESS;
if (response.user) {
userElem.setAttribute(EXAM_CORRECT_USER_ATTR, response.user.id);
userElem.innerHTML = userToHTML(response.user);
const timeElem = row.cells.item(0);
timeElem.innerHTML = moment(response.time).format(this._dateFormat);
timeElem.classList.remove('exam-correct--local-time');
newEntry.users = [response.user];
newEntry.results = response.results;
newEntry.result = response.grade;
} else {
console.error('Invalid response');
return;
}
// TODO set edit button visibility
break;
case 'ambiguous':
// TODO set edit button visibility
status = STATUS.AMBIGUOUS;
if (response.users) {
userElem = this._showUserList(row, response.users, results);
newEntry.users = response.users;
newEntry.results = results.partResults;
newEntry.result = results.result;
}
newEntry.users = response.users;
newEntry.results = typeof results === 'undefined' ? {} : results;
newEntry.result = typeof result === 'undefined' ? undefined : result; // eslint-disable-line no-undef
newEntry.message = response.message || null;
break;
case 'failure':
status = STATUS.FAILURE;
newEntry.users = (response.user && [response.user]) || null;
newEntry.results = results;
newEntry.results = typeof results === 'undefined' ? {} : results;
newEntry.message = response.message || null;
newEntry.result = results.result;
newEntry.result = typeof result === 'undefined' ? undefined : result; // eslint-disable-line no-undef
break;
default:
// TODO show tooltip with 'invalid response'
// TODO set edit button visibility
console.error('Invalid response');
return;
}
row.querySelectorAll('.fa-spin').forEach((elem) => {
setStatus(elem, status);
@ -361,19 +394,23 @@ export class ExamCorrect {
statusCell.appendChild(messageElem);
}
const userCell = row.querySelector('.uw-exam-correct--user-cell');
if (userCell && newEntry.users && newEntry.users.length === 1) {
if (userElem && newEntry.users && newEntry.users.length === 1) {
const user = newEntry.users[0];
userCell.innerHTML = userToHTML(user);
userCell.setAttribute(EXAM_CORRECT_USER_ATTR, user);
} else if (userCell && newEntry.users) {
row.replaceChild(userCell, this._showUserList(row, newEntry.users, request.results));
userElem.innerHTML = userToHTML(user);
userElem.setAttribute(EXAM_CORRECT_USER_ATTR, user.id || user);
} else if (userElem && newEntry.users) {
row.replaceChild(userElem, this._showUserList(row, newEntry.users, { partResults: request.results, result: request.grade } ));
}
for (let [k, v] of Object.entries(newEntry.results)) {
const resultCell = row.cells.item(this._cIndices.get(k));
if (v.result)
if (v === null) {
resultCell.innerHTML = '<i class="fas fa-fw fa-trash"></i>';
resultCell.classList.remove('exam-correct--result-unconfirmed');
} else if (v && v.result) {
resultCell.innerHTML = v.result;
resultCell.classList.remove('exam-correct--result-unconfirmed');
}
}
savedEntries.push(newEntry);
@ -475,8 +512,13 @@ export class ExamCorrect {
console.error('Could not determine cell index from part key!');
} else {
const partCell = document.createElement('TD');
partCell.innerHTML = partResult;
partCell.classList.add('uw-exam-correct--part-cell');
if (partResult === null) {
partCell.innerHTML = '<i class="fas fa-fw fa-trash"></i>';
} else {
partCell.innerHTML = partResult;
}
partCell.classList.add('uw-exam-correct--part-cell', 'exam-correct--result-unconfirmed');
cells.set(cellIndex, partCell);
}
}

View File

@ -10,7 +10,7 @@ table[uw-exam-correct]
min-width: 200px
th.uw-exam-correct--part-cell, td.uw-exam-correct--part-cell
width: min-content
width: 115px
text-align: center
white-space: nowrap
@ -22,12 +22,16 @@ table[uw-exam-correct]
opacity: .5
cursor: pointer
margin-left: 5px
.uw-exam-correct--delete-exam-part ~ .fa-trash:hover
opacity: 1
&:hover
opacity: 1
.uw-exam-correct--delete-exam-part:checked ~ .fa-trash
opacity: 1
color: var(--color-error)
&:hover
color: var(--color-error-dark)
td#uw-exam-correct__result
width: min-content
select
@ -63,7 +67,6 @@ table[uw-exam-correct]
border: 2px solid var(--color-error)
[uw-exam-correct] tbody ul
list-style: none
li
cursor: pointer
text-decoration: underline
@ -73,9 +76,11 @@ table[uw-exam-correct]
width: calc(100% - 18em/14 - #{$exam-correct--input-status-margin})
i
margin-left: $exam-correct--input-status-margin
ul
margin-top: 7px
.exam-correct--local-time
color: var(--color-fontsec)
.exam-correct--local-time, .exam-correct--result-unconfirmed
opacity: .5
font-style: italic
.exam-correct--success

View File

@ -31,6 +31,8 @@ export class HideColumns {
_autoHide;
_mutationObserver;
headerToHider = new Map();
hiderToHeader = new Map();
@ -69,6 +71,9 @@ export class HideColumns {
}
[...this._element.querySelectorAll('th')].filter(th => !th.hasAttribute(HIDE_COLUMNS_NO_HIDE)).forEach(th => this.setupHideButton(th));
this._mutationObserver = new MutationObserver(this._tableMutated.bind(this));
this._mutationObserver.observe(this._element, { childList: true, subtree: true });
}
setupHideButton(th) {
@ -217,6 +222,15 @@ export class HideColumns {
hider.style.top = thR.height + 'px';
}
_tableMutated(mutationList) {
// console.log('_tableMutated', mutationList, observer);
if (!Array.from(mutationList).some(mutation => mutation.type === 'childList'))
return;
[...this._element.querySelectorAll('th')].filter(th => !th.hasAttribute(HIDE_COLUMNS_NO_HIDE)).forEach(th => this.updateColumnDisplay(this.colIndex(th), this.isHiddenColumn(th)));
}
getStorageKey(th) {
// get handler name
const handlerIdent = document.querySelector('[uw-handler]').getAttribute('uw-handler');

View File

@ -413,6 +413,7 @@ UnauthorizedAllocationLecturer: Sie sind nicht als Veranstalter für eine Verans
UnauthorizedCorrector: Sie sind nicht als Korrektor für diese Veranstaltung eingetragen.
UnauthorizedSheetCorrector: Sie sind nicht als Korrektor für dieses Übungsblatt eingetragen.
UnauthorizedExamCorrector: Sie sind nicht als Korrektor für diese Prüfung eingetragen.
UnauthorizedExamCorrectorGrade: Sie haben nicht die Berechtigung für diese Prüfung Gesamtergebnisse einzutragen.
UnauthorizedCorrectorAny: Sie sind nicht als Korrektor für eine Veranstaltung eingetragen.
UnauthorizedRegistered: Sie sind nicht als Teilnehmer für diese Veranstaltung registriert.
UnauthorizedAllocationRegistered: Sie sind nicht als Teilnehmer für diese Zentralanmeldung registriert.
@ -1400,6 +1401,7 @@ ExamRegistrationInviteExplanation: Sie wurden eingeladen, Prüfungsteilnehmer zu
ExamCorrectHeading examname@Text: Prüfungsergebnisse für #{examname} eintragen
ExamCorrectExamResultDelete: Prüfungsergebnis löschen
ExamCorrectExamResultNone: Keine Änderung
ExamCorrectHeadDate: Zeit
ExamCorrectHeadParticipant: Teilnehmer

View File

@ -411,6 +411,7 @@ UnauthorizedAllocationLecturer: You are no administrator for any of the courses
UnauthorizedCorrector: You are no sheet corrector for this course.
UnauthorizedSheetCorrector: You are no corrector for this sheet.
UnauthorizedExamCorrector: You are no corrector for this exam.
UnauthorizedExamCorrectorGrade: You may not enter overall exam achievements for this exam.
UnauthorizedCorrectorAny: You are no corrector for any course.
UnauthorizedRegistered: You are no participant in this course.
UnauthorizedAllocationRegistered: You are no participant in this central allocation.
@ -1412,6 +1413,7 @@ ExamCorrectErrorPartResultOutOfBounds examPartNumber: Exam part result for #{exa
ExamCorrectErrorPartResultOutOfBoundsMax examPartNumber maxPoints: Exam part result for #{examPartNumber} is not between 0 and #{maxPoints}.
ExamCorrectExamResultDelete: Delete exam result
ExamCorrectExamResultNone: No change
SubmissionUserInvitationAccepted shn: You now participate in a submission for #{shn}
SubmissionUserInvitationDeclined shn: You have declined the invitation to participate in a submission for #{shn}

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "uni2work",
"version": "10.6.0",
"version": "11.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@ -1,6 +1,6 @@
{
"name": "uni2work",
"version": "10.6.0",
"version": "11.0.0",
"description": "",
"keywords": [],
"author": "",

View File

@ -1,5 +1,5 @@
name: uniworx
version: 10.6.0
version: 11.0.0
dependencies:
- base

View File

@ -10,10 +10,13 @@ import qualified Data.Aeson as JSON
import qualified Database.Esqueleto as E
import qualified Database.Esqueleto.Utils as E
import Database.Persist.Sql (transactionUndo)
import Handler.Utils
import Handler.Utils.Exam (fetchExam)
import qualified Data.HashMap.Strict as HashMap
data CorrectInterfaceUser
= CorrectInterfaceUser
@ -30,7 +33,7 @@ data CorrectInterfaceResponse
= CorrectInterfaceResponseSuccess
{ cirsUser :: CorrectInterfaceUser
, cirsResults :: Map ExamPartNumber (Maybe ExamResultPoints)
, cirsGrade :: Maybe ExamResultPassedGrade
, cirsGrade :: Maybe (Maybe ExamResultPassedGrade)
, cirsTime :: UTCTime
}
| CorrectInterfaceResponseAmbiguous
@ -44,17 +47,18 @@ data CorrectInterfaceResponse
| CorrectInterfaceResponseNoOp
{ cirnUsers :: Set CorrectInterfaceUser
}
deriveJSON defaultOptions
deriveToJSON defaultOptions
{ constructorTagModifier = camelToPathPiece' 3
, fieldLabelModifier = camelToPathPiece' 1
, sumEncoding = TaggedObject "status" "results"
, omitNothingFields = True
} ''CorrectInterfaceResponse
data CorrectInterfaceRequest
= CorrectInterfaceRequest
{ ciqUser :: Either Text (CryptoID UUID (Key User))
, ciqResults :: Maybe (NonNull (Map ExamPartNumber (Maybe Points)))
, ciqGrade :: Maybe ExamResultPassedGrade
, ciqGrade :: Maybe (Maybe ExamResultPassedGrade)
}
instance FromJSON CorrectInterfaceRequest where
@ -62,7 +66,11 @@ instance FromJSON CorrectInterfaceRequest where
ciqUser <- Right <$> o JSON..: "user" <|> Left <$> o JSON..: "user"
results <- o JSON..:? "results"
ciqResults <- for results $ maybe (fail "Results may not be nullable") return . fromNullable
ciqGrade <- o JSON..:? "grade"
ciqGrade <- if
| "grade" `HashMap.member` o
-> Just <$> o JSON..: "grade"
| otherwise
-> pure Nothing
return CorrectInterfaceRequest{..}
@ -102,7 +110,9 @@ postECorrectR tid ssh csh examn = do
CorrectInterfaceRequest{..} <- requireCheckJsonBody
response <- exceptT return return . hoist runDB $ do
let mayEditResults = False
response <- runDB . exceptT (<$ transactionUndo) return $ do
Entity eId Exam{..} <- lift $ fetchExam tid ssh csh examn
euid <- traverse decrypt ciqUser
@ -157,7 +167,7 @@ postECorrectR tid ssh csh examn = do
audit $ TransactionExamPartResultDeleted examPartId uid
return Nothing
| Just partResult <- mPartResult -> let
mOld = (examPartResultResult . entityVal) <$> mOldResult
mOld = examPartResultResult . entityVal <$> mOldResult
mNew = ExamAttended <$> mPartResult
resultVal = _entityVal . _examPartResultResult
in if
@ -190,20 +200,22 @@ postECorrectR tid ssh csh examn = do
| otherwise -> return Nothing
| otherwise -> return mempty
newExamResult <- lift $ do
newExamResult <- for ciqGrade $ \ciqGrade' -> lift $ do
unless mayEditResults $
permissionDeniedI MsgUnauthorizedExamCorrectorGrade
mOldResult <- getBy $ UniqueExamResult eId uid
if
| Just (Entity oldId _) <- mOldResult, is _Nothing ciqGrade -> do
delete oldId
audit $ TransactionExamResultDeleted eId uid
return Nothing
| Just result <- ciqGrade -> let
| Just (Entity oldId _) <- mOldResult, is _Nothing ciqGrade' -> do
delete oldId
audit $ TransactionExamResultDeleted eId uid
return Nothing
| Just result <- ciqGrade' -> let
mOld = view passedGrade . examResultResult . entityVal <$> mOldResult
resultGrade = review passedGrade result
passedGrade :: Iso' ExamResultGrade ExamResultPassedGrade
passedGrade = iso (fmap $ bool (Left . view passingGrade) Right examShowGrades) (fmap $ either (review passingGrade) id)
in if
| ciqGrade /= mOld -> do
| ciqGrade' /= mOld -> do
newResult <- upsert ExamResult
{ examResultExam = eId
, examResultUser = uid

View File

@ -35,7 +35,7 @@ $newline never
<td .table__td #uw-exam-correct__result>
<select>
<option value="none">
_{MsgExamResultNone}
_{MsgExamCorrectExamResultNone}
$if examShowGrades
<option value="attended">
_{MsgExamResult}

View File

@ -10,7 +10,7 @@ spec = withApp $ do
it "loads the index and checks it looks right" $ do
request $ do
setMethod "GET"
setUrl HomeR
setUrl NewsR
addRequestHeader ("Accept-Language", "de")
statusIs 200
htmlAnyContain "h1" "Aktuelle Termine"
htmlAnyContain "h1" "Aktuelles"