From 83045610a01c5e0e6b74eba902f84cfa0ffe35a0 Mon Sep 17 00:00:00 2001 From: salman2013 Date: Fri, 3 Apr 2026 19:56:03 +0500 Subject: [PATCH 1/5] feat: add feedback xblock --- pyproject.toml | 18 +- src/feedback/.DS_Store | Bin 0 -> 6148 bytes src/feedback/README.rst | 137 ++++++ src/feedback/__init__.py | 9 + src/feedback/apps.py | 28 ++ src/feedback/conf/locale/config.yaml | 4 + src/feedback/extensions/__init__.py | 3 + src/feedback/extensions/filters.py | 193 ++++++++ src/feedback/feedback.py | 449 ++++++++++++++++++ src/feedback/feedbacktests/__init__.py | 4 + src/feedback/feedbacktests/conftest.py | 27 ++ src/feedback/feedbacktests/test_feedback.py | 129 +++++ .../feedbacktests/test_feedback_unit.py | 60 +++ src/feedback/feedbacktests/test_filters.py | 139 ++++++ src/feedback/happy_sad_example.png | Bin 0 -> 28649 bytes src/feedback/happy_sad_happy_example.png | Bin 0 -> 27724 bytes src/feedback/public/default_icons/aface1.png | Bin 0 -> 3115 bytes src/feedback/public/default_icons/aface2.png | Bin 0 -> 2946 bytes src/feedback/public/default_icons/aface3.png | Bin 0 -> 2543 bytes src/feedback/public/default_icons/aface4.png | Bin 0 -> 3114 bytes src/feedback/public/default_icons/aface5.png | Bin 0 -> 3163 bytes .../public/default_icons/amidface1.png | Bin 0 -> 3114 bytes .../public/default_icons/amidface2.png | Bin 0 -> 2543 bytes .../public/default_icons/amidface3.png | Bin 0 -> 2946 bytes .../public/default_icons/amidface4.png | Bin 0 -> 2543 bytes .../public/default_icons/amidface5.png | Bin 0 -> 3114 bytes src/feedback/public/default_icons/anum1.png | Bin 0 -> 1758 bytes src/feedback/public/default_icons/anum2.png | Bin 0 -> 2106 bytes src/feedback/public/default_icons/anum3.png | Bin 0 -> 2194 bytes src/feedback/public/default_icons/anum4.png | Bin 0 -> 1982 bytes src/feedback/public/default_icons/anum5.png | Bin 0 -> 2058 bytes src/feedback/public/default_icons/astar1.png | Bin 0 -> 1393 bytes src/feedback/public/default_icons/astar2.png | Bin 0 -> 1328 bytes src/feedback/public/default_icons/astar3.png | Bin 0 -> 1280 bytes src/feedback/public/default_icons/astar4.png | Bin 0 -> 1125 bytes src/feedback/public/default_icons/astar5.png | Bin 0 -> 886 bytes src/feedback/public/default_icons/iface1.png | Bin 0 -> 2642 bytes src/feedback/public/default_icons/iface2.png | Bin 0 -> 2479 bytes src/feedback/public/default_icons/iface3.png | Bin 0 -> 2075 bytes src/feedback/public/default_icons/iface4.png | Bin 0 -> 2662 bytes src/feedback/public/default_icons/iface5.png | Bin 0 -> 2697 bytes .../public/default_icons/imidface1.png | Bin 0 -> 2662 bytes .../public/default_icons/imidface2.png | Bin 0 -> 2075 bytes .../public/default_icons/imidface3.png | Bin 0 -> 2479 bytes .../public/default_icons/imidface4.png | Bin 0 -> 2075 bytes .../public/default_icons/imidface5.png | Bin 0 -> 2662 bytes src/feedback/public/default_icons/inum1.png | Bin 0 -> 1840 bytes src/feedback/public/default_icons/inum2.png | Bin 0 -> 2210 bytes src/feedback/public/default_icons/inum3.png | Bin 0 -> 2303 bytes src/feedback/public/default_icons/inum4.png | Bin 0 -> 2070 bytes src/feedback/public/default_icons/inum5.png | Bin 0 -> 2167 bytes src/feedback/public/default_icons/istar1.png | Bin 0 -> 1338 bytes src/feedback/public/default_icons/istar2.png | Bin 0 -> 1273 bytes src/feedback/public/default_icons/istar3.png | Bin 0 -> 1221 bytes src/feedback/public/default_icons/istar4.png | Bin 0 -> 1071 bytes src/feedback/public/default_icons/istar5.png | Bin 0 -> 846 bytes src/feedback/settings/__init__.py | 0 src/feedback/settings/common.py | 20 + src/feedback/settings/production.py | 14 + src/feedback/settings/test.py | 24 + src/feedback/static/.DS_Store | Bin 0 -> 6148 bytes src/feedback/static/README.txt | 19 + src/feedback/static/css/feedback.css | 123 +++++ .../static/css/feedback_instructor.css | 9 + .../static/html/feedback_instructor.html | 52 ++ src/feedback/static/js/src/feedback.js | 65 +++ .../static/js/src/feedback_instructor.js | 10 + src/feedback/static/js/src/studio.js | 35 ++ src/feedback/templates/.DS_Store | Bin 0 -> 6148 bytes src/feedback/templates/html/feedback.html | 19 + src/feedback/templates/html/scale_item.html | 19 + src/feedback/templates/html/studio_view.html | 130 +++++ .../feedback_instructor.html | 8 + src/feedback/translations | 1 + src/feedback/utils.py | 6 + 75 files changed, 1750 insertions(+), 4 deletions(-) create mode 100644 src/feedback/.DS_Store create mode 100644 src/feedback/README.rst create mode 100644 src/feedback/__init__.py create mode 100644 src/feedback/apps.py create mode 100644 src/feedback/conf/locale/config.yaml create mode 100644 src/feedback/extensions/__init__.py create mode 100644 src/feedback/extensions/filters.py create mode 100644 src/feedback/feedback.py create mode 100644 src/feedback/feedbacktests/__init__.py create mode 100644 src/feedback/feedbacktests/conftest.py create mode 100644 src/feedback/feedbacktests/test_feedback.py create mode 100644 src/feedback/feedbacktests/test_feedback_unit.py create mode 100644 src/feedback/feedbacktests/test_filters.py create mode 100644 src/feedback/happy_sad_example.png create mode 100644 src/feedback/happy_sad_happy_example.png create mode 100644 src/feedback/public/default_icons/aface1.png create mode 100644 src/feedback/public/default_icons/aface2.png create mode 100644 src/feedback/public/default_icons/aface3.png create mode 100644 src/feedback/public/default_icons/aface4.png create mode 100644 src/feedback/public/default_icons/aface5.png create mode 100644 src/feedback/public/default_icons/amidface1.png create mode 100644 src/feedback/public/default_icons/amidface2.png create mode 100644 src/feedback/public/default_icons/amidface3.png create mode 100644 src/feedback/public/default_icons/amidface4.png create mode 100644 src/feedback/public/default_icons/amidface5.png create mode 100644 src/feedback/public/default_icons/anum1.png create mode 100644 src/feedback/public/default_icons/anum2.png create mode 100644 src/feedback/public/default_icons/anum3.png create mode 100644 src/feedback/public/default_icons/anum4.png create mode 100644 src/feedback/public/default_icons/anum5.png create mode 100644 src/feedback/public/default_icons/astar1.png create mode 100644 src/feedback/public/default_icons/astar2.png create mode 100644 src/feedback/public/default_icons/astar3.png create mode 100644 src/feedback/public/default_icons/astar4.png create mode 100644 src/feedback/public/default_icons/astar5.png create mode 100644 src/feedback/public/default_icons/iface1.png create mode 100644 src/feedback/public/default_icons/iface2.png create mode 100644 src/feedback/public/default_icons/iface3.png create mode 100644 src/feedback/public/default_icons/iface4.png create mode 100644 src/feedback/public/default_icons/iface5.png create mode 100644 src/feedback/public/default_icons/imidface1.png create mode 100644 src/feedback/public/default_icons/imidface2.png create mode 100644 src/feedback/public/default_icons/imidface3.png create mode 100644 src/feedback/public/default_icons/imidface4.png create mode 100644 src/feedback/public/default_icons/imidface5.png create mode 100644 src/feedback/public/default_icons/inum1.png create mode 100644 src/feedback/public/default_icons/inum2.png create mode 100644 src/feedback/public/default_icons/inum3.png create mode 100644 src/feedback/public/default_icons/inum4.png create mode 100644 src/feedback/public/default_icons/inum5.png create mode 100644 src/feedback/public/default_icons/istar1.png create mode 100644 src/feedback/public/default_icons/istar2.png create mode 100644 src/feedback/public/default_icons/istar3.png create mode 100644 src/feedback/public/default_icons/istar4.png create mode 100644 src/feedback/public/default_icons/istar5.png create mode 100644 src/feedback/settings/__init__.py create mode 100644 src/feedback/settings/common.py create mode 100644 src/feedback/settings/production.py create mode 100644 src/feedback/settings/test.py create mode 100644 src/feedback/static/.DS_Store create mode 100644 src/feedback/static/README.txt create mode 100644 src/feedback/static/css/feedback.css create mode 100644 src/feedback/static/css/feedback_instructor.css create mode 100644 src/feedback/static/html/feedback_instructor.html create mode 100644 src/feedback/static/js/src/feedback.js create mode 100644 src/feedback/static/js/src/feedback_instructor.js create mode 100644 src/feedback/static/js/src/studio.js create mode 100644 src/feedback/templates/.DS_Store create mode 100644 src/feedback/templates/html/feedback.html create mode 100644 src/feedback/templates/html/scale_item.html create mode 100644 src/feedback/templates/html/studio_view.html create mode 100644 src/feedback/templates/instructor_dashboard/feedback_instructor.html create mode 120000 src/feedback/translations create mode 100644 src/feedback/utils.py diff --git a/pyproject.toml b/pyproject.toml index e47a579..97cf929 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,6 +30,8 @@ keywords = [ dependencies = [ "XBlock", "Django>=4.2", + "django-crum", + "openedx-filters", ] [project.urls] @@ -52,20 +54,28 @@ docs = [ "sphinx-book-theme", ] -# XBlock entry points will be added here as xblocks are migrated -# Example: -# [project.entry-points."xblock.v1"] -# foo = "foo_xblock:FooXBlock" +[project.entry-points."xblock.v1"] +feedback = "feedback.feedback:FeedbackXBlock" +[project.entry-points."xblock.test.v0"] +feedbacktest = "feedback.feedbacktests:feedbacktests" # Packages live in src/ but are installed without the src prefix # e.g., src/foo_xblock/ is installed as foo_xblock [tool.setuptools] package-dir = {"" = "src"} +include-package-data = true [tool.setuptools.packages.find] where = ["src"] exclude = ["tests*"] +[tool.setuptools.package-data] +"*" = [ + "static/**/*", + "templates/**/*", + "translations/**/*", +] + # Ruff configuration # https://docs.astral.sh/ruff/configuration/ [tool.ruff] diff --git a/src/feedback/.DS_Store b/src/feedback/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f9bb98f9ef369e2d887c98bfe9172469ec017f8c GIT binary patch literal 6148 zcmeHKu};G<5IvWu3T5fg0k(`xh%zG-s&q$mLSlfnP>_pV~E(bj|IjT$krD^K8AYZW=8qm>4*n5FSM8$G}B4x zJ7XPtXJt<)O5YvvK&O)m4T={9L;+WU9dp^{`rqGt{&y$Il_($z{3`{N7Y(8w9?90$ x%ENK34bX1T*f=jUsHec$a;!UCiucj9VJzSdFtnH%L= len(self.prompts): + self.prompt_choice = random.randint(0, len(self.prompts) - 1) + prompt = self.get_prompt() + + # Staff see vote totals, so we have slightly different HTML here. + item_templates_file = "templates/html/scale_item.html" + + # We have five Likert fields right now, but we'd like this to + # be dynamic + indexes = range(5) + + # If the user voted before, we'd like to show that + active_vote = ["checked" if i == self.user_vote else "" + for i in indexes] + + # Confirm that we do have vote totals (this may be uninitialized + # otherwise). This should probably go into __init__ or similar. + self.init_vote_aggregate() + votes = self.vote_aggregate + + # We grab the icons. This should move to a Filesystem field so + # instructors can upload new ones + def get_url(icon_type, i): + ''' + Helper function to generate the URL for the icons shown in the + tool. Takes the type of icon (active, inactive, etc.) and + the number of the icon. + + Note that some icon types may not be actively used in the + styling. For example, at the time of this writing, we do + selected through CSS, rather than by using those icons. + ''' + templates = { + 'inactive': 'public/default_icons/i{set}{i}.png', + 'active': 'public/default_icons/a{set}{i}.png', + } + template = templates[icon_type] + icon_file = template.format(i=i, set=prompt['icon_set']) + return self.runtime.local_resource_url(self, icon_file) + ina_urls = [get_url('inactive', i) for i in range(1, 6)] + act_urls = [get_url('active', i) for i in range(1, 6)] + + # Prepare the Likert scale fragment to be embedded into the feedback form + scale = "".join( + resource_loader.render_django_template( + item_templates_file, + { + 'scale_text': scale_text, + 'unicode_icon': unicode_icon, + 'idx': idx, + 'active': active, + 'vote_cnt': vote_cnt, + 'ina_icon': ina_icon, + 'act_icon': act_icon, + 'is_display_vote_cnt': self.vote_aggregate and (self.show_aggregate_to_students or self.is_staff()), + }, + i18n_service=self.runtime.service(self, 'i18n'), + ) for + (scale_text, + unicode_icon, + idx, + active, + vote_cnt, + act_icon, + ina_icon,) in + zip(prompt['scale_text'], + ICON_SETS[(prompt['icon_set'])], + indexes, + active_vote, + votes, + act_urls, + ina_urls) + ) + if self.user_vote != -1: + _ = self.runtime.service(self, 'i18n').ugettext + response = self.voting_message + else: + response = "" + + # We initialize self.p_user if not initialized -- this sets whether + # or not we show it. From there, if it is less than odds of showing, + # we set the fragment to the rendered XBlock. Otherwise, we return + # empty HTML. There ought to be a way to return None, but XBlocks + # doesn't support that. + if self.p_user == -1: + self.p_user = random.uniform(0, 100) + if self.p_user < self.p: + frag = Fragment() + frag.add_content(resource_loader.render_django_template( + 'templates/html/feedback.html', + context={ + 'self': self, + 'scale': scale, + 'freeform_prompt': prompt['freeform'], + 'likert_prompt': prompt['likert'], + 'response': response, + 'placeholder': prompt['placeholder'] + }, + i18n_service=self.runtime.service(self, 'i18n') + )) + else: + frag = Fragment('') + + # Finally, we do the standard JS+CSS boilerplate. Honestly, XBlocks + # ought to have a sane default here. + frag.add_css(self.resource_string("static/css/feedback.css")) + frag.add_javascript(self.resource_string("static/js/src/feedback.js")) + frag.initialize_js('FeedbackXBlock') + return frag + + def studio_view(self, context): # pylint: disable=unused-argument + """ + Create a fragment used to display the edit view in the Studio. + """ + prompt = self.get_prompt(0) + for idx in range(len(prompt['scale_text'])): + prompt['likert{i}'.format(i=idx)] = prompt['scale_text'][idx] + frag = Fragment() + + prompt.update({ + "display_name": self.display_name, + "voting_message": self.voting_message, + "feedback_message": self.feedback_message, + "show_aggregate_to_students": self.show_aggregate_to_students, + }) + frag.add_content(resource_loader.render_django_template( + 'templates/html/studio_view.html', + prompt, + i18n_service=self.runtime.service(self, 'i18n') + )) + js_str = self.resource_string("static/js/src/studio.js") + frag.add_javascript(six.text_type(js_str)) + frag.initialize_js('FeedbackBlock', + {'icon_set': prompt['icon_set']}) + return frag + + @XBlock.json_handler + def studio_submit(self, + data, suffix=''): # pylint: disable=unused-argument + """ + Called when submitting the form in Studio. + """ + for item in ['freeform', 'likert', 'placeholder', 'icon_set']: + item_submission = data.get(item, None) + if item_submission and len(item_submission) > 0: + self.prompts[0][item] = html.escape(item_submission) + for i in range(5): + likert = data.get('likert{i}'.format(i=i), None) + if likert and len(likert) > 0: + self.prompts[0]['scale_text'][i] = html.escape(likert) + + self.display_name = data.get('display_name') + self.voting_message = data.get('voting_message') + self.feedback_message = data.get('feedback_message') + self.show_aggregate_to_students = data.get("show_aggregate_to_students") + + return {'result': 'success'} + + def init_vote_aggregate(self): + ''' + There are a lot of places we read the aggregate vote counts. We + start out with these uninitialized. This guarantees they are + initialized. We'd prefer to do it this way, rather than default + value, since we do plan to not force scale length to be 5 in the + future. + ''' + if not self.vote_aggregate: + self.vote_aggregate = [0] * (len(self.get_prompt()['scale_text'])) + + def vote(self, data): + """ + Handle voting + """ + # prompt_choice is initialized by student view. + # Ideally, we'd break this out into a function. + prompt = self.get_prompt(self.prompt_choice) # pylint: disable=unused-variable] + + # Make sure we're initialized + self.init_vote_aggregate() + + # Remove old vote if we voted before + if self.user_vote != -1: + self.vote_aggregate[self.user_vote] -= 1 + + self.user_vote = data['vote'] + self.vote_aggregate[self.user_vote] += 1 + + @XBlock.json_handler + def feedback(self, data, suffix=''): # pylint: disable=unused-argument + ''' + Allow students to submit feedback, both numerical and + qualitative. We only update the specific type of feedback + submitted. + + We return the current state. While this is not used by the + client code, it is helpful for testing. For staff users, we + also return the aggregate results. + ''' + _ = self.runtime.service(self, 'i18n').ugettext + + if 'freeform' not in data and 'vote' not in data: + response = {"success": False, + "response": _("Please vote!")} + self.runtime.publish(self, + 'edx.feedbackxblock.nothing_provided', + {}) + if 'vote' in data: + response = {"success": True, + "response": self.voting_message} + self.runtime.publish(self, + 'edx.feedbackxblock.likert_provided', + {'old_vote': self.user_vote, + 'new_vote': data['vote']}) + self.vote(data) + if 'freeform' in data: + response = {"success": True, + "response": self.feedback_message} + self.runtime.publish(self, + 'edx.feedbackxblock.freeform_provided', + {'old_freeform': self.user_freeform, + 'new_freeform': data['freeform']}) + self.user_freeform = data['freeform'] + + response.update({ # pylint: disable=possibly-used-before-assignment + "freeform": self.user_freeform, + "vote": self.user_vote + }) + + if self.show_aggregate_to_students or self.is_staff(): + response['aggregate'] = self.vote_aggregate + + return response + + @staticmethod + def workbench_scenarios(): + """ + A canned scenario for display in the workbench. + + We have three blocks. One shows up all the time (for testing). The + other two show up 50% of the time. + """ + return [ + ("FeedbackXBlock", + """ + + + + + """), + ] + + def is_staff(self): + """ + Return self.xmodule_runtime.user_is_staff if available + + This is not a supported part of the XBlocks API in all + runtimes, and this is a workaround so something reasonable + happens in both workbench and edx-platform + """ + if hasattr(self, "xmodule_runtime") and \ + hasattr(self.xmodule_runtime, "user_is_staff"): + return self.xmodule_runtime.user_is_staff + else: + # In workbench and similar settings, always return true + return True diff --git a/src/feedback/feedbacktests/__init__.py b/src/feedback/feedbacktests/__init__.py new file mode 100644 index 0000000..3ae0280 --- /dev/null +++ b/src/feedback/feedbacktests/__init__.py @@ -0,0 +1,4 @@ +"""FeedbackXBlock test entry point exports.""" + +from .test_feedback import FeedbackTestCase as feedbacktests + diff --git a/src/feedback/feedbacktests/conftest.py b/src/feedback/feedbacktests/conftest.py new file mode 100644 index 0000000..1328b5f --- /dev/null +++ b/src/feedback/feedbacktests/conftest.py @@ -0,0 +1,27 @@ +import pytest +from mock import Mock + +from workbench.runtime import WorkbenchRuntime +from xblock.fields import ScopeIds +from xblock.runtime import DictKeyValueStore, KvsFieldData + +from feedback.feedback import FeedbackXBlock + + +def generate_scope_ids(runtime, block_type): + """ helper to generate scope IDs for an XBlock """ + def_id = runtime.id_generator.create_definition(block_type) + usage_id = runtime.id_generator.create_usage(def_id) + return ScopeIds('user', block_type, def_id, usage_id) + + +@pytest.fixture +def feedback_xblock(): + """Feedback XBlock pytest fixture.""" + runtime = WorkbenchRuntime() + key_store = DictKeyValueStore() + db_model = KvsFieldData(key_store) + ids = generate_scope_ids(runtime, 'feedback') + feedback_xblock = FeedbackXBlock(runtime, db_model, scope_ids=ids) + feedback_xblock.usage_id = Mock() + return feedback_xblock diff --git a/src/feedback/feedbacktests/test_feedback.py b/src/feedback/feedbacktests/test_feedback.py new file mode 100644 index 0000000..ee1be3f --- /dev/null +++ b/src/feedback/feedbacktests/test_feedback.py @@ -0,0 +1,129 @@ +''' +Tests for the FeedbackXBlock that needs to run in Open edX. +''' + + +import mock + + +class PatchRandomMixin(object): + """ + This is a class which will patch random.uniform so that we can + confirm whether randomization works. + """ + def setUp(self): + super(PatchRandomMixin, self).setUp() + self.random_patch_value = None + + def patched_uniform(min, max): + return self.random_patch_value + + patcher = mock.patch("feedback.feedback.random.uniform", + patched_uniform) + patcher.start() + self.addCleanup(patcher.stop) + + def set_random(self, random_patch_value): + self.random_patch_value = random_patch_value + + +# pylint: disable=abstract-method +class FeedbackTestCase(PatchRandomMixin): + """ + Basic tests for the FeedbackXBlock. We set up a page with two + of the block, make sure the page renders, toggle a few ratings, + and call it quits. + """ + + olx_scenarios = { # Currently not used + "two_feedback_block_test_case": """ + + + """ + } + + # This is a stop-gap until we can load OLX and/or OLX from + # normal workbench scenarios + test_configuration = [ + { + "urlname": "feedback_block_test_case_0", + "xblocks": [ # Stopgap until we handle OLX + { + 'blocktype': 'feedback', + 'urlname': 'feedback_0', + 'parameters': {'p': 100} + } + ] + }, + { + "urlname": "feedback_block_test_case_1", + 'xblocks': [ + { + 'blocktype': 'feedback', + 'urlname': 'feedback_1', + 'parameters': {'p': 50} + } + ] + } + ] + + def submit_feedback(self, block, data, desired_state): + """ + Make an AJAX call to the XBlock, and assert the state is as + desired. + """ + resp = self.ajax('feedback', block, data) + self.assertEqual(resp.status_code, 200) + # pylint: disable=no-member + self.assertEqual(resp.data, desired_state) + + # pylint: disable=unused-argument + def check_response(self, block_urlname, rendered): + """ + Confirm that we have a 200 response code (no server error) + + Confirm that we do this stochastically based no `p` + """ + response = self.render_block(block_urlname) + self.assertEqual(response.status_code, 200) + if rendered: + self.assertTrue('feedback_likert_scale' in response.content) + else: + self.assertFalse('feedback_likert_scale' in response.content) + + def test_feedback(self): + """ + Walk through a few ratings. Make sure the blocks don't mix up + state between them, initial state is correct, and final state + is correct. + """ + self.select_student(0) + # We confirm we don't have errors rendering the student view + self.check_response('feedback_0', True) + # At 45, feedback_1 should render + self.set_random(45) + self.check_response('feedback_1', True) + vote_str = 'Thank you for voting!' + feedback_str = 'Thank you for your feedback!' + self.submit_feedback('feedback_0', + {'freeform': 'Worked well', 'vote': 3}, + {'freeform': 'Worked well', 'vote': 3, + 'response': feedback_str, 'success': True}) + self.submit_feedback('feedback_0', + {'vote': 4}, + {'freeform': 'Worked well', 'vote': 4, + 'response': vote_str, 'success': True}) + self.submit_feedback('feedback_0', + {'freeform': 'Worked great'}, + {'freeform': 'Worked great', 'vote': 4, + 'response': feedback_str, 'success': True}) + # And confirm we render correctly + self.check_response('feedback_0', True) + # Feedback 1 should render again; this should be stored in a + # field + self.set_random(55) + self.check_response('feedback_1', True) + + # But it should not render for a new student + self.select_student(1) + self.check_response('feedback_1', False) diff --git a/src/feedback/feedbacktests/test_feedback_unit.py b/src/feedback/feedbacktests/test_feedback_unit.py new file mode 100644 index 0000000..d1705af --- /dev/null +++ b/src/feedback/feedbacktests/test_feedback_unit.py @@ -0,0 +1,60 @@ +""" +Tests for the Feedback XBlock with heavy mocking. +""" + +from mock import Mock + + +def test_template_content(feedback_xblock): + """ Test content of FeedbackXBlock's student view """ + student_fragment = feedback_xblock.render('student_view', Mock()) + assert 'feedback' in student_fragment.content + + +def test_studio_view(feedback_xblock): + """ Test content of FeedbackXBlock's author view """ + student_fragment = feedback_xblock.render('studio_view', Mock()) + assert 'feedback' in student_fragment.content + + +def test_studio_submit(feedback_xblock): + """ Test the FeedbackXBlock's save action """ + request_body = b"""{ + "display_name": "foo", + "voting_message": "bar", + "feedback_message": "baz", + "show_aggregate_to_students": true + }""" + request = Mock(method='POST', body=request_body) + response = feedback_xblock.studio_submit(request) + + assert feedback_xblock.display_name == 'foo' + assert feedback_xblock.voting_message == 'bar' + assert feedback_xblock.feedback_message == 'baz' + assert feedback_xblock.show_aggregate_to_students is True + assert response.status_code == 200 and {'result': 'success'} == response.json, response.json + + +def test_vote(feedback_xblock): + """ Test content of FeedbackXBlock's vote() method """ + feedback_xblock.vote({'vote': 1}) + + +def test_feedback_method(feedback_xblock): + """ Test content of FeedbackXBlock's feedback() method """ + request_body = b"""{ + "freeform": "yes", + "vote": 1 + }""" + request = Mock(method='POST', body=request_body) + response = feedback_xblock.feedback(request) + + expected_response_json = { + "aggregate": [0, 1, 0, 0, 0], + "freeform": "yes", + "response": "Thank you for your feedback!", + "success": True, + "vote": 1, + } + + assert response.status_code == 200 and response.json == expected_response_json, response.json diff --git a/src/feedback/feedbacktests/test_filters.py b/src/feedback/feedbacktests/test_filters.py new file mode 100644 index 0000000..f53805f --- /dev/null +++ b/src/feedback/feedbacktests/test_filters.py @@ -0,0 +1,139 @@ +""" +Test for the instructor dashboard filters. +""" + +from unittest import TestCase +from unittest.mock import Mock, patch +from django.test.utils import override_settings + + +from feedback.extensions.filters import AddFeedbackTab, load_xblock_answers + +class TestFilters(TestCase): + """ + Test suite for the FeedbackXBlock filters. + """ + + def setUp(self) -> None: + """ + Set up the test suite. + """ + self.filter = AddFeedbackTab(filter_type=Mock(), running_pipeline=Mock()) + + @patch("feedback.extensions.filters.get_user_enrollments") + @patch("feedback.extensions.filters.get_block_by_usage_id") + @patch("feedback.extensions.filters.modulestore") + def test_run_filter_without_blocks(self, modulestore_mock, get_block_by_usage_id_mock, get_user_enrollments_mock): + """ + Check the filter is not executed when there are no Feedback blocks in the course. + + Expected result: + - The context is returned without modifications. + """ + modulestore_mock().get_items.return_value = [] + context = {"course": Mock(id="test-course-id"), "sections": []} + template_name = "test-template-name" + + self.filter.run_filter(context, template_name) + + get_block_by_usage_id_mock.assert_not_called() + get_user_enrollments_mock.assert_not_called() + + + @patch("feedback.extensions.filters.get_lms_link_for_item") + @patch("feedback.extensions.filters.get_user_enrollments") + @patch("feedback.extensions.filters.get_block_by_usage_id") + @patch("feedback.extensions.filters.load_single_xblock") + @patch("feedback.extensions.filters.modulestore") + def test_run_filter(self, modulestore_mock, load_single_xblock_mock, get_block_by_usage_id_mock, get_user_enrollments_mock, + get_lms_link_for_item_mock): + """ + Check the filter is executed when there are Feedback blocks in the course. + + Expected result: + - The context is returned with the Feedback blocks information. + """ + modulestore_mock().get_items.return_value = [Mock(location="test-location")] + context = {"course": Mock(id="test-course-id"), "sections": []} + template_name = "test-template-name" + get_user_enrollments_mock.value_list = [(1, "test-username")] + block_mock = Mock( + vote_aggregate=[], + ) + block_mock.get_prompt.return_value = {"scale_text": ["test-scale-text"]} + get_block_by_usage_id_mock.return_value = block_mock, None + get_lms_link_for_item_mock.return_value = "test-url" + load_single_xblock_mock.return_value = Mock( + user_vote=1, + user_freeform="test-user-freeform", + ) + + result = self.filter.run_filter(context, template_name) + + get_block_by_usage_id_mock.assert_called() + get_user_enrollments_mock.assert_called_once() + self.assertEqual(1, len(result.get("context", {})["sections"])) + + @override_settings( + FEATURES={"ENABLE_FEEDBACK_INSTRUCTOR_VIEW":False} + ) + def test_run_filter_disable(self): + context = {"course": Mock(id="test-course-id"), "sections": []} + template_name = "test-template-name" + + new_context = self.filter.run_filter(context, template_name)["context"] + + self.assertEqual(context, new_context) + + @patch("feedback.extensions.filters.load_single_xblock") + def test_load_xblock_answers(self, load_single_xblock_mock): + request_mock = Mock() + students = [(1, "test-username")] + course_id = "test-course-id" + block_id = "test-block-id" + course = Mock() + + single_block = Mock( + user_vote=0, + user_freeform="test-user-freeform", + ) + single_block.get_prompt.return_value = {"scale_text": ["test-scale-text"]} + + load_single_xblock_mock.return_value = single_block + + answers = load_xblock_answers(request_mock, students, course_id, block_id, course) + + self.assertEqual( + [ + { + "username": "test-username", + "user_vote": "test-scale-text", + "user_freeform": "test-user-freeform", + } + ], + answers, + ) + + + @patch("feedback.extensions.filters.load_single_xblock") + def test_load_xblock_answers_skip_empty(self, load_single_xblock_mock): + request_mock = Mock() + students = [(1, "test-username")] + course_id = "test-course-id" + block_id = "test-block-id" + course = Mock() + + single_block = Mock( + user_vote=-1, + user_freeform="", + ) + single_block.get_prompt.return_value = {"scale_text": ["test-scale-text"]} + + load_single_xblock_mock.return_value = single_block + + answers = load_xblock_answers(request_mock, students, course_id, block_id, course) + + self.assertEqual( + [], + answers, + ) diff --git a/src/feedback/happy_sad_example.png b/src/feedback/happy_sad_example.png new file mode 100644 index 0000000000000000000000000000000000000000..2114144d2be3286cf79ff668759f6543ee9e0010 GIT binary patch literal 28649 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

fl@Qf#2aS=mF@o?_I<^is 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 E1FFg#vH$=8 literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/aface1.png b/src/feedback/public/default_icons/aface1.png new file mode 100644 index 0000000000000000000000000000000000000000..360c1f36362579ef2c2a5476b3da26fe8fa6d952 GIT binary patch literal 3115 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 s2MmER1WFUJXU2tBmf6?0mX)6^yE@g(M?R@26` zNsQ)b($-WeD#e(pcocC*QISm+9R_q9lo@Ab_T|0)F^^@K_hu2Q{{Fi6zI)&O-S2+) z`@XwC1VI2A*j#w4%3Rjib55@7)LEaHopd#y8W;jcFp&%qCpVrqb4*lWYNVga5G7Ze z3*U47;m!;9drXcI=jR6rJm&kkald~#k%_{-Un#gAYV7&AQg&Z&dnWWKFgl98F<-JW zCw55rP_7$J$^Lxl{xc*-4Ge)d=1V>+P8nS2#dTq6)6r(tGbcui;xxgT71{mS0k!zx zm%A?%Q2@YMnRde|S$~$~daOnLO^xC?QSyhsT~(ZH*LczpK@c_xYJ+)?sh#W^D$e5Y5}W%Rx*g%M@nJ zpF6Q4m))0lp1;smQmwihs-C0F8F}eHyc!+XSD3?8|h_1$mm zZ9A$DVg1swDV)IV&Itqv77i5+eN5ujFaBKO=rWG~4 zMk=9We9>Q)j9nX#0su_i%94NIE!Fgonb3F2m)DBUO=bW9;&Rj8y>x50j(Y0+$Q4e{ zNiOz`1=nw^)Tq7w03~FPtMm{B0KlvTb0+SShEe9xKe4HATSmZt&(*ex%O~GR32oi@b{> zN3DtT(gnQt$tTyzEmJ~vTn+{(LCcjX5-%VfjP0juhM}Gfg2H{&2W6mPz8#<_)2EC# zw5_}GW_PH??V{?l^>!WE_wfdsnyU3+K z;^S2v8r8uko+MV3&Z3Mi>9``9X`})e?`!T+I6%DqeDgNNK$pgjdrNC9zK)ErXx1L> z?ieVr9V~A>-0L$Yx2;M}woXam@~Nx=jU7N4*#feo%I(roZ8Ye(I%Q_^4{1?h&qlJGNRH5xGF#MCCWVHp z%T}i$XCXD2#ip(_vOv<3`})xt6;xXqI$z+v(?MEQo+Ns-zi4cPfG~@a$v8mXX`+m@ z=vWX6nMMIP2><}T=xtF)UH8DOAiTJXe~?Za)&THpKiA}4xAlt;ixR#=YJj7<-D;<5 zLmRu;)IH^-@n*g|g%>gS8w9b2D`}YJ)iaWn6DRc~%})+IqBfKCF`?76{|2cBqKPSs zDLwQE0S=GemP`vaCRY4z!f*TbjLO?hv#N}KW}oDWAwkf^ou^OSdi|=I95;i%b;Z<6b7QhX z4{M+>_OEATx33xfI+rZzs%xJ9AC)qQV<$-X`9-xkxbr>;&3$EjM|rtd=rT83G{(3+1dB001CyYEtQvltQob26wxx zr@T#D-DPZ0+tkhh-f&o0ViY$=!Y@h}Es}BtgBv-GyACyNZnaUmQ(wH2%!f)UTEDMV z2F(=!0AMC}*=y3ThdADT;JB&pzJNs?P2x?r@0FZT)`W5=^Wn6Fr@7nkfGvnxou9NW zhaVS$(mHR{KiGc$;c=BK)ML@Al@lSW(=GnvC8Is0JDdSPVT|0d;UEB!WasIy`=3-qNrZZ6(1^_To_^)%uJa0<0*gIe9d8R>X*y1el z*23iHN{Jfl^Ca^#$PL55YS>(m^wu~LO_S$?W!W)b%u4Ie4sd0n@K1{}UmWSK&yyTj zm^rxQMSPnh;WNLRC!L)hHKd&O&C}m+b#JTceD-giHWf&gzZ4tno2P!*T=>=dhU2a3 z+mCu%RA!^i9mFMLXuuE{L!hxDPC;_y{7m7rM1PMF{s#yX*mztOUoHRu002ovPDHLk FV1h>&-HreN literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/aface4.png b/src/feedback/public/default_icons/aface4.png new file mode 100644 index 0000000000000000000000000000000000000000..4d9c73befacd0252c7211a23eab1dbba22f8327b GIT binary patch literal 3114 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 Ef?28wrvLx| literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/aface5.png b/src/feedback/public/default_icons/aface5.png new file mode 100644 index 0000000000000000000000000000000000000000..aaa354f44b31a409a193c99ce1e088f0d5488beb GIT binary patch literal 3163 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 B18)ET literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/amidface1.png b/src/feedback/public/default_icons/amidface1.png new file mode 100644 index 0000000000000000000000000000000000000000..4d9c73befacd0252c7211a23eab1dbba22f8327b GIT binary patch literal 3114 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 Ef?28wrvLx| literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/amidface2.png b/src/feedback/public/default_icons/amidface2.png new file mode 100644 index 0000000000000000000000000000000000000000..73e05cc07f676433305f39b29329adfe420a3c49 GIT binary patch literal 2543 zcmVBmf6?0mX)6^yE@g(M?R@26` zNsQ)b($-WeD#e(pcocC*QISm+9R_q9lo@Ab_T|0)F^^@K_hu2Q{{Fi6zI)&O-S2+) z`@XwC1VI2A*j#w4%3Rjib55@7)LEaHopd#y8W;jcFp&%qCpVrqb4*lWYNVga5G7Ze z3*U47;m!;9drXcI=jR6rJm&kkald~#k%_{-Un#gAYV7&AQg&Z&dnWWKFgl98F<-JW zCw55rP_7$J$^Lxl{xc*-4Ge)d=1V>+P8nS2#dTq6)6r(tGbcui;xxgT71{mS0k!zx zm%A?%Q2@YMnRde|S$~$~daOnLO^xC?QSyhsT~(ZH*LczpK@c_xYJ+)?sh#W^D$e5Y5}W%Rx*g%M@nJ zpF6Q4m))0lp1;smQmwihs-C0F8F}eHyc!+XSD3?8|h_1$mm zZ9A$DVg1swDV)IV&Itqv77i5+eN5ujFaBKO=rWG~4 zMk=9We9>Q)j9nX#0su_i%94NIE!Fgonb3F2m)DBUO=bW9;&Rj8y>x50j(Y0+$Q4e{ zNiOz`1=nw^)Tq7w03~FPtMm{B0KlvTb0+SShEe9xKe4HATSmZt&(*ex%O~GR32oi@b{> zN3DtT(gnQt$tTyzEmJ~vTn+{(LCcjX5-%VfjP0juhM}Gfg2H{&2W6mPz8#<_)2EC# zw5_}GW_PH??V{?l^>!WE_wfdsnyU3+K z;^S2v8r8uko+MV3&Z3Mi>9``9X`})e?`!T+I6%DqeDgNNK$pgjdrNC9zK)ErXx1L> z?ieVr9V~A>-0L$Yx2;M}woXam@~Nx=jU7N4*#feo%I(roZ8Ye(I%Q_^4{1?h&qlJGNRH5xGF#MCCWVHp z%T}i$XCXD2#ip(_vOv<3`})xt6;xXqI$z+v(?MEQo+Ns-zi4cPfG~@a$v8mXX`+m@ z=vWX6nMMIP2><}T=xtF)UH8DOAiTJXe~?Za)&THpKiA}4xAlt;ixR#=YJj7<-D;<5 zLmRu;)IH^-@n*g|g%>gS8w9b2D`}YJ)iaWn6DRc~%})+IqBfKCF`?76{|2cBqKPSs zDLwQE0S=GemP`vaCRY4z!f*TbjLO?hv#N}KW}oDWAwkf^ou^OSdi|=I95;i%b;Z<6b7QhX z4{M+>_OEATx33xfI+rZzs%xJ9AC)qQV<$-X`9-xkxbr>;&3$EjM|rtd=rT83G{(3+1dB001CyYEtQvltQob26wxx zr@T#D-DPZ0+tkhh-f&o0ViY$=!Y@h}Es}BtgBv-GyACyNZnaUmQ(wH2%!f)UTEDMV z2F(=!0AMC}*=y3ThdADT;JB&pzJNs?P2x?r@0FZT)`W5=^Wn6Fr@7nkfGvnxou9NW zhaVS$(mHR{KiGc$;c=BK)ML@Al@lSW(=GnvC8Is0JDdSPVT|0d;UEB!WasIy`=3-qNrZZ6(1^_To_^)%uJa0<0*gIe9d8R>X*y1el z*23iHN{Jfl^Ca^#$PL55YS>(m^wu~LO_S$?W!W)b%u4Ie4sd0n@K1{}UmWSK&yyTj zm^rxQMSPnh;WNLRC!L)hHKd&O&C}m+b#JTceD-giHWf&gzZ4tno2P!*T=>=dhU2a3 z+mCu%RA!^i9mFMLXuuE{L!hxDPC;_y{7m7rM1PMF{s#yX*mztOUoHRu002ovPDHLk FV1h>&-HreN literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/amidface3.png b/src/feedback/public/default_icons/amidface3.png new file mode 100644 index 0000000000000000000000000000000000000000..dd2fc9542f475771565b3b1e5ee8208938aa37b2 GIT binary patch literal 2946 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 s2MmER1WFUJXU2tBmf6?0mX)6^yE@g(M?R@26` zNsQ)b($-WeD#e(pcocC*QISm+9R_q9lo@Ab_T|0)F^^@K_hu2Q{{Fi6zI)&O-S2+) z`@XwC1VI2A*j#w4%3Rjib55@7)LEaHopd#y8W;jcFp&%qCpVrqb4*lWYNVga5G7Ze z3*U47;m!;9drXcI=jR6rJm&kkald~#k%_{-Un#gAYV7&AQg&Z&dnWWKFgl98F<-JW zCw55rP_7$J$^Lxl{xc*-4Ge)d=1V>+P8nS2#dTq6)6r(tGbcui;xxgT71{mS0k!zx zm%A?%Q2@YMnRde|S$~$~daOnLO^xC?QSyhsT~(ZH*LczpK@c_xYJ+)?sh#W^D$e5Y5}W%Rx*g%M@nJ zpF6Q4m))0lp1;smQmwihs-C0F8F}eHyc!+XSD3?8|h_1$mm zZ9A$DVg1swDV)IV&Itqv77i5+eN5ujFaBKO=rWG~4 zMk=9We9>Q)j9nX#0su_i%94NIE!Fgonb3F2m)DBUO=bW9;&Rj8y>x50j(Y0+$Q4e{ zNiOz`1=nw^)Tq7w03~FPtMm{B0KlvTb0+SShEe9xKe4HATSmZt&(*ex%O~GR32oi@b{> zN3DtT(gnQt$tTyzEmJ~vTn+{(LCcjX5-%VfjP0juhM}Gfg2H{&2W6mPz8#<_)2EC# zw5_}GW_PH??V{?l^>!WE_wfdsnyU3+K z;^S2v8r8uko+MV3&Z3Mi>9``9X`})e?`!T+I6%DqeDgNNK$pgjdrNC9zK)ErXx1L> z?ieVr9V~A>-0L$Yx2;M}woXam@~Nx=jU7N4*#feo%I(roZ8Ye(I%Q_^4{1?h&qlJGNRH5xGF#MCCWVHp z%T}i$XCXD2#ip(_vOv<3`})xt6;xXqI$z+v(?MEQo+Ns-zi4cPfG~@a$v8mXX`+m@ z=vWX6nMMIP2><}T=xtF)UH8DOAiTJXe~?Za)&THpKiA}4xAlt;ixR#=YJj7<-D;<5 zLmRu;)IH^-@n*g|g%>gS8w9b2D`}YJ)iaWn6DRc~%})+IqBfKCF`?76{|2cBqKPSs zDLwQE0S=GemP`vaCRY4z!f*TbjLO?hv#N}KW}oDWAwkf^ou^OSdi|=I95;i%b;Z<6b7QhX z4{M+>_OEATx33xfI+rZzs%xJ9AC)qQV<$-X`9-xkxbr>;&3$EjM|rtd=rT83G{(3+1dB001CyYEtQvltQob26wxx zr@T#D-DPZ0+tkhh-f&o0ViY$=!Y@h}Es}BtgBv-GyACyNZnaUmQ(wH2%!f)UTEDMV z2F(=!0AMC}*=y3ThdADT;JB&pzJNs?P2x?r@0FZT)`W5=^Wn6Fr@7nkfGvnxou9NW zhaVS$(mHR{KiGc$;c=BK)ML@Al@lSW(=GnvC8Is0JDdSPVT|0d;UEB!WasIy`=3-qNrZZ6(1^_To_^)%uJa0<0*gIe9d8R>X*y1el z*23iHN{Jfl^Ca^#$PL55YS>(m^wu~LO_S$?W!W)b%u4Ie4sd0n@K1{}UmWSK&yyTj zm^rxQMSPnh;WNLRC!L)hHKd&O&C}m+b#JTceD-giHWf&gzZ4tno2P!*T=>=dhU2a3 z+mCu%RA!^i9mFMLXuuE{L!hxDPC;_y{7m7rM1PMF{s#yX*mztOUoHRu002ovPDHLk FV1h>&-HreN literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/amidface5.png b/src/feedback/public/default_icons/amidface5.png new file mode 100644 index 0000000000000000000000000000000000000000..4d9c73befacd0252c7211a23eab1dbba22f8327b GIT binary patch literal 3114 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 Ef?28wrvLx| literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/anum1.png b/src/feedback/public/default_icons/anum1.png new file mode 100644 index 0000000000000000000000000000000000000000..ab0ce3f815eddfbd5cd032d2efb6468f90d6e879 GIT binary patch literal 1758 zcmV<41|j*0P))mx9X1%dPE^Ff?|I>J^ zIrC{|_RO4fRPlHmq%VdS2Pfzt!|ODdMTh6=)CMi4!63~EEHC<^u}M0{@}h~rSLW$V zT0Da(RB4ehym)skr~;~OWhR9~I6>?mr&&SRTx2A0n0+#a7jKSGRRv@|sZnk{SzekO z@X)oz28Bzgh^*5YsI?gkS}eJ9*cZ7v~4^GeyKjV+a7+y3JxK54Pt$Le5yQ9Lq zz06cyn3Ft;6U1At;EoFOi;}r0Cddj^Rx%mrQlIBSkK5soE@&M9P-)RMZ!GwrzPQ{> zBpV@cSZX5X88{zV_XxG2fHWo+|7n2v;_t`5^o=V4njr#*EnA8{Z!DMj7F@hJ$=aXz zn^sz6E2lf2p1AfT1Ev{#M_w*Dy?2!cgUD?62-Q?+NrSA@5!hL2M(w8o=JlWN^^S#J z5KETbO18bbNnX5mhksVMS;&%CtIHYKcd;+P@Y%vbB5>Gxc;lYcx%0ryBiTr+H#Itym`aG~;T27y(&QXH*zmBqv_Z?Z{?l968qAoC;l(o@PMHKP8w3D!k5K5~ zd&1oL9=Aes7-@OGiU_-02hQGjt=&KNVlMAepT`sC002fUKH#AxGEyx)BF=TYl-r8O z=nGfwRDSp0Wv`IQ<14onY`qVo;lSn|C?_%SM#Y zZI|?clNt=JAl2xHb6K|%sn;zzvlXNo=ISIeho4zKBuV2T4mEOh>gnB##)P?tERkde zEe>IhMsj9Ze;#HanIT7m!7wLbnu$yz>Fi1ll{rC#!33ryap0CwHiH&5ymSoGiLJF6 zG7P@6D4Bs`csNPN(2v?8!}1|XT9+?{+*8pQMDIxeK)GeUhoKK>~+303aqxN3FT0;IpCuO-vm~-n){-9&<m68UYe^-L~#6AE)h69-c<3`u1dLQ*40{o3;=M`MXk3^*8_%qk(1XP*{TNwS$@bHtt*++ zJuOf}c`_AccyWDd4du!M@A)40-~_FN$!;Z^YYN`kY)h`83{22QEtYu=1&QIs+s}gb zeEp1Cn2TaA-}4N4BMyJmF~#_!u>ixPx>Kcvuv^Kx665oArw}XjxF39qCM?(!|CWW3T?fT}w?od1qs*>ta^NSP2p3zVo#J883l~0s5Su!H332Sh; zf>e`g%tYX%2BSHF;l-(F%pc_=oM0mGjIZGT0dHIr+RfGvN&o-=07*qoM6N<$g7eBv Ah5!Hn literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/anum2.png b/src/feedback/public/default_icons/anum2.png new file mode 100644 index 0000000000000000000000000000000000000000..08d775052dd7c0e16ba00add0abfb0d71cd2e53f GIT binary patch literal 2106 zcmV-A2*vk_P)XgEQ;1F5}USZ8BA$f#w1ov+PZ4$nriBP zs8XVB|8&y+ncAgeTVUF%txdJ4Q>qdcv4o27BannZu)!p@F~&d7KA-Q-`{T~W5Cdn& z+4rwkcfRNS_<7&=dEfVWWXWU_au?0=cUGtn&8ifbL4_Mta*YyGV2EP4ILrHDiB&2Q zXL%ig*A%OCN<5D)WI2)1EPwN1NCvV)l{$%^FdTo&O~pCxnKCVbqr#KXEPs6|SZ^kG zkqYV7Gv%e284uM`u94_MNo2#0K#N7AQDT`7=X}wB&H8S+BX?FPyPx*Q5;V)}30x(| zYE5d3MtP)4f4EZDP+FAv6~pm2oS`FC`o|@62I)|ot2dFEKm(JW_s3jze{4tV08njE zbv2p$+RANuBGU+gBddJ<8M9;AGB_WksHXIL0U)P!j!+}2pswS*b~Ca3g?M1 znX7d}P!7d80c+9~d2-%Li)Q)G{>j<2t*zj? z2d5d12Y`AL`RRRs`jt4E!8nURCPeu+|9$`5kVAr5nZCsE^(NEFYF%5I+Dae*05)M? z3H|4u_m7{uKJ)Vux8z?OuX*cOH2{R;91lrh`x430>v489+WgxaG|O+#WZrE(_ob>H zs~i9T5;F__F&`6^$!!+>iE^b303b2+*>v}(YwqnW0RRAjqlq6J*ju8`BoWC%aaNdN z-}&J7g)!Gortr?*qaW>-0l@0rxz4{kuSe6~kr^v0F1+-GuaE!$i=z|!KlFJexUQ$w z@`rEK2_#7Xof1a?FtQXBusjh)0#=5+ju!@&GOz$3xwh==zF?mP003KC-T4|^Cc)Cc zq{kCs06?q6XFL=LD}a=XhlqDZoH<}Y^4itq$wZbHQP=X@b^%w>{hVGe0gYz)bni+G ziDb1VweV6=nc=hR|gjpT=w_u_=0#6QJHm>Sk@nHR=W3wQZg84@$rY@mNE?h zOt~Wx4>kbY@JF9Ny)Ak)nwt3-u9PyI0Cs=umOIi=TBN|xjE6$ORNVUSQcxO}6v?!j zl%qlsS9Zr{(MXEH7fm2#>TEu24-^gz-)9r|nX&OTmxRC}Xw(@J8l(b4C8Q9Oz#(-g zcNV5G_EyRO0AlX9CSuYzlW~`L)+!<8$fy#@?0&jXV9keWzK8(;_wl9qPjdOc?l2=X zj4Jv1XvVf!XSqscseHFx1pw~x>F-X(b26G{P~r#`Da5H-kS!dkjlVu!(+t2Y&VTvC zRgdHuwuzxgfuRT^V(N)}Zqk{ODK)RZ*z|n^@UF!d`j;k{oGqlU$_&S&PzuwKns9kz z{rJV!b2gNC;5hc){h?SsNePQaDKxxP0#T`Gux=ZOUXPwx`1+-tD}E}SO;z-HL) z#=MoVqT=85Hot0y;Jtg#Uvy4ym|HTFwd9x~d2il#Q<@jstXiSLaY>|>ixdCEp5k1w zaBa!&`kG%g!|Lt32mZ1N3jk2#k@|tI+P)I0DWH>kMFuT_qlQv46lVco?=E$q2n`v?KsY%zTQtIeT6IM4vt>KmkRhG2ATaCdX|Q?09!7um~L8eeIBtgGrN!tEQz~6OMBLu%}pkwxjC*i3I>>JE{aMFU7Q! zi(yqH(<$-v+31aSTi#JO54DtO-e|W8?K|FRI*Yp=Y1%5ZGbw(q3;@_ zYRVN6+Q*+VUOLnC<(}p=*03XR z^pR9@_B?H7dUDPe{no&A0rRwnDs=;0`_g&Zt9F08#60bza6)eT+>qlj;~asbvmI4J zLP}6pZ|y(^0N0(tI@5YRV9po)`4xMi>H(oRJL`?@uh=p??NCEmSc}mtU$?P_^3U7e z3uCT3E0h$bS`*pTXnyG#OJ)saW`)u!vHWW&f@qc>T@KamQg5n-IfL}zlxNl(wfkfC zHQFCb1ZY;MJ5?KqS`)dyLi=dlDIDjNDz5+l%4&u?OKKBo9~WrFWDwStg=T6IS4;gp`wVOh@3P0;3p?X8E;P k!XIO!45uUTytm;00sR=PEaV%$G5`Po07*qoM6N<$g8casp#T5? literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/anum3.png b/src/feedback/public/default_icons/anum3.png new file mode 100644 index 0000000000000000000000000000000000000000..dcf17140baab3494d83dc2f2bae0c474532f0e36 GIT binary patch literal 2194 zcmV;D2yOR?P)1$E6~`ZEm*kRb9wKE*)GhhYZCQ3KAE<31km00&12kz;r48H)E$Rkng0?8q*dN-a zXyOC~+Bz*-z&+e5MeOuQirR?Kz)2)EP;95NEX%Si%Qk7rl1Nb$&n0)4yUTu<<%*O= zX(`kFe_C-hGrxT^^Jd!@k@dTStxl6kPo)1i;g7vP?jP|)$L1JUfDObGtRPt_(x4^k z9Y&`~zqiV|r^3=)ye_>JFG?4u!h5T%4@x!_V#A!+=%CYqP7izkG&t)D#8>Sd0ICZN zoh?O2+Da>}RC*^AiOMb13Jq5x8<-3=718FD@$UxNWBe^oNgZ-5X z->SyTO4fTP&|XuZ^zwS&-5;I5vj(Ome9!MJd;PHuIs)Nt2PQ-9)de|_^}B-ms;&6> zZjk-LU#>@JQN4ri`Px>+c)hN`vT)0grCaM0ckod6aF7-9g@r|t=94|_jXCk}GGkjzQ*;I(NP$XXRpSXj2PYymLtYzW6 zQ9gaQW;o?ACt|GO+33TwmLgV=4s{QY&&L2jN1!k#roUYz>vspS-{M87>mS$izP7T# zJ$vRFFG>K==%7Em9Z+7$vl-$91RCt+k9~0ac&}Sczj~AD(arV)8?3uZ)-~Am76Jf3 z*LMgxX>0~HRSU{Q!j~}!W0FaFS z^qhA}mFoZi7)UYrV+m59x|{dAf)B={(do$2LesuF=ZpJ_x9K1m@V)fT*w3d|-j^A= zG!;J5Rtf;LjvxzZE&kQL_NmmAY=30>DYNqT!adK?kMEuwk1nXT7S_p3CtZVlz)fUXnJ0c5yc2i5$$n zM8Qe-kxBVkqcuFfx9-m!wu5^b4z@VH{rhXb@ro+x6b3zs&^n#$%<^@FClm4aKf2QP zuAcz_y71RuuYKI8QQ1~uSf?XUl$SBB)LJ6xYx)&oprP!+e@TtZ;}lVpI(?y zx9>k+D>IlW5;YgoVNL*m+V#fjf~*5AtJ1a&UnyADBWUa!YhJCyuek321Oh4?n$x6L zVyAisjVKaL%*O#hN1*3-mF7eSr0sX#YGfl7L5-*V z?&t9B1TNhRQzRk*Adyba$&6KV3Mr*Culelvi@@#eQ2uPuc7?!{){Ar*89HFp+#ETNXaDU_7u|NEGMpaK5qO#onM4i2( z(%f8RtS}0R5MI1cbJyh%?|Bw89fP55J5PN;~T@+yi% zH@>$U=U@~Pd0)4dnj)MC0GsT_qwQ7yPb>g9+FpgRd<@^3isEE4i=I^OMlbKL%*pFM zpjt~zFYm9!&ttxrlEq!j9<-I2N9Py-&=KgJXPfeRz-N_}BHw#%3l2m^=a_wIDab`K zibMtyVc)jNZv5Mqn{!H%uR#=vdb;EkUziijnHlPgv1@FGtFux3+_BMi_HfI?gQH0F z)-#Pt&TQNlUy@K>CFgkl*22?okK{csWTnWSuB{4IzdN|^zEtw^dD`^!U8k`-QW7II!JLt|WMPJ?K zOs}Dg&M{^^vGy7Y7Ar`X?uF~u8<*6=rb6tQtKM;6%oT{c7T7>M5o85icd9O+>K*is zGV}d)rwAtw%|^1#U~Xgz-^Hm=gJbQrx-chPo{sFQu&DGzIoCI@%tn$)XiTd|tt?)Y z2B#xQNbaeysvjt4vUEgT6V{Qakk-;#!a|X>j$n9^6{LlDA`lm1ylA1wH6OwM1EMh3 UD@Po`^#A|>07*qoM6N<$f^?fxe*gdg literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/anum4.png b/src/feedback/public/default_icons/anum4.png new file mode 100644 index 0000000000000000000000000000000000000000..c77db0b864e85a3f36885ab86096a7a2bf5b66cf GIT binary patch literal 1982 zcmV;v2SNCWP)P4-#WyQ(>AARp}OOg^Hw63aBAXLP$fJ*hxqn$8r4Ietv%Md4D|n#WqQ7 zznF6VI)3&&_v3r-JNMr2QN-hM$ln-F7+Vba8BR?S1~o2GD>W*DBv6RuqnzN5#Fj#_ zC@1JB+)%34sj!SL6nT*`oN#yEuK>mVT3wD!SY8-e2t|2*ccqrXsPJSAC)}FxHJ8(6 zG?{z!RC9&cQD?|nrO9y!b0X`td#xsoMn$APoN$N#GwvQ)2#zg=Y#zoFi7}j@r?6T{ zSd2v`jp~qDf1p;^Qc;}Risgmdv;IS7{YJ@VeT+ZKHyi0xpi4u}zYRESo=Dc{08npG zAKzL2>fWk4J(U`S!l*_^t_cJNKwxAO#lA+lnkZ}zSs6upM7pKNgy$7|BSDr-jD}bug!b7UN8F7 zUgo?17#^GtY!FK_i;?brWtTK~H*KC(;Z`9_9j!jQ_vpnTFT)iIOEe0jYbSR;yQO3u zxJNI$pxH>@nDk_l`J$ZFq!InMZrEhLiA2%sFE#AS zv(eyu;B3#d=dF4|NA1#((-~v|K&!%|&QOAkRwfP+@Ac2hi3$o+^R_=X65xB-`H5fN zUcqpJ)Vqp62{MbZNPKj8$SETzD&F+&u`(^N=dVnD%E&n(XY}4uLHnW{8k`S^`|I#R zFvo*Unkkgu{?7K7)!_bO?9?PDp9{d|iHs}+0e~dXlskfa$-MR1j88^5eZ%JSRuY)S zSG(Oy8{q-~fc_+dI~+r*n8yqT6-KC-OeC{>ws2%Q(DZf% zz=G{(pM}{%aiuU6lLQK~2~0he>rI+0tvdfLjRL}5S7t^EdfJt)$}BG+e-hJ>TyR;8 zPG-OVhmel;X9sxl8!KeKP*ZCcK;g$B4 z1?U(z|K(xU7saGW2mn5Y!%Lyq)=~ffYo(??mt@N`H-?wIYe@(S+}fzGQvd*X=iHwr zlN{p=hjVyOwwEQY+{=*|7SEFaP-j^0#=K&z|Lx0bAH;F-AK%#brU3wizK`#{_#nS! zxVJ_tIy@goMasm&e@+~_Cu+}cOE73Dj9Myaf0P4&ZDmFE2K5ufGHF!O-N|C45rxsj zQUm}<0=?E&^#sY@I9MY(cOLpFj4%Migv3%i-dg^f?yvHXi7ai~x*ACW02H`YpLlri zn>#*iivs|}0)M(X)thbeJ83nEjsg?_fB|5aN#l=lS{1I*Q9pmW^8DxXd6Fs0YK+IW zXC`WWRq4@$tGx1&t#{o+W#?0-@?sJITp_llf(Gf1E@>GP?r`gSx8+?@WE+Lim%rRE zYA_N>VmGi>X#!Cm0JfGEo$fGyomc>Hy2C7Dxk9Wpd5cSs=~P%c8=Y#evsP-pHY{tU z=2Ux~=#RO=l8U>c9_+2wjxL4(fF#gAPwdEjgWrhhDSY)Ot>Q&wbTM=|MS@%*qcBoq zB<8lQrA7bxQA=JTxeTK)>h4TPeEuk>O;@PX`feyu4?BXQ|Lm5MYbSR;J~#@azyGjV z(#*zPkqkjOi{^O!tK}cOKT>ebQBUFS&Rr5#uibn25h;0foi^i z-KFC@B%QX$=4sDSr+pMo)V9yulqtqYMqzZi!~DA=_0p47M=J{%0Nk4OH5pgx0Tb@< zTi0!cst5R^+_)>Ur+Urwl%<9;wH#qMp((wF^1*%Ag#pLdVorLL#Yi7-E&u6mQ)&%m zbTOn=5%Oy&qA{Fs=b_(HR+Lc-oAoi5hn?fDu+0;(Ei;}-%*$|M-KpL{S&a0aYVD(S zr$Ce+bOhF#!TiW1zT30DCZqgXoj=OmoeQ+p>T=9PdDl0;a0KFUXilj|t#2$Z49o@M z5I<0>&%L9($x;!;nlOpcCR#}=2_1!Lk_fRp!wJigm?y%8SzbqB*<0}c0my}E4erKm QNB{r;07*qoM6N<$f?KuTnE(I) literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/anum5.png b/src/feedback/public/default_icons/anum5.png new file mode 100644 index 0000000000000000000000000000000000000000..f65fb6759db2e239d653725b3a900754e214d98e GIT binary patch literal 2058 zcmV+l2=(`gP)v_;y& zr|yCf>Ic3c?Jg?N6sq#jBC0Ocl7uR33u)@MX_{smJN72F<2d$=Uo+#GF(2-D;yfIW z9T)zeuAG^3e>wNgx%Zr-$z(E6yjVe+SxzvlV9?=q15shnn)SF2#}d5A2~s$fUP+`m zL9&uWYo)=eCrX$?Qxq91NOzVP4QLKGT2;Qni_-l-f)mC4brzDq%1_1$(#Kx9tA?tk zbn30=DwN=-gNdGcvq~4LA{+Nadz@yo9?$)8E}Z<^Z1{d4KC_%~N7zUz%?gr@Bn(=- z!(nuq^+%g+M;fhrYE8Ls@uGCg#~f|8?Uc+%vkWJ8IjCHq5m)fnlYVz3RnR&BwAc+N z_SL-6Ti;|ObB&M$)?g*Kd2u_k2`|07hO%UxzYt~5UVn1Q6;K1TK_r0<9jN*_9*!=x~hT#N5BGk&SzzC~onhG<5Z0+4ojHxK}Sf z;6(`lx*XJ)JF5IiUQL=4FwmeVfA+&C=SMvSjhb4ze6QEq3Op5m^Jlj&L<$@;KRMR= z)=Mn_5aUD%GU)h{eKxfiLs+vb$zR;`7Q`yA&X0P~nws_a)S?`o z{9pl%xPs@u&{kv8S@Z6TTf!QKDEuQfAlV7@&RD;V`0~F1v#NFS6X( z_ta7}Cty=cF?7D(3&d4kY@U+bk<|S_8~}7UHXlwAbT)4N%S)GL5!32>TJ49N#yS!w zBq2m6UB2i){amW}1Y^QWqnlqfzt7N-3m-l{cQ?)y z!*|=qywO_^0F(|Vswge`)lu7ys4&Q6?g(1~+2Y*?pSc=b$j+UlUmXfb6qQ|aQOQrz>f_N{+3U0K6YBqmqS{$XJO005rtdw#f5 zZ8E1Y=m`un>EvKm^bwxPaDtRC{3rcOzm$W3Y50I~yHq4c3WG_9V{u-_w2`G`(s?Cv zHy7lkX>PMttMi(YD)XX*FnNUQ)Lmbmua;Bp)l?co z_elU~va8&t005?zF7J=}9uHcKdBO0u2H9XL$SkV+?t2?7XdsFi%&3(;{c?MydNQP{ zCVOL^4Wu#HUTZ=gl|Gtc7@@hn zzV<=%MTNcR9;ej=TBljBm*meiTjnC;f%omI!%Y%e&eHVdHx0LU;*(&b(Ki)-nbv+4=uZgjf8si>&CL-o{|Pxm*W@k}VGRB_in`QBZY>E#3f=y2@!ukJ4M z0iQ=UlK9ify(kfxUQYDolpxp0NCGnu7>aG}mBuSy+f!7LyabU1c5O&5@iClWSzn=E zH+O4=;hsN^#>d(!J~*}S>A{f%_M5MCDK)d%P-;U#xj@bF#wV+(^b literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/astar1.png b/src/feedback/public/default_icons/astar1.png new file mode 100644 index 0000000000000000000000000000000000000000..ff94352b6944dc8c8715e00cd6e9481a93e1107b GIT binary patch literal 1393 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 literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/astar5.png b/src/feedback/public/default_icons/astar5.png new file mode 100644 index 0000000000000000000000000000000000000000..1d818f388879a740ed45028232d93ff0a1af6c2b GIT binary patch literal 886 zcmV-+1Bv{JP)G`aSW z?gQBSf$a4ci8>WsT0UVv!O`0tZV3U_HmorwBaO6L3FBvv-{8Am}L5yBoSq_A*<^rlI89Q9J{^=OQQEAXWb`_eI*0F$o)TJhOIbtIG#{;A@b! zfWtZB3M=8Ax&u4MAM`$5V)c zoIqy9tvTq%_xGoNli6SLTq>Sh(OIaby#-98R$$QZT|W>^1ld>pb2_NG z9CN{Of@6;Dg~B4id66E+fT!Y3e<86}2NrCk3Rz~pfCmO((NTyL;epUzdh(_YW#D`O zXI;xe5J#?&b-CjCw`Vy71|t&y53*PqjAqJPt1$T`!vK{@24>Td>Tx6Jlb1y;z?riJx^vDK)$&N? z`gf=`1UGrsg)gOY-HZ*P$`eN)yf&%vUAR~*RnIp%B%FC2I@uQ(x<s(x&QzG literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/iface1.png b/src/feedback/public/default_icons/iface1.png new file mode 100644 index 0000000000000000000000000000000000000000..11cb5bf777cc19e3a955b138d9eb50d93dd4001a GIT binary patch literal 2642 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 A)&Kwi literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/iface2.png b/src/feedback/public/default_icons/iface2.png new file mode 100644 index 0000000000000000000000000000000000000000..78bb27e5a7d62474b3533f682fa852ca0ab7c4a9 GIT binary patch literal 2479 zcmV;g2~hTlP)7L~9m2nb~ccPf<`1dEEyruM_BRI3i?H@4$cajaJA(i!4mFzW2NLoqNu? z_n9CF0`G{J{=WgnAn#cxM&7edjJ!*%`0;xbBI)aCZ0}|ZB)t;36mVn`fof&tHpSY- z$_zIiFL+y4rMRo~UQKRQ%^Ekyn1W zk}DiTFZ|4)xnHlC8}Dvm#3UKRs_5mM%)Xjh%9HAPAjOhQCE(QT6Yj-cV|acU2{ow?S;E+ zwo>aB&OYf+zyC*=%^>@6V@3KaE?xNe5?iEcv81h!i%4DM?nX4Ax4gHq?C##&2PIva zHdFs)EB~A5>0sFW8qBKfEjaZ{d=X!LZ5|P`EMtY&bOR^{iM*%iKi8Aa*SD%0oWei8 z`A2_uv+-h8i5OX@Vu}RVCB=PD%JLMtg|U$c5jHY69K3N^J#dHcxVy>T&Z9lf5LWrK z{Or)P9Bh?1%s#s-D$e$8Bc?+5YUkc_M_aJBd&hinJAr03qVJ9#?F6iwaT-v&fV{M2 zTA+wj)Z5JOmy9}IM8WS8wuzJ~bpxL2vH#mow$QLk)|HD}9*IC!vN4KI^mXdAYp+06_7{J-j?x|J;tus;EADJTxCAC4aI#DRT}P2LOQZYl<>td;g zb|fEAcE8wp6$J(B-z?i7h=PK$`^ARzp`ZZJRCsB9d5>1`S8>X(tR4yq09{AYuNDZ= zIWn0L7eU2#vMen9`5ec7+jU`+B_P?EX5>6;Jcpu-itNG)i`$_Eo-M115@H1;8! zbOu*nS)rd*&dX9qZM%8%<89TJ{cnzyq5cK45@Npgp-`wUUnMUNK}RC2`Jonr71TXA zht>)vPWv~8g;NQRz8{`mZI9koSH)O^kH5 z(zLfVlw*m@`O7eCG=$^r=*e^xR#sWnB?bVH*D=|B=sRWx$JwJV!g+)T2cx}vn;GpI ze=+l0IC}=xUZ2w<9}}yJ^Q?i5s*~xfX#-V}xRcw4wbN#6R)Go0k3I=ixy=F*0)WU~ zH)CURr8`Vg8{#adgic1)p6bp4-zH369ewDGFVY6yA)5CKh0U|1b z-2yMA1b|4RO&REIYVYZ>$crlhAi0_$0Du5xnp?Q30s!ypNggo7QNm`sJ>n<;%;-cw z0I*TusSA9_yW2zn@cKDVh}hc?iw1gPmb@b^<@nxq0Dyo$Y`U|AIxdC%$il1m$>n=C z0Knvs$|I3;2ty6@_<&N>(1U6OcSrMI0TcizcDA;tCggW2br|SjRmpi+~* z&YWzCY6=Noro%uF2cnc=u7RT%P_2!NnBocQ0#hYb>F`WFtR^@!%(ayw-2r6$MWv9b zm%k~|R7alG!)j_~PeL^*Pcm}#Gj5`kh_D=kCs_|$SfG~`NA|#?zwA}JM3}e&7**mPKLU@aXfjnmjt0~RT6RX)fU!3P?6?%xYri?K!`N#N! zIXj++$LJmim&u4enirm&wYiMfqXjJE)}F<-ix%?(taa`<^~O$;vrjCRxP{p_I6dli zRbNZ`&&-GY03ggfaAsFczrnaj$J64de?H{`fVA!S&y^K@8d&+Wo7HuwYB@b|s_rnU zKh6{E*Db_gJ4#D0s7qi|OV7hwgFP^CZhG3uwZ**QpL7_f^hx36uldVogRZ#_Pn zIX53&o)&9TH~bhxRtFO$`yM0eaJBYMhG0jFn&leoVnd^nNT3i3h4n41<&W#{cWFgv z6WgS1YYv52sXsH)U2`KijfoCp3rD4LNsF)D&cg zoq2GXW5HC5Az4%2 zU7wP6{@)zz(l>T(=_+S^U*B+60F}7tr_<34bzU)d-MKApr@zq^7{Y&fe_eXQuK(oflV} zEzq=(99G7BxFd3gFJ<(4T-DDnyji&~|MC4^O&dOV`KrsS z-0Tdi=Er)jt>V>Ge0sR7v`@Q{FvH(FHqdQ8-O0~!k{xkird6_jb{ns%uK8AV?WIRN zzIG>~)1No5NDHDGet>Jt{{oemd*Ax5EIIaBVCWeC z$r$|~2E^P~C$HQ&RMOHqh6h*#eK>bVY*4f_(TGi)@vNvIvYrP_R^Fq=QdZ03E?qxe z00>mOFrR6Q1H9rxT-``xTZ`KAwyfHMC?u_10lP=iCy`6R)PhK~va)n@u(B~To=;oG tlXaryUHW(Yo^@j6J?q5Cd)A4O{{eI5<~v|%5J~_5002ovPDHLkV1j00#+d*B literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/iface3.png b/src/feedback/public/default_icons/iface3.png new file mode 100644 index 0000000000000000000000000000000000000000..4ff2a76db56925a224453bd04069debea2b8ba88 GIT binary patch literal 2075 zcmV+$2;}#PP)w^|0F>rI`?NuaqE{aDPAo|W&8dm1AM&;5RI%? za^bt9w-uUcw4y8)r~kPyy@=2BVUc`cwdmxh&NS?A88zW`7{q3A85BAI8$pv&XR_ec z5v|B`{GQF)aT~@2S{o7ZL-M;I9$r7(hE)en838RuDn1KOyC5Tn69Bb?SvALt? z{2iIhYF9*#DE;HsPgaLI)b|@JGI^`|{N`$zVJe5s`)xtS{`LHLx)-e>-R;&phidLM zk5A>1mgW|JQ<4zr-THdXYSq<$@m0}vl`S2Zk(VneT(ZauN(X_o*DqZuJ@;tXmJzjP zbJMP+e5$`#VMF8RU*uh%z>-1ygZsAZ6Ec0ZM2M#U{_CG!t+h=&a!tXVH|H$ z)LnOGRh1k&C6UXjKG;|gHdBjf(L8?l(AmEaVxuSJ?fiB-kK=aldbV~G(x!qb&~VX( z^4yt&0suha3J!m`<1HSRlwSP$t#$+KwuuK;#PH<6@%w{lg3gz`pOee=`rLXFQqaPW z-YY0%qbWm$7Q)fYpTJ4Yqa;iuP z6-wS&5sN1D5BF3L>4<6Fv0ByNzuSP3hWtGD@N$*|DQs-5sf;f<68FZjh#e=kT^S)- z6!Tcm+wUC-`TcQ0>E9yCE}wmBe?J5S3o}n{2tpIX*KV8{BismXSgk)a-D-va0001T z%ts{&;SL`k9%`+9>3shPmQvTAuGrOP#2E)t96nqv>BBA${gd|B4mIBe?P=*5McFy1 z?L*{88Wlut1u-i$`nk<&hp)>l3UjOp>l?2QfDTz;UE`qIWobcK*Ox<%Sz}!%2OtNC z;6)#7;G+6aYg?ORzn)n^xwIBT<(6bebDWA1iym@rVgb#rw?7P-U52)3%uaKnre-Zm zL{;6R%0ZW|-Lk^+?mii+&J%9qxp+lnPUf;;r@UlwbclqVcXLNi>j=b+;pZ(4 zZkK{lW zc7<6$l^Lf30S98Wom6s=7v7p*ghZj)98A~*<7`+0)&MdU+f!Bpz5(&Sz!tOZ_><@) zoGnejN}@(EP|Y+7y7zwkCRWg(Lp2H`#MPh>vXWT>%=()jKLtH|CjJn^m{N&qoKRe^ zlYo`V7DZx3{Zf^2R@j^bdMvfQ6T%k6;2jd8GfqoN4MjCgZ(rX}uw^Zpn^Nr28J`>( zjAwy~LJA~aY61^X4gmn5{QjIgQxx~Crggky{oaNYU*Jx4YF6}AVb4Wo zrYHpW#Yt#88PUo4^H5cD=Biw4UxvVwGhJ!xq}ARkLETLqy{O7wRI(7?OcL99TEuU% zFxat{mh;3e@XQ6Ccy#av7HZ;Uh{X*2YHq?xi z^k3)eW&}@SN3gN65wP{^YmKOB4T#>C6B$U*#{HYy(pmMd^g8r-GGE#M`oG02zeFeP z1W`Y@x}y9(>VHQ4^0lsC$FK=rpYHE^O4{ZZOEG(3tUO+KYQ)c`)-wL^51(P606XO$ zTX{sFfX6p?04uJ1&x$xSVH((Tu%TA%w~Y(y`u|j3SBF_D)~ma-H@XdGc=n-!lh)Ui z@US~i)wS)wr7DFVRu@t~di%r56WH4lNXaigDq^~)@y6eyq--j_kb`XnK-s;stl}?S zuFoy+1yTKQx2WvgKjm0DDx>gHQM8+{kBawkLVe>`75P`DOc!ls&PK_$lvMA-rzoaL zRbO*?_r)hlTh79D1vg5QV!eoSPb>Zk-m9;9sd8XqDu)qSoVT_tJ2555^Y?)#Ro9ws ze_Yr3U)@w5WyO}4YhR8J_s*N2Zd@B4eQ@j5qpdA^`%GHm(xm+5@tMM?)CIxe^k*v# znqiwxE-t6e9ZXZ?IH=;-FeY3D!%=JEi>&yQF*r=#Dd-)xwi+4)MlpqF`4p@z# zc@qB+l2bBXIPt6HtETx+#^?VqfKl=I)W!dN);u^ojSiUNwdrN~;!V+XA0BbOv!a5S zwfF8zFSPf!NC!K|@qW4h0F4{IIyr8GXi3q^*m#ETA<>z#+6!UcIo8>cIo8>c{{cV=1r~V0ybb^W002ovPDHLk FV1mpU|JVQk literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/iface4.png b/src/feedback/public/default_icons/iface4.png new file mode 100644 index 0000000000000000000000000000000000000000..1a70456cfe3d8d38c09841f312eedb3b6c801699 GIT binary patch literal 2662 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 U5Oe*uod5s;07*qoM6N<$f=xjuTL1t6 literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/iface5.png b/src/feedback/public/default_icons/iface5.png new file mode 100644 index 0000000000000000000000000000000000000000..27eeade71d056646a413e8700169dbe625cdbc9b GIT binary patch literal 2697 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 U5Oe*uod5s;07*qoM6N<$f=xjuTL1t6 literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/imidface2.png b/src/feedback/public/default_icons/imidface2.png new file mode 100644 index 0000000000000000000000000000000000000000..4ff2a76db56925a224453bd04069debea2b8ba88 GIT binary patch literal 2075 zcmV+$2;}#PP)w^|0F>rI`?NuaqE{aDPAo|W&8dm1AM&;5RI%? za^bt9w-uUcw4y8)r~kPyy@=2BVUc`cwdmxh&NS?A88zW`7{q3A85BAI8$pv&XR_ec z5v|B`{GQF)aT~@2S{o7ZL-M;I9$r7(hE)en838RuDn1KOyC5Tn69Bb?SvALt? z{2iIhYF9*#DE;HsPgaLI)b|@JGI^`|{N`$zVJe5s`)xtS{`LHLx)-e>-R;&phidLM zk5A>1mgW|JQ<4zr-THdXYSq<$@m0}vl`S2Zk(VneT(ZauN(X_o*DqZuJ@;tXmJzjP zbJMP+e5$`#VMF8RU*uh%z>-1ygZsAZ6Ec0ZM2M#U{_CG!t+h=&a!tXVH|H$ z)LnOGRh1k&C6UXjKG;|gHdBjf(L8?l(AmEaVxuSJ?fiB-kK=aldbV~G(x!qb&~VX( z^4yt&0suha3J!m`<1HSRlwSP$t#$+KwuuK;#PH<6@%w{lg3gz`pOee=`rLXFQqaPW z-YY0%qbWm$7Q)fYpTJ4Yqa;iuP z6-wS&5sN1D5BF3L>4<6Fv0ByNzuSP3hWtGD@N$*|DQs-5sf;f<68FZjh#e=kT^S)- z6!Tcm+wUC-`TcQ0>E9yCE}wmBe?J5S3o}n{2tpIX*KV8{BismXSgk)a-D-va0001T z%ts{&;SL`k9%`+9>3shPmQvTAuGrOP#2E)t96nqv>BBA${gd|B4mIBe?P=*5McFy1 z?L*{88Wlut1u-i$`nk<&hp)>l3UjOp>l?2QfDTz;UE`qIWobcK*Ox<%Sz}!%2OtNC z;6)#7;G+6aYg?ORzn)n^xwIBT<(6bebDWA1iym@rVgb#rw?7P-U52)3%uaKnre-Zm zL{;6R%0ZW|-Lk^+?mii+&J%9qxp+lnPUf;;r@UlwbclqVcXLNi>j=b+;pZ(4 zZkK{lW zc7<6$l^Lf30S98Wom6s=7v7p*ghZj)98A~*<7`+0)&MdU+f!Bpz5(&Sz!tOZ_><@) zoGnejN}@(EP|Y+7y7zwkCRWg(Lp2H`#MPh>vXWT>%=()jKLtH|CjJn^m{N&qoKRe^ zlYo`V7DZx3{Zf^2R@j^bdMvfQ6T%k6;2jd8GfqoN4MjCgZ(rX}uw^Zpn^Nr28J`>( zjAwy~LJA~aY61^X4gmn5{QjIgQxx~Crggky{oaNYU*Jx4YF6}AVb4Wo zrYHpW#Yt#88PUo4^H5cD=Biw4UxvVwGhJ!xq}ARkLETLqy{O7wRI(7?OcL99TEuU% zFxat{mh;3e@XQ6Ccy#av7HZ;Uh{X*2YHq?xi z^k3)eW&}@SN3gN65wP{^YmKOB4T#>C6B$U*#{HYy(pmMd^g8r-GGE#M`oG02zeFeP z1W`Y@x}y9(>VHQ4^0lsC$FK=rpYHE^O4{ZZOEG(3tUO+KYQ)c`)-wL^51(P606XO$ zTX{sFfX6p?04uJ1&x$xSVH((Tu%TA%w~Y(y`u|j3SBF_D)~ma-H@XdGc=n-!lh)Ui z@US~i)wS)wr7DFVRu@t~di%r56WH4lNXaigDq^~)@y6eyq--j_kb`XnK-s;stl}?S zuFoy+1yTKQx2WvgKjm0DDx>gHQM8+{kBawkLVe>`75P`DOc!ls&PK_$lvMA-rzoaL zRbO*?_r)hlTh79D1vg5QV!eoSPb>Zk-m9;9sd8XqDu)qSoVT_tJ2555^Y?)#Ro9ws ze_Yr3U)@w5WyO}4YhR8J_s*N2Zd@B4eQ@j5qpdA^`%GHm(xm+5@tMM?)CIxe^k*v# znqiwxE-t6e9ZXZ?IH=;-FeY3D!%=JEi>&yQF*r=#Dd-)xwi+4)MlpqF`4p@z# zc@qB+l2bBXIPt6HtETx+#^?VqfKl=I)W!dN);u^ojSiUNwdrN~;!V+XA0BbOv!a5S zwfF8zFSPf!NC!K|@qW4h0F4{IIyr8GXi3q^*m#ETA<>z#+6!UcIo8>cIo8>c{{cV=1r~V0ybb^W002ovPDHLk FV1mpU|JVQk literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/imidface3.png b/src/feedback/public/default_icons/imidface3.png new file mode 100644 index 0000000000000000000000000000000000000000..78bb27e5a7d62474b3533f682fa852ca0ab7c4a9 GIT binary patch literal 2479 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 literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/imidface4.png b/src/feedback/public/default_icons/imidface4.png new file mode 100644 index 0000000000000000000000000000000000000000..4ff2a76db56925a224453bd04069debea2b8ba88 GIT binary patch literal 2075 zcmV+$2;}#PP)w^|0F>rI`?NuaqE{aDPAo|W&8dm1AM&;5RI%? za^bt9w-uUcw4y8)r~kPyy@=2BVUc`cwdmxh&NS?A88zW`7{q3A85BAI8$pv&XR_ec z5v|B`{GQF)aT~@2S{o7ZL-M;I9$r7(hE)en838RuDn1KOyC5Tn69Bb?SvALt? z{2iIhYF9*#DE;HsPgaLI)b|@JGI^`|{N`$zVJe5s`)xtS{`LHLx)-e>-R;&phidLM zk5A>1mgW|JQ<4zr-THdXYSq<$@m0}vl`S2Zk(VneT(ZauN(X_o*DqZuJ@;tXmJzjP zbJMP+e5$`#VMF8RU*uh%z>-1ygZsAZ6Ec0ZM2M#U{_CG!t+h=&a!tXVH|H$ z)LnOGRh1k&C6UXjKG;|gHdBjf(L8?l(AmEaVxuSJ?fiB-kK=aldbV~G(x!qb&~VX( z^4yt&0suha3J!m`<1HSRlwSP$t#$+KwuuK;#PH<6@%w{lg3gz`pOee=`rLXFQqaPW z-YY0%qbWm$7Q)fYpTJ4Yqa;iuP z6-wS&5sN1D5BF3L>4<6Fv0ByNzuSP3hWtGD@N$*|DQs-5sf;f<68FZjh#e=kT^S)- z6!Tcm+wUC-`TcQ0>E9yCE}wmBe?J5S3o}n{2tpIX*KV8{BismXSgk)a-D-va0001T z%ts{&;SL`k9%`+9>3shPmQvTAuGrOP#2E)t96nqv>BBA${gd|B4mIBe?P=*5McFy1 z?L*{88Wlut1u-i$`nk<&hp)>l3UjOp>l?2QfDTz;UE`qIWobcK*Ox<%Sz}!%2OtNC z;6)#7;G+6aYg?ORzn)n^xwIBT<(6bebDWA1iym@rVgb#rw?7P-U52)3%uaKnre-Zm zL{;6R%0ZW|-Lk^+?mii+&J%9qxp+lnPUf;;r@UlwbclqVcXLNi>j=b+;pZ(4 zZkK{lW zc7<6$l^Lf30S98Wom6s=7v7p*ghZj)98A~*<7`+0)&MdU+f!Bpz5(&Sz!tOZ_><@) zoGnejN}@(EP|Y+7y7zwkCRWg(Lp2H`#MPh>vXWT>%=()jKLtH|CjJn^m{N&qoKRe^ zlYo`V7DZx3{Zf^2R@j^bdMvfQ6T%k6;2jd8GfqoN4MjCgZ(rX}uw^Zpn^Nr28J`>( zjAwy~LJA~aY61^X4gmn5{QjIgQxx~Crggky{oaNYU*Jx4YF6}AVb4Wo zrYHpW#Yt#88PUo4^H5cD=Biw4UxvVwGhJ!xq}ARkLETLqy{O7wRI(7?OcL99TEuU% zFxat{mh;3e@XQ6Ccy#av7HZ;Uh{X*2YHq?xi z^k3)eW&}@SN3gN65wP{^YmKOB4T#>C6B$U*#{HYy(pmMd^g8r-GGE#M`oG02zeFeP z1W`Y@x}y9(>VHQ4^0lsC$FK=rpYHE^O4{ZZOEG(3tUO+KYQ)c`)-wL^51(P606XO$ zTX{sFfX6p?04uJ1&x$xSVH((Tu%TA%w~Y(y`u|j3SBF_D)~ma-H@XdGc=n-!lh)Ui z@US~i)wS)wr7DFVRu@t~di%r56WH4lNXaigDq^~)@y6eyq--j_kb`XnK-s;stl}?S zuFoy+1yTKQx2WvgKjm0DDx>gHQM8+{kBawkLVe>`75P`DOc!ls&PK_$lvMA-rzoaL zRbO*?_r)hlTh79D1vg5QV!eoSPb>Zk-m9;9sd8XqDu)qSoVT_tJ2555^Y?)#Ro9ws ze_Yr3U)@w5WyO}4YhR8J_s*N2Zd@B4eQ@j5qpdA^`%GHm(xm+5@tMM?)CIxe^k*v# znqiwxE-t6e9ZXZ?IH=;-FeY3D!%=JEi>&yQF*r=#Dd-)xwi+4)MlpqF`4p@z# zc@qB+l2bBXIPt6HtETx+#^?VqfKl=I)W!dN);u^ojSiUNwdrN~;!V+XA0BbOv!a5S zwfF8zFSPf!NC!K|@qW4h0F4{IIyr8GXi3q^*m#ETA<>z#+6!UcIo8>cIo8>c{{cV=1r~V0ybb^W002ovPDHLk FV1mpU|JVQk literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/imidface5.png b/src/feedback/public/default_icons/imidface5.png new file mode 100644 index 0000000000000000000000000000000000000000..1a70456cfe3d8d38c09841f312eedb3b6c801699 GIT binary patch literal 2662 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 U5Oe*uod5s;07*qoM6N<$f=xjuTL1t6 literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/inum1.png b/src/feedback/public/default_icons/inum1.png new file mode 100644 index 0000000000000000000000000000000000000000..4ee2a4e30a9c219d70632370fa16ccdef1622c9a GIT binary patch literal 1840 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 Z;D1-t?h)s3h(G`U002ovPDHLkV1jI)dL;k= literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/inum4.png b/src/feedback/public/default_icons/inum4.png new file mode 100644 index 0000000000000000000000000000000000000000..80a0411fd98c33444f03ac6803cfa8dfb3ba1e38 GIT binary patch literal 2070 zcmV+x2p*|>t7xDu81=R#VjYxf^tXl&K!j9LSsCwjU~=6=fRgLAlSZ2EIPVPgLXNkFtz zykM3{z{44QVvq=iz{YR=X@IC1T+o3C&%uVufOxjue=>f$h*jg3DUX`zZMZ~XIo zt)Z*eed~@QkD4J#tYN~Sds>x$%c&Fwz{P4~@|&Hdf- z2#HWIs&!l+L0}cL{_0{daJCe%S57P@HGCetc2gl!rcLK z64F8)y4bM)jEd$Pb?}BI+o!16ar7c>Wov5OyBW(FFgfv+D%F2EQr%Bkk=eX8aerOw z+N^7`EuVh*(HC_{51z(9o|h3R5seXx7LCrByyqxAcz=F%sY^H)WR9aH3!5R|p2^H1 zjUc3jO51y^`u3v{;8;%W3RM%0wQAw)>Ydr+js*ZX8#}c z8u={_=2iA)GP6k}zpGiCS-{OK;AZYgt2dAOJkG`rZ%*T2UI0+n+RU6L|;5Fm@+=$?D;Q|oxeUPFjdRS(Q6*X|KCl1zP zIPlRo_hHhatXFaZoKq>rLNk~xR@RU96Okt&+^VTM`}a10;N_)Bew^{*a$xwe&&--K znTr~9C>>S$JJhd#-Z2P%+uw)@XOABj0BNC+!oj>)e4d@G$2~GDaj5j`>sFAgPTm?a zu3P~6r?y2e<~ki*FEq9SK!vJl&$?fEZquq!R_&h7{7G1G`##uBT_cLxDWs^07zOO<@4|^6ZyEa`_t-rcP_Vv%D|I{ znlox=cSy9h*u9D=?f1)ixOQ4k?Ub3epg$n8Uzg|WM^`9Jbc0vTbNq>7l?tXwDix4IW%PIwY8diTw++UqX8I?MG>Q zk4+pLX`wcJaGE|)ezqyqDW7l-v)Shz53 zd)l29mv^7Migc;S_di?G$MK%_`UBniVmX~ayptU3(!CFRx9tdr?zXq3%EsvDNDH-3 zQS;u3t8`Cs&PvBs?-m&VC~7siCFkgRfONX=j*MmFRS)3v@Xt1-{(KVMA_D-8&Y1Jz znQvQ$)KF5Q=42;Cgo*v#VbbV~6{@Dgmm3}Pzi4S-`Q~)yH54T1?-rc6;#3O@@|(I= zHaB#-pF}7?bteH2M|G!12127Vs$1HBUU!;0nOpGMis5F^Gcua5RH-gJtzulOh4z!tzGVU6AtE;5KU0MBB}{%4TMH#Bzj4r zm+T??eQ*xW!9)TdiBJ$TTO2JFCxlBF*av|B0Xoou15djPIRF3v07*qoM6N<$g2AHu AzyJUM literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/inum5.png b/src/feedback/public/default_icons/inum5.png new file mode 100644 index 0000000000000000000000000000000000000000..edef13bd146d372787ee5da9476efdaadedb1fea GIT binary patch literal 2167 zcmV--2#EKIP)G#^`Hqax5zLvE^U&ZYwoPLa+~BUbcDL-<*@aM(P?p!C=Ho-GR%w@pKmO=(4^5n zA@AK@T$XR{^0=Ioc_h1#6xq@0mK`T+2cHhxSBioImd+K4r*R|sf#F;>n~9<{L}$dX zVf>CttJWDB?sQ-2?77vgv44w>P>VM%+mJkaykts^Ze3Ajv!eGIP)Ia#=@d&Gqgd^+csuz&-PR#^@eKBP*A6Y%aa1H)60Tn9ACdm9$nOCIjRk%#43g z*IM|sjNluy^IVb@NE>#Zsw2F-pO&y|&0-Ij9Qck^xBTg3tqHe4xB06Q{+!|5t#h)i z|M>UeOU=+0Ol6(UUo%@6JWeb^a+Nmq<5NWE{qfC(PT`!8+4q(ta$4o~OwSV1D8kHm z`X^u2w%;EGj^a=*mvsbC<`By9p14(h#Ecviddv|6i-_5+;}qtx9}!ufSpSP;pD z%_K?4Ws3z|0DuX%+_Zc8#a~g0hzw5$H;$qSNgm+#X$l;WLV#S?Plx#^2WM8Wyzsq(zdj3-xY_E z&O)=pgPK#008F9)b6qm6u*0hMTqJbz9;t;7#w%cT{!m0LeeL} zFl@F^hDLToZcpJ}6mJ@p>Y_6k!nwZ)28(I8VEI7F%3W6b+&7?%~17YE&Qcb>9tHsneXdDT7Um~hL{>K6CNfU&Ib)CbK2 zM*Da(57t!tYx%hW005wce)!(Px!$CF6^*R3-#_}_ti_+#w4A@f!?~(I ztX(=sjpS|-2nZqpr007n@P0yv~&P%r*wkUt>>K`@%0DzbO6i)Pv z@Knj1?D^a&V{Dq9>5K1L;XZ)N^1XW~*Vbpi?kqzT9MDpj=S5QFsX1C9@TF=kIzl0DpHd{&(iOWA#*^6DK}EZ(?m=^T;6Z=9dg?k=zY=*(qk zi-H5b+`4)K&uOoAs@4}*5(|j;QWt!@?zIeKeD81<7RvF@kVHjXW~N~?Q<>7HN)%)~_L tC>;rAGlg7s{B(Y-h@T`Ddf*=b@ITtstd!o$k&plY002ovPDHLkV1lA+DDD6N literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/istar1.png b/src/feedback/public/default_icons/istar1.png new file mode 100644 index 0000000000000000000000000000000000000000..d036f9402bcc4a0bd21f3611ee8cb482f2c59062 GIT binary patch literal 1338 zcmV-A1;zS_P)R00009a7bBm000XU z000XU0RWnu7ytkS>`6pHRCt{2n}KnwObmpt1gC`i+Ntg5Op_INzjr_-sqE{dWtzAVd54w1xNE*Cyu!$$F$rfFj+276HuL>wY|?(_5W z&WV3}d#geSyRbo&GMv!yh7(#boPekygiF{MQYK(;IFqnMiRA>F!11O{p&+BlK(d*D z2%41PG-0>7HZ1EUn@alvld=qFQjX=?aAm}{(tcT%KMZH?iQ)RNm2zP3(>I3u3>VAw zVJqdp$*1<%EY{}wz&&jOUv)W9J}T|^fq87rZ5o||Ee|AIpVC!-l8gJtQ!@&fPps{oGz z<6uk(%J_IdjF+){QOzNK2zA78{uuC|)bz@-td8Zj0&B(KZT|o_t7w;^_Q%IZBS=}6 zjp}$z7pJZw+}eR{R!(F?a~ShdiTi=``Fx*Dm5E}wH9|JTt_2&R6jEmsLvxF=Q5WY! zaZONLX6*6?SIcm{s;cgD&)3&i^H~#|IKs_y3dJ>maa+%P^2X<7O1OFMm0{aerKS8o z;qsdpzlGupXRz{-Rr(Q^B(xM#{P<8D;&AC#fyQXXO z8gx5cRUyUl!-pGLFD4Y{1jX=QGuTvIWa%Z(+ z5hI3sCT!Q`p&4un4t_V5P|{8<9u&(x3*X=0i1Zy6Mml8&1P;-j4Y%dAD6+n7>A&vI zJ__&e?+Eq2q)4SI>b7_IY8$ur9HBN>C2lQax~$8cT=RobPf3TgVz`;I8!hNXaP0Gr zALh*Rh>0)UYh-gPSWQcL!Q&-Vt}v+%|pQ>rnFw{P(|nN$1`#9D|+u8+8Fel z7PM_H#sd%sVI_|0F$5d4{##;R%BOe^*D)cZztc82;v$GViEB0$$FyITIC)abJ9ygO zJN&8tA?~-(LICP31k*VIJV~vYE^Y{OpZ!kSM~sJ#AIC0g6oDa;ghTq6$m?c#<)aPGx!Hl-cn zIStxEpz2v$(F6L53A5M`wEp%i&9}=R)fmk#RTT8K0TBZwy3NG_j{Y3?Ct$N%oaTRWtVzAX(C1X*VJK$5SBH-1L}x(1hpi_^}%Gl3>!d#)Oz(nVdRJy7X#A$_V%`k zB7F2R>>a_kFAjsfG7VuX(p}#x(J@#NCTd<5g;yUh!#E0)JZ4R@6nGY%ix1MiE&$j1R=Hr$XRZm&*wIOi4Hu;HO|4Kp2I=U6czUZo2<>qg3+TtHFA%YN~qeP$E)BsiduqzBGd)BwqnM zv$YhLpLFSmF{#w$o)vn|5W?wRhiuL{PI(?WvM8wBN+m*ZD9yw@q4LZ!Oiz7Lrg$k@ z^ldz&V%bh+ZO=a&l2?**Q=ZXs{0Qe%N*9*cEdG>AY8}KW&6b2x+IpkK=ffwhe!HnO zlxA~-d)f(!hbYh8&dF>cjHX?;P?_N*f|2#?6WM_jergzP4lb ze!B0sM^J;wp~ZiO~rwRKE26d|#LLQBAQDj7m8 zj-8JJ7IU!(@!S-sbH7*O*E;E$`zYXA5yE?n8w>4cYk!E;oa!K((k;G)ds6SiH_Kj= zkB}Jm9WY+bkV9~idao(tQ|qi3uQS&%5z^&iz=1dueMU3{jyWEh2ELs;mV3Z9-h;JO>VvVEH##X7S1?&XYeJP|7 z>Xh_a`X4m*J_-nRMF{E>oD3 zH^QHPl3vzOelFyfaMR6oVnC_k#|~YtCvC>!?)0*T^0wGu>S}63q2(b6YaJEw9H})T zZN`G%|2kWv<0u$!!>J)|_J%UGgE-owX-`ktdp^KDYD(Xxm;0B%!u`8oF~BWSfHSw$ j)+wwp+}55U{5t#rI1a!}b-=b~00000NkvXXu0mjfWj;~v literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/istar3.png b/src/feedback/public/default_icons/istar3.png new file mode 100644 index 0000000000000000000000000000000000000000..f7d34afd9fc4fc9bfa43f2854245b7355a53882e GIT binary patch literal 1221 zcmV;$1UmbPP)Q% z_xrsO93_C=ZdYqfiU}bkVTDMsfU2q*Ve>q19>8yY4ea-Oek;NXkxOuZHAryW!>`F= zLI{sFT1AC$5*%0XO1a%`bsJfh)h%jWJaz~rzzQ%0xL&W#_b#BEwFS)^Rv_WT4mx$M zb-`#hTNPyjVu1uFM)K{eF`cSS^R!D9O`!tut)Zbg?hzV%=x3JyDQ5>;|Q*55rw?U0G9>@ z@GeSD@I5qzFQN=IcDY=d?^p&3`KD8U7szC3`%?xglmRNjV^)A5*EcQxRv7bCeFJMD z*N`&g8d8SbW=XJ`S4gEBC&C4fC!ieA23#ip21mus}$=3AkCh7eBg zC}0)JaLn-6O8A7t1o!Z+;oU}SU&sujG=ERB25I{n8O0`LFvB*Ch~k^+)tI3-J${Ou zWJ|80RGiNm@Ty%u7388;TTI&D-1;EONyOY{Z17H-pnuE^A2nxHQKAgBb){AWSDaQowoV$gW zx2M{%iT9YW`xQ{;Y&gf7vc6$E1+3dNTb#Jd0vPXm3m|AtS*jaz%yO3^$zEHwA1GM$=_-oMIM0Vx_eqP-Xir<<4~z?q1RB5=@wNcneTn!KwPSS3p<^F9o0!)h6!UTxUTFx5AJ`YKt3=A>AJO8ZytV%GSW zEk0~rp@lWX3N5*TWr1D3oT>|k0@M;5;x1EPXn)88UZzE<#PJ2yI7o< zqyXE-O6_(T{=^OXVz9ed0d@@&VDB%J`|E<5HurRcz8K^#R)9?sCrVz5nd<6*n1Y~* zs|<95LGu;4gf(M+-@DM&1-CYO0an^YjM7HxI)S{kHdYt8aTj;D;o|=LlV2M>V5Y5k jLFUrh_S%~F5LSs_V#b=2L4@Eq00000NkvXXu0mjf|8OqD literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/istar4.png b/src/feedback/public/default_icons/istar4.png new file mode 100644 index 0000000000000000000000000000000000000000..bd6eea6c222423a3b93acfc5774ccf2ca848f4f3 GIT binary patch literal 1071 zcmV+~1kn45P)j1fz8;G$mLRRSru2m2R^%%&{l~kXWZX}TR0pJ5UCtLTKwAg|K@tk;Ce%M2V0+3t{(Qp{;N$L?cmy@H0`{N@&Y`q9iYm zLfAcc*qTCHVqKHW&S7aPe00v$6d(v07o@+xzlS+cB(U#1+C571g8W^bn{-5E zZ#Sy!#w{vsYCHHBi{nC&L>Oyf^(lgO3wR9aF5kz+cXJ;u+Z0`$nj5y}gK>DcQ6=Yz z9GdeeGGijt&mzNuLSk|(uol+E#Tr>J`GCJs$#2d0s|YF}N@)n#fM*%j+5orow}<=_ zB6*`fpU>B`h2`0RPqOM!Qm3NSXCn#a=*Pnz~3FZxyo{_WR?a7_dnTO@^pQd<&B=%lcEGCdb?mxWtoExo=@!PtDjg zPg8#!ah$pV)@6x0Vmc`=$7=N9LjgHkFyW|!Fq?qaOl@yjWft|EH?lB4L(VrF#AaEu zz|XUJ-SamUAE6oG5);)y-4{(Po-NRuf!(T`dG9QXtJHnw{^o7b9w5m5!USvID@;ai z9dZ_nsqP>10pPuFVU%^;dwby4p$K+=JLgdfmRc4jQyV|57vR>R2y%ZbSS~ICdfiyl z$eC^(iihrR1xp{L@z9u(BXT4zFS_+)_cts5asL>NiOh!Z>R(@+52 literal 0 HcmV?d00001 diff --git a/src/feedback/public/default_icons/istar5.png b/src/feedback/public/default_icons/istar5.png new file mode 100644 index 0000000000000000000000000000000000000000..f52d31405376b85478856eedbe5f33edd30767c7 GIT binary patch literal 846 zcmV-U1F`&xP)cbU-?w1ef3v zD8Z+<8ctl6AKQR2<~}LXYF7&$d;H#b9HRetC*#kp5JaROk4H~L3EhaYC<8|S#I9B}@6j_$(0sKrvIo*J+X_~)*^Qw0gIYJ1bze$or$FA_rc(n(rszTs3 z#cW|psb7KjeIK>86|k^5VzxFVrJM~sR%jZG z`Ca0Otssafod~31tC3hql%G&wC^iO(Ad#XFCy1GeeXY^9?a#CDOgtO!z`O8HR)5W7 zkvz8MYodns7GheY!9&wDoeTs6LG@)LR!1{5H1NR~#}kD~!iOj6vlMuVz(WdbD~JUP zX(Ebllf17l`8L<~*{1P`&e3S9Ck6D3~* z50EYum`_mZa>Xb2_V^m=7^3Knl>2>DjbDYP_%6!r%8%DCwUK;*F>rBGk|$EA=9!BB ze!mCh_TID*XDR-k%DqYP(Hiyzx1r^kK@UJhJ0B~LLkJ&LgXzwcK31Jq+nbP?(C%^m zHe7L>xvz0cvZrT<)RGc5eeFbUgP=a2Prc=~#Q7^8NNaBGZcS^a^ydSM*L_~{KHfX6t0U|ce6o=GZ*&Fz Y04R1g5S`?X{Qv*}07*qoM6N<$f?_y^@Bjb+ literal 0 HcmV?d00001 diff --git a/src/feedback/settings/__init__.py b/src/feedback/settings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/feedback/settings/common.py b/src/feedback/settings/common.py new file mode 100644 index 0000000..a62debf --- /dev/null +++ b/src/feedback/settings/common.py @@ -0,0 +1,20 @@ +""" +Common Django settings for eox_hooks project. +For more information on this file, see +https://docs.djangoproject.com/en/2.22/topics/settings/ +For the full list of settings and their values, see +https://docs.djangoproject.com/en/2.22/ref/settings/ +""" +from feedback import ROOT_DIRECTORY + +INSTALLED_APPS = [ + "feedback", +] + + +def plugin_settings(settings): + """ + Set of plugin settings used by the Open Edx platform. + More info: https://github.com/openedx/edx-platform/blob/master/openedx/core/djangoapps/plugins/README.rst + """ + settings.MAKO_TEMPLATE_DIRS_BASE.append(ROOT_DIRECTORY / "templates") diff --git a/src/feedback/settings/production.py b/src/feedback/settings/production.py new file mode 100644 index 0000000..b0fccf0 --- /dev/null +++ b/src/feedback/settings/production.py @@ -0,0 +1,14 @@ +""" +Common Django settings for eox_hooks project. +For more information on this file, see +https://docs.djangoproject.com/en/2.22/topics/settings/ +For the full list of settings and their values, see +https://docs.djangoproject.com/en/2.22/ref/settings/ +""" + + +def plugin_settings(settings): # pylint: disable=unused-argument + """ + Set of plugin settings used by the Open Edx platform. + More info: https://github.com/openedx/edx-platform/blob/master/openedx/core/djangoapps/plugins/README.rst + """ diff --git a/src/feedback/settings/test.py b/src/feedback/settings/test.py new file mode 100644 index 0000000..1277001 --- /dev/null +++ b/src/feedback/settings/test.py @@ -0,0 +1,24 @@ +""" +Common Test settings for eox_hooks project. +For more information on this file, see +https://docs.djangoproject.com/en/2.22/topics/settings/ +For the full list of settings and their values, see +https://docs.djangoproject.com/en/2.22/ref/settings/ +""" +from workbench.settings import * # pylint: disable=wildcard-import + +from django.conf.global_settings import LOGGING + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'feedback', + 'workbench', +] + +FEATURES = { + "ENABLE_FEEDBACK_INSTRUCTOR_VIEW": True, +} + +SECRET_KEY = 'fake-key' diff --git a/src/feedback/static/.DS_Store b/src/feedback/static/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..6b971a75f2ba8b3d21d9bf45cb46ab414b88df12 GIT binary patch literal 6148 zcmeHK%}N6?5T0p!SQMmq@|Z`kFHmAxpP(0y(iRlyvV|gE^J3!Bm+-1bpTTc3({{H8 zk0LSy$(PLU?gyLf5E0KFR}-Q!5mgw1EQ^AOx@a1hvlv-&Oy8Se2J~=T?d)l%@7DT!-`C19 zO?#+xZ0py#lsYcXfHU9>I0Mc=i2>Z%BGsv)&(44|;0){;knGO>$lgFyEb6lVu*-ek_80o-cJBF ha*kYNquPV4;TH{)qGS<$4hQ;=KqkZ|XW$nY_yWW4Lu>#5 literal 0 HcmV?d00001 diff --git a/src/feedback/static/README.txt b/src/feedback/static/README.txt new file mode 100644 index 0000000..0472ef6 --- /dev/null +++ b/src/feedback/static/README.txt @@ -0,0 +1,19 @@ +This static directory is for files that should be included in your kit as plain +static files. + +You can ask the runtime for a URL that will retrieve these files with: + + url = self.runtime.local_resource_url(self, "static/js/lib.js") + +The default implementation is very strict though, and will not serve files from +the static directory. It will serve files from a directory named "public". +Create a directory alongside this one named "public", and put files there. +Then you can get a url with code like this: + + url = self.runtime.local_resource_url(self, "public/js/lib.js") + +The sample code includes a function you can use to read the content of files +in the static directory, like this: + + frag.add_javascript(self.resource_string("static/js/my_block.js")) + diff --git a/src/feedback/static/css/feedback.css b/src/feedback/static/css/feedback.css new file mode 100644 index 0000000..9c5981a --- /dev/null +++ b/src/feedback/static/css/feedback.css @@ -0,0 +1,123 @@ +/* CSS for FeedbackXBlock */ + +/* Overall block. We limit width, and put a very faint + border around it. */ +.feedback_block { + display: inline-block; + border: 1px solid rgba(0, 0, 0, .1); + padding: 10px; + max-width: 100%; +} + +/* Little thank you message div after people vote */ +.feedback_thank_you { + color: green; +} + +/* Label for the freeform text input. We want a little + space between this and the Likert input.*/ +.feedback_block .feedback_header_div { + margin-top: 1em; +} + +/* Fieldset for the Likert radio buttons */ +.feedback_block .feedback_likert_field { + padding: 0; + margin: 0; +} + +/* The div around everything with a radio button */ +.feedback_block .feedback_likert_rating { + cursor: pointer; + border-radius: 5px; + display: inline-block; + text-align: center; + padding: 0 10px; +} + +/* Hide checked icon */ +.feedback_icon_active { + display: none; +} + +.feedback_icon_inactive { + display: inline-block; +} + +/* But show it if we are checked... */ +.feedback_block input[type="radio"]:checked ~ .feedback_icon_active { + display: inline-block; +} + +/* ... while hiding the unchecked icon */ +.feedback_block input[type="radio"]:checked ~ .feedback_icon_inactive { + display: none; +} + +.feedback_icon { + border: 1px solid rgba(255, 255, 255, 0); + padding: 1px; + height: 60px; + width: 60px; +} + +.feedback_block input[type="radio"]:focus ~ .feedback_icon, +.feedback_block input[type="radio"]:hover ~ .feedback_icon { + border-color: #999; +} + +.feedback_block .feedback_likert_label { + cursor: pointer; +} + +.feedback_block .feedback_freeform_input { + margin-bottom: 1em; +} + +.feedback_block .feedback_freeform_area { + height: inherit; + width: 100%; +} + +.feedback_block .feedback_rating_active { + color: blue; + font-weight: bold; + background-color: blanchedalmond; +} + +.feedback_block .feedback_radio { + opacity: 0; + width: 1px; + padding: 0; + margin: 0; + position: absolute; +} + +.feedback_block .feedback_sr_text { + opacity: 0; + width: 1px; + height: 1px; + padding: 0; + margin: 0; + position: absolute; + clip: rect(1px, 1px, 1px, 1px); + left: -10000px; + overflow: hidden; +} + +.feedback_block label { + display: inline; +} + +.feedback_block .feedback_likert_field { + border-style: none; +} + +.feedback_block .feedback_submit_feedback { + width: 100%; +} + +.feedback_likert_scale { + display: flex; + flex-flow: row wrap; +} diff --git a/src/feedback/static/css/feedback_instructor.css b/src/feedback/static/css/feedback_instructor.css new file mode 100644 index 0000000..881dc04 --- /dev/null +++ b/src/feedback/static/css/feedback_instructor.css @@ -0,0 +1,9 @@ +.feedback-instructor-wrapper { + width: 100%; + display: flex; + flex-direction: column; +} + +.go-back { + margin: 16px 0px 16px 0px; +} diff --git a/src/feedback/static/html/feedback_instructor.html b/src/feedback/static/html/feedback_instructor.html new file mode 100644 index 0000000..1668e55 --- /dev/null +++ b/src/feedback/static/html/feedback_instructor.html @@ -0,0 +1,52 @@ +{% load i18n %} + +

+
+
+ + + + + + + + + + + {% for block in blocks %} + + + + + + + {% endfor %} + +
+ {% trans "Component" %} + + {% trans "Number of ratings" %} + + {% trans "Average rating" %} + + {% trans "Feedback " %} +
+ + +
    + {% for vote_aggregate in block.vote_aggregate %} +
  • {{ vote_aggregate.scale_text }}: {{ vote_aggregate.count }}
  • + {% endfor %} +
+
{{ block.average_rating }} +
    + {% for feedback in block.answers %} +
  • {% trans "Comment" %}: {{ feedback.user_freeform }}. {% trans "Vote" %}: {% if feedback.user_vote != -1 %} {{ feedback.user_vote }} {% else %} {% trans "No vote" %} {% endif %}
  • + {% endfor %} +
+
+
+
+ + + diff --git a/src/feedback/static/js/src/feedback.js b/src/feedback/static/js/src/feedback.js new file mode 100644 index 0000000..5353d5b --- /dev/null +++ b/src/feedback/static/js/src/feedback.js @@ -0,0 +1,65 @@ +/* Javascript for FeedbackXBlock. */ +// Work-around so we can log in edx-platform, but not fail in Workbench +if (typeof Logger === 'undefined') { + var Logger = { + log: function (a) { + console.log(JSON.stringify(a) + '/' + JSON.stringify(a)); + } + }; +} + +function FeedbackXBlock(runtime, element) { + function getLikedVote() { + if ($('.feedback_radio:checked', element).length === 0) { + return -1; + } + + return parseInt($('.feedback_radio:checked', element).attr('data-id').split('_')[1]); + } + + function getFeedbackMessage() { + return $('.feedback_freeform_area', element).val(); + } + + function updateVoteCount(data) { + if (data.success && data.aggregate && $('.feedback_vote_count', element).length) { + $('.feedback_vote_count', element).each(function (idx) { + $(this).text('(' + data.aggregate[idx] + ')'); + }); + } + } + + function submit_feedback(freeform, vote) { + var feedback = {}; + if (freeform) { + feedback['freeform'] = freeform; + } + if (vote !== -1) { + feedback['vote'] = vote; + } + + Logger.log('edx.feedbackxblock.submitted', feedback); + $.ajax({ + type: 'POST', + url: runtime.handlerUrl(element, 'feedback'), + data: JSON.stringify(feedback), + success: function (data) { + $('.feedback_thank_you', element).text(data.response || ''); + updateVoteCount(data); + } + }); + } + + $('.feedback_submit_feedback', element).click(function () { + submit_feedback(getFeedbackMessage(), -1); + }); + + $('.feedback_radio', element).change(function () { + Logger.log('edx.feedbackxblock.likert_changed', { vote: getLikedVote() }); + submit_feedback(false, getLikedVote()); + }); + + $('.feedback_freeform_area', element).change(function () { + Logger.log('edx.feedbackxblock.freeform_changed', { freeform: getFeedbackMessage() }); + }); +} diff --git a/src/feedback/static/js/src/feedback_instructor.js b/src/feedback/static/js/src/feedback_instructor.js new file mode 100644 index 0000000..7107cb9 --- /dev/null +++ b/src/feedback/static/js/src/feedback_instructor.js @@ -0,0 +1,10 @@ +$(function () { + + const cssUrl = "https://cdn.jsdelivr.net/npm/@edx/paragon@20.45.5/dist/paragon.min.css"; + + $('').attr({ + href: cssUrl, + rel: "stylesheet" + }).appendTo('head'); + +}); diff --git a/src/feedback/static/js/src/studio.js b/src/feedback/static/js/src/studio.js new file mode 100644 index 0000000..56a8f6e --- /dev/null +++ b/src/feedback/static/js/src/studio.js @@ -0,0 +1,35 @@ +function FeedbackBlock(runtime, element, data) { + // When the user asks to save, read the form data and send it via AJAX + $(element).find('.save-button').bind('click', function() { + var handlerUrl = runtime.handlerUrl(element, 'studio_submit'); + + var form_data = { + likert: $(element).find('input[name=likert]').val(), + likert0: $(element).find('input[name=likert0]').val(), + likert1: $(element).find('input[name=likert1]').val(), + likert2: $(element).find('input[name=likert2]').val(), + likert3: $(element).find('input[name=likert3]').val(), + likert4: $(element).find('input[name=likert4]').val(), + freeform: $(element).find('input[name=freeform]').val(), + placeholder: $(element).find('input[name=placeholder]').val(), + display_name: $(element).find('input[name=display_name]').val(), + voting_message: $(element).find('input[name=voting_message]').val(), + feedback_message: $(element).find('input[name=feedback_message]').val(), + show_aggregate_to_students: $(element).find('select[name=show_aggregate_to_students]').val() === 'True', + icon_set: $(element).find('select[name=icon_set]').val() + }; + runtime.notify('save', {state: 'start'}); + $.post(handlerUrl, JSON.stringify(form_data)).done(function(response) { + runtime.notify('save', {state: 'end'}); + }); + }); + + // When the user hits cancel, use Studio's proprietary notify() + // extension + $(element).find('.cancel-button').bind('click', function() { + runtime.notify('cancel', {}); + }); + + // Select the right icon set in the dropdown + $(element).find('select[name=icon_set]').val(data['icon_set']); +} diff --git a/src/feedback/templates/.DS_Store b/src/feedback/templates/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..325cebda8e39709cbd4e65fb74cdde3eddc7b95e GIT binary patch literal 6148 zcmeHKK~BRk5FD3C1aaws14oM=^aEh3@Pa-7nnof>4XJ?K^C6yqIP#M|0&!s0HYHI2 z0S7>6S6Yuf_Qv+4&DsFWv?(UQ7(hxF9PO}p!=zt)V57)Lr;%qY&nL4*U9AQqmH4X) z$h%8W;szC#{r7ip+wH6BEX$X5PA*+P9^S3*ACCL|#fSZ?visX`48u$D>Ue^8TxvTnhU*C!E?_2(7YN~)LpbGrD0?gTB z>25$RRRL8%71$^s-v>(Y9iGY-)TL39z@fMjSUgc3ujiB}90 z!pYk>&P8kkhHw}^GoKS@Ht~jH;t9)GKODvd)KV2t1^NnXh2~iD|H=FJ|9+6RQ~_1s zUnyXcY?e*ArI=d>o0D8?>1T8?8P^8fgs|dMF~>?O-luybZ>2(X5!--dXnGLvGH9U+ H{HOxYKf7cw literal 0 HcmV?d00001 diff --git a/src/feedback/templates/html/feedback.html b/src/feedback/templates/html/feedback.html new file mode 100644 index 0000000..8a3c1fa --- /dev/null +++ b/src/feedback/templates/html/feedback.html @@ -0,0 +1,19 @@ +{% load i18n %} + + diff --git a/src/feedback/templates/html/scale_item.html b/src/feedback/templates/html/scale_item.html new file mode 100644 index 0000000..aafd399 --- /dev/null +++ b/src/feedback/templates/html/scale_item.html @@ -0,0 +1,19 @@ +{% load i18n %} + + diff --git a/src/feedback/templates/html/studio_view.html b/src/feedback/templates/html/studio_view.html new file mode 100644 index 0000000..6249731 --- /dev/null +++ b/src/feedback/templates/html/studio_view.html @@ -0,0 +1,130 @@ +{% load i18n %} + +
+
    +
  • {% trans "This XBlock allows you to collect student feedback on pieces of the course. This may be helpful either for course improvement, or to give students a chance to reflect on what they have done." %}
  • + +
  • +
    + + +
    + {% trans "The name of the component." %} +
  • + +
  • +
    + + +
    + {% trans "The message to show after user vote." %} +
  • + +
  • +
    + + +
    + {% trans "The message to show after user feedback." %} +
  • + +
  • +
    + + +
    + {% trans "Whether to show the aggregate report to students." %} +
  • + +
  • +
    + + +
    + {% trans "Example: Please provide us feedback on this section."%} +
  • + +
  • +
    + + +
    + {% trans "This is shown as grayed out text before the student has answered." %} +
  • + +
  • +
    + + +
    + {% trans "We can either show happy/sad faces, numbers 1-5 or stars." %} +
  • + +
  • +
    + + +
    + {% trans "Example: Please rate your overall experience with this section." %} +
  • + +
  • +
    + + +
    + {% trans "Example: Excellent!" %} +
  • + +
  • +
    + + +
    + {% trans "Example: Good" %} +
  • + +
  • +
    + + +
    + {% trans "Example: Average" %} +
  • + +
  • +
    + + +
    + {% trans "Example: Fair" %} +
  • + +
  • +
    + + +
    + {% trans "Example: Poor" %} +
  • +
+ + +
diff --git a/src/feedback/templates/instructor_dashboard/feedback_instructor.html b/src/feedback/templates/instructor_dashboard/feedback_instructor.html new file mode 100644 index 0000000..c060c55 --- /dev/null +++ b/src/feedback/templates/instructor_dashboard/feedback_instructor.html @@ -0,0 +1,8 @@ +<%page args="section_data" expression_filter="h"/> +<%! from openedx.core.djangolib.markup import HTML %> + +<%include file="/courseware/xqa_interface.html/"/> + + diff --git a/src/feedback/translations b/src/feedback/translations new file mode 120000 index 0000000..618b7e2 --- /dev/null +++ b/src/feedback/translations @@ -0,0 +1 @@ +conf/locale \ No newline at end of file diff --git a/src/feedback/utils.py b/src/feedback/utils.py new file mode 100644 index 0000000..6b01fe2 --- /dev/null +++ b/src/feedback/utils.py @@ -0,0 +1,6 @@ +"""Utilities for feedback app""" + + +def _(text): + """Dummy `gettext` replacement to make string extraction tools scrape strings marked for translation""" + return text From b42f4b10ba0d1cecb0c3f9a17b06f1150a3587e0 Mon Sep 17 00:00:00 2001 From: salman2013 Date: Mon, 6 Apr 2026 11:17:52 +0500 Subject: [PATCH 2/5] fix: run make format and fix lint issues --- src/feedback/extensions/filters.py | 4 ++-- src/feedback/feedback.py | 9 ++++----- src/feedback/feedbacktests/conftest.py | 4 ++-- src/feedback/feedbacktests/test_feedback.py | 6 +++--- src/feedback/feedbacktests/test_feedback_unit.py | 2 +- src/feedback/feedbacktests/test_filters.py | 3 ++- src/feedback/settings/test.py | 2 -- 7 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/feedback/extensions/filters.py b/src/feedback/extensions/filters.py index 2813907..2fdbcc2 100644 --- a/src/feedback/extensions/filters.py +++ b/src/feedback/extensions/filters.py @@ -2,6 +2,7 @@ Open edX Filters needed for instructor dashboard integration. """ import importlib.resources + from crum import get_current_request from django.conf import settings from django.template import Context, Template @@ -10,8 +11,7 @@ try: from cms.djangoapps.contentstore.utils import get_lms_link_for_item - from lms.djangoapps.courseware.block_render import (get_block_by_usage_id, - load_single_xblock) + from lms.djangoapps.courseware.block_render import get_block_by_usage_id, load_single_xblock from openedx.core.djangoapps.enrollments.data import get_user_enrollments from xmodule.modulestore.django import modulestore except ImportError: diff --git a/src/feedback/feedback.py b/src/feedback/feedback.py index d2f37ca..e651ba7 100644 --- a/src/feedback/feedback.py +++ b/src/feedback/feedback.py @@ -1,5 +1,4 @@ # pylint: disable=E1101 -# coding: utf-8 """ This is an XBlock designed to allow people to provide feedback on our course resources, and to think and synthesize about their experience @@ -7,13 +6,13 @@ """ import html +import importlib.resources import random -import importlib.resources import six from web_fragments.fragment import Fragment from xblock.core import XBlock -from xblock.fields import Scope, Integer, String, List, Float, Boolean +from xblock.fields import Boolean, Float, Integer, List, Scope, String from feedback.utils import _ @@ -298,7 +297,7 @@ def studio_view(self, context): # pylint: disable=unused-argument """ prompt = self.get_prompt(0) for idx in range(len(prompt['scale_text'])): - prompt['likert{i}'.format(i=idx)] = prompt['scale_text'][idx] + prompt[f'likert{idx}'] = prompt['scale_text'][idx] frag = Fragment() prompt.update({ @@ -329,7 +328,7 @@ def studio_submit(self, if item_submission and len(item_submission) > 0: self.prompts[0][item] = html.escape(item_submission) for i in range(5): - likert = data.get('likert{i}'.format(i=i), None) + likert = data.get(f'likert{i}', None) if likert and len(likert) > 0: self.prompts[0]['scale_text'][i] = html.escape(likert) diff --git a/src/feedback/feedbacktests/conftest.py b/src/feedback/feedbacktests/conftest.py index 1328b5f..fb9ff28 100644 --- a/src/feedback/feedbacktests/conftest.py +++ b/src/feedback/feedbacktests/conftest.py @@ -1,6 +1,6 @@ -import pytest -from mock import Mock +from unittest.mock import Mock +import pytest from workbench.runtime import WorkbenchRuntime from xblock.fields import ScopeIds from xblock.runtime import DictKeyValueStore, KvsFieldData diff --git a/src/feedback/feedbacktests/test_feedback.py b/src/feedback/feedbacktests/test_feedback.py index ee1be3f..e683a62 100644 --- a/src/feedback/feedbacktests/test_feedback.py +++ b/src/feedback/feedbacktests/test_feedback.py @@ -3,16 +3,16 @@ ''' -import mock +from unittest import mock -class PatchRandomMixin(object): +class PatchRandomMixin: """ This is a class which will patch random.uniform so that we can confirm whether randomization works. """ def setUp(self): - super(PatchRandomMixin, self).setUp() + super().setUp() self.random_patch_value = None def patched_uniform(min, max): diff --git a/src/feedback/feedbacktests/test_feedback_unit.py b/src/feedback/feedbacktests/test_feedback_unit.py index d1705af..5d43c23 100644 --- a/src/feedback/feedbacktests/test_feedback_unit.py +++ b/src/feedback/feedbacktests/test_feedback_unit.py @@ -2,7 +2,7 @@ Tests for the Feedback XBlock with heavy mocking. """ -from mock import Mock +from unittest.mock import Mock def test_template_content(feedback_xblock): diff --git a/src/feedback/feedbacktests/test_filters.py b/src/feedback/feedbacktests/test_filters.py index f53805f..344970c 100644 --- a/src/feedback/feedbacktests/test_filters.py +++ b/src/feedback/feedbacktests/test_filters.py @@ -4,11 +4,12 @@ from unittest import TestCase from unittest.mock import Mock, patch -from django.test.utils import override_settings +from django.test.utils import override_settings from feedback.extensions.filters import AddFeedbackTab, load_xblock_answers + class TestFilters(TestCase): """ Test suite for the FeedbackXBlock filters. diff --git a/src/feedback/settings/test.py b/src/feedback/settings/test.py index 1277001..2521d2f 100644 --- a/src/feedback/settings/test.py +++ b/src/feedback/settings/test.py @@ -7,8 +7,6 @@ """ from workbench.settings import * # pylint: disable=wildcard-import -from django.conf.global_settings import LOGGING - INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', From 7c97a5ef53b68d32c639fa651612a98b8c7dd7c0 Mon Sep 17 00:00:00 2001 From: salman2013 Date: Mon, 6 Apr 2026 11:57:04 +0500 Subject: [PATCH 3/5] fix: manual lit issues --- src/feedback/__init__.py | 1 + src/feedback/extensions/filters.py | 21 +- src/feedback/feedback.py | 299 ++++++++---------- src/feedback/feedbacktests/__init__.py | 1 + src/feedback/feedbacktests/conftest.py | 6 +- src/feedback/feedbacktests/test_feedback.py | 72 ++--- .../feedbacktests/test_feedback_unit.py | 32 +- src/feedback/feedbacktests/test_filters.py | 16 +- src/feedback/settings/common.py | 1 + src/feedback/settings/test.py | 15 +- 10 files changed, 211 insertions(+), 253 deletions(-) diff --git a/src/feedback/__init__.py b/src/feedback/__init__.py index 3c7f611..0a2388e 100644 --- a/src/feedback/__init__.py +++ b/src/feedback/__init__.py @@ -3,6 +3,7 @@ course resources, and to think and synthesize about their experience in the course. """ + import os from pathlib import Path diff --git a/src/feedback/extensions/filters.py b/src/feedback/extensions/filters.py index 2fdbcc2..b015e87 100644 --- a/src/feedback/extensions/filters.py +++ b/src/feedback/extensions/filters.py @@ -1,6 +1,7 @@ """ Open edX Filters needed for instructor dashboard integration. """ + import importlib.resources from crum import get_current_request @@ -29,9 +30,7 @@ class AddFeedbackTab(PipelineStep): """Add forum_notifier tab to instructor dashboard by adding a new context with feedback data.""" - def run_filter( - self, context, template_name - ): # pylint: disable=unused-argument, arguments-differ + def run_filter(self, context, template_name): # pylint: disable=unused-argument, arguments-differ """Execute filter that modifies the instructor dashboard context. Args: context (dict): the context for the instructor dashboard. @@ -43,9 +42,7 @@ def run_filter( } course = context["course"] - template = Template( - self.resource_string(f"static/html/{TEMPLATE_CATEGORY}.html") - ) + template = Template(self.resource_string(f"static/html/{TEMPLATE_CATEGORY}.html")) request = get_current_request() @@ -58,9 +55,7 @@ def run_filter( html = template.render(Context(context)) frag = Fragment(html) frag.add_css(self.resource_string(f"static/css/{TEMPLATE_CATEGORY}.css")) - frag.add_javascript( - self.resource_string(f"static/js/src/{TEMPLATE_CATEGORY}.js") - ) + frag.add_javascript(self.resource_string(f"static/js/src/{TEMPLATE_CATEGORY}.js")) section_data = { "fragment": frag, @@ -88,9 +83,7 @@ def load_blocks(request, course): """ course_id = str(course.id) - feedback_blocks = modulestore().get_items( - course.id, qualifiers={"category": BLOCK_CATEGORY} - ) + feedback_blocks = modulestore().get_items(course.id, qualifiers={"category": BLOCK_CATEGORY}) blocks = [] @@ -172,9 +165,7 @@ def load_xblock_answers(request, students, course_id, block_id, course): """ answers = [] for user_id, username in students: - student_xblock_instance = load_single_xblock( - request, user_id, course_id, block_id, course - ) + student_xblock_instance = load_single_xblock(request, user_id, course_id, block_id, course) if student_xblock_instance: prompt = student_xblock_instance.get_prompt() if student_xblock_instance.user_freeform: diff --git a/src/feedback/feedback.py b/src/feedback/feedback.py index e651ba7..360def8 100644 --- a/src/feedback/feedback.py +++ b/src/feedback/feedback.py @@ -29,8 +29,7 @@ DEFAULT_FREEFORM = _("What did you learn from this? What was missing?") DEFAULT_LIKERT = _("How would you rate this as a learning experience?") DEFAULT_DEFAULT = _( - "Think about the material, and try to synthesize key " - "lessons learned, as well as key gaps in our presentation." + "Think about the material, and try to synthesize key lessons learned, as well as key gaps in our presentation." ) DEFAULT_PLACEHOLDER = _( "Take a little bit of time to reflect here. " @@ -50,7 +49,7 @@ } -@XBlock.needs('i18n') +@XBlock.needs("i18n") class FeedbackXBlock(XBlock): """ This is an XBlock -- eventually, hopefully an aside -- which @@ -58,6 +57,7 @@ class FeedbackXBlock(XBlock): long time, but Dartmouth finally encourage me to start to build this. """ + # This is a list of prompts. If we have multiple elements in the # list, one will be chosen at random. This is currently not # exposed in the UX. If the prompt is missing any portions, we @@ -75,60 +75,34 @@ class FeedbackXBlock(XBlock): ], scope=Scope.settings, help=_("Freeform user prompt"), - xml_node=True + xml_node=True, ) prompt_choice = Integer( - default=-1, scope=Scope.user_state, - help=_("Random number generated for p. -1 if uninitialized") + default=-1, scope=Scope.user_state, help=_("Random number generated for p. -1 if uninitialized") ) - user_vote = Integer( - default=-1, scope=Scope.user_state, - help=_("How user voted. -1 if didn't vote") - ) + user_vote = Integer(default=-1, scope=Scope.user_state, help=_("How user voted. -1 if didn't vote")) # pylint: disable=invalid-name - p = Float( - default=100, scope=Scope.settings, - help=_("What percent of the time should this show?") - ) + p = Float(default=100, scope=Scope.settings, help=_("What percent of the time should this show?")) - p_user = Float( - default=-1, scope=Scope.user_state, - help=_("Random number generated for p. -1 if uninitialized") - ) + p_user = Float(default=-1, scope=Scope.user_state, help=_("Random number generated for p. -1 if uninitialized")) - vote_aggregate = List( - default=None, scope=Scope.user_state_summary, - help=_("A list of user votes") - ) + vote_aggregate = List(default=None, scope=Scope.user_state_summary, help=_("A list of user votes")) - user_freeform = String(default="", scope=Scope.user_state, - help=_("Feedback")) + user_freeform = String(default="", scope=Scope.user_state, help=_("Feedback")) - display_name = String( - display_name=_("Display Name"), - default=_("Provide Feedback"), - scopde=Scope.settings - ) + display_name = String(display_name=_("Display Name"), default=_("Provide Feedback"), scopde=Scope.settings) - voting_message = String( - display_name=_("Voting message"), - default=_("Thank you for voting!"), - scope=Scope.settings - ) + voting_message = String(display_name=_("Voting message"), default=_("Thank you for voting!"), scope=Scope.settings) feedback_message = String( - display_name=_("Feedback message"), - default=_("Thank you for your feedback!"), - scope=Scope.settings + display_name=_("Feedback message"), default=_("Thank you for your feedback!"), scope=Scope.settings ) show_aggregate_to_students = Boolean( - display_name=_("Show aggregate to students"), - default=False, - scope=Scope.settings + display_name=_("Show aggregate to students"), default=False, scope=Scope.settings ) @classmethod @@ -145,7 +119,7 @@ def get_prompt(self, index=-1): if index == -1: index = self.prompt_choice - _ = self.runtime.service(self, 'i18n').ugettext + _ = self.runtime.service(self, "i18n").ugettext # This is the default prompt if something is not specified in the # settings dictionary. Note that this is not the same as the default # above. The default above is the prompt the instructor starts from @@ -155,18 +129,12 @@ def get_prompt(self, index=-1): # intended as a well-structured, coherent response. This is designed # as generic, to work with any content as a safe fallback. prompt = { - 'freeform': _("Please reflect on this course material"), - 'default_text': _("Please take time to meaningfully reflect " - "on your experience with this course " - "material."), - 'likert': _("Please rate your overall experience"), - 'scale_text': [_("Excellent"), - _("Good"), - _("Average"), - _("Fair"), - _("Poor")], - 'icon_set': 'num', - 'placeholder': _("Please take a moment to thoughtfully reflect.") + "freeform": _("Please reflect on this course material"), + "default_text": _("Please take time to meaningfully reflect on your experience with this course material."), + "likert": _("Please rate your overall experience"), + "scale_text": [_("Excellent"), _("Good"), _("Average"), _("Fair"), _("Poor")], + "icon_set": "num", + "placeholder": _("Please take a moment to thoughtfully reflect."), } prompt.update(self.prompts[index]) @@ -193,8 +161,7 @@ def student_view(self, context=None): # pylint: disable=unused-argument indexes = range(5) # If the user voted before, we'd like to show that - active_vote = ["checked" if i == self.user_vote else "" - for i in indexes] + active_vote = ["checked" if i == self.user_vote else "" for i in indexes] # Confirm that we do have vote totals (this may be uninitialized # otherwise). This should probably go into __init__ or similar. @@ -204,7 +171,7 @@ def student_view(self, context=None): # pylint: disable=unused-argument # We grab the icons. This should move to a Filesystem field so # instructors can upload new ones def get_url(icon_type, i): - ''' + """ Helper function to generate the URL for the icons shown in the tool. Takes the type of icon (active, inactive, etc.) and the number of the icon. @@ -212,50 +179,55 @@ def get_url(icon_type, i): Note that some icon types may not be actively used in the styling. For example, at the time of this writing, we do selected through CSS, rather than by using those icons. - ''' + """ templates = { - 'inactive': 'public/default_icons/i{set}{i}.png', - 'active': 'public/default_icons/a{set}{i}.png', + "inactive": "public/default_icons/i{set}{i}.png", + "active": "public/default_icons/a{set}{i}.png", } template = templates[icon_type] - icon_file = template.format(i=i, set=prompt['icon_set']) + icon_file = template.format(i=i, set=prompt["icon_set"]) return self.runtime.local_resource_url(self, icon_file) - ina_urls = [get_url('inactive', i) for i in range(1, 6)] - act_urls = [get_url('active', i) for i in range(1, 6)] + + ina_urls = [get_url("inactive", i) for i in range(1, 6)] + act_urls = [get_url("active", i) for i in range(1, 6)] # Prepare the Likert scale fragment to be embedded into the feedback form scale = "".join( resource_loader.render_django_template( item_templates_file, { - 'scale_text': scale_text, - 'unicode_icon': unicode_icon, - 'idx': idx, - 'active': active, - 'vote_cnt': vote_cnt, - 'ina_icon': ina_icon, - 'act_icon': act_icon, - 'is_display_vote_cnt': self.vote_aggregate and (self.show_aggregate_to_students or self.is_staff()), + "scale_text": scale_text, + "unicode_icon": unicode_icon, + "idx": idx, + "active": active, + "vote_cnt": vote_cnt, + "ina_icon": ina_icon, + "act_icon": act_icon, + "is_display_vote_cnt": self.vote_aggregate and (self.show_aggregate_to_students or self.is_staff()), }, - i18n_service=self.runtime.service(self, 'i18n'), - ) for - (scale_text, - unicode_icon, - idx, - active, - vote_cnt, - act_icon, - ina_icon,) in - zip(prompt['scale_text'], - ICON_SETS[(prompt['icon_set'])], + i18n_service=self.runtime.service(self, "i18n"), + ) + for ( + scale_text, + unicode_icon, + idx, + active, + vote_cnt, + act_icon, + ina_icon, + ) in zip( + prompt["scale_text"], + ICON_SETS[(prompt["icon_set"])], indexes, active_vote, votes, act_urls, - ina_urls) + ina_urls, + strict=False, + ) ) if self.user_vote != -1: - _ = self.runtime.service(self, 'i18n').ugettext + _ = self.runtime.service(self, "i18n").ugettext response = self.voting_message else: response = "" @@ -269,26 +241,28 @@ def get_url(icon_type, i): self.p_user = random.uniform(0, 100) if self.p_user < self.p: frag = Fragment() - frag.add_content(resource_loader.render_django_template( - 'templates/html/feedback.html', - context={ - 'self': self, - 'scale': scale, - 'freeform_prompt': prompt['freeform'], - 'likert_prompt': prompt['likert'], - 'response': response, - 'placeholder': prompt['placeholder'] - }, - i18n_service=self.runtime.service(self, 'i18n') - )) + frag.add_content( + resource_loader.render_django_template( + "templates/html/feedback.html", + context={ + "self": self, + "scale": scale, + "freeform_prompt": prompt["freeform"], + "likert_prompt": prompt["likert"], + "response": response, + "placeholder": prompt["placeholder"], + }, + i18n_service=self.runtime.service(self, "i18n"), + ) + ) else: - frag = Fragment('') + frag = Fragment("") # Finally, we do the standard JS+CSS boilerplate. Honestly, XBlocks # ought to have a sane default here. frag.add_css(self.resource_string("static/css/feedback.css")) frag.add_javascript(self.resource_string("static/js/src/feedback.js")) - frag.initialize_js('FeedbackXBlock') + frag.initialize_js("FeedbackXBlock") return frag def studio_view(self, context): # pylint: disable=unused-argument @@ -296,59 +270,59 @@ def studio_view(self, context): # pylint: disable=unused-argument Create a fragment used to display the edit view in the Studio. """ prompt = self.get_prompt(0) - for idx in range(len(prompt['scale_text'])): - prompt[f'likert{idx}'] = prompt['scale_text'][idx] + for idx in range(len(prompt["scale_text"])): + prompt[f"likert{idx}"] = prompt["scale_text"][idx] frag = Fragment() - prompt.update({ - "display_name": self.display_name, - "voting_message": self.voting_message, - "feedback_message": self.feedback_message, - "show_aggregate_to_students": self.show_aggregate_to_students, - }) - frag.add_content(resource_loader.render_django_template( - 'templates/html/studio_view.html', - prompt, - i18n_service=self.runtime.service(self, 'i18n') - )) + prompt.update( + { + "display_name": self.display_name, + "voting_message": self.voting_message, + "feedback_message": self.feedback_message, + "show_aggregate_to_students": self.show_aggregate_to_students, + } + ) + frag.add_content( + resource_loader.render_django_template( + "templates/html/studio_view.html", prompt, i18n_service=self.runtime.service(self, "i18n") + ) + ) js_str = self.resource_string("static/js/src/studio.js") frag.add_javascript(six.text_type(js_str)) - frag.initialize_js('FeedbackBlock', - {'icon_set': prompt['icon_set']}) + frag.initialize_js("FeedbackBlock", {"icon_set": prompt["icon_set"]}) return frag @XBlock.json_handler - def studio_submit(self, - data, suffix=''): # pylint: disable=unused-argument + def studio_submit(self, data, suffix=""): # pylint: disable=unused-argument """ Called when submitting the form in Studio. """ - for item in ['freeform', 'likert', 'placeholder', 'icon_set']: + for item in ["freeform", "likert", "placeholder", "icon_set"]: item_submission = data.get(item, None) if item_submission and len(item_submission) > 0: self.prompts[0][item] = html.escape(item_submission) for i in range(5): - likert = data.get(f'likert{i}', None) + likert = data.get(f"likert{i}", None) if likert and len(likert) > 0: - self.prompts[0]['scale_text'][i] = html.escape(likert) + self.prompts[0]["scale_text"][i] = html.escape(likert) - self.display_name = data.get('display_name') - self.voting_message = data.get('voting_message') - self.feedback_message = data.get('feedback_message') + self.display_name = data.get("display_name") + self.voting_message = data.get("voting_message") + self.feedback_message = data.get("feedback_message") self.show_aggregate_to_students = data.get("show_aggregate_to_students") - return {'result': 'success'} + return {"result": "success"} def init_vote_aggregate(self): - ''' + """ There are a lot of places we read the aggregate vote counts. We start out with these uninitialized. This guarantees they are initialized. We'd prefer to do it this way, rather than default value, since we do plan to not force scale length to be 5 in the future. - ''' + """ if not self.vote_aggregate: - self.vote_aggregate = [0] * (len(self.get_prompt()['scale_text'])) + self.vote_aggregate = [0] * (len(self.get_prompt()["scale_text"])) def vote(self, data): """ @@ -356,8 +330,7 @@ def vote(self, data): """ # prompt_choice is initialized by student view. # Ideally, we'd break this out into a function. - prompt = self.get_prompt(self.prompt_choice) # pylint: disable=unused-variable] - + _prompt = self.get_prompt(self.prompt_choice) # pylint: disable=unused-variable # Make sure we're initialized self.init_vote_aggregate() @@ -365,12 +338,12 @@ def vote(self, data): if self.user_vote != -1: self.vote_aggregate[self.user_vote] -= 1 - self.user_vote = data['vote'] + self.user_vote = data["vote"] self.vote_aggregate[self.user_vote] += 1 @XBlock.json_handler - def feedback(self, data, suffix=''): # pylint: disable=unused-argument - ''' + def feedback(self, data, suffix=""): # pylint: disable=unused-argument + """ Allow students to submit feedback, both numerical and qualitative. We only update the specific type of feedback submitted. @@ -378,39 +351,36 @@ def feedback(self, data, suffix=''): # pylint: disable=unused-argument We return the current state. While this is not used by the client code, it is helpful for testing. For staff users, we also return the aggregate results. - ''' - _ = self.runtime.service(self, 'i18n').ugettext - - if 'freeform' not in data and 'vote' not in data: - response = {"success": False, - "response": _("Please vote!")} - self.runtime.publish(self, - 'edx.feedbackxblock.nothing_provided', - {}) - if 'vote' in data: - response = {"success": True, - "response": self.voting_message} - self.runtime.publish(self, - 'edx.feedbackxblock.likert_provided', - {'old_vote': self.user_vote, - 'new_vote': data['vote']}) + """ + _ = self.runtime.service(self, "i18n").ugettext + + if "freeform" not in data and "vote" not in data: + response = {"success": False, "response": _("Please vote!")} + self.runtime.publish(self, "edx.feedbackxblock.nothing_provided", {}) + if "vote" in data: + response = {"success": True, "response": self.voting_message} + self.runtime.publish( + self, "edx.feedbackxblock.likert_provided", {"old_vote": self.user_vote, "new_vote": data["vote"]} + ) self.vote(data) - if 'freeform' in data: - response = {"success": True, - "response": self.feedback_message} - self.runtime.publish(self, - 'edx.feedbackxblock.freeform_provided', - {'old_freeform': self.user_freeform, - 'new_freeform': data['freeform']}) - self.user_freeform = data['freeform'] - - response.update({ # pylint: disable=possibly-used-before-assignment - "freeform": self.user_freeform, - "vote": self.user_vote - }) + if "freeform" in data: + response = {"success": True, "response": self.feedback_message} + self.runtime.publish( + self, + "edx.feedbackxblock.freeform_provided", + {"old_freeform": self.user_freeform, "new_freeform": data["freeform"]}, + ) + self.user_freeform = data["freeform"] + + response.update( + { # pylint: disable=possibly-used-before-assignment + "freeform": self.user_freeform, + "vote": self.user_vote, + } + ) if self.show_aggregate_to_students or self.is_staff(): - response['aggregate'] = self.vote_aggregate + response["aggregate"] = self.vote_aggregate return response @@ -423,13 +393,15 @@ def workbench_scenarios(): other two show up 50% of the time. """ return [ - ("FeedbackXBlock", - """ + ( + "FeedbackXBlock", + """ - """), + """, + ), ] def is_staff(self): @@ -440,8 +412,7 @@ def is_staff(self): runtimes, and this is a workaround so something reasonable happens in both workbench and edx-platform """ - if hasattr(self, "xmodule_runtime") and \ - hasattr(self.xmodule_runtime, "user_is_staff"): + if hasattr(self, "xmodule_runtime") and hasattr(self.xmodule_runtime, "user_is_staff"): return self.xmodule_runtime.user_is_staff else: # In workbench and similar settings, always return true diff --git a/src/feedback/feedbacktests/__init__.py b/src/feedback/feedbacktests/__init__.py index 3ae0280..b6763b4 100644 --- a/src/feedback/feedbacktests/__init__.py +++ b/src/feedback/feedbacktests/__init__.py @@ -2,3 +2,4 @@ from .test_feedback import FeedbackTestCase as feedbacktests +__all__ = ["feedbacktests"] diff --git a/src/feedback/feedbacktests/conftest.py b/src/feedback/feedbacktests/conftest.py index fb9ff28..43a9ea2 100644 --- a/src/feedback/feedbacktests/conftest.py +++ b/src/feedback/feedbacktests/conftest.py @@ -9,10 +9,10 @@ def generate_scope_ids(runtime, block_type): - """ helper to generate scope IDs for an XBlock """ + """helper to generate scope IDs for an XBlock""" def_id = runtime.id_generator.create_definition(block_type) usage_id = runtime.id_generator.create_usage(def_id) - return ScopeIds('user', block_type, def_id, usage_id) + return ScopeIds("user", block_type, def_id, usage_id) @pytest.fixture @@ -21,7 +21,7 @@ def feedback_xblock(): runtime = WorkbenchRuntime() key_store = DictKeyValueStore() db_model = KvsFieldData(key_store) - ids = generate_scope_ids(runtime, 'feedback') + ids = generate_scope_ids(runtime, "feedback") feedback_xblock = FeedbackXBlock(runtime, db_model, scope_ids=ids) feedback_xblock.usage_id = Mock() return feedback_xblock diff --git a/src/feedback/feedbacktests/test_feedback.py b/src/feedback/feedbacktests/test_feedback.py index e683a62..63c0ea9 100644 --- a/src/feedback/feedbacktests/test_feedback.py +++ b/src/feedback/feedbacktests/test_feedback.py @@ -1,7 +1,6 @@ -''' +""" Tests for the FeedbackXBlock that needs to run in Open edX. -''' - +""" from unittest import mock @@ -11,6 +10,7 @@ class PatchRandomMixin: This is a class which will patch random.uniform so that we can confirm whether randomization works. """ + def setUp(self): super().setUp() self.random_patch_value = None @@ -18,8 +18,7 @@ def setUp(self): def patched_uniform(min, max): return self.random_patch_value - patcher = mock.patch("feedback.feedback.random.uniform", - patched_uniform) + patcher = mock.patch("feedback.feedback.random.uniform", patched_uniform) patcher.start() self.addCleanup(patcher.stop) @@ -48,23 +47,13 @@ class FeedbackTestCase(PatchRandomMixin): { "urlname": "feedback_block_test_case_0", "xblocks": [ # Stopgap until we handle OLX - { - 'blocktype': 'feedback', - 'urlname': 'feedback_0', - 'parameters': {'p': 100} - } - ] + {"blocktype": "feedback", "urlname": "feedback_0", "parameters": {"p": 100}} + ], }, { "urlname": "feedback_block_test_case_1", - 'xblocks': [ - { - 'blocktype': 'feedback', - 'urlname': 'feedback_1', - 'parameters': {'p': 50} - } - ] - } + "xblocks": [{"blocktype": "feedback", "urlname": "feedback_1", "parameters": {"p": 50}}], + }, ] def submit_feedback(self, block, data, desired_state): @@ -72,7 +61,7 @@ def submit_feedback(self, block, data, desired_state): Make an AJAX call to the XBlock, and assert the state is as desired. """ - resp = self.ajax('feedback', block, data) + resp = self.ajax("feedback", block, data) self.assertEqual(resp.status_code, 200) # pylint: disable=no-member self.assertEqual(resp.data, desired_state) @@ -87,9 +76,9 @@ def check_response(self, block_urlname, rendered): response = self.render_block(block_urlname) self.assertEqual(response.status_code, 200) if rendered: - self.assertTrue('feedback_likert_scale' in response.content) + self.assertTrue("feedback_likert_scale" in response.content) else: - self.assertFalse('feedback_likert_scale' in response.content) + self.assertFalse("feedback_likert_scale" in response.content) def test_feedback(self): """ @@ -99,31 +88,32 @@ def test_feedback(self): """ self.select_student(0) # We confirm we don't have errors rendering the student view - self.check_response('feedback_0', True) + self.check_response("feedback_0", True) # At 45, feedback_1 should render self.set_random(45) - self.check_response('feedback_1', True) - vote_str = 'Thank you for voting!' - feedback_str = 'Thank you for your feedback!' - self.submit_feedback('feedback_0', - {'freeform': 'Worked well', 'vote': 3}, - {'freeform': 'Worked well', 'vote': 3, - 'response': feedback_str, 'success': True}) - self.submit_feedback('feedback_0', - {'vote': 4}, - {'freeform': 'Worked well', 'vote': 4, - 'response': vote_str, 'success': True}) - self.submit_feedback('feedback_0', - {'freeform': 'Worked great'}, - {'freeform': 'Worked great', 'vote': 4, - 'response': feedback_str, 'success': True}) + self.check_response("feedback_1", True) + vote_str = "Thank you for voting!" + feedback_str = "Thank you for your feedback!" + self.submit_feedback( + "feedback_0", + {"freeform": "Worked well", "vote": 3}, + {"freeform": "Worked well", "vote": 3, "response": feedback_str, "success": True}, + ) + self.submit_feedback( + "feedback_0", {"vote": 4}, {"freeform": "Worked well", "vote": 4, "response": vote_str, "success": True} + ) + self.submit_feedback( + "feedback_0", + {"freeform": "Worked great"}, + {"freeform": "Worked great", "vote": 4, "response": feedback_str, "success": True}, + ) # And confirm we render correctly - self.check_response('feedback_0', True) + self.check_response("feedback_0", True) # Feedback 1 should render again; this should be stored in a # field self.set_random(55) - self.check_response('feedback_1', True) + self.check_response("feedback_1", True) # But it should not render for a new student self.select_student(1) - self.check_response('feedback_1', False) + self.check_response("feedback_1", False) diff --git a/src/feedback/feedbacktests/test_feedback_unit.py b/src/feedback/feedbacktests/test_feedback_unit.py index 5d43c23..bd28c3b 100644 --- a/src/feedback/feedbacktests/test_feedback_unit.py +++ b/src/feedback/feedbacktests/test_feedback_unit.py @@ -6,47 +6,47 @@ def test_template_content(feedback_xblock): - """ Test content of FeedbackXBlock's student view """ - student_fragment = feedback_xblock.render('student_view', Mock()) - assert 'feedback' in student_fragment.content + """Test content of FeedbackXBlock's student view""" + student_fragment = feedback_xblock.render("student_view", Mock()) + assert "feedback" in student_fragment.content def test_studio_view(feedback_xblock): - """ Test content of FeedbackXBlock's author view """ - student_fragment = feedback_xblock.render('studio_view', Mock()) - assert 'feedback' in student_fragment.content + """Test content of FeedbackXBlock's author view""" + student_fragment = feedback_xblock.render("studio_view", Mock()) + assert "feedback" in student_fragment.content def test_studio_submit(feedback_xblock): - """ Test the FeedbackXBlock's save action """ + """Test the FeedbackXBlock's save action""" request_body = b"""{ "display_name": "foo", "voting_message": "bar", "feedback_message": "baz", "show_aggregate_to_students": true }""" - request = Mock(method='POST', body=request_body) + request = Mock(method="POST", body=request_body) response = feedback_xblock.studio_submit(request) - assert feedback_xblock.display_name == 'foo' - assert feedback_xblock.voting_message == 'bar' - assert feedback_xblock.feedback_message == 'baz' + assert feedback_xblock.display_name == "foo" + assert feedback_xblock.voting_message == "bar" + assert feedback_xblock.feedback_message == "baz" assert feedback_xblock.show_aggregate_to_students is True - assert response.status_code == 200 and {'result': 'success'} == response.json, response.json + assert response.status_code == 200 and {"result": "success"} == response.json, response.json def test_vote(feedback_xblock): - """ Test content of FeedbackXBlock's vote() method """ - feedback_xblock.vote({'vote': 1}) + """Test content of FeedbackXBlock's vote() method""" + feedback_xblock.vote({"vote": 1}) def test_feedback_method(feedback_xblock): - """ Test content of FeedbackXBlock's feedback() method """ + """Test content of FeedbackXBlock's feedback() method""" request_body = b"""{ "freeform": "yes", "vote": 1 }""" - request = Mock(method='POST', body=request_body) + request = Mock(method="POST", body=request_body) response = feedback_xblock.feedback(request) expected_response_json = { diff --git a/src/feedback/feedbacktests/test_filters.py b/src/feedback/feedbacktests/test_filters.py index 344970c..6ee112a 100644 --- a/src/feedback/feedbacktests/test_filters.py +++ b/src/feedback/feedbacktests/test_filters.py @@ -40,14 +40,19 @@ def test_run_filter_without_blocks(self, modulestore_mock, get_block_by_usage_id get_block_by_usage_id_mock.assert_not_called() get_user_enrollments_mock.assert_not_called() - @patch("feedback.extensions.filters.get_lms_link_for_item") @patch("feedback.extensions.filters.get_user_enrollments") @patch("feedback.extensions.filters.get_block_by_usage_id") @patch("feedback.extensions.filters.load_single_xblock") @patch("feedback.extensions.filters.modulestore") - def test_run_filter(self, modulestore_mock, load_single_xblock_mock, get_block_by_usage_id_mock, get_user_enrollments_mock, - get_lms_link_for_item_mock): + def test_run_filter( + self, + modulestore_mock, + load_single_xblock_mock, + get_block_by_usage_id_mock, + get_user_enrollments_mock, + get_lms_link_for_item_mock, + ): """ Check the filter is executed when there are Feedback blocks in the course. @@ -75,9 +80,7 @@ def test_run_filter(self, modulestore_mock, load_single_xblock_mock, get_block_b get_user_enrollments_mock.assert_called_once() self.assertEqual(1, len(result.get("context", {})["sections"])) - @override_settings( - FEATURES={"ENABLE_FEEDBACK_INSTRUCTOR_VIEW":False} - ) + @override_settings(FEATURES={"ENABLE_FEEDBACK_INSTRUCTOR_VIEW": False}) def test_run_filter_disable(self): context = {"course": Mock(id="test-course-id"), "sections": []} template_name = "test-template-name" @@ -115,7 +118,6 @@ def test_load_xblock_answers(self, load_single_xblock_mock): answers, ) - @patch("feedback.extensions.filters.load_single_xblock") def test_load_xblock_answers_skip_empty(self, load_single_xblock_mock): request_mock = Mock() diff --git a/src/feedback/settings/common.py b/src/feedback/settings/common.py index a62debf..2ca4307 100644 --- a/src/feedback/settings/common.py +++ b/src/feedback/settings/common.py @@ -5,6 +5,7 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/2.22/ref/settings/ """ + from feedback import ROOT_DIRECTORY INSTALLED_APPS = [ diff --git a/src/feedback/settings/test.py b/src/feedback/settings/test.py index 2521d2f..f537396 100644 --- a/src/feedback/settings/test.py +++ b/src/feedback/settings/test.py @@ -5,18 +5,19 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/2.22/ref/settings/ """ -from workbench.settings import * # pylint: disable=wildcard-import + +from workbench.settings import * # noqa: F403 # pylint: disable=wildcard-import INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'feedback', - 'workbench', + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "feedback", + "workbench", ] FEATURES = { "ENABLE_FEEDBACK_INSTRUCTOR_VIEW": True, } -SECRET_KEY = 'fake-key' +SECRET_KEY = "fake-key" From 5c0fef793530dbb08385c15cf78284333e53ddd8 Mon Sep 17 00:00:00 2001 From: salman2013 Date: Tue, 7 Apr 2026 15:41:42 +0500 Subject: [PATCH 4/5] fix: comments as per review --- .gitignore | 3 +++ pyproject.toml | 7 +++++++ src/feedback/numerical_example.png | Bin 0 -> 24694 bytes src/feedback/templates/.DS_Store | Bin 6148 -> 0 bytes 4 files changed, 10 insertions(+) create mode 100644 src/feedback/numerical_example.png delete mode 100644 src/feedback/templates/.DS_Store diff --git a/.gitignore b/.gitignore index 0bcd497..0e46e2e 100644 --- a/.gitignore +++ b/.gitignore @@ -217,3 +217,6 @@ __marimo__/ # Sphinx documentation docs/_build/ + +# macOS system files +**/.DS_Store diff --git a/pyproject.toml b/pyproject.toml index 5276094..957f524 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,6 +43,7 @@ Documentation = "https://xblocks-extra.readthedocs.io" dev = [ "build", "ruff", + "edx-i18n-tools", ] test = [ "pytest>=7.0", @@ -58,6 +59,12 @@ docs = [ audio = "audio:AudioXBlock" feedback = "feedback.feedback:FeedbackXBlock" +[project.entry-points."xblock.test.v0"] +feedbacktest = "feedback.feedbacktests:feedbacktests" + +[project.entry-points."lms.djangoapp"] +feedback = "feedback.apps:FeedbackConfig" + # Packages live in src/ but are installed without the src prefix # e.g., src/foo_xblock/ is installed as foo_xblock [tool.setuptools] diff --git a/src/feedback/numerical_example.png b/src/feedback/numerical_example.png new file mode 100644 index 0000000000000000000000000000000000000000..6acc304236ca24e18f80291e289a90c268f85a49 GIT binary patch literal 24694 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 BR$u@C literal 0 HcmV?d00001 diff --git a/src/feedback/templates/.DS_Store b/src/feedback/templates/.DS_Store deleted file mode 100644 index 325cebda8e39709cbd4e65fb74cdde3eddc7b95e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKK~BRk5FD3C1aaws14oM=^aEh3@Pa-7nnof>4XJ?K^C6yqIP#M|0&!s0HYHI2 z0S7>6S6Yuf_Qv+4&DsFWv?(UQ7(hxF9PO}p!=zt)V57)Lr;%qY&nL4*U9AQqmH4X) z$h%8W;szC#{r7ip+wH6BEX$X5PA*+P9^S3*ACCL|#fSZ?visX`48u$D>Ue^8TxvTnhU*C!E?_2(7YN~)LpbGrD0?gTB z>25$RRRL8%71$^s-v>(Y9iGY-)TL39z@fMjSUgc3ujiB}90 z!pYk>&P8kkhHw}^GoKS@Ht~jH;t9)GKODvd)KV2t1^NnXh2~iD|H=FJ|9+6RQ~_1s zUnyXcY?e*ArI=d>o0D8?>1T8?8P^8fgs|dMF~>?O-luybZ>2(X5!--dXnGLvGH9U+ H{HOxYKf7cw From f2116292862de4a666d134d52e32de3f58d061b7 Mon Sep 17 00:00:00 2001 From: salman2013 Date: Fri, 10 Apr 2026 16:18:39 +0500 Subject: [PATCH 5/5] fix: delete translations for testing purpose --- src/feedback/translations | 1 - 1 file changed, 1 deletion(-) delete mode 120000 src/feedback/translations diff --git a/src/feedback/translations b/src/feedback/translations deleted file mode 120000 index 618b7e2..0000000 --- a/src/feedback/translations +++ /dev/null @@ -1 +0,0 @@ -conf/locale \ No newline at end of file