Skip to content

Commit 8958433

Browse files
authored
fix: assessments buttons (#339)
* fix: assessments buttons - Unfocus after clicking an assessment - Assessment is now changed after select and not after fully checked solution
1 parent e449ba0 commit 8958433

File tree

6 files changed

+74
-47
lines changed

6 files changed

+74
-47
lines changed

lms/lmsdb/models.py

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -619,16 +619,11 @@ def view_solution(self) -> None:
619619
def start_checking(self) -> bool:
620620
return self.set_state(Solution.STATES.IN_CHECKING)
621621

622-
def set_state(
623-
self, new_state: SolutionState,
624-
assessment: Optional[SolutionAssessment] = None, **kwargs,
625-
) -> bool:
622+
def set_state(self, new_state: SolutionState, **kwargs) -> bool:
626623
# Optional: filter the old state of the object
627624
# to make sure that no two processes set the state together
628625
requested_solution = (Solution.id == self.id)
629626
updates_dict = {Solution.state.name: new_state.name}
630-
if assessment is not None:
631-
updates_dict[Solution.assessment.name] = assessment
632627
changes = Solution.update(
633628
**updates_dict, **kwargs,
634629
).where(requested_solution)
@@ -771,19 +766,20 @@ def _base_next_unchecked(cls):
771766
cls.submission_timestamp.asc(),
772767
)
773768

769+
def change_assessment(self, assessment_id: Optional[int] = None) -> bool:
770+
assessment = SolutionAssessment.get_or_none(
771+
SolutionAssessment.id == assessment_id,
772+
)
773+
requested_solution = (Solution.id == self.id)
774+
updates_dict = {Solution.assessment.name: assessment}
775+
changes = Solution.update(**updates_dict).where(requested_solution)
776+
return changes.execute() == 1
777+
774778
def mark_as_checked(
775779
self,
776-
assessment_id: Optional[int] = None,
777780
by: Optional[Union[User, int]] = None,
778781
) -> bool:
779-
assessment = SolutionAssessment.get_or_none(
780-
SolutionAssessment.id == assessment_id,
781-
)
782-
return self.set_state(
783-
Solution.STATES.DONE,
784-
assessment=assessment,
785-
checker=by,
786-
)
782+
return self.set_state(Solution.STATES.DONE, checker=by)
787783

788784
@classmethod
789785
def next_unchecked(cls) -> Optional['Solution']:

lms/lmsweb/views.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -673,17 +673,20 @@ def shared_solution(shared_url: str, file_id: Optional[int] = None):
673673
)
674674

675675

676+
@webapp.route('/assessment/<int:solution_id>', methods=['POST'])
677+
@login_required
678+
@managers_only
679+
def assessment(solution_id: int):
680+
assessment_id = request.json.get('assessment')
681+
updated = solutions.change_assessment(solution_id, assessment_id)
682+
return jsonify({'success': updated})
683+
684+
676685
@webapp.route('/checked/<int:exercise_id>/<int:solution_id>', methods=['POST'])
677686
@login_required
678687
@managers_only
679-
def done_checking(exercise_id, solution_id):
680-
if request.method == 'POST':
681-
assessment_id = request.json.get('assessment')
682-
else: # it's a GET
683-
assessment_id = request.args.get('assessment')
684-
is_updated = solutions.mark_as_checked(
685-
solution_id, current_user.id, assessment_id,
686-
)
688+
def done_checking(exercise_id: int, solution_id: int):
689+
is_updated = solutions.mark_as_checked(solution_id, current_user.id)
687690
next_solution = solutions.get_next_unchecked(exercise_id)
688691
next_solution_id = getattr(next_solution, 'id', None)
689692
return jsonify({'success': is_updated, 'next': next_solution_id})

lms/models/solutions.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,16 @@ def get_message_and_addressee(
6565
return msg, addressee
6666

6767

68-
def mark_as_checked(
69-
solution_id: int, checker_id: int, assessment_id: Optional[int] = None,
68+
def change_assessment(
69+
solution_id: int, assessment_id: Optional[int] = None,
7070
) -> bool:
7171
checked_solution: Solution = Solution.get_by_id(solution_id)
72-
is_updated = checked_solution.mark_as_checked(
73-
assessment_id=assessment_id, by=checker_id,
74-
)
72+
return checked_solution.change_assessment(assessment_id=assessment_id)
73+
74+
75+
def mark_as_checked(solution_id: int, checker_id: int) -> bool:
76+
checked_solution: Solution = Solution.get_by_id(solution_id)
77+
is_updated = checked_solution.mark_as_checked(by=checker_id)
7578
msg = _(
7679
'Your solution for the "%(subject)s" exercise has been checked.',
7780
subject=checked_solution.exercise.subject,

lms/static/checker.js

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
function trackFinished(exerciseId, solutionId, element) {
22
element.addEventListener('click', () => {
3-
const assessment = document.querySelector('input[name="assessment"]:checked');
4-
const assessmentValue = (assessment !== null) ? assessment.value : null;
53
const xhr = new XMLHttpRequest();
64
xhr.open('POST', `/checked/${exerciseId}/${solutionId}`, true);
75
xhr.setRequestHeader('Content-Type', 'application/json');
@@ -20,20 +18,33 @@ function trackFinished(exerciseId, solutionId, element) {
2018
}
2119
};
2220

23-
xhr.send(JSON.stringify({
24-
assessment: assessmentValue,
25-
}));
21+
xhr.send(JSON.stringify({}));
2622
});
2723
}
2824

2925
function changeAssessmentsAttributes(assessmentGroup, item) {
3026
if (item.value == assessmentGroup.dataset.checkedid) {
3127
item.removeAttribute('checked');
3228
item.checked = false;
33-
assessmentGroup.dataset.checkedid = 'None';
29+
assessmentGroup.dataset.checkedid = null;
3430
} else {
3531
assessmentGroup.dataset.checkedid = item.value;
3632
}
33+
document.activeElement.blur();
34+
35+
const xhr = new XMLHttpRequest();
36+
xhr.open('POST', `/assessment/${solutionId}`, true);
37+
xhr.setRequestHeader('Content-Type', 'application/json');
38+
xhr.responseType = 'json';
39+
xhr.onreadystatechange = () => {
40+
if (xhr.readyState === 4) {
41+
if (xhr.status !== 200) {
42+
console.log(xhr.status);
43+
}
44+
}
45+
};
46+
47+
xhr.send(JSON.stringify({assessment: assessmentGroup.dataset.checkedid}));
3748
}
3849

3950
function trackAssessmentButtons() {

tests/test_notifications.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ def test_user_commented_after_check(
175175
client = conftest.get_logged_user(student_user.username)
176176

177177
# Marking the solution as checked
178-
solutions.mark_as_checked(solution.id, staff_user.id, 1)
178+
solutions.mark_as_checked(solution.id, staff_user.id)
179179
solution = Solution.get_by_id(solution.id)
180180

181181
# Sending comments after solution checked

tests/test_solutions.py

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def test_mark_as_checked(
132132
):
133133
# Basic functionality
134134
assert solution.state == Solution.STATES.CREATED.name
135-
marked = solutions.mark_as_checked(solution.id, staff_user.id, 2)
135+
marked = solutions.mark_as_checked(solution.id, staff_user.id)
136136
# HELL WITH PEEWEE!!!
137137
solution = Solution.get_by_id(solution.id)
138138
assert marked
@@ -142,7 +142,7 @@ def test_mark_as_checked(
142142
# Not duplicating things
143143
staff_user2 = conftest.create_staff_user(index=1)
144144
solution2 = conftest.create_solution(exercise, student_user)
145-
marked = solutions.mark_as_checked(solution2.id, staff_user2.id, 3)
145+
marked = solutions.mark_as_checked(solution2.id, staff_user2.id)
146146
solution2 = Solution.get_by_id(solution2.id)
147147
assert solution2.state == Solution.STATES.DONE.name
148148
assert solution2.checker == staff_user2
@@ -171,21 +171,21 @@ def test_get_next_unchecked(
171171
assert unchecked.exercise.id == solution1.exercise.id
172172
assert unchecked == solution1
173173

174-
solutions.mark_as_checked(solution1.id, staff_user, 4)
174+
solutions.mark_as_checked(solution1.id, staff_user)
175175
unchecked = solutions.get_next_unchecked(exercise.id)
176176
assert unchecked is not None
177177
assert unchecked.exercise.id == solution3.exercise.id
178178
assert unchecked == solution3
179179

180-
solutions.mark_as_checked(solution3.id, staff_user, 1)
180+
solutions.mark_as_checked(solution3.id, staff_user)
181181
unchecked = solutions.get_next_unchecked(exercise.id)
182182
assert unchecked is None
183183

184184
unchecked = solutions.get_next_unchecked()
185185
assert unchecked is not None
186186
assert unchecked == solution2
187187

188-
solutions.mark_as_checked(solution2.id, staff_user, 2)
188+
solutions.mark_as_checked(solution2.id, staff_user)
189189
unchecked = solutions.get_next_unchecked()
190190
assert unchecked is None
191191

@@ -563,7 +563,7 @@ def test_last_view_status(
563563
solution = Solution.get_by_id(solution.id)
564564
assert solution.last_status_view == SolutionStatusView.NOT_CHECKED.name
565565

566-
solutions.mark_as_checked(solution.id, staff_user.id, 3)
566+
solutions.mark_as_checked(solution.id, staff_user.id)
567567
solution = Solution.get_by_id(solution.id)
568568
assert solution.last_status_view == SolutionStatusView.NOT_CHECKED.name
569569
client.get(f'/view/{solution.id}')
@@ -590,8 +590,6 @@ def test_done_checking(
590590
client = conftest.get_logged_user(staff_user.username)
591591
response = client.post(
592592
f'/checked/{solution.exercise.id}/{solution.id}',
593-
data=json.dumps({'assessment': 1}),
594-
content_type='application/json',
595593
)
596594
assert response.status_code == 200
597595

@@ -636,14 +634,30 @@ def test_solutions_of_user(
636634
solution: Solution, _assessments,
637635
):
638636
conftest.create_usercourse(student_user, course)
639-
solutions.mark_as_checked(solution.id, staff_user.id, 2)
637+
client = conftest.get_logged_user(staff_user.username)
638+
client.post(
639+
f'/assessment/{solution.id}',
640+
data=json.dumps({'assessment': 2}),
641+
content_type='application/json',
642+
)
640643
solution = Solution.get_by_id(solution.id)
644+
assert solution.assessment.name == 'Nice'
645+
646+
client.post(
647+
f'/assessment/{solution.id}',
648+
data=json.dumps({'assessment': None}),
649+
content_type='application/json',
650+
)
641651

642652
exercise2 = conftest.create_exercise(course, 2)
643653
solution2 = conftest.create_solution(exercise2, student_user)
644-
solutions.mark_as_checked(solution2.id, staff_user.id)
654+
client.post(
655+
f'/assessment/{solution2.id}',
656+
data=json.dumps({'assessment': 3}),
657+
content_type='application/json',
658+
)
645659
solution2 = Solution.get_by_id(solution2.id)
646660

647661
exercises = solution.of_user(student_user.id, from_all_courses=True)
648-
assert exercises[0].get('assessment') == 'Nice'
649-
assert exercises[1].get('assessment') is None
662+
assert exercises[0].get('assessment') is None
663+
assert exercises[1].get('assessment') == 'Try again'

0 commit comments

Comments
 (0)