From 5c7d19983184f715a7e7836fc4ccdfb5127840b5 Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Mon, 20 Oct 2025 15:34:09 -0700 Subject: [PATCH] surveyReport run survey report to see return data --- README.md | 2 +- mesh_bot.py | 12 ++++--- modules/survey.py | 79 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 86 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 3e097e4..66c8871 100644 --- a/README.md +++ b/README.md @@ -197,7 +197,7 @@ Players can `q: join` to join the game, `q: leave` to leave the game, `q: score` To Answer a question, just type the answer prefixed with `q: ` #### Survey -To use the Survey feature edit the json files in data/survey multiple surveys are possible such as `survey snow` +To use the Survey feature edit the json files in data/survey multiple surveys are possible such as `survey snow` you can pull data back with `survey report` or `survey report snow` ## Other Install Options diff --git a/mesh_bot.py b/mesh_bot.py index 1d11775..b999128 100755 --- a/mesh_bot.py +++ b/mesh_bot.py @@ -1037,7 +1037,6 @@ def quizHandler(message, nodeID, deviceID): return "🧠Please provide an answer or command, or send q: ?" def surveyHandler(message, nodeID, deviceID): - from modules.settings import surveyTracker user_id = nodeID location = get_node_location(nodeID, deviceID) msg = '' @@ -1056,10 +1055,13 @@ def surveyHandler(message, nodeID, deviceID): return survey_module.end_survey(user_id=nodeID) # Handle report command - if surveySays == "report": - #return survey_module.quiz_report() - # reminder to fix int and open question reporting - return "Report not implemented yet" + if 'report' in surveySays: + if str(nodeID) not in bbs_admin_list: + return "You do not have permission to view survey reports." + # remove the words 'survey' and 'report' from the message + report = msg_lower.replace("survey", "").replace("report", "").strip() + results = survey_module.get_survey_results(survey_name=report if report else None) + return survey_module.format_survey_results(results) # Update last played or add new tracker entry found = False diff --git a/modules/survey.py b/modules/survey.py index baa42d7..66481dd 100644 --- a/modules/survey.py +++ b/modules/survey.py @@ -10,6 +10,8 @@ import json import os # For file operations +import csv +from datetime import datetime from collections import Counter from modules.log import * @@ -98,7 +100,7 @@ class SurveyModule: try: with open(filename, 'a', encoding='utf-8') as f: # Always write: timestamp, userID, position, answers... - timestamp = datetime.datetime.now().strftime('%d%m%Y%H%M%S') + timestamp = datetime.now().strftime('%d%m%Y%H%M%S') user_id_str = str(user_id) location = self.responses[user_id].get('location', "N/A") answers = list(map(str, self.responses[user_id]['answers'])) @@ -108,6 +110,81 @@ class SurveyModule: except Exception as e: logger.error(f"Error saving responses to {filename}: {e}") + def format_survey_results(self, results): + if isinstance(results, dict) and "error" in results: + return results["error"] + if not results: + return "No results found." + msg = "📊 Survey Results:\n" + for idx, q in enumerate(results): + msg += f"\nQ{idx+1}: {q['question']}\n" + if q['type'] == 'multiple_choice': + for opt, count in q['summary'].items(): + msg += f" {opt}: {count}\n" + elif q['type'] == 'integer': + s = q['summary'] + msg += f" Count: {s['count']}, Avg: {s['average']:.2f}, Min: {s['min']}, Max: {s['max']}\n" + elif q['type'] == 'text': + msg += f" Responses: {q['summary']['responses_count']}\n" + return msg + + def get_survey_results(self, survey_name='example'): + if survey_name not in self.surveys: + return {"error": f"Survey '{survey_name}' not found."} + filename = os.path.join(self.response_dir, f'{survey_name}_responses.csv') + questions = self.surveys[survey_name] + results = [] + try: + with open(filename, encoding='utf-8') as f: + reader = csv.reader(f) + lines = [] + for row in reader: + if not row or len(row) < 4: + continue + # If location field is split due to comma, join columns 2 and 3 + if row[2].startswith('[') and not row[2].endswith(']') and len(row) > 4: + location = row[2] + ',' + row[3] + answers = row[4:] + else: + location = row[2] + answers = row[3:] + lines.append(answers) + + for q_idx, question in enumerate(questions): + qtype = question.get('type', 'multiple_choice') + answers = [row[q_idx] for row in lines if len(row) > q_idx] + + summary = {} + if qtype == 'multiple_choice': + counts = Counter(answers) + summary = {chr(65+i): counts.get(chr(65+i), 0) for i in range(len(question.get('options', [])))} + + elif qtype == 'integer': + ints = [int(a) for a in answers if a.isdigit()] + summary = { + "count": len(ints), + "average": sum(ints)/len(ints) if ints else 0, + "min": min(ints) if ints else None, + "max": max(ints) if ints else None + } + + elif qtype == 'text': + summary = {"responses_count": len([a for a in answers if a.strip()])} + + + results.append({ + "question": question['question'], + "type": qtype, + "summary": summary + }) + + return results + except FileNotFoundError: + return {"error": f"No responses recorded yet for '{survey_name}'."} + except Exception as e: + logger.error(f"Error summarizing survey results: {e}") + return NO_ALERTS + def answer(self, user_id, answer, location=None): try: """Record an answer and return the next question or end message."""