From 867b5e44565073981c52b658a8ba10c551af5ce2 Mon Sep 17 00:00:00 2001 From: Someone Date: Mon, 31 Jan 2022 19:49:51 +0100 Subject: [PATCH] modules/DialogManagedCourseFeedback.py --- modules/DialogManagedCourseFeedback.py | 181 +++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 modules/DialogManagedCourseFeedback.py diff --git a/modules/DialogManagedCourseFeedback.py b/modules/DialogManagedCourseFeedback.py new file mode 100644 index 0000000..f98290d --- /dev/null +++ b/modules/DialogManagedCourseFeedback.py @@ -0,0 +1,181 @@ +# Mattermost Bot module. +# Copyright (c) 2016-2022 by Someone (aka. Jan Vales ) +# published under MIT-License + +from inspect import cleandoc +import csv +import os +import re + + +# pylint: disable=wrong-import-position +from AbstractCommand import AbstractCommand +class DialogManagedCourseFeedback(AbstractCommand): + TRIGGER = "course-feedback" + CONFIG = {"display_name": "somebot-command", "auto_complete": True, + "auto_complete_hint": "['--help']", + } + CONFIG["auto_complete_desc"] = CONFIG["description"] = AbstractCommand.ICON_PRIVATE+"Run in course-channel. Opens dialog to edit/delete course-feedback." + + + def __init__(self, team_id, datadir): + super().__init__(team_id) + + self.datadir = datadir + + + def on_POST(self, request, data): + if re.match(r"^(-|—|–)+help$", data["text"]): + request.respond_cmd_temp(cleandoc(""" + ## :pencil:``Course feedback!``:rocket: + We want your feedback in order to find out which courses need to be improved asap to achieve the excellence we are accustomed to, or better. + The feedback will be anonymized during aggregation, then analyzed and discussed with the appropriate people like the course admins, the deans of study affairs and the vice rector for teaching matters and/or the in-house lawyers. + + What we want to know: + + Feedback for this course. + + How much time did you spent on this course. + + How did you like the modalities of this course? (Would you want it to be applied to others?) + + This course's modalities - describe them in a few words. (Also consider updating the info in VoWi - its a work resource for us and we use it to represent you) + + Feedback about this survey for :fsinf:. (This will not be shared outside of FSInf) + + :information_source: *We are your legaly appointed representatives - we will never forward any personal info about you without your explicit permission.* :) + """)) + return + + c = self.bot.api.get_channel(data["channel_id"]) + + #if c["type"] != 'O' or c["name"] in ["town-square", "off-topic"] or c["display_name"][0] == "=": + # request.respond_cmd_err("``/"+self.TRIGGER+"`` must be run in a course-channel.") + # return + + self._open_dialog(request, data) + request.respond_cmd_temp("## :white_check_mark: Success! :)\n#### Opened dialog.") + + + def on_POST_interactive(self, request, data): + self._open_dialog(request, data) + request.respond() + + + def on_POST_dialog(self, request, data): + import pprint + print("on_POST_dialog") + pprint.pprint(data) + + if data["submission"]["feedback_hours"] and int(data["submission"]["feedback_hours"]) < 0: + request.respond(200, {"errors": {"feedback_hours": "Hours must be positive."}}) + return + + if data["submission"]["feedback_hours"] and int(data["submission"]["feedback_hours"]) > 4464: + request.respond(200, {"errors": {"feedback_hours": "Hours must be smaller than 4465. Did you really spend EVERY HOUR of the semester for this course? Did you not sleep at all?"}}) + return + + + c = self.bot.api.get_channel(data["channel_id"]) + + self._response_store(self.datadir+data["callback_id"], "-feedback_distance.txt", data["submission"]["feedback_distance"], c["name"]) + self._response_store(self.datadir+data["callback_id"], "-feedback_course.txt", data["submission"]["feedback_course"], c["name"]) + self._response_store(self.datadir+data["callback_id"], "-feedback_hours.txt", data["submission"]["feedback_hours"], c["name"]) + self._response_store(self.datadir+data["callback_id"], "-feedback_modus.txt", data["submission"]["feedback_modus"], c["name"]) + self._response_store(self.datadir+data["callback_id"], "-feedback_modus_like.txt", data["submission"]["feedback_modus_like"], c["name"]) + self._response_store(self.datadir+data["callback_id"], "-feedback_fsinf.txt", data["submission"]["feedback_fsinf"], c["name"]) + + request.respond(200, {}) + + + def _open_dialog(self, request, data): + #import pprint + #print("on_POST_interactive") + #pprint.pprint(data) + + callback_id = "res-"+data["team_id"]+"-"+data["channel_id"]+"-"+data["user_id"] + + feedback_distance = self._response_load(self.datadir+callback_id, "-feedback_distance.txt") + feedback_course = self._response_load(self.datadir+callback_id, "-feedback_course.txt") + feedback_hours = self._response_load(self.datadir+callback_id, "-feedback_hours.txt") + feedback_modus = self._response_load(self.datadir+callback_id, "-feedback_modus.txt") + feedback_modus_like = self._response_load(self.datadir+callback_id, "-feedback_modus_like.txt", "0") + feedback_fsinf = self._response_load(self.datadir+callback_id, "-feedback_fsinf.txt") + + dialog = { + "callback_id": callback_id, + "title": "Course feedback", + "submit_label":"Submit", + "elements":[{ + "display_name": "Was there an online option? Was it possible to complete the course only online? What did you think about the online option? (Max. 3000 characters)", + "placeholder": "Type here. Max. 3000 characters.\n+ Was it communicated?\n+ bla?\n+ bla?", + "name": "feedback_distance", + "type": "textarea", + "help_text": "All your imput on all questions will be anonymized during aggregation. Aggregated input will be analyzed by FSInf and further used/forwarded to the course admins, the deans of study affairs, the vice rector for teaching and possibly others that are deemed able to fix things. You can edit/clear it at any time.", + "optional": True, + "default": feedback_distance + },{ + "display_name": "How many hours did you invest into this course?", + "placeholder": "Hours. Positive integer.", + "name": "feedback_hours", + "type": "text", + "subtype": "number", + "optional": True, + "default": feedback_hours + },{ + "display_name": "Describe the modalities (issues encountered and possible improvements) in a few words (Max. 3000 characters)", + "placeholder": "Type here. Max. 3000 characters.\n+ What was it? \n+ Were deadlines announced in a timely manner?\n+ Was the grading surprising?\n+ Random changes during the semester?", + "name": "feedback_modus", + "type": "textarea", + "optional": True, + "default": feedback_modus + },{ + "display_name": "How did you like the modalities of this course? (Do you want it to be applied to others?)", + "placeholder": "Type here. Max. 3000 characters.", + "name": "feedback_modus_like", + "type": "radio", + "options": [ + {"text": "I loved it", "value": "2" }, + {"text": "I liked it", "value": "1" }, + {"text": "I'm indifferent/Don't want to answer (default)", "value": "0" }, + {"text": "I disliked it", "value": "-1" }, + {"text": "I hated it", "value": "-2" }, + ], + "optional": True, + "default": feedback_modus_like + },{ + "display_name": "Your Comment/Feedback about the course (Max. 3000 characters)", + "placeholder": "Type here. Max. 3000 characters.\n+ What should be changed?\n+ What was unfair?\n+ What was really good?", + "name": "feedback_course", + "type": "textarea", + "optional": True, + "default": feedback_course + },{ + "display_name": "Feedback (about this survey) for FSInf (Max. 3000 characters)", + "placeholder": "Type here. Max. 3000 characters.", + "name": "feedback_fsinf", + "type": "textarea", + "help_text": "Your input will be anonymized during aggregation. Aggregated input will be analyzed by FSInf. We will not forward this text to anyone. You can edit/clear it at any time.", + "optional": True, + "default": feedback_fsinf + }] + } + + self.bot.api.open_dialog(data["trigger_id"], self.URL+"/dialog", dialog) + + + def _response_load(self, path, filename, default=""): + path = path+filename + ret = default + if os.path.isfile(path): + with open(path, "r") as f: + ret = f.read() + return ret + + + def _response_store(self, path, filename, data, channelname=""): + path = path+filename + data = str(data).strip() + if data == "" or data == "None" or data == "0": + if os.path.isfile(path): + os.remove(path) + self.bot.debug_chan("``course-feedback::"+channelname+filename+"`` result deleted.") + else: + with open(path, "w") as f: + f.write(data) + self.bot.debug_chan("``course-feedback::"+channelname+filename+"`` result stored.\n```\n"+data+"\n```") -- 2.43.0