Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement GetQuestionnaireResult, GetMyResponses, GetResponse and DeleteResponse #1265

Merged
merged 10 commits into from
Sep 2, 2024
41 changes: 32 additions & 9 deletions controller/questionnaire.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,6 @@ import (
"gopkg.in/guregu/null.v4"
)

// Response Responseの構造体
type Response struct {
model.IQuestionnaire
model.IValidation
model.IScaleLabel
model.IRespondent
model.IResponse
}

// Questionnaire Questionnaireの構造体
type Questionnaire struct {
model.IQuestionnaire
Expand Down Expand Up @@ -380,3 +371,35 @@ https://anke-to.trap.jp/responses/new/%d`,
questionnaireID,
)
}

func (q Questionnaire) GetQuestionnaireResult(ctx echo.Context, questionnaireID int, userID string) (openapi.Result, error) {
res := openapi.Result{}

params := openapi.GetQuestionnaireResponsesParams{}
responses, err := q.GetQuestionnaireResponses(ctx, questionnaireID, params, userID)
if err != nil {
ctx.Logger().Errorf("failed to get questionnaire responses: %+v", err)
return openapi.Result{}, echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get questionnaire responses: %w", err))
}

for _, response := range responses {
tmp := struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI 現状openapi側の書き方があんまりよくないせいでopenapi由来のtype.go使えてないので後で修正します

Body []openapi.ResponseBody `json:"body"`
IsDraft bool `json:"is_draft"`
ModifiedAt time.Time `json:"modified_at"`
QuestionnaireId int `json:"questionnaire_id"`
ResponseId int `json:"response_id"`
SubmittedAt time.Time `json:"submitted_at"`
}{
Body: response.Body,
IsDraft: response.IsDraft,
ModifiedAt: response.ModifiedAt,
QuestionnaireId: response.QuestionnaireId,
ResponseId: response.ResponseId,
SubmittedAt: response.SubmittedAt,
}
res = append(res, tmp)
}

return res, nil
}
155 changes: 155 additions & 0 deletions controller/response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package controller

import (
"errors"
"fmt"
"net/http"
"time"

"github.com/labstack/echo/v4"
"github.com/traPtitech/anke-to/model"
"github.com/traPtitech/anke-to/openapi"
)

// Response Responseの構造体
type Response struct {
model.IQuestionnaire
model.IRespondent
model.IResponse
model.ITarget
}

func NewResponse() *Response {
return &Response{}
}

func (r Response) GetMyResponses(ctx echo.Context, params openapi.GetMyResponsesParams, userID string) (openapi.ResponsesWithQuestionnaireInfo, error) {
res := openapi.ResponsesWithQuestionnaireInfo{}

sort := string(*params.Sort)
responsesID := []int{}
responsesID, err := r.IRespondent.GetMyResponseIDs(ctx.Request().Context(), sort, userID)
if err != nil {
ctx.Logger().Errorf("failed to get my responses ID: %+v", err)
return openapi.ResponsesWithQuestionnaireInfo{}, echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get questionnaire responses: %w", err))
}

for _, responseID := range responsesID {
responseDetail, err := r.IRespondent.GetRespondentDetail(ctx.Request().Context(), responseID)
if err != nil {
ctx.Logger().Errorf("failed to get respondent detail: %+v", err)
return openapi.ResponsesWithQuestionnaireInfo{}, echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get respondent detail: %w", err))
}

questionnaire, _, _, _, _, _, err := r.IQuestionnaire.GetQuestionnaireInfo(ctx.Request().Context(), responseDetail.QuestionnaireID)
if err != nil {
ctx.Logger().Errorf("failed to get questionnaire info: %+v", err)
return openapi.ResponsesWithQuestionnaireInfo{}, echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get questionnaire info: %w", err))
}

isTargetingMe, err := r.ITarget.IsTargetingMe(ctx.Request().Context(), responseDetail.QuestionnaireID, userID)
if err != nil {
ctx.Logger().Errorf("failed to get target info: %+v", err)
return openapi.ResponsesWithQuestionnaireInfo{}, echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get target info: %w", err))
}

questionnaireInfo := struct {
CreatedAt time.Time `json:"created_at"`
IsTargetingMe bool `json:"is_targeting_me"`
ModifiedAt time.Time `json:"modified_at"`
ResponseDueDateTime *time.Time `json:"response_due_date_time,omitempty"`
Title string `json:"title"`
}{
CreatedAt: questionnaire.CreatedAt,
IsTargetingMe: isTargetingMe,
ModifiedAt: questionnaire.ModifiedAt,
ResponseDueDateTime: &questionnaire.ResTimeLimit.Time,
Title: questionnaire.Title,
}

response, err := respondentDetail2Response(ctx, responseDetail)
if err != nil {
ctx.Logger().Errorf("failed to convert respondent detail into response: %+v", err)
return openapi.ResponsesWithQuestionnaireInfo{}, echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to convert respondent detail into response: %w", err))
}

tmp := struct {
Body []openapi.ResponseBody `json:"body"`
IsDraft bool `json:"is_draft"`
ModifiedAt time.Time `json:"modified_at"`
QuestionnaireId int `json:"questionnaire_id"`
QuestionnaireInfo *struct {
CreatedAt time.Time `json:"created_at"`
IsTargetingMe bool `json:"is_targeting_me"`
ModifiedAt time.Time `json:"modified_at"`
ResponseDueDateTime *time.Time `json:"response_due_date_time,omitempty"`
Title string `json:"title"`
} `json:"questionnaire_info,omitempty"`
Respondent openapi.TraqId `json:"respondent"`
ResponseId int `json:"response_id"`
SubmittedAt time.Time `json:"submitted_at"`
}{
Body: response.Body,
IsDraft: response.IsDraft,
ModifiedAt: response.ModifiedAt,
QuestionnaireId: response.QuestionnaireId,
QuestionnaireInfo: &questionnaireInfo,
Respondent: userID,
ResponseId: response.ResponseId,
SubmittedAt: response.SubmittedAt,
}
res = append(res, tmp)
}

return res, nil
}

func (r Response) GetResponse(ctx echo.Context, responseID openapi.ResponseIDInPath) (openapi.Response, error) {
responseDetail, err := r.IRespondent.GetRespondentDetail(ctx.Request().Context(), responseID)
if err != nil {
if errors.Is(err, model.ErrRecordNotFound) {
ctx.Logger().Errorf("failed to find response by response ID: %+v", err)
return openapi.Response{}, echo.NewHTTPError(http.StatusNotFound, fmt.Errorf("failed to find response by response ID: %w", err))
}
ctx.Logger().Errorf("failed to get respondent detail: %+v", err)
return openapi.Response{}, echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get respondent detail: %w", err))
}

res, err := respondentDetail2Response(ctx, responseDetail)
if err != nil {
ctx.Logger().Errorf("failed to convert respondent detail into response: %+v", err)
return openapi.Response{}, echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to convert respondent detail into response: %w", err))
}

return res, nil
}

func (r Response) DeleteResponse(ctx echo.Context, responseID openapi.ResponseIDInPath, userID string) error {
limit, err := r.IQuestionnaire.GetQuestionnaireLimitByResponseID(ctx.Request().Context(), responseID)
if err != nil {
if errors.Is(err, model.ErrRecordNotFound) {
ctx.Logger().Errorf("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().Errorf("unable delete the expired response")
return echo.NewHTTPError(http.StatusMethodNotAllowed, fmt.Errorf("unable delete the expired response"))
}

err = r.IRespondent.DeleteRespondent(ctx.Request().Context(), responseID)
if err != nil {
ctx.Logger().Errorf("failed to delete respondent: %+v", err)
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to delete respondent: %w", err))
}

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))
}

return nil
}
12 changes: 12 additions & 0 deletions handler/questionnaire.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,18 @@ func (h Handler) PostQuestionnaireResponse(ctx echo.Context, questionnaireID ope
// (GET /questionnaires/{questionnaireID}/result)
func (h Handler) GetQuestionnaireResult(ctx echo.Context, questionnaireID openapi.QuestionnaireIDInPath) error {
res := openapi.Result{}
userID, err := getUserID(ctx)
if err != nil {
ctx.Logger().Errorf("failed to get userID: %+v", err)
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get userID: %w", err))
}

q := controller.NewQuestionnaire()
res, err = q.GetQuestionnaireResult(ctx, questionnaireID, userID)
if err != nil {
ctx.Logger().Errorf("failed to get questionnaire result: %+v", err)
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get questionnaire result: %w", err))
}

return ctx.JSON(200, res)
}
36 changes: 35 additions & 1 deletion handler/response.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,60 @@
package handler

import (
"fmt"
"net/http"

"github.com/labstack/echo/v4"
"github.com/traPtitech/anke-to/controller"
"github.com/traPtitech/anke-to/openapi"
)

// (GET /responses/myResponses)
func (h Handler) GetMyResponses(ctx echo.Context, params openapi.GetMyResponsesParams) error {
res := []openapi.ResponsesWithQuestionnaireInfo{}
res := openapi.ResponsesWithQuestionnaireInfo{}
userID, err := getUserID(ctx)
if err != nil {
ctx.Logger().Errorf("failed to get userID: %+v", err)
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get userID: %w", err))
}

r := controller.NewResponse()
res, err = r.GetMyResponses(ctx, params, userID)
if err != nil {
ctx.Logger().Errorf("failed to get my responses: %+v", err)
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get my responses: %w", err))
}
return ctx.JSON(200, res)
}

// (DELETE /responses/{responseID})
func (h Handler) DeleteResponse(ctx echo.Context, responseID openapi.ResponseIDInPath) error {
userID, err := getUserID(ctx)
if err != nil {
ctx.Logger().Errorf("failed to get userID: %+v", err)
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get userID: %w", err))
}

r := controller.NewResponse()
err = r.DeleteResponse(ctx, responseID, userID)
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))
}

return ctx.NoContent(200)
}

// (GET /responses/{responseID})
func (h Handler) GetResponse(ctx echo.Context, responseID openapi.ResponseIDInPath) error {
res := openapi.Response{}

r := controller.NewResponse()
res, err := r.GetResponse(ctx, responseID)
if err != nil {
ctx.Logger().Errorf("failed to get response: %+v", err)
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get response: %w", err))
}
return ctx.JSON(200, res)
}

Expand Down
1 change: 1 addition & 0 deletions model/respondents.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ type IRespondent interface {
GetRespondentDetail(ctx context.Context, responseID int) (RespondentDetail, error)
GetRespondentDetails(ctx context.Context, questionnaireID int, sort string, onlyMyResponse bool, userID string) ([]RespondentDetail, error)
GetRespondentsUserIDs(ctx context.Context, questionnaireIDs []int) ([]Respondents, error)
GetMyResponseIDs(ctx context.Context, sort string, userID string) ([]int, error)
CheckRespondent(ctx context.Context, userID string, questionnaireID int) (bool, error)
}
19 changes: 19 additions & 0 deletions model/respondents_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,25 @@ func (*Respondent) GetRespondentsUserIDs(ctx context.Context, questionnaireIDs [
return respondents, nil
}

// GetMyResponses 自分のすべての回答を取得
func (*Respondent) GetMyResponseIDs(ctx context.Context, userID string) ([]int, error) {
db, err := getTx(ctx)
if err != nil {
return nil, fmt.Errorf("failed to get transaction: %w", err)
}

responsesID := []int{}
Eraxyso marked this conversation as resolved.
Show resolved Hide resolved
err = db.
Where("user_traqid = ?", userID).
Select("response_id").
Find(&responsesID).Error
if err != nil {
return nil, fmt.Errorf("failed to get responsesID: %w", err)
}

return responsesID, nil
}

// CheckRespondent 回答者かどうかの確認
func (*Respondent) CheckRespondent(ctx context.Context, userID string, questionnaireID int) (bool, error) {
db, err := getTx(ctx)
Expand Down
Loading
Loading