Add correction steps
This commit is contained in:
parent
1d8c4a375c
commit
7201c3d02a
326
corrections.go
Normal file
326
corrections.go
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
router.GET("/api/surveys/:sid/questions/:qid/corrections", apiHandler(questionHandler(
|
||||||
|
func(q Question, _ []byte) HTTPResponse {
|
||||||
|
if cts, err := q.GetCorrectionTemplates(); err != nil {
|
||||||
|
return APIErrorResponse{err: err}
|
||||||
|
} else {
|
||||||
|
return APIResponse{cts}
|
||||||
|
}
|
||||||
|
}), adminRestricted))
|
||||||
|
router.POST("/api/surveys/:sid/questions/:qid/corrections", apiHandler(questionHandler(func(q Question, body []byte) HTTPResponse {
|
||||||
|
var new CorrectionTemplate
|
||||||
|
if err := json.Unmarshal(body, &new); err != nil {
|
||||||
|
return APIErrorResponse{err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatApiResponse(q.NewCorrectionTemplate(new.Label, new.Score, new.ScoreExplaination))
|
||||||
|
}), adminRestricted))
|
||||||
|
|
||||||
|
router.GET("/api/surveys/:sid/questions/:qid/corrections/:cid", apiHandler(correctionHandler(
|
||||||
|
func(ct CorrectionTemplate, _ []byte) HTTPResponse {
|
||||||
|
if users, err := ct.GetUserCorrected(); err != nil {
|
||||||
|
return APIErrorResponse{err: err}
|
||||||
|
} else {
|
||||||
|
return APIResponse{users}
|
||||||
|
}
|
||||||
|
}), adminRestricted))
|
||||||
|
router.PUT("/api/surveys/:sid/questions/:qid/corrections/:cid", apiHandler(correctionHandler(func(current CorrectionTemplate, body []byte) HTTPResponse {
|
||||||
|
var new CorrectionTemplate
|
||||||
|
if err := json.Unmarshal(body, &new); err != nil {
|
||||||
|
return APIErrorResponse{err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
new.Id = current.Id
|
||||||
|
if err := new.Update(); err != nil {
|
||||||
|
return APIErrorResponse{err: err}
|
||||||
|
} else {
|
||||||
|
return APIResponse{new}
|
||||||
|
}
|
||||||
|
}), adminRestricted))
|
||||||
|
router.DELETE("/api/surveys/:sid/questions/:qid/corrections/:cid", apiHandler(correctionHandler(func(ct CorrectionTemplate, body []byte) HTTPResponse {
|
||||||
|
return formatApiResponse(ct.Delete())
|
||||||
|
}), adminRestricted))
|
||||||
|
|
||||||
|
router.GET("/api/users/:uid/questions/:qid", apiAuthHandler(func(u *User, ps httprouter.Params, body []byte) HTTPResponse {
|
||||||
|
return userHandler(func(u User, _ []byte) HTTPResponse {
|
||||||
|
if qid, err := strconv.Atoi(string(ps.ByName("qid"))); err != nil {
|
||||||
|
return APIErrorResponse{err: err}
|
||||||
|
} else if question, err := getQuestion(qid); err != nil {
|
||||||
|
return APIErrorResponse{err: err}
|
||||||
|
} else {
|
||||||
|
return formatApiResponse(question.ComputeScoreQuestion(&u))
|
||||||
|
}
|
||||||
|
})(ps, body)
|
||||||
|
}, adminRestricted))
|
||||||
|
|
||||||
|
router.GET("/api/users/:uid/corrections", apiHandler(userHandler(
|
||||||
|
func(u User, _ []byte) HTTPResponse {
|
||||||
|
return formatApiResponse(u.GetCorrections())
|
||||||
|
}), adminRestricted))
|
||||||
|
router.POST("/api/users/:uid/corrections", apiHandler(userHandler(func(u User, body []byte) HTTPResponse {
|
||||||
|
var new UserCorrection
|
||||||
|
if err := json.Unmarshal(body, &new); err != nil {
|
||||||
|
return APIErrorResponse{err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatApiResponse(u.NewCorrection(new.IdTemplate))
|
||||||
|
}), adminRestricted))
|
||||||
|
router.DELETE("/api/users/:uid/corrections/:cid", apiHandler(userCorrectionHandler(func(u User, uc UserCorrection, body []byte) HTTPResponse {
|
||||||
|
return formatApiResponse(uc.Delete(u))
|
||||||
|
}), adminRestricted))
|
||||||
|
}
|
||||||
|
|
||||||
|
func correctionHandler(f func(CorrectionTemplate, []byte) HTTPResponse) func(httprouter.Params, []byte) HTTPResponse {
|
||||||
|
return func(ps httprouter.Params, body []byte) HTTPResponse {
|
||||||
|
return questionHandler(func(q Question, body []byte) HTTPResponse {
|
||||||
|
if cid, err := strconv.Atoi(string(ps.ByName("cid"))); err != nil {
|
||||||
|
return APIErrorResponse{err: err}
|
||||||
|
} else if correction, err := q.GetCorrectionTemplate(cid); err != nil {
|
||||||
|
return APIErrorResponse{err: err}
|
||||||
|
} else {
|
||||||
|
return f(correction, body)
|
||||||
|
}
|
||||||
|
})(ps, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func userCorrectionHandler(f func(User, UserCorrection, []byte) HTTPResponse) func(httprouter.Params, []byte) HTTPResponse {
|
||||||
|
return func(ps httprouter.Params, body []byte) HTTPResponse {
|
||||||
|
return userHandler(func(u User, body []byte) HTTPResponse {
|
||||||
|
if cid, err := strconv.Atoi(string(ps.ByName("cid"))); err != nil {
|
||||||
|
return APIErrorResponse{err: err}
|
||||||
|
} else if correction, err := u.GetCorrection(cid); err != nil {
|
||||||
|
return APIErrorResponse{err: err}
|
||||||
|
} else {
|
||||||
|
return f(u, correction, body)
|
||||||
|
}
|
||||||
|
})(ps, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type CorrectionTemplate struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
IdQuestion int64 `json:"id_question"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
Score int `json:"score"`
|
||||||
|
ScoreExplaination string `json:"score_explaination,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Question) GetCorrectionTemplates() (ct []CorrectionTemplate, err error) {
|
||||||
|
if rows, errr := DBQuery("SELECT id_template, id_question, label, score, score_explanation FROM correction_templates WHERE id_question=?", q.Id); errr != nil {
|
||||||
|
return nil, errr
|
||||||
|
} else {
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var c CorrectionTemplate
|
||||||
|
if err = rows.Scan(&c.Id, &c.IdQuestion, &c.Label, &c.Score, &c.ScoreExplaination); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ct = append(ct, c)
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Question) GetCorrectionTemplate(id int) (c CorrectionTemplate, err error) {
|
||||||
|
err = DBQueryRow("SELECT id_template, id_question, label, score, score_explanation FROM correction_templates WHERE id_question=? AND id_template=?", q.Id, id).Scan(&c.Id, &c.IdQuestion, &c.Label, &c.Score, &c.ScoreExplaination)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCorrectionTemplate(id int64) (c CorrectionTemplate, err error) {
|
||||||
|
err = DBQueryRow("SELECT id_template, id_question, label, score, score_explanation FROM correction_templates WHERE id_template=?", id).Scan(&c.Id, &c.IdQuestion, &c.Label, &c.Score, &c.ScoreExplaination)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Question) NewCorrectionTemplate(label string, score int, score_explaination string) (CorrectionTemplate, error) {
|
||||||
|
if res, err := DBExec("INSERT INTO correction_templates (id_question, label, score, score_explanation) VALUES (?, ?, ?, ?)", q.Id, label, score, score_explaination); err != nil {
|
||||||
|
return CorrectionTemplate{}, err
|
||||||
|
} else if cid, err := res.LastInsertId(); err != nil {
|
||||||
|
return CorrectionTemplate{}, err
|
||||||
|
} else {
|
||||||
|
return CorrectionTemplate{cid, q.Id, label, score, score_explaination}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *CorrectionTemplate) Update() error {
|
||||||
|
_, err := DBExec("UPDATE correction_templates SET id_question = ?, label = ?, score = ?, score_explanation = ? WHERE id_template = ?", t.IdQuestion, t.Label, t.Score, t.ScoreExplaination, t.Id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *CorrectionTemplate) Delete() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM correction_templates WHERE id_template = ?", t.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *CorrectionTemplate) GetUserCorrected() (ucs []UserCorrection, err error) {
|
||||||
|
if rows, errr := DBQuery("SELECT id_correction, id_user, id_template FROM student_corrected WHERE id_template=?", t.Id); errr != nil {
|
||||||
|
return nil, errr
|
||||||
|
} else {
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var c UserCorrection
|
||||||
|
if err = rows.Scan(&c.Id, &c.IdUser, &c.IdTemplate); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ucs = append(ucs, c)
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClearTemplates() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM correction_templates"); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserCorrection struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
IdUser int64 `json:"id_user,omitempty"`
|
||||||
|
IdTemplate int64 `json:"id_template"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) GetCorrections() (uc []UserCorrection, err error) {
|
||||||
|
if rows, errr := DBQuery("SELECT id_correction, id_template FROM student_corrected WHERE id_user=?", u.Id); errr != nil {
|
||||||
|
return nil, errr
|
||||||
|
} else {
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var c UserCorrection
|
||||||
|
if err = rows.Scan(&c.Id, &c.IdTemplate); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uc = append(uc, c)
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) GetCorrectionsTemplate() (tpls []int64, err error) {
|
||||||
|
if rows, errr := DBQuery("SELECT id_template FROM student_corrected WHERE id_user=?", u.Id); errr != nil {
|
||||||
|
return nil, errr
|
||||||
|
} else {
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var tpl int64
|
||||||
|
if err = rows.Scan(&tpl); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tpls = append(tpls, tpl)
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) GetCorrection(id int) (c UserCorrection, err error) {
|
||||||
|
err = DBQueryRow("SELECT id_correction, id_template FROM student_corrected WHERE id_user=? AND id_correction=?", u.Id, id).Scan(&c.Id, &c.IdTemplate)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) NewCorrection(id int64) (*UserCorrectionSummary, error) {
|
||||||
|
if res, err := DBExec("INSERT INTO student_corrected (id_user, id_template) VALUES (?, ?)", u.Id, id); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if cid, err := res.LastInsertId(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if ucs, err := u.ComputeScoreQuestion(id); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
ucs.LastId = cid
|
||||||
|
return ucs, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *UserCorrection) Delete(u User) (*UserCorrectionSummary, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM student_corrected WHERE id_correction = ?", c.Id); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if _, err := res.RowsAffected(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if ucs, err := u.ComputeScoreQuestion(c.IdTemplate); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return ucs, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserCorrectionSummary struct {
|
||||||
|
LastId int64 `json:"last_id,omitempty"`
|
||||||
|
Score int `json:"score"`
|
||||||
|
ScoreExplaination string `json:"score_explaination"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) ComputeScoreQuestion(idtpl int64) (*UserCorrectionSummary, error) {
|
||||||
|
if tpl, err := GetCorrectionTemplate(idtpl); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if question, err := getQuestion(int(tpl.IdQuestion)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return question.ComputeScoreQuestion(u)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Question) ComputeScoreQuestion(u *User) (*UserCorrectionSummary, error) {
|
||||||
|
if templates, err := q.GetCorrectionTemplates(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if corrections, err := u.GetCorrectionsTemplate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
tpls := map[int64]CorrectionTemplate{}
|
||||||
|
for _, tpl := range templates {
|
||||||
|
tpls[tpl.Id] = tpl
|
||||||
|
}
|
||||||
|
|
||||||
|
score := 100
|
||||||
|
var expl []string
|
||||||
|
|
||||||
|
for _, correction := range corrections {
|
||||||
|
if _, ok := tpls[correction]; ok {
|
||||||
|
score += tpls[correction].Score
|
||||||
|
if tpls[correction].ScoreExplaination != "" {
|
||||||
|
expl = append(expl, tpls[correction].ScoreExplaination)
|
||||||
|
}
|
||||||
|
delete(tpls, correction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &UserCorrectionSummary{Score: score, ScoreExplaination: strings.Join(expl, ". ")}, nil
|
||||||
|
}
|
||||||
|
}
|
11
db.go
11
db.go
@ -137,6 +137,17 @@ CREATE TABLE IF NOT EXISTS correction_templates(
|
|||||||
score_explanation TEXT,
|
score_explanation TEXT,
|
||||||
FOREIGN KEY(id_question) REFERENCES survey_quests(id_question)
|
FOREIGN KEY(id_question) REFERENCES survey_quests(id_question)
|
||||||
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin;
|
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin;
|
||||||
|
`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := db.Exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS student_corrected(
|
||||||
|
id_correction INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
id_user INTEGER NOT NULL,
|
||||||
|
id_template INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY(id_user) REFERENCES users(id_user),
|
||||||
|
FOREIGN KEY(id_template) REFERENCES correction_templates(id_template)
|
||||||
|
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin;
|
||||||
`); err != nil {
|
`); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,11 @@ angular.module("AtsebaytApp")
|
|||||||
'update': {method: 'PUT'},
|
'update': {method: 'PUT'},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
.factory("CorrectionTemplate", function($resource) {
|
||||||
|
return $resource("/api/surveys/:surveyId/questions/:questId/corrections/:correctId", { surveyId: '@id', questId: '@id', correctId: '@id' }, {
|
||||||
|
'update': {method: 'PUT'},
|
||||||
|
})
|
||||||
|
})
|
||||||
.factory("MyResponse", function($resource) {
|
.factory("MyResponse", function($resource) {
|
||||||
return $resource("/api/surveys/:surveyId/responses/:respId", { surveyId: '@id', respId: '@id' })
|
return $resource("/api/surveys/:surveyId/responses/:respId", { surveyId: '@id', respId: '@id' })
|
||||||
})
|
})
|
||||||
@ -135,7 +140,8 @@ angular.module("AtsebaytApp")
|
|||||||
<td class="bg-success" ng-if="survey.end_availability < $ctrl.now && survey.corrected">Corrigé</td>
|
<td class="bg-success" ng-if="survey.end_availability < $ctrl.now && survey.corrected">Corrigé</td>
|
||||||
<td ng-if="survey.start_availability > $ctrl.now">{{ survey.start_availability | date: "medium" }} <svg class="bi bi-arrow-bar-right" width="1em" height="1em" viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12.146 6.646a.5.5 0 01.708 0l3 3a.5.5 0 010 .708l-3 3a.5.5 0 01-.708-.708L14.793 10l-2.647-2.646a.5.5 0 010-.708z" clip-rule="evenodd"></path><path fill-rule="evenodd" d="M8 10a.5.5 0 01.5-.5H15a.5.5 0 010 1H8.5A.5.5 0 018 10zm-2.5 6a.5.5 0 01-.5-.5v-11a.5.5 0 011 0v11a.5.5 0 01-.5.5z" clip-rule="evenodd"></path></svg></td>
|
<td ng-if="survey.start_availability > $ctrl.now">{{ survey.start_availability | date: "medium" }} <svg class="bi bi-arrow-bar-right" width="1em" height="1em" viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12.146 6.646a.5.5 0 01.708 0l3 3a.5.5 0 010 .708l-3 3a.5.5 0 01-.708-.708L14.793 10l-2.647-2.646a.5.5 0 010-.708z" clip-rule="evenodd"></path><path fill-rule="evenodd" d="M8 10a.5.5 0 01.5-.5H15a.5.5 0 010 1H8.5A.5.5 0 018 10zm-2.5 6a.5.5 0 01-.5-.5v-11a.5.5 0 011 0v11a.5.5 0 01-.5.5z" clip-rule="evenodd"></path></svg></td>
|
||||||
<td ng-if="survey.start_availability <= $ctrl.now"><svg class="bi bi-arrow-bar-left" width="1em" height="1em" viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.854 6.646a.5.5 0 00-.708 0l-3 3a.5.5 0 000 .708l3 3a.5.5 0 00.708-.708L5.207 10l2.647-2.646a.5.5 0 000-.708z" clip-rule="evenodd"></path><path fill-rule="evenodd" d="M12 10a.5.5 0 00-.5-.5H5a.5.5 0 000 1h6.5a.5.5 0 00.5-.5zm2.5 6a.5.5 0 01-.5-.5v-11a.5.5 0 011 0v11a.5.5 0 01-.5.5z" clip-rule="evenodd"></path></svg> {{ survey.end_availability | date: "medium" }}</td>
|
<td ng-if="survey.start_availability <= $ctrl.now"><svg class="bi bi-arrow-bar-left" width="1em" height="1em" viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.854 6.646a.5.5 0 00-.708 0l-3 3a.5.5 0 000 .708l3 3a.5.5 0 00.708-.708L5.207 10l2.647-2.646a.5.5 0 000-.708z" clip-rule="evenodd"></path><path fill-rule="evenodd" d="M12 10a.5.5 0 00-.5-.5H5a.5.5 0 000 1h6.5a.5.5 0 00.5-.5zm2.5 6a.5.5 0 01-.5-.5v-11a.5.5 0 011 0v11a.5.5 0 01-.5.5z" clip-rule="evenodd"></path></svg> {{ survey.end_availability | date: "medium" }}</td>
|
||||||
<td ng-if="$ctrl.islogged">N/A</td>
|
<td ng-if="$ctrl.islogged && !survey.corrected">N/A</td>
|
||||||
|
<td ng-if="$ctrl.islogged && survey.corrected" ng-controller="ScoreController">{{ score.score }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
<tfoot ng-if="$ctrl.isadmin">
|
<tfoot ng-if="$ctrl.isadmin">
|
||||||
@ -276,19 +282,43 @@ angular.module("AtsebaytApp")
|
|||||||
})
|
})
|
||||||
|
|
||||||
.controller("ScoreController", function($scope, SurveyScore) {
|
.controller("ScoreController", function($scope, SurveyScore) {
|
||||||
$scope.score = SurveyScore.get({ surveyId: $scope.survey.id, questId: $scope.question.id })
|
$scope.score = SurveyScore.get({ surveyId: $scope.survey.id })
|
||||||
})
|
})
|
||||||
|
|
||||||
.controller("QuestionController", function($scope, Survey, SurveyQuest, SurveyQuest, AllResponses, $http, $routeParams) {
|
.controller("QuestionController", function($scope, Survey, SurveyQuest, SurveyQuest, AllResponses, CorrectionTemplate, $http, $routeParams) {
|
||||||
$scope.survey = Survey.get({ surveyId: $routeParams.surveyId });
|
$scope.survey = Survey.get({ surveyId: $routeParams.surveyId });
|
||||||
$scope.survey.$promise.then(function(survey) {
|
$scope.survey.$promise.then(function(survey) {
|
||||||
survey.start_availability = Date.parse(survey.start_availability)
|
survey.start_availability = Date.parse(survey.start_availability)
|
||||||
survey.end_availability = Date.parse(survey.end_availability)
|
survey.end_availability = Date.parse(survey.end_availability)
|
||||||
})
|
})
|
||||||
$scope.question = SurveyQuest.get({ surveyId: $routeParams.surveyId, questId: $routeParams.questId });
|
$scope.question = SurveyQuest.get({ surveyId: $routeParams.surveyId, questId: $routeParams.questId });
|
||||||
$scope.responses = AllResponses.query({ surveyId: $routeParams.surveyId, questId: $routeParams.questId });
|
$scope.responses = AllResponses.query({ surveyId: $routeParams.surveyId, questId: $routeParams.questId }, function (responses) {
|
||||||
|
$scope.users_corrected = {}
|
||||||
|
|
||||||
|
responses.forEach(function(r) {
|
||||||
|
$http({
|
||||||
|
url: "/api/users/" + r.id_user + "/questions/" + $routeParams.questId
|
||||||
|
}).then(function(response) {
|
||||||
|
$scope.users_corrected[r.id_user] = response.data
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
$scope.submitCorrection = function() {
|
$scope.submitCorrection = function() {
|
||||||
|
if ($scope.users_corrected[this.response.id_user]) {
|
||||||
|
if (this.response.score === undefined)
|
||||||
|
this.response.score = $scope.users_corrected[this.response.id_user].score
|
||||||
|
if ($scope.users_corrected[this.response.id_user].score_explaination && (!this.response.score_explaination || this.response.score_explaination.indexOf($scope.users_corrected[this.response.id_user].score_explaination) == -1)) {
|
||||||
|
if (this.response.score_explaination)
|
||||||
|
this.response.score_explaination += '\n' + $scope.users_corrected[this.response.id_user].score_explaination
|
||||||
|
else
|
||||||
|
this.response.score_explaination = $scope.users_corrected[this.response.id_user].score_explaination
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.response.id_corrector = $scope.user.id
|
||||||
|
if (!this.response.time_scored)
|
||||||
|
this.response.time_scored = (new Date()).toISOString()
|
||||||
this.response.$update()
|
this.response.$update()
|
||||||
}
|
}
|
||||||
$scope.submitCorrections = function() {
|
$scope.submitCorrections = function() {
|
||||||
@ -296,6 +326,76 @@ angular.module("AtsebaytApp")
|
|||||||
response.$update()
|
response.$update()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$scope.templates = CorrectionTemplate.query({ surveyId: $routeParams.surveyId, questId: $routeParams.questId }, function (tpls) {
|
||||||
|
$scope.template_corrected = {}
|
||||||
|
tpls.forEach(function(tpl) {
|
||||||
|
$scope.template_corrected[tpl.id] = {}
|
||||||
|
|
||||||
|
CorrectionTemplate.query({ surveyId: $routeParams.surveyId, questId: $routeParams.questId, correctId: tpl.id }, function (cts) {
|
||||||
|
cts.forEach(function(ct) {
|
||||||
|
$scope.template_corrected[tpl.id][ct.id_user] = ct
|
||||||
|
})
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.changeCorrection = function(id_user) {
|
||||||
|
var tpl = this.template
|
||||||
|
if ($scope.template_corrected[tpl.id] && $scope.template_corrected[tpl.id][id_user]) {
|
||||||
|
$http({
|
||||||
|
url: "/api/users/" + id_user + "/corrections/" + $scope.template_corrected[tpl.id][id_user].id,
|
||||||
|
method: "DELETE"
|
||||||
|
}).then(function(response) {
|
||||||
|
$scope.template_corrected[tpl.id][id_user] = false
|
||||||
|
$scope.users_corrected[id_user] = response.data
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
$http({
|
||||||
|
url: "/api/users/" + id_user + "/corrections",
|
||||||
|
data: {id_template: tpl.id},
|
||||||
|
method: "POST"
|
||||||
|
}).then(function(response) {
|
||||||
|
if ($scope.template_corrected[tpl.id] === undefined)
|
||||||
|
$scope.template_corrected[tpl.id] = {}
|
||||||
|
$scope.template_corrected[tpl.id][id_user] = { id: response.data.last_id, id_template: tpl.id }
|
||||||
|
$scope.users_corrected[id_user] = response.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.deleteTemplate = function() {
|
||||||
|
var template = new CorrectionTemplate({
|
||||||
|
id: $('#tcid').val() == "" ? null : parseInt($('#tcid').val()),
|
||||||
|
})
|
||||||
|
|
||||||
|
template.$remove({ surveyId: $scope.survey.id, questId: $scope.question.id, correctId: template.id }, function() {
|
||||||
|
$scope.templates = CorrectionTemplate.query({ surveyId: $scope.survey.id, questId: $scope.question.id });
|
||||||
|
angular.element('#correctionTemplateModal').modal('hide')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.saveTemplate = function() {
|
||||||
|
var template = new CorrectionTemplate({
|
||||||
|
id: $('#tcid').val() == "" ? null : parseInt($('#tcid').val()),
|
||||||
|
id_question: parseInt($('#tcidquestion').val()),
|
||||||
|
label: $('#tclabel').val(),
|
||||||
|
score: parseInt($('#tcscore').val()),
|
||||||
|
score_explaination: $('#tcexplaination').val()
|
||||||
|
})
|
||||||
|
|
||||||
|
if (template.id) {
|
||||||
|
template.$update({ surveyId: $scope.survey.id, questId: $scope.question.id, correctId: template.id }, function () {
|
||||||
|
$scope.templates = CorrectionTemplate.query({ surveyId: $scope.survey.id, questId: $scope.question.id });
|
||||||
|
angular.element('#correctionTemplateModal').modal('hide')
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
template.$save({ surveyId: $scope.survey.id, questId: $scope.question.id }, function () {
|
||||||
|
$scope.templates = CorrectionTemplate.query({ surveyId: $scope.survey.id, questId: $scope.question.id });
|
||||||
|
angular.element('#correctionTemplateModal').modal('hide')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
.controller("QuestionsController", function($scope, SurveyQuest, MyResponse, $http, $location) {
|
.controller("QuestionsController", function($scope, SurveyQuest, MyResponse, $http, $location) {
|
||||||
@ -424,3 +524,24 @@ angular.module("AtsebaytApp")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
.controller("CorrectionsTemplateController", function($scope, CorrectionTemplate) {
|
||||||
|
$scope.addTemplate = function() {
|
||||||
|
var element = angular.element('#correctionTemplateModal');
|
||||||
|
var tpl = new CorrectionTemplate({id_question: $scope.question.id})
|
||||||
|
if (element.data('bs.modal'))
|
||||||
|
element.data('bs.modal')._config.template = tpl
|
||||||
|
element.modal({
|
||||||
|
template: tpl
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.editTemplate = function() {
|
||||||
|
var element = angular.element('#correctionTemplateModal');
|
||||||
|
if (element.data('bs.modal'))
|
||||||
|
element.data('bs.modal')._config.template = this.template
|
||||||
|
element.modal({
|
||||||
|
template: this.template
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
@ -10,10 +10,10 @@
|
|||||||
{{ question.title }}
|
{{ question.title }}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<form class="mb-5" ng-submit="submitCorrections()" ng-cloak>
|
<div class="mb-5" ng-submit="submitCorrections()" ng-cloak>
|
||||||
<div class="card mb-2" ng-repeat="response in responses">
|
<form 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 type="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" ng-if="question.kind == 'text'"></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="card-text" ng-if="question.kind == 'mcq'" ng-controller="ProposalsController">
|
||||||
<div class="form-group form-check" ng-repeat="proposal in proposals">
|
<div class="form-group form-check" ng-repeat="proposal in proposals">
|
||||||
@ -28,31 +28,114 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="row">
|
||||||
<div class="input-group mb-1">
|
<div class="col-6" ng-controller="CorrectionsTemplateController">
|
||||||
|
<div ng-repeat="template in templates">
|
||||||
|
<div class="form-group mb-2 form-check">
|
||||||
|
<input type="checkbox" class="form-check-input" id="u{{response.id_user}}p{{template.id}}" ng-checked="template_corrected[template.id][response.id_user]" ng-click="changeCorrection(response.id_user)">
|
||||||
|
<label class="form-check-label" for="u{{response.id_user}}p{{template.id}}">{{ template.label }}</label>
|
||||||
|
<button type="button" class="btn btn-sm btn-primary ml-1 float-right" ng-click="editTemplate()"><svg class="bi bi-pencil" width="1em" height="1em" viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.293 3.293a1 1 0 011.414 0l2 2a1 1 0 010 1.414l-9 9a1 1 0 01-.39.242l-3 1a1 1 0 01-1.266-1.265l1-3a1 1 0 01.242-.391l9-9zM14 4l2 2-9 9-3 1 1-3 9-9z" clip-rule="evenodd"></path><path fill-rule="evenodd" d="M14.146 8.354l-2.5-2.5.708-.708 2.5 2.5-.708.708zM5 12v.5a.5.5 0 00.5.5H6v.5a.5.5 0 00.5.5H7v.5a.5.5 0 00.5.5H8v-1.5a.5.5 0 00-.5-.5H7v-.5a.5.5 0 00-.5-.5H5z" clip-rule="evenodd"></path></svg></button>
|
||||||
|
<button type="button" class="btn btn-sm btn-info ml-1 float-right" ng-click="addTemplate()" ng-if="$last"><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></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-info ml-1 float-right" ng-click="addTemplate()" ng-if="templates.length === 0"><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 un template</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-6">
|
||||||
|
<div class="form-group row mb-2">
|
||||||
|
<div class="col-6 input-group">
|
||||||
<input class="form-control" type="number" ng-model="response.score" integer>
|
<input class="form-control" type="number" ng-model="response.score" integer>
|
||||||
<div class="input-group-append">
|
<div class="input-group-append">
|
||||||
<span class="input-group-text">/100</span>
|
<span class="input-group-text">/100</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-6 row">
|
||||||
|
<label class="col-4 col-form-label">Auto :</label>
|
||||||
|
<div class="col-8">
|
||||||
|
<input type="text" class="form-control-plaintext" value="{{ users_corrected[response.id_user].score}} / 100" readonly>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
|
||||||
<textarea class="form-control" rows="1" ng-model="response.score_explaination" placeholder="Appréciation"></textarea>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row" ng-if="response.time_scored">
|
</div>
|
||||||
<label class="col-2 col-form-label col-form-label-sm">Correction effectuée :</label>
|
<div class="form-group mb-2">
|
||||||
<div class="col-10">
|
<textarea class="form-control" rows="1" ng-model="response.score_explaination" placeholder="Appréciation : "></textarea>
|
||||||
|
{{ users_corrected[response.id_user].score_explaination }}
|
||||||
|
</div>
|
||||||
|
<div class="form-group row mb-1" ng-if="response.time_scored">
|
||||||
|
<label class="col-4 col-form-label col-form-label-sm">Correction effectuée :</label>
|
||||||
|
<div class="col-8">
|
||||||
<input type="text" class="form-control-plaintext form-control-sm" value="{{ response.time_scored | date:'medium'}}" readonly>
|
<input type="text" class="form-control-plaintext form-control-sm" value="{{ response.time_scored | date:'medium'}}" readonly>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row" ng-if="response.time_scored">
|
<div class="form-group row mb-1" ng-if="response.time_scored">
|
||||||
<label class="col-2 col-form-label col-form-label-sm">Correcteur :</label>
|
<label class="col-4 col-form-label col-form-label-sm">Correcteur :</label>
|
||||||
<div class="col-10">
|
<div class="col-8">
|
||||||
<input type="text" class="form-control-plaintext form-control-sm" value="{{ response.id_corrector }}" readonly>
|
<input type="text" class="form-control-plaintext form-control-sm" value="{{ response.id_corrector }}" readonly>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary" ng-disabled="submitInProgress">Soumettre les corrections</button>
|
<button type="submit" class="btn btn-primary" ng-disabled="submitInProgress">Soumettre les corrections</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<div class="modal fade" id="correctionTemplateModal" tabindex="-1" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Édition de modèle de correction</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form ng-submit="saveTemplate()">
|
||||||
|
<input type="hidden" id="tcid">
|
||||||
|
<input type="hidden" id="tcidquestion">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="tclabel">Label</label>
|
||||||
|
<input type="text" class="form-control" id="tclabel" placeholder="Label">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="tcscore">Score</label>
|
||||||
|
<input type="number" class="form-control" id="tcscore" placeholder="Score">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="tcexplaination">Explaination</label>
|
||||||
|
<textarea class="form-control" id="tcexplaination" placeholder="Explaination"></textarea>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-danger" id="tcdelbtn" ng-click="deleteTemplate()">Supprimer</button>
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Annuler</button>
|
||||||
|
<button type="button" class="btn btn-primary" ng-click="saveTemplate()">Enregistrer</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$('#correctionTemplateModal').on('show.bs.modal', function (event) {
|
||||||
|
var template = $(this).data('bs.modal')._config.template
|
||||||
|
|
||||||
|
var modal = $(this)
|
||||||
|
modal.find('#tclabel').val("")
|
||||||
|
modal.find('#tcscore').val(0)
|
||||||
|
modal.find('#tcexplaination').val("")
|
||||||
|
modal.find('#tcidquestion').val(0)
|
||||||
|
modal.find('#tcid').val(0)
|
||||||
|
|
||||||
|
modal.find('#tclabel').val(template.label)
|
||||||
|
modal.find('#tcscore').val(template.score)
|
||||||
|
modal.find('#tcexplaination').val(template.score_explaination)
|
||||||
|
modal.find('#tcidquestion').val(template.id_question)
|
||||||
|
modal.find('#tcid').val(template.id)
|
||||||
|
|
||||||
|
if (template.id) {
|
||||||
|
modal.find('#tcdelbtn').show()
|
||||||
|
} else {
|
||||||
|
modal.find('#tcdelbtn').hide()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
@ -109,7 +109,14 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</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>
|
<div class="ml-3 card-text alert alert-success" ng-if="!question.edit && (question.response.score_explaination || question.response.score)">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-auto">
|
||||||
|
<strong>{{question.response.score}} %</strong>
|
||||||
|
</div>
|
||||||
|
<p class="col mb-0" style="white-space: pre-line">{{ question.response.score_explaination }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user