Skip to content

Commit

Permalink
Merge pull request #1265 from traPtitech/fix/openapi-1
Browse files Browse the repository at this point in the history
feat: implement GetQuestionnaireResult, GetMyResponses, GetResponse and DeleteResponse
  • Loading branch information
Eraxyso authored Sep 2, 2024
2 parents 3b6fad2 + 7cba992 commit 0421e8e
Show file tree
Hide file tree
Showing 10 changed files with 441 additions and 11 deletions.
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 @@ -424,3 +415,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 {
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 @@ -183,6 +183,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)
}
20 changes: 20 additions & 0 deletions model/respondents_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,26 @@ 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{}
err = db.
Model(&Respondents{}).
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

0 comments on commit 0421e8e

Please sign in to comment.