From f57d04e20bfc718164eb5644904e6dcfdd4db5b6 Mon Sep 17 00:00:00 2001 From: kaitoyama Date: Sun, 29 Mar 2026 15:59:04 +0900 Subject: [PATCH 1/7] Add paging to myResponses --- controller/adapter.go | 28 +++-- controller/response.go | 101 +++++++--------- controller/response_test.go | 101 +++++++++++++++- docs/swagger/swagger.yaml | 24 +++- handler/response.go | 5 + model/respondents.go | 17 +++ model/respondents_impl.go | 235 ++++++++++++++++++++++++++++++++++++ openapi/server.go | 9 +- openapi/spec.go | 173 +++++++++++++------------- openapi/types.go | 11 +- 10 files changed, 534 insertions(+), 170 deletions(-) diff --git a/controller/adapter.go b/controller/adapter.go index 26d03669..020ad136 100644 --- a/controller/adapter.go +++ b/controller/adapter.go @@ -211,7 +211,7 @@ func questionnaire2QuestionnaireDetail(questionnaires model.Questionnaires, admi return res, nil } -func respondentDetail2Response(ctx echo.Context, respondentDetail model.RespondentDetail) (openapi.Response, error) { +func respondentDetail2ResponseWithMetadata(ctx echo.Context, respondentDetail model.RespondentDetail, respondent *string, isAnonymous bool) (openapi.Response, error) { oResponseBodies := []openapi.ResponseBody{} for _, r := range respondentDetail.Responses { oResponseBody := openapi.ResponseBody{} @@ -318,17 +318,6 @@ func respondentDetail2Response(ctx echo.Context, respondentDetail model.Responde oResponseBodies = append(oResponseBodies, oResponseBody) } - isAnonymous, err := model.NewQuestionnaire().GetResponseIsAnonymousByQuestionnaireID(ctx.Request().Context(), respondentDetail.QuestionnaireID) - if err != nil { - ctx.Logger().Errorf("failed to get response is anonymous: %+v", err) - return openapi.Response{}, err - } - - respondent := &respondentDetail.TraqID - if isAnonymous { - respondent = nil - } - res := openapi.Response{ Body: oResponseBodies, IsAnonymous: isAnonymous, @@ -343,6 +332,21 @@ func respondentDetail2Response(ctx echo.Context, respondentDetail model.Responde return res, nil } +func respondentDetail2Response(ctx echo.Context, respondentDetail model.RespondentDetail) (openapi.Response, error) { + isAnonymous, err := model.NewQuestionnaire().GetResponseIsAnonymousByQuestionnaireID(ctx.Request().Context(), respondentDetail.QuestionnaireID) + if err != nil { + ctx.Logger().Errorf("failed to get response is anonymous: %+v", err) + return openapi.Response{}, err + } + + respondent := &respondentDetail.TraqID + if isAnonymous { + respondent = nil + } + + return respondentDetail2ResponseWithMetadata(ctx, respondentDetail, respondent, isAnonymous) +} + func responseBody2ResponseMetas(body []openapi.NewResponseBody, questions []model.Questions) ([]*model.ResponseMeta, error) { res := []*model.ResponseMeta{} diff --git a/controller/response.go b/controller/response.go index 4041b103..2f30e212 100644 --- a/controller/response.go +++ b/controller/response.go @@ -50,7 +50,9 @@ func NewResponse( } func (r *Response) GetMyResponses(ctx echo.Context, params openapi.GetMyResponsesParams, userID string) (openapi.ResponsesWithQuestionnaireInfo, error) { - res := openapi.ResponsesWithQuestionnaireInfo{} + res := openapi.ResponsesWithQuestionnaireInfo{ + ResponseGroups: []openapi.ResponseWithQuestionnaireInfoItem{}, + } var sort string if params.Sort == nil { @@ -58,80 +60,63 @@ func (r *Response) GetMyResponses(ctx echo.Context, params openapi.GetMyResponse } else { sort = string(*params.Sort) } + var pageNum int + if params.Page == nil { + pageNum = 1 + } else { + pageNum = int(*params.Page) + } + if pageNum < 1 { + pageNum = 1 + } var questionnaireIDs []int if params.QuestionnaireIDs == nil { questionnaireIDs = nil } else { questionnaireIDs = *params.QuestionnaireIDs } - responsesID, err := r.IRespondent.GetMyResponseIDs(ctx.Request().Context(), sort, userID, questionnaireIDs, params.IsDraft) - 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)) - } - - responseLists := make(map[int][]openapi.Response) - var responseQuestionnaireIDs []int - - 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)) - } - 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 := openapi.Response{ - Body: response.Body, - IsDraft: response.IsDraft, - ModifiedAt: response.ModifiedAt, - QuestionnaireId: response.QuestionnaireId, - Respondent: &userID, - ResponseId: response.ResponseId, - SubmittedAt: response.SubmittedAt, - IsAnonymous: response.IsAnonymous, + responseGroups, pageMax, err := r.IRespondent.GetMyResponseGroups(ctx.Request().Context(), sort, userID, questionnaireIDs, params.IsDraft, pageNum) + if err != nil { + if errors.Is(err, model.ErrTooLargePageNum) || errors.Is(err, model.ErrInvalidSortParam) { + ctx.Logger().Infof("invalid myResponses params: %+v", err) + return openapi.ResponsesWithQuestionnaireInfo{}, echo.NewHTTPError(http.StatusBadRequest, err) } - responseLists[responseDetail.QuestionnaireID] = append(responseLists[responseDetail.QuestionnaireID], tmp) - responseQuestionnaireIDs = append(responseQuestionnaireIDs, responseDetail.QuestionnaireID) + ctx.Logger().Errorf("failed to get my response groups: %+v", err) + return openapi.ResponsesWithQuestionnaireInfo{}, echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get questionnaire responses: %w", err)) } + res.PageMax = pageMax - questionnaireIDExists := make(map[int]bool, len(responseQuestionnaireIDs)) - for _, questionnaireID := range responseQuestionnaireIDs { - if questionnaireIDExists[questionnaireID] { - continue + for _, responseGroup := range responseGroups { + var responseDueDateTime *time.Time + if responseGroup.QuestionnaireInfo.ResponseDueDateTime.Valid { + dueDateTime := responseGroup.QuestionnaireInfo.ResponseDueDateTime.Time + responseDueDateTime = &dueDateTime } - questionnaireIDExists[questionnaireID] = true - questionnaire, _, _, _, _, _, _, _, err := r.IQuestionnaire.GetQuestionnaireInfo(ctx.Request().Context(), 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)) + groupItem := openapi.ResponseWithQuestionnaireInfoItem{ + QuestionnaireInfo: openapi.QuestionnaireInfo{ + CreatedAt: responseGroup.QuestionnaireInfo.CreatedAt, + IsTargetingMe: responseGroup.QuestionnaireInfo.IsTargetingMe, + ModifiedAt: responseGroup.QuestionnaireInfo.ModifiedAt, + ResponseDueDateTime: responseDueDateTime, + Title: responseGroup.QuestionnaireInfo.Title, + }, + Responses: []openapi.Response{}, } - isTargetingMe, err := r.ITarget.IsTargetingMe(ctx.Request().Context(), 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)) - } + for _, responseDetail := range responseGroup.Responses { + respondent := userID + response, err := respondentDetail2ResponseWithMetadata(ctx, responseDetail, &respondent, responseGroup.QuestionnaireInfo.IsAnonymous) + 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)) + } - questionnaireInfo := openapi.QuestionnaireInfo{ - CreatedAt: questionnaire.CreatedAt, - IsTargetingMe: isTargetingMe, - ModifiedAt: questionnaire.ModifiedAt, - ResponseDueDateTime: &questionnaire.ResTimeLimit.Time, - Title: questionnaire.Title, + groupItem.Responses = append(groupItem.Responses, response) } - responses := responseLists[questionnaireID] - res = append(res, openapi.ResponseWithQuestionnaireInfoItem{ - QuestionnaireInfo: questionnaireInfo, - Responses: responses, - }) + res.ResponseGroups = append(res.ResponseGroups, groupItem) } return res, nil diff --git a/controller/response_test.go b/controller/response_test.go index cdbb497a..b2c09b5c 100644 --- a/controller/response_test.go +++ b/controller/response_test.go @@ -148,7 +148,7 @@ func TestGetMyResponses(t *testing.T) { rec = httptest.NewRecorder() req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) ctx = e.NewContext(req, rec) - _, err = q.PostQuestionnaireResponse(ctx, questionnaireDetail.QuestionnaireId, newResponse, userOne) + response0, err := q.PostQuestionnaireResponse(ctx, questionnaireDetail.QuestionnaireId, newResponse, userOne) require.NoError(t, err) newResponse = sampleResponse @@ -159,7 +159,7 @@ func TestGetMyResponses(t *testing.T) { rec = httptest.NewRecorder() req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) ctx = e.NewContext(req, rec) - _, err = q.PostQuestionnaireResponse(ctx, questionnaireDetail.QuestionnaireId, newResponse, userOne) + response1, err := q.PostQuestionnaireResponse(ctx, questionnaireDetail.QuestionnaireId, newResponse, userOne) require.NoError(t, err) newResponse = sampleResponse @@ -171,7 +171,7 @@ func TestGetMyResponses(t *testing.T) { rec = httptest.NewRecorder() req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) ctx = e.NewContext(req, rec) - _, err = q.PostQuestionnaireResponse(ctx, questionnaireDetail.QuestionnaireId, newResponse, userOne) + responseDraft, err := q.PostQuestionnaireResponse(ctx, questionnaireDetail.QuestionnaireId, newResponse, userOne) require.NoError(t, err) newResponse = sampleResponse @@ -205,6 +205,7 @@ func TestGetMyResponses(t *testing.T) { type expect struct { isErr bool err error + pageMax *int responseIDList *[]int } type test struct { @@ -220,6 +221,11 @@ func TestGetMyResponses(t *testing.T) { sortSubmittedAtDesc := (openapi.ResponseSortInQuery)("-submitted_at") sortModifiedAt := (openapi.ResponseSortInQuery)("modified_at") sortModifiedAtDesc := (openapi.ResponseSortInQuery)("-modified_at") + pageZero := 0 + largePageNum := 100000000 + pageOne := 1 + constTrue := true + constFalse := false testCases := []test{ { @@ -228,6 +234,9 @@ func TestGetMyResponses(t *testing.T) { userID: userOne, params: openapi.GetMyResponsesParams{}, }, + expect: expect{ + pageMax: &pageOne, + }, }, { description: "invalid param sort", @@ -249,6 +258,9 @@ func TestGetMyResponses(t *testing.T) { Sort: &sortSubmittedAt, }, }, + expect: expect{ + pageMax: &pageOne, + }, }, { description: "sort -submitted_at", @@ -258,6 +270,9 @@ func TestGetMyResponses(t *testing.T) { Sort: &sortSubmittedAtDesc, }, }, + expect: expect{ + pageMax: &pageOne, + }, }, { description: "sort traqid", @@ -267,6 +282,9 @@ func TestGetMyResponses(t *testing.T) { Sort: &sortTraqID, }, }, + expect: expect{ + pageMax: &pageOne, + }, }, { description: "sort -traqid", @@ -276,6 +294,9 @@ func TestGetMyResponses(t *testing.T) { Sort: &sortTraqIDDesc, }, }, + expect: expect{ + pageMax: &pageOne, + }, }, { description: "sort modified_at", @@ -285,6 +306,9 @@ func TestGetMyResponses(t *testing.T) { Sort: &sortModifiedAt, }, }, + expect: expect{ + pageMax: &pageOne, + }, }, { description: "sort -modified_at", @@ -294,6 +318,59 @@ func TestGetMyResponses(t *testing.T) { Sort: &sortModifiedAtDesc, }, }, + expect: expect{ + pageMax: &pageOne, + }, + }, + { + description: "page less than one treated as first page", + args: args{ + userID: userOne, + params: openapi.GetMyResponsesParams{ + Page: &pageZero, + }, + }, + expect: expect{ + pageMax: &pageOne, + }, + }, + { + description: "too large page num", + args: args{ + userID: userOne, + params: openapi.GetMyResponsesParams{ + Page: &largePageNum, + }, + }, + expect: expect{ + isErr: true, + }, + }, + { + description: "draft only", + args: args{ + userID: userOne, + params: openapi.GetMyResponsesParams{ + IsDraft: &constTrue, + }, + }, + expect: expect{ + pageMax: &pageOne, + responseIDList: &[]int{responseDraft.ResponseId}, + }, + }, + { + description: "non draft only", + args: args{ + userID: userOne, + params: openapi.GetMyResponsesParams{ + IsDraft: &constFalse, + }, + }, + expect: expect{ + pageMax: &pageOne, + responseIDList: &[]int{response0.ResponseId, response1.ResponseId}, + }, }, { description: "special user", @@ -302,6 +379,7 @@ func TestGetMyResponses(t *testing.T) { params: openapi.GetMyResponsesParams{}, }, expect: expect{ + pageMax: &pageOne, responseIDList: &[]int{response4.ResponseId}, }, }, @@ -312,6 +390,7 @@ func TestGetMyResponses(t *testing.T) { params: openapi.GetMyResponsesParams{}, }, expect: expect{ + pageMax: &pageZero, responseIDList: &[]int{}, }, }, @@ -322,6 +401,12 @@ func TestGetMyResponses(t *testing.T) { if testCase.args.params.Sort != nil { params.Add("sort", string(*testCase.args.params.Sort)) } + if testCase.args.params.Page != nil { + params.Add("page", fmt.Sprint(*testCase.args.params.Page)) + } + if testCase.args.params.IsDraft != nil { + params.Add("isDraft", fmt.Sprint(*testCase.args.params.IsDraft)) + } e = echo.New() req = httptest.NewRequest(http.MethodGet, "/responses/myResponses"+params.Encode(), nil) rec = httptest.NewRecorder() @@ -341,7 +426,11 @@ func TestGetMyResponses(t *testing.T) { continue } - for _, responseList := range responseLists { + if testCase.expect.pageMax != nil { + assertion.Equal(*testCase.expect.pageMax, responseLists.PageMax, testCase.description, "pageMax") + } + + for _, responseList := range responseLists.ResponseGroups { if testCase.args.params.Sort != nil { switch *testCase.args.params.Sort { case "submitted_at": @@ -398,7 +487,7 @@ func TestGetMyResponses(t *testing.T) { if testCase.expect.responseIDList != nil { responseIDList := []int{} - for _, responseList := range responseLists { + for _, responseList := range responseLists.ResponseGroups { for _, response := range responseList.Responses { responseIDList = append(responseIDList, response.ResponseId) } @@ -410,7 +499,7 @@ func TestGetMyResponses(t *testing.T) { assertion.Equal(*testCase.expect.responseIDList, responseIDList, testCase.description, "responseIDList") } - for _, responseList := range responseLists { + for _, responseList := range responseLists.ResponseGroups { for _, response := range responseList.Responses { assertion.Equal(testCase.args.userID, *response.Respondent, testCase.description, "response with no respondent") } diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 25c0f3bf..4ad2439f 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -298,18 +298,21 @@ paths: # TODO 変数の命名を確認する operationId: getMyResponses tags: - response - description: 自分のすべての回答のリストを取得します。 + description: 自分のすべての回答のリストを、アンケートごとにまとめてページ単位で取得します。 parameters: - $ref: "#/components/parameters/responseSortInQuery" + - $ref: "#/components/parameters/pageInQuery" - $ref: "#/components/parameters/questionnaireIDsInQuery" - $ref: "#/components/parameters/isDraftInQuery" responses: "200": - description: 正常に取得できました。回答の配列を返します。 + description: 正常に取得できました。ページ情報付きの回答一覧を返します。 content: application/json: schema: $ref: "#/components/schemas/ResponsesWithQuestionnaireInfo" + "400": + description: 与えられた情報の形式が異なります "500": description: 自分の回答のリストを取得できませんでした /traq/users: @@ -1009,9 +1012,20 @@ components: items: $ref: "#/components/schemas/Response" ResponsesWithQuestionnaireInfo: - type: array - items: - $ref: "#/components/schemas/ResponseWithQuestionnaireInfoItem" + type: object + properties: + page_max: + type: integer + example: 1 + description: | + 合計のページ数 + response_groups: + type: array + items: + $ref: "#/components/schemas/ResponseWithQuestionnaireInfoItem" + required: + - page_max + - response_groups QuestionnaireInfo: type: object allOf: diff --git a/handler/response.go b/handler/response.go index 5ee21aeb..f458f188 100644 --- a/handler/response.go +++ b/handler/response.go @@ -1,6 +1,7 @@ package handler import ( + "errors" "fmt" "net/http" @@ -18,6 +19,10 @@ func (h Handler) GetMyResponses(ctx echo.Context, params openapi.GetMyResponsesP res, err := h.Response.GetMyResponses(ctx, params, userID) if err != nil { + var httpErr *echo.HTTPError + if errors.As(err, &httpErr) { + return httpErr + } ctx.Logger().Errorf("failed to get my responses: %+v", err) return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get my responses: %w", err)) } diff --git a/model/respondents.go b/model/respondents.go index ea700357..67e9a62a 100644 --- a/model/respondents.go +++ b/model/respondents.go @@ -4,10 +4,26 @@ package model import ( "context" + "time" "gopkg.in/guregu/null.v4" ) +type MyResponseQuestionnaireInfo struct { + QuestionnaireID int + Title string + CreatedAt time.Time + ModifiedAt time.Time + ResponseDueDateTime null.Time + IsAnonymous bool + IsTargetingMe bool +} + +type MyResponseGroup struct { + QuestionnaireInfo MyResponseQuestionnaireInfo + Responses []RespondentDetail +} + // IRespondent RespondentのRepository type IRespondent interface { InsertRespondent(ctx context.Context, userID string, questionnaireID int, submittedAt null.Time) (int, error) @@ -18,6 +34,7 @@ type IRespondent interface { GetRespondentInfos(ctx context.Context, userID string, questionnaireIDs ...int) ([]RespondentInfo, error) GetRespondentDetail(ctx context.Context, responseID int) (RespondentDetail, error) GetRespondentDetails(ctx context.Context, questionnaireID int, sort string, onlyMyResponse bool, userID string, isDraft *bool) ([]RespondentDetail, error) + GetMyResponseGroups(ctx context.Context, sort string, userID string, questionnaireIDs []int, isDraft *bool, pageNum int) ([]MyResponseGroup, int, error) GetRespondentsUserIDs(ctx context.Context, questionnaireIDs []int) ([]Respondents, error) GetMyResponseIDs(ctx context.Context, sort string, userID string, questionnaireIDs []int, isDraft *bool) ([]int, error) CheckRespondent(ctx context.Context, userID string, questionnaireID int) (bool, error) diff --git a/model/respondents_impl.go b/model/respondents_impl.go index db0246c6..652503f5 100755 --- a/model/respondents_impl.go +++ b/model/respondents_impl.go @@ -429,6 +429,241 @@ func (*Respondent) GetRespondentDetails(ctx context.Context, questionnaireID int return respondentDetails, nil } +type myResponseGroupRow struct { + QuestionnaireID int `gorm:"column:questionnaire_id"` + Title string `gorm:"column:title"` + CreatedAt time.Time `gorm:"column:created_at"` + ModifiedAt time.Time `gorm:"column:modified_at"` + ResTimeLimit null.Time `gorm:"column:res_time_limit"` + IsAnonymous bool `gorm:"column:is_anonymous"` + IsTargetingMe bool `gorm:"column:is_targeting_me"` + FirstResponseID int `gorm:"column:first_response_id"` +} + +func buildMyResponseBaseQuery(db *gorm.DB, userID string, questionnaireIDs []int, isDraft *bool) *gorm.DB { + query := db. + Table("respondents"). + Joins("INNER JOIN questionnaires ON respondents.questionnaire_id = questionnaires.id"). + Where("respondents.deleted_at IS NULL AND questionnaires.deleted_at IS NULL AND respondents.user_traqid = ?", userID) + + if questionnaireIDs != nil { + query = query.Where("respondents.questionnaire_id IN (?)", questionnaireIDs) + } + + if isDraft != nil { + if *isDraft { + query = query.Where("respondents.submitted_at IS NULL") + } else { + query = query.Where("respondents.submitted_at IS NOT NULL") + } + } + + return query +} + +func setMyResponseGroupOrder(query *gorm.DB, sort string) (*gorm.DB, error) { + switch sort { + case "": + return query.Order("first_response_id"), nil + case "submitted_at": + return query. + Order("MIN(respondents.submitted_at)"). + Order("first_response_id"), nil + case "-submitted_at": + return query. + Order("MAX(respondents.submitted_at) DESC"). + Order("first_response_id"), nil + case "modified_at": + return query. + Order("MIN(respondents.modified_at)"). + Order("first_response_id"), nil + case "-modified_at": + return query. + Order("MAX(respondents.modified_at) DESC"). + Order("first_response_id"), nil + case "traqid", "-traqid": + return query.Order("first_response_id"), nil + default: + return nil, fmt.Errorf("failed to convert sort param to group order: %w", ErrInvalidSortParam) + } +} + +// GetMyResponseGroups 自分の回答をアンケートごとにまとめて取得 +func (*Respondent) GetMyResponseGroups(ctx context.Context, sort string, userID string, questionnaireIDs []int, isDraft *bool, pageNum int) ([]MyResponseGroup, int, error) { + db, err := getTx(ctx) + if err != nil { + return nil, 0, fmt.Errorf("failed to get transaction: %w", err) + } + + baseQuery := buildMyResponseBaseQuery(db, userID, questionnaireIDs, isDraft) + + var count int64 + err = baseQuery. + Session(&gorm.Session{}). + Distinct("respondents.questionnaire_id"). + Count(&count).Error + if err != nil { + return nil, 0, fmt.Errorf("failed to count my response questionnaires: %w", err) + } + + if count == 0 { + return []MyResponseGroup{}, 0, nil + } + + pageMax := (int(count) + 19) / 20 + if pageNum > pageMax { + return nil, 0, ErrTooLargePageNum + } + + groupRows := []myResponseGroupRow{} + groupQuery := buildMyResponseBaseQuery(db, userID, questionnaireIDs, isDraft). + Select( + "respondents.questionnaire_id, questionnaires.title, questionnaires.created_at, questionnaires.modified_at, questionnaires.res_time_limit, questionnaires.is_anonymous, "+ + "EXISTS(SELECT 1 FROM targets WHERE targets.questionnaire_id = questionnaires.id AND targets.user_traqid = ?) AS is_targeting_me, "+ + "MIN(respondents.response_id) AS first_response_id", + userID, + ). + Group("respondents.questionnaire_id, questionnaires.id, questionnaires.title, questionnaires.created_at, questionnaires.modified_at, questionnaires.res_time_limit, questionnaires.is_anonymous") + groupQuery, err = setMyResponseGroupOrder(groupQuery, sort) + if err != nil { + return nil, 0, fmt.Errorf("failed to set my response group order: %w", err) + } + + err = groupQuery. + Limit(20). + Offset((pageNum - 1) * 20). + Find(&groupRows).Error + if err != nil { + return nil, 0, fmt.Errorf("failed to get my response groups: %w", err) + } + + if len(groupRows) == 0 { + return []MyResponseGroup{}, pageMax, nil + } + + groups := make([]MyResponseGroup, 0, len(groupRows)) + groupIndexByQuestionnaireID := make(map[int]int, len(groupRows)) + pageQuestionnaireIDs := make([]int, 0, len(groupRows)) + for i, row := range groupRows { + groups = append(groups, MyResponseGroup{ + QuestionnaireInfo: MyResponseQuestionnaireInfo{ + QuestionnaireID: row.QuestionnaireID, + Title: row.Title, + CreatedAt: row.CreatedAt, + ModifiedAt: row.ModifiedAt, + ResponseDueDateTime: row.ResTimeLimit, + IsAnonymous: row.IsAnonymous, + IsTargetingMe: row.IsTargetingMe, + }, + Responses: []RespondentDetail{}, + }) + groupIndexByQuestionnaireID[row.QuestionnaireID] = i + pageQuestionnaireIDs = append(pageQuestionnaireIDs, row.QuestionnaireID) + } + + respondents := []Respondents{} + respondentQuery := db. + Session(&gorm.Session{}). + Where("respondents.deleted_at IS NULL AND respondents.user_traqid = ? AND respondents.questionnaire_id IN (?)", userID, pageQuestionnaireIDs). + Select("ResponseID", "QuestionnaireID", "UserTraqid", "ModifiedAt", "SubmittedAt") + if isDraft != nil { + if *isDraft { + respondentQuery = respondentQuery.Where("submitted_at IS NULL") + } else { + respondentQuery = respondentQuery.Where("submitted_at IS NOT NULL") + } + } + respondentQuery, _, err = setRespondentsOrder(respondentQuery, sort) + if err != nil { + return nil, 0, fmt.Errorf("failed to set respondents order: %w", err) + } + + err = respondentQuery.Find(&respondents).Error + if err != nil { + return nil, 0, fmt.Errorf("failed to get respondents for my response groups: %w", err) + } + + if len(respondents) == 0 { + return groups, pageMax, nil + } + + responseIDs := make([]int, 0, len(respondents)) + respondentDetailMap := make(map[int]*RespondentDetail, len(respondents)) + responseIDsByQuestionnaireID := make(map[int][]int, len(groupRows)) + for _, respondent := range respondents { + groupIdx := groupIndexByQuestionnaireID[respondent.QuestionnaireID] + groups[groupIdx].Responses = append(groups[groupIdx].Responses, RespondentDetail{ + ResponseID: respondent.ResponseID, + TraqID: respondent.UserTraqid, + QuestionnaireID: respondent.QuestionnaireID, + ModifiedAt: respondent.ModifiedAt, + SubmittedAt: respondent.SubmittedAt, + Responses: []ResponseBody{}, + }) + lastIdx := len(groups[groupIdx].Responses) - 1 + respondentDetailMap[respondent.ResponseID] = &groups[groupIdx].Responses[lastIdx] + responseIDs = append(responseIDs, respondent.ResponseID) + responseIDsByQuestionnaireID[respondent.QuestionnaireID] = append(responseIDsByQuestionnaireID[respondent.QuestionnaireID], respondent.ResponseID) + } + + questions := []Questions{} + err = db. + Preload("Responses", func(db *gorm.DB) *gorm.DB { + return db. + Select("ResponseID", "QuestionID", "Body"). + Where("response_id IN (?)", responseIDs) + }). + Where("questionnaire_id IN (?)", pageQuestionnaireIDs). + Order("questionnaire_id"). + Order("question_num"). + Select("ID", "QuestionnaireID", "QuestionNum", "Type"). + Find(&questions).Error + if err != nil { + return nil, 0, fmt.Errorf("failed to get questions for my response groups: %w", err) + } + + for _, question := range questions { + responseBodyMap := make(map[int][]string) + for _, response := range question.Responses { + if response.Body.Valid { + responseBodyMap[response.ResponseID] = append(responseBodyMap[response.ResponseID], response.Body.String) + } + } + + for _, responseID := range responseIDsByQuestionnaireID[question.QuestionnaireID] { + respondentDetail := respondentDetailMap[responseID] + if respondentDetail == nil { + continue + } + + responseBodies := responseBodyMap[responseID] + responseBody := ResponseBody{ + QuestionID: question.ID, + QuestionType: question.Type, + } + + switch question.Type { + case "MultipleChoice", "Checkbox", "Dropdown": + if responseBodies == nil { + responseBody.OptionResponse = []string{} + } else { + responseBody.OptionResponse = responseBodies + } + default: + if len(responseBodies) == 0 { + responseBody.Body = null.NewString("", false) + } else { + responseBody.Body = null.NewString(responseBodies[0], true) + } + } + + respondentDetail.Responses = append(respondentDetail.Responses, responseBody) + } + } + + return groups, pageMax, nil +} + // GetRespondentsUserIDs 回答者のユーザーID取得 func (*Respondent) GetRespondentsUserIDs(ctx context.Context, questionnaireIDs []int) ([]Respondents, error) { db, err := getTx(ctx) diff --git a/openapi/server.go b/openapi/server.go index 5c98442c..59048549 100644 --- a/openapi/server.go +++ b/openapi/server.go @@ -1,6 +1,6 @@ // Package openapi provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.0 DO NOT EDIT. package openapi import ( @@ -298,6 +298,13 @@ func (w *ServerInterfaceWrapper) GetMyResponses(ctx echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter sort: %s", err)) } + // ------------- Optional query parameter "page" ------------- + + err = runtime.BindQueryParameter("form", true, false, "page", ctx.QueryParams(), ¶ms.Page) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter page: %s", err)) + } + // ------------- Optional query parameter "questionnaireIDs" ------------- err = runtime.BindQueryParameter("form", false, false, "questionnaireIDs", ctx.QueryParams(), ¶ms.QuestionnaireIDs) diff --git a/openapi/spec.go b/openapi/spec.go index 2de1e539..dcfe3da1 100644 --- a/openapi/spec.go +++ b/openapi/spec.go @@ -1,6 +1,6 @@ // Package openapi provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.0 DO NOT EDIT. package openapi import ( @@ -18,91 +18,92 @@ import ( // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/openapi/types.go b/openapi/types.go index dd4d62c3..67b5e9eb 100644 --- a/openapi/types.go +++ b/openapi/types.go @@ -1,6 +1,6 @@ // Package openapi provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.0 DO NOT EDIT. package openapi import ( @@ -645,7 +645,11 @@ type ResponseWithQuestionnaireInfoItem struct { type Responses = []Response // ResponsesWithQuestionnaireInfo defines model for ResponsesWithQuestionnaireInfo. -type ResponsesWithQuestionnaireInfo = []ResponseWithQuestionnaireInfoItem +type ResponsesWithQuestionnaireInfo struct { + // PageMax 合計のページ数 + PageMax int `json:"page_max"` + ResponseGroups []ResponseWithQuestionnaireInfoItem `json:"response_groups"` +} // SortType question、questionnaire用のソートの種類 type SortType string @@ -806,6 +810,9 @@ type GetMyResponsesParams struct { // Sort 並び順 (作成日時が新しい "submitted_at", 作成日時が古い "-submitted_at", TraqIDの昇順 "traqid", TraqIDの降順 "-traqid", 更新日時が新しい "modified_at", 更新日時が古い "-modified_at" ) Sort *ResponseSortInQuery `form:"sort,omitempty" json:"sort,omitempty"` + // Page 何ページ目か (未定義の場合は1ページ目) + Page *PageInQuery `form:"page,omitempty" json:"page,omitempty"` + // QuestionnaireIDs 取得したい情報のアンケートをフィルタリングするためのパラメータ。複数指定可能。 QuestionnaireIDs *QuestionnaireIDsInQuery `form:"questionnaireIDs,omitempty" json:"questionnaireIDs,omitempty"` From 91a0c7f0f6c85f2ff8652fc5dacee11f88f44a0e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 29 Mar 2026 16:11:17 +0900 Subject: [PATCH 2/7] chore: regenerate generated files --- openapi/server.go | 2 +- openapi/spec.go | 2 +- openapi/types.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openapi/server.go b/openapi/server.go index 59048549..3d3eb453 100644 --- a/openapi/server.go +++ b/openapi/server.go @@ -1,6 +1,6 @@ // Package openapi provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.0 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. package openapi import ( diff --git a/openapi/spec.go b/openapi/spec.go index dcfe3da1..37e5f89a 100644 --- a/openapi/spec.go +++ b/openapi/spec.go @@ -1,6 +1,6 @@ // Package openapi provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.0 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. package openapi import ( diff --git a/openapi/types.go b/openapi/types.go index 67b5e9eb..5798b386 100644 --- a/openapi/types.go +++ b/openapi/types.go @@ -1,6 +1,6 @@ // Package openapi provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.0 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. package openapi import ( From cecb695d8a0fded5401afaf47c7100bdb0b1c609 Mon Sep 17 00:00:00 2001 From: kaitoyama <45167401+kaitoyama@users.noreply.github.com> Date: Wed, 1 Apr 2026 01:34:48 +0900 Subject: [PATCH 3/7] Address myResponses review comments --- controller/adapter.go | 4 + controller/response.go | 10 +- controller/response_test.go | 228 ++++++++++-------------------------- docs/swagger/swagger.yaml | 1 - handler/response.go | 7 +- model/respondents.go | 2 +- model/respondents_impl.go | 41 +------ openapi/server.go | 7 -- openapi/spec.go | 22 ++-- openapi/types.go | 3 - 10 files changed, 88 insertions(+), 237 deletions(-) diff --git a/controller/adapter.go b/controller/adapter.go index 020ad136..b4986edb 100644 --- a/controller/adapter.go +++ b/controller/adapter.go @@ -318,6 +318,10 @@ func respondentDetail2ResponseWithMetadata(ctx echo.Context, respondentDetail mo oResponseBodies = append(oResponseBodies, oResponseBody) } + if isAnonymous { + respondent = nil + } + res := openapi.Response{ Body: oResponseBodies, IsAnonymous: isAnonymous, diff --git a/controller/response.go b/controller/response.go index 2f30e212..936de56d 100644 --- a/controller/response.go +++ b/controller/response.go @@ -54,12 +54,6 @@ func (r *Response) GetMyResponses(ctx echo.Context, params openapi.GetMyResponse ResponseGroups: []openapi.ResponseWithQuestionnaireInfoItem{}, } - var sort string - if params.Sort == nil { - sort = "" - } else { - sort = string(*params.Sort) - } var pageNum int if params.Page == nil { pageNum = 1 @@ -76,9 +70,9 @@ func (r *Response) GetMyResponses(ctx echo.Context, params openapi.GetMyResponse questionnaireIDs = *params.QuestionnaireIDs } - responseGroups, pageMax, err := r.IRespondent.GetMyResponseGroups(ctx.Request().Context(), sort, userID, questionnaireIDs, params.IsDraft, pageNum) + responseGroups, pageMax, err := r.IRespondent.GetMyResponseGroups(ctx.Request().Context(), userID, questionnaireIDs, params.IsDraft, pageNum) if err != nil { - if errors.Is(err, model.ErrTooLargePageNum) || errors.Is(err, model.ErrInvalidSortParam) { + if errors.Is(err, model.ErrTooLargePageNum) { ctx.Logger().Infof("invalid myResponses params: %+v", err) return openapi.ResponsesWithQuestionnaireInfo{}, echo.NewHTTPError(http.StatusBadRequest, err) } diff --git a/controller/response_test.go b/controller/response_test.go index b2c09b5c..3ca83ab1 100644 --- a/controller/response_test.go +++ b/controller/response_test.go @@ -196,6 +196,31 @@ func TestGetMyResponses(t *testing.T) { response4, err := q.PostQuestionnaireResponse(ctx, questionnaireDetail.QuestionnaireId, newResponse, "myResponsesSpecialUser") require.NoError(t, err) + questionnaireAnonymous := sampleQuestionnaire + questionnaireAnonymous.IsAnonymous = true + e = echo.New() + body, err = json.Marshal(questionnaireAnonymous) + require.NoError(t, err) + req = httptest.NewRequest(http.MethodPost, "/questionnaires", bytes.NewReader(body)) + rec = httptest.NewRecorder() + req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) + ctx = e.NewContext(req, rec) + questionnaireAnonymousDetail, err := q.PostQuestionnaire(ctx, questionnaireAnonymous) + require.NoError(t, err) + + AddQuestionID2SampleResponse(questionnaireAnonymousDetail.QuestionnaireId) + + newResponse = sampleResponse + e = echo.New() + body, err = json.Marshal(newResponse) + require.NoError(t, err) + req = httptest.NewRequest(http.MethodPost, fmt.Sprintf("/questionnaires/%d/responses", questionnaireAnonymousDetail.QuestionnaireId), bytes.NewReader(body)) + rec = httptest.NewRecorder() + req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) + ctx = e.NewContext(req, rec) + responseAnonymous, err := q.PostQuestionnaireResponse(ctx, questionnaireAnonymousDetail.QuestionnaireId, newResponse, userOne) + require.NoError(t, err) + AddQuestionID2SampleResponseMutex.Unlock() type args struct { @@ -203,10 +228,11 @@ func TestGetMyResponses(t *testing.T) { params openapi.GetMyResponsesParams } type expect struct { - isErr bool - err error - pageMax *int - responseIDList *[]int + isErr bool + err error + pageMax *int + responseIDList *[]int + nilRespondentResponseID *[]int } type test struct { description string @@ -214,13 +240,6 @@ func TestGetMyResponses(t *testing.T) { expect } - sortInvalid := (openapi.ResponseSortInQuery)("abcde") - sortTraqID := (openapi.ResponseSortInQuery)("traqid") - sortTraqIDDesc := (openapi.ResponseSortInQuery)("-traqid") - sortSubmittedAt := (openapi.ResponseSortInQuery)("submitted_at") - sortSubmittedAtDesc := (openapi.ResponseSortInQuery)("-submitted_at") - sortModifiedAt := (openapi.ResponseSortInQuery)("modified_at") - sortModifiedAtDesc := (openapi.ResponseSortInQuery)("-modified_at") pageZero := 0 largePageNum := 100000000 pageOne := 1 @@ -235,91 +254,8 @@ func TestGetMyResponses(t *testing.T) { params: openapi.GetMyResponsesParams{}, }, expect: expect{ - pageMax: &pageOne, - }, - }, - { - description: "invalid param sort", - args: args{ - userID: userOne, - params: openapi.GetMyResponsesParams{ - Sort: &sortInvalid, - }, - }, - expect: expect{ - isErr: true, - }, - }, - { - description: "sort submitted_at", - args: args{ - userID: userOne, - params: openapi.GetMyResponsesParams{ - Sort: &sortSubmittedAt, - }, - }, - expect: expect{ - pageMax: &pageOne, - }, - }, - { - description: "sort -submitted_at", - args: args{ - userID: userOne, - params: openapi.GetMyResponsesParams{ - Sort: &sortSubmittedAtDesc, - }, - }, - expect: expect{ - pageMax: &pageOne, - }, - }, - { - description: "sort traqid", - args: args{ - userID: userOne, - params: openapi.GetMyResponsesParams{ - Sort: &sortTraqID, - }, - }, - expect: expect{ - pageMax: &pageOne, - }, - }, - { - description: "sort -traqid", - args: args{ - userID: userOne, - params: openapi.GetMyResponsesParams{ - Sort: &sortTraqIDDesc, - }, - }, - expect: expect{ - pageMax: &pageOne, - }, - }, - { - description: "sort modified_at", - args: args{ - userID: userOne, - params: openapi.GetMyResponsesParams{ - Sort: &sortModifiedAt, - }, - }, - expect: expect{ - pageMax: &pageOne, - }, - }, - { - description: "sort -modified_at", - args: args{ - userID: userOne, - params: openapi.GetMyResponsesParams{ - Sort: &sortModifiedAtDesc, - }, - }, - expect: expect{ - pageMax: &pageOne, + pageMax: &pageOne, + nilRespondentResponseID: &[]int{responseAnonymous.ResponseId}, }, }, { @@ -355,8 +291,9 @@ func TestGetMyResponses(t *testing.T) { }, }, expect: expect{ - pageMax: &pageOne, - responseIDList: &[]int{responseDraft.ResponseId}, + pageMax: &pageOne, + responseIDList: &[]int{responseDraft.ResponseId}, + nilRespondentResponseID: &[]int{}, }, }, { @@ -368,8 +305,9 @@ func TestGetMyResponses(t *testing.T) { }, }, expect: expect{ - pageMax: &pageOne, - responseIDList: &[]int{response0.ResponseId, response1.ResponseId}, + pageMax: &pageOne, + responseIDList: &[]int{response0.ResponseId, response1.ResponseId, responseAnonymous.ResponseId}, + nilRespondentResponseID: &[]int{responseAnonymous.ResponseId}, }, }, { @@ -379,8 +317,9 @@ func TestGetMyResponses(t *testing.T) { params: openapi.GetMyResponsesParams{}, }, expect: expect{ - pageMax: &pageOne, - responseIDList: &[]int{response4.ResponseId}, + pageMax: &pageOne, + responseIDList: &[]int{response4.ResponseId}, + nilRespondentResponseID: &[]int{}, }, }, { @@ -390,17 +329,15 @@ func TestGetMyResponses(t *testing.T) { params: openapi.GetMyResponsesParams{}, }, expect: expect{ - pageMax: &pageZero, - responseIDList: &[]int{}, + pageMax: &pageZero, + responseIDList: &[]int{}, + nilRespondentResponseID: &[]int{}, }, }, } for _, testCase := range testCases { params := url.Values{} - if testCase.args.params.Sort != nil { - params.Add("sort", string(*testCase.args.params.Sort)) - } if testCase.args.params.Page != nil { params.Add("page", fmt.Sprint(*testCase.args.params.Page)) } @@ -430,61 +367,6 @@ func TestGetMyResponses(t *testing.T) { assertion.Equal(*testCase.expect.pageMax, responseLists.PageMax, testCase.description, "pageMax") } - for _, responseList := range responseLists.ResponseGroups { - if testCase.args.params.Sort != nil { - switch *testCase.args.params.Sort { - case "submitted_at": - var preCreatedAt time.Time - for _, response := range responseList.Responses { - if !preCreatedAt.IsZero() { - assertion.False(preCreatedAt.After(response.SubmittedAt), testCase.description, "submitted_at") - } - preCreatedAt = response.SubmittedAt - } - case "-submitted_at": - var preCreatedAt time.Time - for _, response := range responseList.Responses { - if !preCreatedAt.IsZero() { - assertion.False(preCreatedAt.Before(response.SubmittedAt), testCase.description, "-submitted_at") - } - preCreatedAt = response.SubmittedAt - } - case "traqid": - var preTraqID string - for _, response := range responseList.Responses { - if preTraqID != "" { - assertion.False(preTraqID > *response.Respondent, testCase.description, "traqid") - } - preTraqID = *response.Respondent - } - case "-traqid": - var preTraqID string - for _, response := range responseList.Responses { - if preTraqID != "" { - assertion.False(preTraqID < *response.Respondent, testCase.description, "-traqid") - } - preTraqID = *response.Respondent - } - case "modified_at": - var preModifiedAt time.Time - for _, response := range responseList.Responses { - if !preModifiedAt.IsZero() { - assertion.False(preModifiedAt.After(response.ModifiedAt), testCase.description, "modified_at") - } - preModifiedAt = response.ModifiedAt - } - case "-modified_at": - var preModifiedAt time.Time - for _, response := range responseList.Responses { - if !preModifiedAt.IsZero() { - assertion.False(preModifiedAt.Before(response.ModifiedAt), testCase.description, "-modified_at") - } - preModifiedAt = response.ModifiedAt - } - } - } - } - if testCase.expect.responseIDList != nil { responseIDList := []int{} for _, responseList := range responseLists.ResponseGroups { @@ -499,9 +381,29 @@ func TestGetMyResponses(t *testing.T) { assertion.Equal(*testCase.expect.responseIDList, responseIDList, testCase.description, "responseIDList") } + if testCase.expect.nilRespondentResponseID != nil { + nilRespondentResponseID := []int{} + for _, responseList := range responseLists.ResponseGroups { + for _, response := range responseList.Responses { + if response.Respondent == nil { + nilRespondentResponseID = append(nilRespondentResponseID, response.ResponseId) + } + } + } + sort.Slice(*testCase.expect.nilRespondentResponseID, func(i, j int) bool { + return (*testCase.expect.nilRespondentResponseID)[i] < (*testCase.expect.nilRespondentResponseID)[j] + }) + sort.Slice(nilRespondentResponseID, func(i, j int) bool { return nilRespondentResponseID[i] < nilRespondentResponseID[j] }) + assertion.Equal(*testCase.expect.nilRespondentResponseID, nilRespondentResponseID, testCase.description, "nilRespondentResponseID") + } + for _, responseList := range responseLists.ResponseGroups { for _, response := range responseList.Responses { - assertion.Equal(testCase.args.userID, *response.Respondent, testCase.description, "response with no respondent") + if response.Respondent == nil { + assertion.True(response.IsAnonymous, testCase.description, "response with nil respondent should be anonymous") + continue + } + assertion.Equal(testCase.args.userID, *response.Respondent, testCase.description, "response respondent should match userID") } } } diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 4ad2439f..b1d041b4 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -300,7 +300,6 @@ paths: # TODO 変数の命名を確認する - response description: 自分のすべての回答のリストを、アンケートごとにまとめてページ単位で取得します。 parameters: - - $ref: "#/components/parameters/responseSortInQuery" - $ref: "#/components/parameters/pageInQuery" - $ref: "#/components/parameters/questionnaireIDsInQuery" - $ref: "#/components/parameters/isDraftInQuery" diff --git a/handler/response.go b/handler/response.go index f458f188..29910fbb 100644 --- a/handler/response.go +++ b/handler/response.go @@ -1,7 +1,6 @@ package handler import ( - "errors" "fmt" "net/http" @@ -19,12 +18,8 @@ func (h Handler) GetMyResponses(ctx echo.Context, params openapi.GetMyResponsesP res, err := h.Response.GetMyResponses(ctx, params, userID) if err != nil { - var httpErr *echo.HTTPError - if errors.As(err, &httpErr) { - return httpErr - } 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 err } return ctx.JSON(200, res) } diff --git a/model/respondents.go b/model/respondents.go index 67e9a62a..f60aac96 100644 --- a/model/respondents.go +++ b/model/respondents.go @@ -34,7 +34,7 @@ type IRespondent interface { GetRespondentInfos(ctx context.Context, userID string, questionnaireIDs ...int) ([]RespondentInfo, error) GetRespondentDetail(ctx context.Context, responseID int) (RespondentDetail, error) GetRespondentDetails(ctx context.Context, questionnaireID int, sort string, onlyMyResponse bool, userID string, isDraft *bool) ([]RespondentDetail, error) - GetMyResponseGroups(ctx context.Context, sort string, userID string, questionnaireIDs []int, isDraft *bool, pageNum int) ([]MyResponseGroup, int, error) + GetMyResponseGroups(ctx context.Context, userID string, questionnaireIDs []int, isDraft *bool, pageNum int) ([]MyResponseGroup, int, error) GetRespondentsUserIDs(ctx context.Context, questionnaireIDs []int) ([]Respondents, error) GetMyResponseIDs(ctx context.Context, sort string, userID string, questionnaireIDs []int, isDraft *bool) ([]int, error) CheckRespondent(ctx context.Context, userID string, questionnaireID int) (bool, error) diff --git a/model/respondents_impl.go b/model/respondents_impl.go index 652503f5..f7734028 100755 --- a/model/respondents_impl.go +++ b/model/respondents_impl.go @@ -461,35 +461,8 @@ func buildMyResponseBaseQuery(db *gorm.DB, userID string, questionnaireIDs []int return query } -func setMyResponseGroupOrder(query *gorm.DB, sort string) (*gorm.DB, error) { - switch sort { - case "": - return query.Order("first_response_id"), nil - case "submitted_at": - return query. - Order("MIN(respondents.submitted_at)"). - Order("first_response_id"), nil - case "-submitted_at": - return query. - Order("MAX(respondents.submitted_at) DESC"). - Order("first_response_id"), nil - case "modified_at": - return query. - Order("MIN(respondents.modified_at)"). - Order("first_response_id"), nil - case "-modified_at": - return query. - Order("MAX(respondents.modified_at) DESC"). - Order("first_response_id"), nil - case "traqid", "-traqid": - return query.Order("first_response_id"), nil - default: - return nil, fmt.Errorf("failed to convert sort param to group order: %w", ErrInvalidSortParam) - } -} - // GetMyResponseGroups 自分の回答をアンケートごとにまとめて取得 -func (*Respondent) GetMyResponseGroups(ctx context.Context, sort string, userID string, questionnaireIDs []int, isDraft *bool, pageNum int) ([]MyResponseGroup, int, error) { +func (*Respondent) GetMyResponseGroups(ctx context.Context, userID string, questionnaireIDs []int, isDraft *bool, pageNum int) ([]MyResponseGroup, int, error) { db, err := getTx(ctx) if err != nil { return nil, 0, fmt.Errorf("failed to get transaction: %w", err) @@ -523,11 +496,8 @@ func (*Respondent) GetMyResponseGroups(ctx context.Context, sort string, userID "MIN(respondents.response_id) AS first_response_id", userID, ). - Group("respondents.questionnaire_id, questionnaires.id, questionnaires.title, questionnaires.created_at, questionnaires.modified_at, questionnaires.res_time_limit, questionnaires.is_anonymous") - groupQuery, err = setMyResponseGroupOrder(groupQuery, sort) - if err != nil { - return nil, 0, fmt.Errorf("failed to set my response group order: %w", err) - } + Group("respondents.questionnaire_id, questionnaires.id, questionnaires.title, questionnaires.created_at, questionnaires.modified_at, questionnaires.res_time_limit, questionnaires.is_anonymous"). + Order("first_response_id") err = groupQuery. Limit(20). @@ -573,10 +543,7 @@ func (*Respondent) GetMyResponseGroups(ctx context.Context, sort string, userID respondentQuery = respondentQuery.Where("submitted_at IS NOT NULL") } } - respondentQuery, _, err = setRespondentsOrder(respondentQuery, sort) - if err != nil { - return nil, 0, fmt.Errorf("failed to set respondents order: %w", err) - } + respondentQuery = respondentQuery.Order("response_id") err = respondentQuery.Find(&respondents).Error if err != nil { diff --git a/openapi/server.go b/openapi/server.go index 3d3eb453..4ddadc0c 100644 --- a/openapi/server.go +++ b/openapi/server.go @@ -291,13 +291,6 @@ func (w *ServerInterfaceWrapper) GetMyResponses(ctx echo.Context) error { // Parameter object where we will unmarshal all parameters from the context var params GetMyResponsesParams - // ------------- Optional query parameter "sort" ------------- - - err = runtime.BindQueryParameter("form", true, false, "sort", ctx.QueryParams(), ¶ms.Sort) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter sort: %s", err)) - } - // ------------- Optional query parameter "page" ------------- err = runtime.BindQueryParameter("form", true, false, "page", ctx.QueryParams(), ¶ms.Page) diff --git a/openapi/spec.go b/openapi/spec.go index 37e5f89a..5d69b2d8 100644 --- a/openapi/spec.go +++ b/openapi/spec.go @@ -93,17 +93,17 @@ var swaggerSpec = []string{ "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/openapi/types.go b/openapi/types.go index 5798b386..0976093b 100644 --- a/openapi/types.go +++ b/openapi/types.go @@ -807,9 +807,6 @@ type GetQuestionnaireResponsesParams struct { // GetMyResponsesParams defines parameters for GetMyResponses. type GetMyResponsesParams struct { - // Sort 並び順 (作成日時が新しい "submitted_at", 作成日時が古い "-submitted_at", TraqIDの昇順 "traqid", TraqIDの降順 "-traqid", 更新日時が新しい "modified_at", 更新日時が古い "-modified_at" ) - Sort *ResponseSortInQuery `form:"sort,omitempty" json:"sort,omitempty"` - // Page 何ページ目か (未定義の場合は1ページ目) Page *PageInQuery `form:"page,omitempty" json:"page,omitempty"` From 81d39d94972b6389230f163cb474711ba35f81e4 Mon Sep 17 00:00:00 2001 From: kaitoyama <45167401+kaitoyama@users.noreply.github.com> Date: Wed, 1 Apr 2026 01:42:35 +0900 Subject: [PATCH 4/7] Fix myResponses test expectations --- controller/response_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controller/response_test.go b/controller/response_test.go index 3ca83ab1..695285a5 100644 --- a/controller/response_test.go +++ b/controller/response_test.go @@ -306,8 +306,8 @@ func TestGetMyResponses(t *testing.T) { }, expect: expect{ pageMax: &pageOne, - responseIDList: &[]int{response0.ResponseId, response1.ResponseId, responseAnonymous.ResponseId}, - nilRespondentResponseID: &[]int{responseAnonymous.ResponseId}, + responseIDList: &[]int{response0.ResponseId, response1.ResponseId}, + nilRespondentResponseID: &[]int{}, }, }, { From bc2f58bb8c9174dba62af1108f55ba22e86cee7d Mon Sep 17 00:00:00 2001 From: kaitoyama <45167401+kaitoyama@users.noreply.github.com> Date: Wed, 1 Apr 2026 01:47:57 +0900 Subject: [PATCH 5/7] Return bad request for invalid response body --- controller/questionnaire.go | 4 ++-- controller/response.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/controller/questionnaire.go b/controller/questionnaire.go index 4767aa0c..172cfaf3 100644 --- a/controller/questionnaire.go +++ b/controller/questionnaire.go @@ -1043,8 +1043,8 @@ func (q *Questionnaire) PostQuestionnaireResponse(c echo.Context, questionnaireI responseMetas, err := responseBody2ResponseMetas(params.Body, questions) if err != nil { - c.Logger().Errorf("failed to convert response body to response metas: %+v", err) - return res, echo.NewHTTPError(http.StatusInternalServerError, err) + c.Logger().Infof("invalid response body: %+v", err) + return res, echo.NewHTTPError(http.StatusBadRequest, fmt.Errorf("invalid response body: %w", err)) } // validationでチェック diff --git a/controller/response.go b/controller/response.go index 936de56d..596d2195 100644 --- a/controller/response.go +++ b/controller/response.go @@ -196,8 +196,8 @@ func (r *Response) EditResponse(ctx echo.Context, responseID openapi.ResponseIDI 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)) + ctx.Logger().Infof("invalid response body: %+v", err) + return echo.NewHTTPError(http.StatusBadRequest, fmt.Errorf("invalid response body: %w", err)) } // validationでチェック From 51bac831133e0540cd4ec12ab2748c1c7c72be12 Mon Sep 17 00:00:00 2001 From: kaitoyama <45167401+kaitoyama@users.noreply.github.com> Date: Wed, 1 Apr 2026 17:39:45 +0900 Subject: [PATCH 6/7] Fix my responses test expectations --- controller/response_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controller/response_test.go b/controller/response_test.go index 695285a5..3ca83ab1 100644 --- a/controller/response_test.go +++ b/controller/response_test.go @@ -306,8 +306,8 @@ func TestGetMyResponses(t *testing.T) { }, expect: expect{ pageMax: &pageOne, - responseIDList: &[]int{response0.ResponseId, response1.ResponseId}, - nilRespondentResponseID: &[]int{}, + responseIDList: &[]int{response0.ResponseId, response1.ResponseId, responseAnonymous.ResponseId}, + nilRespondentResponseID: &[]int{responseAnonymous.ResponseId}, }, }, { From 811140a4871c5d35283cee37eb07d6c896cb9c4d Mon Sep 17 00:00:00 2001 From: kaitoyama <45167401+kaitoyama@users.noreply.github.com> Date: Wed, 1 Apr 2026 18:03:41 +0900 Subject: [PATCH 7/7] Isolate controller test fixtures --- controller/questionnaire_test.go | 13 ++++++++----- controller/response_test.go | 25 ++++++++++++++++++------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/controller/questionnaire_test.go b/controller/questionnaire_test.go index 978f3610..ef9dd0fa 100644 --- a/controller/questionnaire_test.go +++ b/controller/questionnaire_test.go @@ -212,6 +212,9 @@ func TestGetQuestionnaires(t *testing.T) { assertion := assert.New(t) + uniqueSearchTitle := fmt.Sprintf("search test %d", time.Now().UnixNano()) + specialTargetUser := fmt.Sprintf("stgq%d", time.Now().UnixNano()) + questionnaire := sampleQuestionnaire e := echo.New() body, err := json.Marshal(questionnaire) @@ -224,7 +227,7 @@ func TestGetQuestionnaires(t *testing.T) { require.NoError(t, err) questionnaire = sampleQuestionnaire - questionnaire.Title = "search test" + questionnaire.Title = uniqueSearchTitle e = echo.New() body, err = json.Marshal(questionnaire) require.NoError(t, err) @@ -236,7 +239,7 @@ func TestGetQuestionnaires(t *testing.T) { require.NoError(t, err) questionnaire = sampleQuestionnaire - questionnaire.Title = "search test" + questionnaire.Title = uniqueSearchTitle e = echo.New() body, err = json.Marshal(questionnaire) require.NoError(t, err) @@ -260,7 +263,7 @@ func TestGetQuestionnaires(t *testing.T) { require.NoError(t, err) questionnaire = sampleQuestionnaire - questionnaire.Target.Users = []string{"specialTargetUser"} + questionnaire.Target.Users = []string{specialTargetUser} e = echo.New() body, err = json.Marshal(questionnaire) require.NoError(t, err) @@ -293,7 +296,7 @@ func TestGetQuestionnaires(t *testing.T) { sortTitleDesc := (openapi.SortInQuery)("-title") sortModifiedAt := (openapi.SortInQuery)("modified_at") sortModifiedAtDesc := (openapi.SortInQuery)("-modified_at") - searchTest := (openapi.SearchInQuery)("search test") + searchTest := openapi.SearchInQuery(uniqueSearchTitle) largePageNum := 100000000 constTrue := true @@ -435,7 +438,7 @@ func TestGetQuestionnaires(t *testing.T) { { description: "only targeting by me special target user", args: args{ - userID: "specialTargetUser", + userID: specialTargetUser, params: openapi.GetQuestionnairesParams{ OnlyTargetingMe: &constTrue, }, diff --git a/controller/response_test.go b/controller/response_test.go index 3ca83ab1..4cb3aee1 100644 --- a/controller/response_test.go +++ b/controller/response_test.go @@ -245,13 +245,16 @@ func TestGetMyResponses(t *testing.T) { pageOne := 1 constTrue := true constFalse := false + questionnaireIDs := []int{questionnaireDetail.QuestionnaireId, questionnaireAnonymousDetail.QuestionnaireId} testCases := []test{ { description: "valid", args: args{ userID: userOne, - params: openapi.GetMyResponsesParams{}, + params: openapi.GetMyResponsesParams{ + QuestionnaireIDs: &questionnaireIDs, + }, }, expect: expect{ pageMax: &pageOne, @@ -263,7 +266,8 @@ func TestGetMyResponses(t *testing.T) { args: args{ userID: userOne, params: openapi.GetMyResponsesParams{ - Page: &pageZero, + Page: &pageZero, + QuestionnaireIDs: &questionnaireIDs, }, }, expect: expect{ @@ -275,7 +279,8 @@ func TestGetMyResponses(t *testing.T) { args: args{ userID: userOne, params: openapi.GetMyResponsesParams{ - Page: &largePageNum, + Page: &largePageNum, + QuestionnaireIDs: &questionnaireIDs, }, }, expect: expect{ @@ -287,7 +292,8 @@ func TestGetMyResponses(t *testing.T) { args: args{ userID: userOne, params: openapi.GetMyResponsesParams{ - IsDraft: &constTrue, + IsDraft: &constTrue, + QuestionnaireIDs: &questionnaireIDs, }, }, expect: expect{ @@ -301,7 +307,8 @@ func TestGetMyResponses(t *testing.T) { args: args{ userID: userOne, params: openapi.GetMyResponsesParams{ - IsDraft: &constFalse, + IsDraft: &constFalse, + QuestionnaireIDs: &questionnaireIDs, }, }, expect: expect{ @@ -314,7 +321,9 @@ func TestGetMyResponses(t *testing.T) { description: "special user", args: args{ userID: "myResponsesSpecialUser", - params: openapi.GetMyResponsesParams{}, + params: openapi.GetMyResponsesParams{ + QuestionnaireIDs: &questionnaireIDs, + }, }, expect: expect{ pageMax: &pageOne, @@ -326,7 +335,9 @@ func TestGetMyResponses(t *testing.T) { description: "user with no record", args: args{ userID: "myResponsesNoRecord", - params: openapi.GetMyResponsesParams{}, + params: openapi.GetMyResponsesParams{ + QuestionnaireIDs: &questionnaireIDs, + }, }, expect: expect{ pageMax: &pageZero,