diff --git a/controller/adapter.go b/controller/adapter.go index 110703d9..4284a385 100644 --- a/controller/adapter.go +++ b/controller/adapter.go @@ -276,3 +276,69 @@ func respondentDetail2Response(ctx echo.Context, respondentDetail model.Responde return res, nil } + +func responseBody2ResponseMetas(body []openapi.ResponseBody, questions []model.Questions) ([]*model.ResponseMeta, error) { + res := []*model.ResponseMeta{} + + for i, b := range body { + switch questions[i].Type { + case "Text": + bText, err := b.AsResponseBodyText() + if err != nil { + return nil, err + } + res = append(res, &model.ResponseMeta{ + QuestionID: questions[i].ID, + Data: bText.Answer, + }) + case "TextLong": + bTextLong, err := b.AsResponseBodyTextLong() + if err != nil { + return nil, err + } + res = append(res, &model.ResponseMeta{ + QuestionID: questions[i].ID, + Data: bTextLong.Answer, + }) + case "Number": + bNumber, err := b.AsResponseBodyNumber() + if err != nil { + return nil, err + } + res = append(res, &model.ResponseMeta{ + QuestionID: questions[i].ID, + Data: strconv.FormatFloat(float64(bNumber.Answer), 'f', -1, 32), + }) + case "SingleChoice": + bSingleChoice, err := b.AsResponseBodySingleChoice() + if err != nil { + return nil, err + } + res = append(res, &model.ResponseMeta{ + QuestionID: questions[i].ID, + Data: strconv.FormatInt(int64(bSingleChoice.Answer), 10), + }) + case "MultipleChoice": + bMultipleChoice, err := b.AsResponseBodyMultipleChoice() + if err != nil { + return nil, err + } + for _, a := range bMultipleChoice.Answer { + res = append(res, &model.ResponseMeta{ + QuestionID: questions[i].ID, + Data: strconv.FormatInt(int64(a), 10), + }) + } + case "LinearScale": + bScale, err := b.AsResponseBodyScale() + if err != nil { + return nil, err + } + res = append(res, &model.ResponseMeta{ + QuestionID: questions[i].ID, + Data: strconv.FormatInt(int64(bScale.Answer), 10), + }) + } + } + return res, nil +} diff --git a/controller/response.go b/controller/response.go index 4d21be47..bb3fd0e3 100644 --- a/controller/response.go +++ b/controller/response.go @@ -17,6 +17,7 @@ type Response struct { model.IRespondent model.IResponse model.ITarget + model.IQuestion } func NewResponse() *Response { @@ -132,3 +133,44 @@ func (r Response) DeleteResponse(ctx echo.Context, responseID openapi.ResponseID return nil } + +func (r Response) EditResponse(ctx echo.Context, responseID openapi.ResponseIDInPath, req openapi.EditResponseJSONRequestBody) error { + limit, err := r.IQuestionnaire.GetQuestionnaireLimitByResponseID(ctx.Request().Context(), responseID) + if err != nil { + if errors.Is(err, model.ErrRecordNotFound) { + ctx.Logger().Infof("failed to find response by response ID: %+v", err) + return echo.NewHTTPError(http.StatusNotFound, fmt.Errorf("failed to find response by response ID: %w", err)) + } + ctx.Logger().Errorf("failed to get questionnaire limit by response ID: %+v", err) + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get questionnaire limit by response ID: %w", err)) + } + + if limit.Valid && limit.Time.Before(time.Now()) { + ctx.Logger().Info("unable to edit the expired response") + return echo.NewHTTPError(http.StatusMethodNotAllowed, fmt.Errorf("unable edit the expired response")) + } + + err = r.IResponse.DeleteResponse(ctx.Request().Context(), responseID) + if err != nil { + ctx.Logger().Errorf("failed to delete response: %+v", err) + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to delete response: %w", err)) + } + + questions, err := r.IQuestion.GetQuestions(ctx.Request().Context(), req.QuestionnaireId) + + responseMetas, err := responseBody2ResponseMetas(req.Body, questions) + if err != nil { + ctx.Logger().Errorf("failed to convert response body into response metas: %+v", err) + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to convert response body into response metas: %w", err)) + } + + if len(responseMetas) > 0 { + err = r.IResponse.InsertResponses(ctx.Request().Context(), responseID, responseMetas) + if err != nil { + ctx.Logger().Errorf("failed to insert responses: %+v", err) + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to insert responses: %w", err)) + } + } + + return nil +} \ No newline at end of file diff --git a/handler/response.go b/handler/response.go index 1f47bcd2..a7dfbfa5 100644 --- a/handler/response.go +++ b/handler/response.go @@ -60,5 +60,22 @@ func (h Handler) GetResponse(ctx echo.Context, responseID openapi.ResponseIDInPa // (PATCH /responses/{responseID}) func (h Handler) EditResponse(ctx echo.Context, responseID openapi.ResponseIDInPath) error { + req := openapi.EditResponseJSONRequestBody{} + if err := ctx.Bind(&req); err != nil { + ctx.Logger().Errorf("failed to bind Responses: %+v", err) + return echo.NewHTTPError(http.StatusBadRequest, fmt.Errorf("failed to bind Responses: %w", err)) + } + + validate, err := getValidator(ctx) + if err != nil { + ctx.Logger().Errorf("failed to get validator: %+v", err) + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get validator: %w", err)) + } + + err = validate.Struct(req) + if err != nil { + ctx.Logger().Errorf("failed to validate request body: %+v", err) + return echo.NewHTTPError(http.StatusBadRequest, fmt.Errorf("failed to validate request body: %w", err)) + } return ctx.NoContent(200) }