Skip to content

Commit

Permalink
Submitted surveys are saved and success is reported. Started with res…
Browse files Browse the repository at this point in the history
…ult aggregation.
  • Loading branch information
mworrell committed Apr 14, 2010
1 parent 63bc957 commit 6ec348e
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 10 deletions.
1 change: 1 addition & 0 deletions modules/mod_survey/mod_survey.erl
Expand Up @@ -207,6 +207,7 @@ new_question(Type) ->

%% @doc Install the survey models
install(Context) ->
m_survey:install(Context),
z_datamodel:manage(?MODULE, datamodel(), Context).

datamodel() ->
Expand Down
95 changes: 94 additions & 1 deletion modules/mod_survey/models/m_survey.erl
Expand Up @@ -27,7 +27,11 @@
-export([
m_find_value/3,
m_to_list/2,
m_value/2
m_value/2,

insert_survey_submission/3,
survey_stats/2,
install/1
]).

-include_lib("zotonic.hrl").
Expand Down Expand Up @@ -68,3 +72,92 @@ question_to_value([Id|Ids], Qs, Acc) ->
{Id, [{id, Id}, {type, Type}, {name, Name}, {html, Html}]};
question_to_value1(Id, undefined) ->
{Id, [{id, Id}, {type, undefined}]}.



%% @doc Save a survey, connect to the current visitor and user (if any)
insert_survey_submission(SurveyId, Answers, Context) ->
UserId = z_acl:user(Context),
%% Delete previous answers of this user, if any
case UserId of
undefined -> nop;
_Other -> z_db:q("delete from survey_answer where survey_id = $1 and user_id = $2", [SurveyId, UserId], Context)
end,
insert_questions(SurveyId, UserId, Answers, Context).

insert_questions(_SurveyId, _UserId, [], _Context) ->
ok;
insert_questions(SurveyId, UserId, [{QuestionId, Answers}|Rest], Context) ->
insert_answers(SurveyId, UserId, QuestionId, Answers, Context),
insert_questions(SurveyId, UserId, Rest, Context).

insert_answers(_SurveyId, _UserId, _QuestionId, [], _Context) ->
ok;
insert_answers(SurveyId, UserId, QuestionId, [{Name, Answer}|As], Context) ->
Args = case Answer of
{text, Text} -> [SurveyId, UserId, QuestionId, Name, undefined, Text];
Value -> [SurveyId, UserId, QuestionId, Name, z_convert:to_list(Value), undefined]
end,
z_db:q("insert into survey_answer (survey_id, user_id, question, name, value, text) values ($1, $2, $3, $4, $5, $6)", Args, Context),
insert_answers(SurveyId, UserId, QuestionId, As, Context).


%% @doc Fetch the aggregate answers of a survey, omitting the open text answers.
%% @spec survey_stats(int(), Context) -> [ {QuestionId, [{Name, [{Value,Count}] }] } ]
survey_stats(SurveyId, Context) ->
Rows = z_db:q("
select question, name, value, count(*)
from survey_answer
where survey_id = $1 and value is not null
group by question, name, value
order by question, name, value", [SurveyId], Context),
group_questions(Rows, []).

group_questions([], Acc) ->
lists:reverse(Acc);
group_questions([{Question,_,_,_}|_] = Answers, Acc) ->
{Qs,Answers1} = lists:splitwith(fun({Q,_,_,_}) -> Q == Question end, Answers),
NVs = case Qs of
[{_, Name, Value, Count}|QsTail] -> group_values(Name, [{Value, Count}], QsTail, []);
[] -> []
end,
group_questions(Answers1, [{Question,NVs}|Acc]).

group_values(Name, Values, [], Acc) ->
[{Name, Values}|Acc];
group_values(Name, Values, [{_,Name,V,C}|Rs], Acc) ->
group_values(Name, [{V,C}|Values], Rs, Acc);
group_values(Name, Values, [{_,N,V,C}|Rs], Acc) ->
group_values(N, [{V,C}], Rs, [{Name,Values}|Acc]).


%% @doc Install tables used for storing survey results
install(Context) ->
z_db:ensure_table(survey_answer, [
#column_def{name=id, type="serial", is_nullable=false},
#column_def{name=survey_id, type="integer", is_nullable=false},
#column_def{name=user_id, type="integer", is_nullable=true},
#column_def{name=question, type="character varying", length=32, is_nullable=false},
#column_def{name=name, type="character varying", length=32, is_nullable=false},
#column_def{name=value, type="character varying", length=80, is_nullable=true},
#column_def{name=text, type="bytea", is_nullable=true}
], Context),

% Add some indices and foreign keys, ignore errors
z_db:equery("create index fki_survey_answer_survey_id on survey_answer(survey_id)", Context),
z_db:equery("alter table survey_answer add
constraint fk_survey_answer_survey_id foreign key (survey_id) references rsc(id)
on update cascade on delete cascade", Context),

z_db:equery("create index fki_survey_answer_user_id on survey_answer(user_id)", Context),
z_db:equery("alter table survey_answer add
constraint fk_survey_answer_user_id foreign key (user_id) references rsc(id)
on update cascade on delete cascade", Context),

%% For aggregating answers to survey questions (group by name)
z_db:equery("create index survey_answer_survey_name_key on survey_answer(survey_id, name)", Context),
z_db:equery("create index survey_answer_survey_question_key on survey_answer(survey_id, question)", Context),
z_db:equery("create index survey_answer_survey_user_key on survey_answer(survey_id, user_id)", Context),

ok.

2 changes: 1 addition & 1 deletion modules/mod_survey/questions/survey_q_longanswer.erl
Expand Up @@ -55,7 +55,7 @@ answer(Q, Context) ->
undefined -> {error, missing};
Value -> case z_string:trim(Value) of
[] -> {error, missing};
V -> {ok, [{Name, V}]}
V -> {ok, [{Name, {text, V}}]}
end
end.

Expand Down
11 changes: 7 additions & 4 deletions modules/mod_survey/questions/survey_q_narrative.erl
Expand Up @@ -54,12 +54,14 @@ answer(Q, Context) ->

answer_inputs([], _Context, Acc) ->
{ok, Acc};
answer_inputs([Name|Rest], Context, Acc) ->
answer_inputs([{IsSelect,Name}|Rest], Context, Acc) ->
case z_context:get_q(Name, Context) of
undefined -> {error, missing};
Value -> case z_string:trim(Value) of
[] -> {error, missing};
V -> answer_inputs(Rest, Context, [{Name, V}|Acc])
V ->
V1 = case IsSelect of true -> V; false -> {text, V} end,
answer_inputs(Rest, Context, [{Name,V1}|Acc])
end
end.

Expand All @@ -73,11 +75,12 @@ parse([$[|T], in_text, [], Acc, InputAcc) ->
parse(T, in_input, [], Acc, InputAcc);
parse([$]|T], in_input, Input, Acc, InputAcc) ->
Input1 = lists:reverse(Input),
{Name, Elt} = case is_select(Input1) of
IsSelect = is_select(Input1),
{Name, Elt} = case IsSelect of
true -> build_select(Input1);
false -> build_input(Input1)
end,
parse(T, in_text, [], [Elt|Acc], [Name|InputAcc]);
parse(T, in_text, [], [Elt|Acc], [{IsSelect, Name}|InputAcc]);
parse([H|T], in_input, Input, Acc, InputAcc) ->
parse(T, in_input, [H|Input], Acc, InputAcc);
parse([10|T], in_text, [], Acc, InputAcc) ->
Expand Down
2 changes: 1 addition & 1 deletion modules/mod_survey/questions/survey_q_shortanswer.erl
Expand Up @@ -55,7 +55,7 @@ answer(Q, Context) ->
undefined -> {error, missing};
Value -> case z_string:trim(Value) of
[] -> {error, missing};
V -> {ok, [{Name, V}]}
V -> {ok, [{Name, {text, V}}]}
end
end.

Expand Down
15 changes: 12 additions & 3 deletions modules/mod_survey/support/survey_submit.erl
Expand Up @@ -16,8 +16,17 @@ submit(SurveyId, FormId, Context) ->
z_render:growl_error("Could not read survey information.", Context);
{survey, QIds, Qs} ->
{Answers, Missing, Accepted} = collect_answers(QIds, Qs, Context),
?DEBUG({Answers, Missing}),
mark_accepted(Accepted, mark_missing(Missing, Context))
case Missing of
[] ->
m_survey:insert_survey_submission(SurveyId, Answers, Context),
Context1 = mark_accepted(Accepted, mark_missing(Missing, Context)),
z_render:wire([
{slide_up, [{target, FormId}]},
{slide_down, [{target, FormId ++ "-success"}]}
], Context1);
_ ->
mark_accepted(Accepted, mark_missing(Missing, Context))
end
end.


Expand All @@ -40,7 +49,7 @@ collect_answers(QIds, Qs, Context) ->
collect_answers(QIds, Qs, Context, [], [], []).


collect_answers([], Qs, Context, Answers, Missing, Accepted) ->
collect_answers([], _Qs, _Context, Answers, Missing, Accepted) ->
{Answers, Missing, Accepted};
collect_answers([QId|QIds], Qs, Context, Answers, Missing, Accepted) ->
Q = proplists:get_value(QId, Qs),
Expand Down
8 changes: 8 additions & 0 deletions modules/mod_survey/templates/survey.tpl
Expand Up @@ -19,6 +19,10 @@

{% wire id=#survey type="submit" postback={survey_submit id=id} delegate="mod_survey" %}
<form id="{{ #survey }}" class="survey" method="POST" action="postback">
<p>
{{ m.rsc[id].summary }}
</p>

{% for q_id, q in m.survey.questions[id] %}
<div id="{{ q_id }}" class="survey-question clear-fix">
{{ q.html }}
Expand All @@ -30,4 +34,8 @@
<button class="survey-submit">Ready</button>
</form>

<div id="{{ #survey }}-success" style="display: none">
{{ m.rsc[id].body|show_media }}
</div>

{% endblock %}

0 comments on commit 6ec348e

Please sign in to comment.