Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Customizable evaluation results filters #2232

Open
wants to merge 56 commits into
base: main
Choose a base branch
from

Conversation

jooooosef
Copy link
Collaborator

@jooooosef jooooosef commented Jun 24, 2024

fix #1786

@jooooosef jooooosef marked this pull request as draft June 24, 2024 20:49
@jooooosef jooooosef changed the title Customizable evaluation results filters #1786 Customizable evaluation results filters Jun 24, 2024
@ybrnr ybrnr force-pushed the iss1786 branch 4 times, most recently from 0127464 to ca11745 Compare July 8, 2024 15:48
Copy link
Member

@janno42 janno42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • looks good, most parts work as expected
  • tests not reviewed yet

evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
evap/results/views.py Outdated Show resolved Hide resolved
evap/results/views.py Outdated Show resolved Hide resolved
evap/results/views.py Outdated Show resolved Hide resolved
evap/results/views.py Outdated Show resolved Hide resolved
evap/results/views.py Outdated Show resolved Hide resolved
evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
evap/results/views.py Show resolved Hide resolved
evap/results/tests/test_views.py Outdated Show resolved Hide resolved
evap/results/tests/test_views.py Outdated Show resolved Hide resolved
evap/results/tests/test_views.py Outdated Show resolved Hide resolved
evap/results/tests/test_views.py Outdated Show resolved Hide resolved
evap/results/tests/test_views.py Outdated Show resolved Hide resolved
evap/results/tests/test_views.py Outdated Show resolved Hide resolved
@richardebeling richardebeling changed the title Customizable evaluation results filters Customizable evaluation results filters Oct 14, 2024
@ybrnr ybrnr force-pushed the iss1786 branch 2 times, most recently from 9bd5cea to 8aaee00 Compare October 21, 2024 16:22
@ybrnr ybrnr force-pushed the iss1786 branch 2 times, most recently from e77a156 to 73c3a65 Compare October 28, 2024 22:50
@jooooosef jooooosef marked this pull request as ready for review November 18, 2024 22:04
evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
evap/results/tests/test_views.py Outdated Show resolved Hide resolved
evap/results/tests/test_views.py Outdated Show resolved Hide resolved
evap/results/tests/test_views.py Show resolved Hide resolved
evap/results/tests/test_views.py Outdated Show resolved Hide resolved
evap/results/tools.py Outdated Show resolved Hide resolved
evap/results/views.py Show resolved Hide resolved
evap/results/views.py Outdated Show resolved Hide resolved
evap/results/views.py Show resolved Hide resolved
evap/staff/templates/staff_user_form.html Show resolved Hide resolved
evap/results/tools.py Outdated Show resolved Hide resolved
evap/results/tools.py Outdated Show resolved Hide resolved
evap/results/tools.py Outdated Show resolved Hide resolved
evap/results/views.py Outdated Show resolved Hide resolved
evap/results/tests/test_views.py Outdated Show resolved Hide resolved
evap/results/tests/test_views.py Outdated Show resolved Hide resolved
evap/results/tests/test_views.py Outdated Show resolved Hide resolved
ybrnr and others added 11 commits December 16, 2024 21:32
made the can_see_general_textanswers and the contributor counterpart also consider the represtened users
make difference between remove_textanswers_that_the_user_must_not_see and can_textanswer_be_seen_by clearer for the future
when users cannot or should not click specific textanswer buttons (because it does not make sense) they should still be there for consistency but should be disabled
removed unnecessary comment and fixed HTML broken indentations and whitespaces
jooooosef and others added 2 commits December 16, 2024 22:19
implemented smaller changes that were quested in PR.
- removed comments
- itereated over enums directly
- changed the name in this itereation from con_view to contributor_view (same for gen_view)
- correclty formatted HTML comment
- made things that should be in one line to be in one line
- implemented variables for reused expected answers (on method and instance level) in test_views.py

Co-authored-by: Yannik <[email protected]>
showing a tooltip with title is not possible since the tag has the disabled class and therefore does not accept any mouse events.
Also: formatted code.

Co-authored-by: Yannik <[email protected]>
Copy link
Collaborator

@Kakadus Kakadus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some last comments from me :)

evap/results/views.py Outdated Show resolved Hide resolved
evap/results/views.py Outdated Show resolved Hide resolved
evap/results/tools.py Outdated Show resolved Hide resolved
jooooosef and others added 5 commits January 6, 2025 20:41
Removed tooltip from individual buttons and added a big one on label of the results button groups, since it is not simply possible to show a tooltip on a disabled button.

Co-authored-by: Yannik <[email protected]>
Test seems to be deleted by accident.
Added it again.
should (maybe?) be a lil faster. But was recommend so here.
This uses the db to check if one of the represented users is a responsible.
Copy link
Member

@janno42 janno42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This nice, want have.
(After changing these little things)

evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
evap/results/templates/results_evaluation_detail.html Outdated Show resolved Hide resolved
@jooooosef
Copy link
Collaborator Author

jooooosef commented Jan 13, 2025

I just realised that when I use the contributor and go in a contribution where I dont have general_textanswers rights but can edit change the contributor settings that the value for the view_general_results parameter is not set correctly.
Example:
user: [email protected]
contribution: Operating Systems I
click on ratings

Why is that? @janno42

removed tooltips and changed some labels
@janno42
Copy link
Member

janno42 commented Jan 20, 2025

I just realised that when I use the contributor and go in a contribution where I dont have general_textanswers rights but can edit change the contributor settings that the value for the view_general_results parameter is not set correctly. Example: user: [email protected] contribution: Operating Systems I click on ratings

Why is that? @janno42

Probably because you don't set the value and in evaluation_detail_parse_get_parameters the default is FULL?

Copy link
Member

@niklasmohrin niklasmohrin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks mostly good

Comment on lines 35 to +36
<div class="col-auto">
<div class="btn-switch btn-switch-light my-auto d-print-none">
<div class="btn-switch-label">{% translate 'View' %}</div>
<div class="btn-switch btn-group">
{% if user.is_staff and view == 'export' or is_contributor %}
<a
href="{% if is_contributor %}{% url 'results:evaluation_detail' evaluation.course.semester.id evaluation.id %}?view=export{% endif %}"
role="button"
class="btn btn-sm btn-light{% if view == 'export' %} active{% endif %}"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="{% blocktranslate %}Shows filtered view meant for personal export. Other contributors' results and private answers are hidden.{% endblocktranslate %}"
>
{% translate 'Export' context 'view mode' %}
</a>

{% endif %}
<a
href="{% url 'results:evaluation_detail' evaluation.course.semester.id evaluation.id %}?view=full"
role="button"
class="btn btn-sm btn-light{% if view == 'full' %} active{% endif %}"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="{% translate 'Shows all results available for you.' %}"
>
{% translate 'Full' %}
</a>
{% if not evaluation.can_publish_rating_results %}
<button
type="button"
disabled
class="btn btn-sm btn-light"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="{% blocktranslate %}The results of this evaluation have not been published because it didn't get enough votes.{% endblocktranslate %}"
>
{% if evaluation.course.is_private %}
{% translate 'Participant' %}
{% else %}
{% translate 'Public' %}
{% endif %}
</button>
{% else %}
<a
href="{% url 'results:evaluation_detail' evaluation.course.semester.id evaluation.id %}?view=public"
role="button"
class="btn btn-sm btn-light{% if view == 'public' %} active{% endif %}"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="
{% if evaluation.course.is_private %}
{% translate 'Shows results available for the participants.' %}"
>
{% translate 'Participant' %}
{% else %}
{% translate 'Shows results available for everyone logged in.' %}"
>
{% translate 'Public' %}
{% endif %}
</a>
{% endif %}
<div class="row">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The second line is indented too far here

@@ -21,7 +21,7 @@
{% if evaluation.state != evaluation.State.PUBLISHED %}
<div class="alert alert-warning">{% translate 'This is a preview. The results have not been published yet.' %}</div>
{% endif %}

{# manager is automatically a reviewer (so these are all groups that can see the buttons) #}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{# manager is automatically a reviewer (so these are all groups that can see the buttons) #}

Comment on lines +505 to +507
page_with_ratings_general_get_parameter = self.app.get(
self.url + "?view_contributor_results=ratings", user=self.manager
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean this?

Suggested change
page_with_ratings_general_get_parameter = self.app.get(
self.url + "?view_contributor_results=ratings", user=self.manager
)
page_with_ratings_contributor_get_parameter = self.app.get(
self.url + "?view_contributor_results=ratings", user=self.manager
)

self.assertNotIn(".responsible_contributor_orig_notreviewed.", page)
self.assertIn(".responsible_contributor_additional_orig_published.", page)
self.assertNotIn(".responsible_contributor_additional_orig_hidden.", page)
def helper_test_general(self, user, view_general_results, expected_visible_textanswers):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can refactor this to merge the two helper_test_* methods:

from itertools import product

def check_with_view(
    self,
    user,
    all_textanswers,
    expected_visible_textanswers,
    general=ViewGeneralResults,
    contributor=ViewContributorResults,
):
    textanswers_not_in = list(set(all_textanswers) - set(expected_visible_textanswers))
    for general_view, contributor_view in product(general, contributor):
        page = self.app.get(
            f"/results/semester/1/evaluation/1?view_general_results={general_view.value}&view_contributor_results={contributor_view.value}",
            user=user,
        )

        for answer in expected_visible_textanswers:
            self.assertIn(answer, page)
        for answer in textanswers_not_in:
            self.assertNotIn(answer, page)

The above checks all combinations of the given general and contributor views, and the arguments each default to checking all variants. You can still have helper_test_general and helper_test_contributor, but let them use check_with_view so that their logic is not duplicated. Maybe this would even be a way to shorten some parts like the following?

        self.helper_test_general(user, ViewGeneralResults.FULL, [])
        self.helper_test_general(user, ViewGeneralResults.RATINGS, [])

        self.helper_test_contributor(user, ViewContributorResults.FULL, [])
        self.helper_test_contributor(user, ViewContributorResults.RATINGS, [])
        self.helper_test_contributor(user, ViewContributorResults.PERSONAL, [])

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In particular, the case "person sees nothing" seems to be checked a couple of times

self.helper_test_contributor(user, ViewContributorResults.RATINGS, [])
self.helper_test_contributor(user, ViewContributorResults.PERSONAL, [])

user = "[email protected]"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just assign this once at the beginning of the function

Comment on lines +526 to +537
if view_contributor_results == ViewContributorResults.RATINGS:
return False
if user.is_reviewer:
return True
if (
view_contributor_results == ViewContributorResults.PERSONAL or textanswer.is_private
): # private textanswers should only be seen by the contributor and reviewer
return contributor == user
if view_contributor_results == ViewContributorResults.FULL:
# users can see textanswers if the contributor is one of their represented users (which includes the user itself)
if contributor in represented_users:
return True
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this a bit hard to understand, how do you feel about the following?

Suggested change
if view_contributor_results == ViewContributorResults.RATINGS:
return False
if user.is_reviewer:
return True
if (
view_contributor_results == ViewContributorResults.PERSONAL or textanswer.is_private
): # private textanswers should only be seen by the contributor and reviewer
return contributor == user
if view_contributor_results == ViewContributorResults.FULL:
# users can see textanswers if the contributor is one of their represented users (which includes the user itself)
if contributor in represented_users:
return True
match view_contributor_results:
case ViewContributorResults.RATINGS:
return False
case ViewContributorResults.PERSONAL:
return user.is_reviewer or contributor == user
case ViewContributorResults.FULL:
if user.is_reviewer:
return True
if textanswer.is_private:
return user == contributor
return contributor in represented_users


if textanswer.is_private:
return contributor == user

# NOTE: when changing this behavior, make sure all changes are also reflected in results.tools.textanswers_visible_to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So just to make sure: We checked that textanswers_visible_to does not need any changes?

Comment on lines +431 to +446
try:
view_contributor_results = ViewContributorResults(
request.GET.get("view_contributor_results", ViewContributorResults.FULL)
)
except ValueError as e:
raise BadRequest from e

try:
view_general_results = ViewGeneralResults(
request.GET.get(
"view_general_results",
ViewGeneralResults.FULL,
)
)
except ValueError as e:
raise BadRequest from e
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can merge these two, and also the contributor one below:

Suggested change
try:
view_contributor_results = ViewContributorResults(
request.GET.get("view_contributor_results", ViewContributorResults.FULL)
)
except ValueError as e:
raise BadRequest from e
try:
view_general_results = ViewGeneralResults(
request.GET.get(
"view_general_results",
ViewGeneralResults.FULL,
)
)
except ValueError as e:
raise BadRequest from e
try:
view_general_results = ViewGeneralResults(request.GET.get("view_general_results", ViewGeneralResults.FULL))
view_contributor_results = ViewContributorResults(
request.GET.get("view_contributor_results", ViewContributorResults.FULL)
)
contributor = get_object_or_404(UserProfile, pk=request.GET.get("contributor_id", request.user.id))
except ValueError as e:
raise BadRequest from e

Comment on lines 458 to +459
represented_users = [view_as_user]
if view != "export":
represented_users += list(view_as_user.represented_users.all())
# redirect to non-public view if there is none because the results have not been published
if not evaluation.can_publish_rating_results and view == "public":
view = "full"
represented_users += list(view_as_user.represented_users.all())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two lines can just be represented_users = [view_as_user, *view_as_user.represented_users.all()]

Comment on lines +220 to +221
if evaluation.is_user_contributor(view_as_user):
contributor_personal = True
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can just write contributor_personal = evaluation.is_user_contributor(view_as_user) from the start

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here: contributor_textanswers = view_as_user.is_reviewer or evaluation.user_is_contributor(view_as_user)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and for the third one:

    contributor_textanswers = view_as_user.is_reviewer or evaluation.user_is_contributor(view_as_user)
    contributor_personal = evaluation.is_user_contributor(view_as_user)

    user_represents_responsible = any(user in represented_users for user in evaluation.course.responsibles.all())
    user_represents_general_visibilty_contributor = any(
        evaluation.is_user_contributor(user)
        and evaluation.contributions.filter(
            contributor=user,
            textanswer_visibility=Contribution.TextAnswerVisibility.GENERAL_TEXTANSWERS,
        ).exists()
        for user in represented_users
    )

    general_textanswers = (
        view_as_user.is_reviewer or user_represents_responsible or user_represents_general_visibilty_contributor
    )

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Customizable evaluation results filters
6 participants