From b2f8dbfae77d0abe6d3c655e1e3c8984ee6e8b56 Mon Sep 17 00:00:00 2001 From: AliasAlreadyTaken Date: Fri, 20 Sep 2024 13:32:44 +0200 Subject: [PATCH] Implements answer_question --- README.md | 29 +++++++++--- api.lua | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 145 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 17ef68f..c27ae2e 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ Returns a table `{survey}` with the values of this UUID or `nil`, if it does not yl_survey.create_survey(owner, allow_names, allow_anonymous, allow_changes, timestamp_start, timestamp_end) ``` -Returns `true, s_id` if successful, `false, "errormessage` if not. +Returns `true, s_id` if successful, `false, "errormessage"` if not. Creates a survey owned by `owner`. `allow_names`, `allow_anonymous`, `allow_changes` are booleans, `timestamp_start` and `timestamp_end` are utc timestamps. @@ -78,7 +78,7 @@ If both allow_names and allow_anonymous are false, then noone can answer this su yl_survey.edit_survey(s_id, owner, allow_names, allow_anonymous, allow_changes, timestamp_start, timestamp_end, delete_responses) ``` -Returns `true, s_id, amount_deleted_records` if successful, `false, "errormessage` if not. +Returns `true, s_id, amount_deleted_records` if successful, `false, "errormessage"` if not. Changes the properties of the survey `s_id` to the values given. `delete_responses` is boolean, optional and defaults to `false`, but if `true` it deletes all prior responses of the survey. See `create_survey` for the other values. @@ -104,7 +104,7 @@ yl_survey.evaluate(s_id) yl_survey.create_question(s_id, question, category, sort, {allowed_types}, {answers}, enabled) ``` -Returns `true, q_id` if successful, `false, "errormessage` if not. +Returns `true, q_id` if successful, `false, "errormessage"` if not. Adds a question to the survey identified by `s_id`. @@ -120,7 +120,7 @@ Adds a question to the survey identified by `s_id`. yl_survey.edit_question(s_id, q_id, question, sort, category, {allowed_types}, {answers}, enabled, delete_responses) ``` -Returns `true, q_id` if successful, `false, "errormessage` if not. +Returns `true, q_id` if successful, `false, "errormessage"` if not. Changes in the survey `s_id` the properties of the question `q_id` to the values given. `delete_responses` is boolean, optional and defaults to `false`, but if `true` it deletes all prior responses to this particular question. See `create_question` for the other values. @@ -137,10 +137,25 @@ yl_survey.list_questions(s_id, include_responses) Returns `true, {{question1}, {question2}, ... }` if one or more questions were found, `false, {}` if none were found. ``` -yl_survey.answer(playername, s_id) +yl_survey.get_question(s_id, q_id, include_responses, playername) ``` -Returns `boolean, number or string`. `boolean` indicates whether the survey was found and displayed to the player or not. If `false`, then string is the errormessage. If `true`, then number is the amount of answers this survey has on record from that player. +* s_id: string, required. This is the survey/UUID the question is added to. +* q_id: number, required. +* include_responses: boolean, optional, defaults to `false`. If `true`, the responses to that question are included. +* playername: string, optional. If given, returns only the responses of this player. May be empty `{}` if the player did not answer this question yet. No effect if include_responses is not `true`. + +Returns `true, {question}` if successful, `false, "errormessage"` if not. + +``` +yl_survey.answer_question(s_id, q_id, playername, {responses}, overwrite) +``` + +The `{responses}` need to be in a format like `{"0" = "the freetext answer, "4" = "The fourth answer", "5" = "Fifth answer"}` + +If `overwrite` is true, the responses are stored even if the same playername already answered that question. The old reponses are removed. + +Returns `true, {overwritten responses}` if successful. `overwritten responses` is the table that was stored before this function replaced it with `{responses}`. May be `{}` if no responses were written over. Returns `false, "errormessage"` if not successful. ``` yl_survey.create_book(playername, s_id) @@ -154,7 +169,7 @@ Creates a book of the answers of the survey and places it in the player's invent yl_survey.validate_questions(s_id) ``` -Returns `true, number` if successfully validated `number` amount of questions, `false, "errormessage` if teh validation was not successful. +Returns `true, number` if successfully validated `number` amount of questions, `false, "errormessage"` if teh validation was not successful. ## Limitations diff --git a/api.lua b/api.lua index 69ef712..74cc7f9 100644 --- a/api.lua +++ b/api.lua @@ -24,7 +24,7 @@ end function yl_survey.get_record(id) return get_record(id) end --- yl_survey.create_survey +-- validations -- local function validate_nil_or_positive(value) @@ -74,6 +74,43 @@ local function validate_questiontype(allowed_types) return true end +local function validate_responses(t_answers, responses) + + -- Defense + if (validate(t_answers, "table", false) == false) then + return false + end + if (validate(responses, "table", false) == false) then + return false + end + + -- If the responses are not JSON-able, return false + if (minetest.write_json(responses) == nil) then + return false + end + + -- If there is a response not matched in t_answers, return false + for k, v in pairs(responses) do + local r_id = tonumber(k) + if r_id and (r_id > 0) then + local found = false + for kk, vv in pairs(t_answers) do + if (v == vv) then + found = true + end + end + if (found == false) then + return false + end + end + end + + return true +end + +-- yl_survey.create_survey +-- + local function create_survey(owner, allow_names, allow_anonymous, allow_changes, timestamp_start, timestamp_end) -- Defense @@ -319,7 +356,7 @@ local function create_question(id, question, category, sort, allowed_types, end local record = yl_survey.get_record(id) - core.log("action", "record =" .. dump(record)) + -- Specialcase : given sort is a duplicate if ((type(sort) == "number") and (yl_survey.is_duplicate(record, sort) == true)) then @@ -334,7 +371,6 @@ local function create_question(id, question, category, sort, allowed_types, end -- Payload - core.log("action", "record =" .. dump(record)) -- if sort is nil, then find next sort local next_sort = sort or yl_survey.find_next_free_number(record, "sort") @@ -351,9 +387,9 @@ local function create_question(id, question, category, sort, allowed_types, answers = answers, responses = {} } - core.log("action", "record =" .. dump(record)) + record[tostring(next_q_id)] = t_question - core.log("action", "record =" .. dump(record)) + -- Store local success = yl_survey.save(id, record) if (success == true) then @@ -521,9 +557,7 @@ local function remove_question(id, q_id, delete_responses) for _, _ in pairs(n_responses) do no = no + 1 end record[tostring(q_id)] = nil else - record[tostring(q_id)] = { - responses = n_responses - } + record[tostring(q_id)] = {responses = n_responses} end -- Store @@ -544,7 +578,7 @@ end -- list_questions -- -function list_questions(id, include_responses) +local function list_questions(id, include_responses) -- Defense if (validate(id, "string", false) == false) then return false, yl_survey.t("id must be string") @@ -585,3 +619,83 @@ end function yl_survey.list_questions(s_id, include_responses) return list_questions(s_id, include_responses) end + +-- yl_survey.answer_question +-- + +local function answer_question(id, q_id, playername, responses, overwrite) + -- Defense + if (validate(id, "string", false) == false) then + return false, yl_survey.t("id must be string") + end + if (validate(q_id, "number", false) == false) then + return false, "q_id must be number" + end + if (q_id <= 0) then return false, "q_id must be positive number" end + if (validate(playername, "string", false) == false) then + return false, yl_survey.t("playername must be string") + end + if (validate(responses, "table", false) == false) then + return false, yl_survey.t("responses must be table") + end + if (validate(overwrite, "boolean", true) == false) then + return false, yl_survey.t("overwrite must be boolean") + end + + -- Get survey + + local record = yl_survey.get_record(id) + + if (record == nil) then + return false, yl_survey.t("record does not exist") + end + + -- Get question + + if (record[tostring(q_id)] == nil) then + return false, yl_survey.t("question does not exist") + end + + local t_question = table.copy(record[tostring(q_id)]) + + -- Get responses + + local all_responses = t_question["responses"] + + local overwritten_responses = {} + + if (all_responses and next(all_responses[playername]) ~= nil) then + overwritten_responses = all_responses[playername] or {} + end + + if ((overwrite ~= true) and (overwritten_responses ~= nil)) then + return false, + "previous responses cannot be written over without overwrite true" + end + + responses["q"] = t_question["question"] + + if (record[tostring(q_id)]["responses"] == nil) then + record[tostring(q_id)]["responses"] = {} + end + + if (validate_responses(t_question["answers"], responses) == false) then + return false, "responses do not fit the questions" + end + + record[tostring(q_id)]["responses"][playername] = responses + + -- Store + local success = yl_survey.save(id, record) + if (success == true) then + yl_survey.data[id] = record + return true, overwritten_responses or {} + else + return false, yl_survey.t("Could not store") + end + +end + +function yl_survey.answer_question(id, q_id, playername, responses, overwrite) + return answer_question(id, q_id, playername, responses, overwrite) +end