Implement MCQ
This commit is contained in:
parent
7267af8513
commit
00f196bac3
@ -50,6 +50,11 @@ angular.module("AtsebaytApp")
|
|||||||
'update': {method: 'PUT'},
|
'update': {method: 'PUT'},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
.factory("QuestProposal", function($resource) {
|
||||||
|
return $resource("/api/surveys/:surveyId/questions/:questId/proposals", { surveyId: '@id', questId: '@id' }, {
|
||||||
|
'update': {method: 'PUT'},
|
||||||
|
})
|
||||||
|
})
|
||||||
.factory("User", function($resource) {
|
.factory("User", function($resource) {
|
||||||
return $resource("/api/users/:userId", { userId: '@id' }, {
|
return $resource("/api/users/:userId", { userId: '@id' }, {
|
||||||
'update': {method: 'PUT'},
|
'update': {method: 'PUT'},
|
||||||
@ -314,8 +319,14 @@ angular.module("AtsebaytApp")
|
|||||||
responses.forEach(function(response) {
|
responses.forEach(function(response) {
|
||||||
if (!questions[idxquestions[response.id_question]].response) {
|
if (!questions[idxquestions[response.id_question]].response) {
|
||||||
if (response.value) {
|
if (response.value) {
|
||||||
questions[idxquestions[response.id_question]].value = response.value;
|
|
||||||
questions[idxquestions[response.id_question]].response = response;
|
questions[idxquestions[response.id_question]].response = response;
|
||||||
|
if (questions[idxquestions[response.id_question]].kind == "text") {
|
||||||
|
questions[idxquestions[response.id_question]].value = response.value;
|
||||||
|
} else {
|
||||||
|
response.value.split(",").forEach(function (val) {
|
||||||
|
questions[idxquestions[response.id_question]]["p" + val] = true;
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -326,7 +337,18 @@ angular.module("AtsebaytApp")
|
|||||||
$scope.submitInProgress = true;
|
$scope.submitInProgress = true;
|
||||||
var res = [];
|
var res = [];
|
||||||
$scope.questions.forEach(function(q) {
|
$scope.questions.forEach(function(q) {
|
||||||
|
if (q.kind == "text")
|
||||||
res.push({"id_question": q.id, "value": q.value})
|
res.push({"id_question": q.id, "value": q.value})
|
||||||
|
else {
|
||||||
|
var values = [];
|
||||||
|
Object.keys(q).forEach(function (k) {
|
||||||
|
if (r = k.match(/^p([0-9]+)$/)) {
|
||||||
|
if (q[k])
|
||||||
|
values.push(r[1])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
res.push({"id_question": q.id, "value": values.join(",")})
|
||||||
|
}
|
||||||
});
|
});
|
||||||
$http({
|
$http({
|
||||||
url: "/api/surveys/" + $scope.survey.id,
|
url: "/api/surveys/" + $scope.survey.id,
|
||||||
@ -376,3 +398,29 @@ angular.module("AtsebaytApp")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
.controller("ProposalsController", function($scope, QuestProposal) {
|
||||||
|
$scope.proposals = QuestProposal.query({ surveyId: $scope.survey.id, questId: $scope.question.id });
|
||||||
|
|
||||||
|
$scope.saveProposal = function() {
|
||||||
|
if (this.proposal.id) {
|
||||||
|
this.proposal.$update({ surveyId: $scope.survey.id, questId: $scope.question.id });
|
||||||
|
} else {
|
||||||
|
this.proposal.$save({ surveyId: $scope.survey.id, questId: $scope.question.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.addProposal = function() {
|
||||||
|
$scope.proposals.push(new QuestProposal({}))
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.deleteProposal = function() {
|
||||||
|
if (this.proposal.id) {
|
||||||
|
this.proposal.$remove(function() {
|
||||||
|
$scope.proposals = QuestProposal.query({ surveyId: $scope.survey.id, questId: $scope.question.id });
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$scope.proposals.splice($scope.proposals.indexOf(this.proposal), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
@ -14,7 +14,13 @@
|
|||||||
<div class="card mb-2" ng-repeat="response in responses">
|
<div class="card mb-2" ng-repeat="response in responses">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<button class="btn btn-success ml-1 float-right" ng-click="submitCorrection()"><svg class="bi bi-check" width="1em" height="1em" viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M15.854 5.646a.5.5 0 010 .708l-7 7a.5.5 0 01-.708 0l-3.5-3.5a.5.5 0 11.708-.708L8.5 12.293l6.646-6.647a.5.5 0 01.708 0z" clip-rule="evenodd"></path></svg></button>
|
<button class="btn btn-success ml-1 float-right" ng-click="submitCorrection()"><svg class="bi bi-check" width="1em" height="1em" viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M15.854 5.646a.5.5 0 010 .708l-7 7a.5.5 0 01-.708 0l-3.5-3.5a.5.5 0 11.708-.708L8.5 12.293l6.646-6.647a.5.5 0 01.708 0z" clip-rule="evenodd"></path></svg></button>
|
||||||
<p class="card-text" style="white-space: pre-line" ng-bind="response.value"></p>
|
<p class="card-text" style="white-space: pre-line" ng-bind="response.value" ng-if="question.kind == 'text'"></p>
|
||||||
|
<div class="card-text" ng-if="question.kind == 'mcq'" ng-controller="ProposalsController">
|
||||||
|
<div class="form-group form-check" ng-repeat="proposal in proposals">
|
||||||
|
<input type="checkbox" disabled class="form-check-input" id="p{{proposal.id}}" ng-checked="response.value.indexOf(proposal.id) != -1">
|
||||||
|
<label class="form-check-label" for="p{{proposal.id}}">{{ proposal.label }}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-group mb-1">
|
<div class="input-group mb-1">
|
||||||
|
@ -86,7 +86,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="card-text text-center text-danger" ng-if="question.kind == 'mcq'">QCM non implémentés</p>
|
<div ng-controller="ProposalsController" ng-if="question.kind == 'mcq'">
|
||||||
|
<div class="form-group form-check" ng-if="!question.edit" ng-repeat="proposal in proposals">
|
||||||
|
<input type="checkbox" class="form-check-input" id="p{{proposal.id}}" ng-model="question['p' + proposal.id]" ng-disabled="survey.readonly">
|
||||||
|
<label class="form-check-label" for="p{{proposal.id}}">{{ proposal.label }}</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row" ng-if="question.edit" ng-repeat="proposal in proposals">
|
||||||
|
<div class="col">
|
||||||
|
<input type="text" class="form-control" id="pi{{proposal.id}}" placeholder="Label" ng-model="proposal.label">
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<button type="button" class="btn btn-success ml-1" ng-click="saveProposal()" ng-if="question.edit && question.kind == 'mcq'"><svg class="bi bi-check" width="1em" height="1em" viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M15.854 5.646a.5.5 0 010 .708l-7 7a.5.5 0 01-.708 0l-3.5-3.5a.5.5 0 11.708-.708L8.5 12.293l6.646-6.647a.5.5 0 01.708 0z" clip-rule="evenodd"></path></svg></button>
|
||||||
|
<button type="button" class="btn btn-danger ml-1" ng-click="deleteProposal()" ng-if="question.edit && question.kind == 'mcq'"><svg class="bi bi-trash-fill" width="1em" height="1em" viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.5 3a1 1 0 00-1 1v1a1 1 0 001 1H5v9a2 2 0 002 2h6a2 2 0 002-2V6h.5a1 1 0 001-1V4a1 1 0 00-1-1H12a1 1 0 00-1-1H9a1 1 0 00-1 1H4.5zm3 4a.5.5 0 01.5.5v7a.5.5 0 01-1 0v-7a.5.5 0 01.5-.5zM10 7a.5.5 0 01.5.5v7a.5.5 0 01-1 0v-7A.5.5 0 0110 7zm3 .5a.5.5 0 00-1 0v7a.5.5 0 001 0v-7z" clip-rule="evenodd"></path></svg></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-info ml-1" ng-click="addProposal()" ng-if="question.edit && question.kind == 'mcq'"><svg class="bi bi-plus" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 3.5a.5.5 0 01.5.5v4a.5.5 0 01-.5.5H4a.5.5 0 010-1h3.5V4a.5.5 0 01.5-.5z" clip-rule="evenodd"></path><path fill-rule="evenodd" d="M7.5 8a.5.5 0 01.5-.5h4a.5.5 0 010 1H8.5V12a.5.5 0 01-1 0V8z" clip-rule="evenodd"></path></svg> Ajouter des proposals
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p class="card-text alert alert-success" style="white-space: pre-line" ng-if="!question.edit && (question.response.score_explaination || question.response.score)"><strong>{{question.response.score}} :</strong> {{ question.response.score_explaination }}</p>
|
<p class="card-text alert alert-success" style="white-space: pre-line" ng-if="!question.edit && (question.response.score_explaination || question.response.score)"><strong>{{question.response.score}} :</strong> {{ question.response.score_explaination }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
147
proposals.go
Normal file
147
proposals.go
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
router.GET("/api/questions/:qid/proposals", apiAuthHandler(questionAuthHandler(
|
||||||
|
func(q Question, u *User, _ []byte) HTTPResponse {
|
||||||
|
return formatApiResponse(q.GetProposals())
|
||||||
|
}), loggedUser))
|
||||||
|
router.GET("/api/surveys/:sid/questions/:qid/proposals", apiAuthHandler(questionAuthHandler(
|
||||||
|
func(q Question, u *User, _ []byte) HTTPResponse {
|
||||||
|
return formatApiResponse(q.GetProposals())
|
||||||
|
}), loggedUser))
|
||||||
|
router.POST("/api/surveys/:sid/questions/:qid/proposals", apiAuthHandler(questionAuthHandler(func(q Question, u *User, body []byte) HTTPResponse {
|
||||||
|
var new Proposal
|
||||||
|
if err := json.Unmarshal(body, &new); err != nil {
|
||||||
|
return APIErrorResponse{err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatApiResponse(q.NewProposal(new.Label))
|
||||||
|
}), adminRestricted))
|
||||||
|
router.PUT("/api/surveys/:sid/questions/:qid/proposals/:pid", apiAuthHandler(proposalAuthHandler(func(current Proposal, u *User, body []byte) HTTPResponse {
|
||||||
|
var new Proposal
|
||||||
|
if err := json.Unmarshal(body, &new); err != nil {
|
||||||
|
return APIErrorResponse{err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
new.Id = current.Id
|
||||||
|
return formatApiResponse(new.Update())
|
||||||
|
}), adminRestricted))
|
||||||
|
router.DELETE("/api/surveys/:sid/questions/:qid/proposals/:pid", apiAuthHandler(proposalAuthHandler(func(p Proposal, u *User, body []byte) HTTPResponse {
|
||||||
|
return formatApiResponse(p.Delete())
|
||||||
|
}), adminRestricted))
|
||||||
|
}
|
||||||
|
|
||||||
|
func proposalHandler(f func(Proposal, []byte) HTTPResponse) func(httprouter.Params, []byte) HTTPResponse {
|
||||||
|
return func(ps httprouter.Params, body []byte) HTTPResponse {
|
||||||
|
var question *Question = nil
|
||||||
|
|
||||||
|
if qid, err := strconv.Atoi(string(ps.ByName("qid"))); err == nil {
|
||||||
|
if q, err := getQuestion(qid); err == nil {
|
||||||
|
question = &q
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pid, err := strconv.Atoi(string(ps.ByName("pid"))); err != nil {
|
||||||
|
return APIErrorResponse{err: err}
|
||||||
|
} else if question == nil {
|
||||||
|
if proposal, err := getProposal(pid); err != nil {
|
||||||
|
return APIErrorResponse{err: err}
|
||||||
|
} else {
|
||||||
|
return f(proposal, body)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if proposal, err := question.GetProposal(pid); err != nil {
|
||||||
|
return APIErrorResponse{err: err}
|
||||||
|
} else {
|
||||||
|
return f(proposal, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func proposalAuthHandler(f func(Proposal, *User, []byte) HTTPResponse) func(*User, httprouter.Params, []byte) HTTPResponse {
|
||||||
|
return func(u *User, ps httprouter.Params, body []byte) HTTPResponse {
|
||||||
|
return proposalHandler(func(p Proposal, body []byte) HTTPResponse {
|
||||||
|
return f(p, u, body)
|
||||||
|
})(ps, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Proposal struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
IdQuestion int64 `json:"id_question"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Question) GetProposals() (proposals []Proposal, err error) {
|
||||||
|
if rows, errr := DBQuery("SELECT id_proposal, id_question, label FROM survey_proposals WHERE id_question=?", q.Id); errr != nil {
|
||||||
|
return nil, errr
|
||||||
|
} else {
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var p Proposal
|
||||||
|
if err = rows.Scan(&p.Id, &p.IdQuestion, &p.Label); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
proposals = append(proposals, p)
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getProposal(id int) (p Proposal, err error) {
|
||||||
|
err = DBQueryRow("SELECT id_proposal, id_question, label FROM survey_proposals WHERE id_proposal=?", id).Scan(&p.Id, &p.IdQuestion, &p.Label)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Question) GetProposal(id int) (p Proposal, err error) {
|
||||||
|
err = DBQueryRow("SELECT id_proposal, id_question, label FROM survey_proposals WHERE id_proposal=? AND id_question=?", id, q.Id).Scan(&p.Id, &p.IdQuestion, &p.Label)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Question) NewProposal(label string) (Proposal, error) {
|
||||||
|
if res, err := DBExec("INSERT INTO survey_proposals (id_question, label) VALUES (?, ?)", q.Id, label); err != nil {
|
||||||
|
return Proposal{}, err
|
||||||
|
} else if pid, err := res.LastInsertId(); err != nil {
|
||||||
|
return Proposal{}, err
|
||||||
|
} else {
|
||||||
|
return Proposal{pid, q.Id, label}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Proposal) Update() (Proposal, error) {
|
||||||
|
_, err := DBExec("UPDATE survey_proposals SET id_question = ?, label = ? WHERE id_proposal = ?", p.IdQuestion, p.Label, p.Id)
|
||||||
|
return p, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Proposal) Delete() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM survey_proposals WHERE id_proposal = ?", p.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClearProposals() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM survey_proposals"); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user