diff --git a/controller/adapter.go b/controller/adapter.go new file mode 100644 index 00000000..4284a385 --- /dev/null +++ b/controller/adapter.go @@ -0,0 +1,344 @@ +package controller + +import ( + "strconv" + + "github.com/labstack/echo/v4" + "github.com/traPtitech/anke-to/model" + "github.com/traPtitech/anke-to/openapi" + "gopkg.in/guregu/null.v4" +) + +func questionnaireInfo2questionnaireSummary(questionnaireInfo model.QuestionnaireInfo, allResponded bool, hasMyDraft bool, hasMyResponse bool, respondedDateTimeByMe null.Time) *openapi.QuestionnaireSummary { + res := openapi.QuestionnaireSummary{ + AllResponded: allResponded, + CreatedAt: questionnaireInfo.CreatedAt, + Description: questionnaireInfo.Description, + HasMyDraft: hasMyDraft, + HasMyResponse: hasMyResponse, + // IsAllowingMultipleResponses: questionnaireInfo.IsAllowingMultipleResponses, + // IsAnonymous: questionnaireInfo.IsAnonymous, + // IsPublished: questionnaireInfo.IsPublished, + IsTargetingMe: questionnaireInfo.IsTargeted, + ModifiedAt: questionnaireInfo.ModifiedAt, + QuestionnaireId: questionnaireInfo.ID, + Title: questionnaireInfo.Title, + } + if respondedDateTimeByMe.Valid { + res.RespondedDateTimeByMe = &respondedDateTimeByMe.Time + } else { + res.RespondedDateTimeByMe = nil + } + if questionnaireInfo.ResTimeLimit.Valid { + res.ResponseDueDateTime = &questionnaireInfo.ResTimeLimit.Time + } else { + res.ResponseDueDateTime = nil + } + return &res +} + +func convertResponseViewableBy(resShareType openapi.ResShareType) string { + switch resShareType { + case "admins": + return "administrators" + case "respondents": + return "respondents" + case "anyone": + return "public" + default: + return "administrators" + } +} + +func convertResSharedTo(resSharedTo string) openapi.ResShareType { + switch resSharedTo { + case "administrators": + return "admins" + case "respondents": + return "respondents" + case "public": + return "anyone" + default: + return "admins" + } + +} + +func createUsersAndGroups(users []string, groups []string) openapi.UsersAndGroups { + res := openapi.UsersAndGroups{ + Users: users, + Groups: groups, + } + return res +} + +func convertOptions(options []model.Options) openapi.QuestionSettingsSingleChoice { + res := openapi.QuestionSettingsSingleChoice{} + for _, option := range options { + res.Options = append(res.Options, option.Body) + } + return res +} + +func convertQuestions(questions []model.Questions) []openapi.Question { + res := []openapi.Question{} + for _, question := range questions { + q := openapi.Question{ + CreatedAt: question.CreatedAt, + // Description: question.Description, + IsRequired: question.IsRequired, + QuestionId: question.ID, + QuestionnaireId: question.QuestionnaireID, + Title: question.Body, + } + switch question.Type { + case "Text": + q.FromQuestionSettingsText( + openapi.QuestionSettingsText{ + QuestionType: "Text", + }, + ) + case "TextArea": + q.FromQuestionSettingsText( + openapi.QuestionSettingsText{ + QuestionType: "TextLong", + }, + ) + case "Number": + q.FromQuestionSettingsNumber( + openapi.QuestionSettingsNumber{ + QuestionType: "Number", + }, + ) + case "Radio": + q.FromQuestionSettingsSingleChoice( + openapi.QuestionSettingsSingleChoice{ + QuestionType: "Radio", + Options: convertOptions(question.Options).Options, + }, + ) + case "MultipleChoice": + q.FromQuestionSettingsMultipleChoice( + openapi.QuestionSettingsMultipleChoice{ + QuestionType: "MultipleChoice", + Options: convertOptions(question.Options).Options, + }, + ) + case "LinearScale": + q.FromQuestionSettingsScale( + openapi.QuestionSettingsScale{ + QuestionType: "LinearScale", + MinLabel: &question.ScaleLabels[0].ScaleLabelLeft, + MaxLabel: &question.ScaleLabels[0].ScaleLabelRight, + MinValue: question.ScaleLabels[0].ScaleMin, + MaxValue: question.ScaleLabels[0].ScaleMax, + }, + ) + } + } + return res +} + +func convertRespondents(respondents []model.Respondents) []string { + res := []string{} + for _, respondent := range respondents { + res = append(res, respondent.UserTraqid) + } + return res +} + +func questionnaire2QuestionnaireDetail(questionnaires model.Questionnaires, adminUsers []string, adminGroups []string, targetUsers []string, targetGroups []string, respondents []string) openapi.QuestionnaireDetail { + res := openapi.QuestionnaireDetail{ + Admins: createUsersAndGroups(adminUsers, adminGroups), + CreatedAt: questionnaires.CreatedAt, + Description: questionnaires.Description, + // IsAllowingMultipleResponses: questionnaires.IsAllowingMultipleResponses, + // IsAnonymous: questionnaires.IsAnonymous, + // IsPublished: questionnaires.IsPublished, + ModifiedAt: questionnaires.ModifiedAt, + QuestionnaireId: questionnaires.ID, + Questions: convertQuestions(questionnaires.Questions), + Respondents: respondents, + ResponseDueDateTime: &questionnaires.ResTimeLimit.Time, + ResponseViewableBy: convertResSharedTo(questionnaires.ResSharedTo), + Targets: createUsersAndGroups(targetUsers, targetGroups), + Title: questionnaires.Title, + } + return res +} + +func respondentDetail2Response(ctx echo.Context, respondentDetail model.RespondentDetail) (openapi.Response, error) { + oResponseBodies := []openapi.ResponseBody{} + for j, r := range respondentDetail.Responses { + oResponseBody := openapi.ResponseBody{} + switch r.QuestionType { + case "Text": + if r.Body.Valid { + oResponseBody.FromResponseBodyText( + openapi.ResponseBodyText{ + Answer: r.Body.String, + QuestionType: "Text", + }, + ) + } + case "TextArea": + if r.Body.Valid { + oResponseBody.FromResponseBodyText( + openapi.ResponseBodyText{ + Answer: r.Body.String, + QuestionType: "TextLong", + }, + ) + } + case "Number": + if r.Body.Valid { + answer, err := strconv.ParseFloat(r.Body.String, 32) + if err != nil { + ctx.Logger().Errorf("failed to convert string to float: %+v", err) + return openapi.Response{}, err + } + oResponseBody.FromResponseBodyNumber( + openapi.ResponseBodyNumber{ + Answer: float32(answer), + QuestionType: "Number", + }, + ) + } + case "MultipleChoice": + if r.Body.Valid { + answer := []int{} + questionnaire, _, _, _, _, _, err := model.NewQuestionnaire().GetQuestionnaireInfo(ctx.Request().Context(), r.QuestionID) + if err != nil { + ctx.Logger().Errorf("failed to get questionnaire info: %+v", err) + return openapi.Response{}, err + } + for _, a := range r.OptionResponse { + for i, o := range questionnaire.Questions[j].Options { + if a == o.Body { + answer = append(answer, i) + } + } + } + oResponseBody.FromResponseBodyMultipleChoice( + openapi.ResponseBodyMultipleChoice{ + Answer: answer, + QuestionType: "MultipleChoice", + }, + ) + } + case "Checkbox": + if r.Body.Valid { + questionnaire, _, _, _, _, _, err := model.NewQuestionnaire().GetQuestionnaireInfo(ctx.Request().Context(), r.QuestionID) + if err != nil { + ctx.Logger().Errorf("failed to get questionnaire info: %+v", err) + return openapi.Response{}, err + } + for _, a := range r.OptionResponse { + for i, o := range questionnaire.Questions[j].Options { + if a == o.Body { + oResponseBody.FromResponseBodySingleChoice( + openapi.ResponseBodySingleChoice{ + Answer: i, + QuestionType: "SingleChoice", + }, + ) + } + } + } + } + case "LinearScale": + if r.Body.Valid { + answer, err := strconv.Atoi(r.Body.String) + if err != nil { + ctx.Logger().Errorf("failed to convert string to int: %+v", err) + return openapi.Response{}, err + } + oResponseBody.FromResponseBodyScale( + openapi.ResponseBodyScale{ + Answer: answer, + QuestionType: "LinearScale", + }, + ) + } + } + oResponseBodies = append(oResponseBodies, oResponseBody) + } + + res := openapi.Response{ + Body: oResponseBodies, + IsDraft: respondentDetail.SubmittedAt.Valid, + ModifiedAt: respondentDetail.ModifiedAt, + QuestionnaireId: respondentDetail.QuestionnaireID, + Respondent: respondentDetail.TraqID, + ResponseId: respondentDetail.ResponseID, + SubmittedAt: respondentDetail.SubmittedAt.Time, + } + + 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/questionnaire.go b/controller/questionnaire.go new file mode 100644 index 00000000..3c583503 --- /dev/null +++ b/controller/questionnaire.go @@ -0,0 +1,442 @@ +package controller + +import ( + "context" + "errors" + "fmt" + "net/http" + "strings" + "time" + + "github.com/labstack/echo/v4" + "github.com/traPtitech/anke-to/model" + "github.com/traPtitech/anke-to/openapi" + "github.com/traPtitech/anke-to/traq" + "gopkg.in/guregu/null.v4" +) + +// Questionnaire Questionnaireの構造体 +type Questionnaire struct { + model.IQuestionnaire + model.ITarget + model.ITargetGroup + model.IAdministrator + model.IAdministratorGroup + model.IQuestion + model.IOption + model.IScaleLabel + model.IValidation + model.ITransaction + traq.IWebhook + Response +} + +func NewQuestionnaire() *Questionnaire { + return &Questionnaire{} +} + +const MaxTitleLength = 50 + +func (q Questionnaire) GetQuestionnaires(ctx echo.Context, userID string, params openapi.GetQuestionnairesParams) (openapi.QuestionnaireList, error) { + res := openapi.QuestionnaireList{} + sort := string(*params.Sort) + search := string(*params.Search) + pageNum := int(*params.Page) + if pageNum < 1 { + pageNum = 1 + } + + questionnaireList, pageMax, err := q.IQuestionnaire.GetQuestionnaires(ctx.Request().Context(), userID, sort, search, pageNum, *params.OnlyTargetingMe, *params.OnlyAdministratedByMe) + if err != nil { + return res, err + } + + for _, questionnaire := range questionnaireList { + targets, err := q.ITarget.GetTargets(ctx.Request().Context(), []int{questionnaire.ID}) + if err != nil { + return res, err + } + allRespondend := false + if len(targets) == 0 { + allRespondend = true + } else { + respondents, err := q.IRespondent.GetRespondentsUserIDs(ctx.Request().Context(), []int{questionnaire.ID}) + if err != nil { + return res, err + } + allRespondend = isAllTargetsReponded(targets, respondents) + } + + hasMyDraft := false + hasMyResponse := false + respondendDateTimeByMe := null.Time{} + + myRespondents, err := q.GetRespondentInfos(ctx.Request().Context(), userID, questionnaire.ID) + if err != nil { + return res, err + } + for _, respondent := range myRespondents { + if !respondent.SubmittedAt.Valid { + hasMyDraft = true + } + if respondent.SubmittedAt.Valid { + if !respondendDateTimeByMe.Valid { + respondendDateTimeByMe = respondent.SubmittedAt + } + hasMyResponse = true + } + } + + res.PageMax = pageMax + res.Questionnaires = append(res.Questionnaires, *questionnaireInfo2questionnaireSummary(questionnaire, allRespondend, hasMyDraft, hasMyResponse, respondendDateTimeByMe)) + } + return res, nil +} + +func (q Questionnaire) PostQuestionnaire(c echo.Context, userID string, params openapi.PostQuestionnaireJSONRequestBody) (openapi.QuestionnaireDetail, error) { + responseDueDateTime := null.Time{} + if params.ResponseDueDateTime != nil { + responseDueDateTime.Valid = true + responseDueDateTime.Time = *params.ResponseDueDateTime + } + if responseDueDateTime.Valid { + isBefore := responseDueDateTime.ValueOrZero().Before(time.Now()) + if isBefore { + c.Logger().Infof("invalid resTimeLimit: %+v", responseDueDateTime) + return openapi.QuestionnaireDetail{}, echo.NewHTTPError(http.StatusBadRequest, "invalid resTimeLimit") + } + } + + questionnaireID := 0 + + err := q.ITransaction.Do(c.Request().Context(), nil, func(ctx context.Context) error { + questionnaireID, err := q.InsertQuestionnaire(ctx, params.Title, params.Description, responseDueDateTime, convertResponseViewableBy(params.ResponseViewableBy)) + if err != nil { + c.Logger().Errorf("failed to insert questionnaire: %+v", err) + return err + } + allTargetUsers, err := rollOutUsersAndGroups(params.Targets.Users, params.Targets.Groups) + if err != nil { + c.Logger().Errorf("failed to roll out users and groups: %+v", err) + return err + } + targetGroupNames, err := uuid2GroupNames(params.Targets.Groups) + if err != nil { + c.Logger().Errorf("failed to get group names: %+v", err) + return err + } + err = q.InsertTargets(ctx, questionnaireID, allTargetUsers) + if err != nil { + c.Logger().Errorf("failed to insert targets: %+v", err) + return err + } + err = q.InsertTargetGroups(ctx, questionnaireID, params.Targets.Groups) + if err != nil { + c.Logger().Errorf("failed to insert target groups: %+v", err) + return err + } + allAdminUsers, err := rollOutUsersAndGroups(params.Admins.Users, params.Admins.Groups) + if err != nil { + c.Logger().Errorf("failed to roll out administrators: %+v", err) + return err + } + adminGroupNames, err := uuid2GroupNames(params.Admins.Groups) + if err != nil { + c.Logger().Errorf("failed to get group names: %+v", err) + return err + } + err = q.InsertAdministrators(ctx, questionnaireID, allAdminUsers) + if err != nil { + c.Logger().Errorf("failed to insert administrators: %+v", err) + return err + } + err = q.InsertAdministratorGroups(ctx, questionnaireID, params.Admins.Groups) + if err != nil { + c.Logger().Errorf("failed to insert administrator groups: %+v", err) + return err + } + + message := createQuestionnaireMessage( + questionnaireID, + params.Title, + params.Description, + append(allAdminUsers, adminGroupNames...), + responseDueDateTime, + append(allTargetUsers, targetGroupNames...), + ) + err = q.PostMessage(message) + if err != nil { + c.Logger().Errorf("failed to post message: %+v", err) + return err + } + + return nil + }) + if err != nil { + c.Logger().Errorf("failed to create a questionnaire: %+v", err) + return openapi.QuestionnaireDetail{}, echo.NewHTTPError(http.StatusInternalServerError, "failed to create a questionnaire") + } + questionnaireInfo, targets, targetGroups, admins, adminGroups, respondents, err := q.GetQuestionnaireInfo(c.Request().Context(), questionnaireID) + if err != nil { + c.Logger().Errorf("failed to get questionnaire info: %+v", err) + return openapi.QuestionnaireDetail{}, echo.NewHTTPError(http.StatusInternalServerError, "failed to get questionnaire info") + } + + questionnaireDetail := questionnaire2QuestionnaireDetail(*questionnaireInfo, admins, adminGroups, targets, targetGroups, respondents) + return questionnaireDetail, nil +} +func (q Questionnaire) GetQuestionnaire(ctx echo.Context, questionnaireID int) (openapi.QuestionnaireDetail, error) { + questionnaireInfo, targets, targetGroups, admins, adminGroups, respondents, err := q.GetQuestionnaireInfo(ctx.Request().Context(), questionnaireID) + if err != nil { + return openapi.QuestionnaireDetail{}, err + } + questionnaireDetail := questionnaire2QuestionnaireDetail(*questionnaireInfo, admins, adminGroups, targets, targetGroups, respondents) + return questionnaireDetail, nil +} + +func (q Questionnaire) EditQuestionnaire(c echo.Context, questionnaireID int, params openapi.EditQuestionnaireJSONRequestBody) error { + responseDueDateTime := null.Time{} + if params.ResponseDueDateTime != nil { + responseDueDateTime.Valid = true + responseDueDateTime.Time = *params.ResponseDueDateTime + } + err := q.ITransaction.Do(c.Request().Context(), nil, func(ctx context.Context) error { + err := q.UpdateQuestionnaire(ctx, params.Title, params.Description, responseDueDateTime, string(params.ResponseViewableBy), questionnaireID) + if err != nil && !errors.Is(err, model.ErrNoRecordUpdated) { + c.Logger().Errorf("failed to update questionnaire: %+v", err) + return err + } + err = q.DeleteTargets(ctx, questionnaireID) + if err != nil { + c.Logger().Errorf("failed to delete targets: %+v", err) + return err + } + err = q.DeleteTargetGroups(ctx, questionnaireID) + if err != nil { + c.Logger().Errorf("failed to delete target groups: %+v", err) + return err + } + allTargetUsers, err := rollOutUsersAndGroups(params.Targets.Users, params.Targets.Groups) + if err != nil { + c.Logger().Errorf("failed to roll out users and groups: %+v", err) + return err + } + err = q.InsertTargets(ctx, questionnaireID, allTargetUsers) + if err != nil { + c.Logger().Errorf("failed to insert targets: %+v", err) + return err + } + err = q.InsertTargetGroups(ctx, questionnaireID, params.Targets.Groups) + if err != nil { + c.Logger().Errorf("failed to insert target groups: %+v", err) + return err + } + err = q.DeleteAdministrators(ctx, questionnaireID) + if err != nil { + c.Logger().Errorf("failed to delete administrators: %+v", err) + return err + } + err = q.DeleteAdministratorGroups(ctx, questionnaireID) + if err != nil { + c.Logger().Errorf("failed to delete administrator groups: %+v", err) + return err + } + allAdminUsers, err := rollOutUsersAndGroups(params.Admins.Users, params.Admins.Groups) + if err != nil { + c.Logger().Errorf("failed to roll out administrators: %+v", err) + return err + } + err = q.InsertAdministrators(ctx, questionnaireID, allAdminUsers) + if err != nil { + c.Logger().Errorf("failed to insert administrators: %+v", err) + return err + } + err = q.InsertAdministratorGroups(ctx, questionnaireID, params.Admins.Groups) + if err != nil { + c.Logger().Errorf("failed to insert administrator groups: %+v", err) + return err + } + + return nil + }) + if err != nil { + c.Logger().Errorf("failed to update a questionnaire: %+v", err) + return echo.NewHTTPError(http.StatusInternalServerError, "failed to update a questionnaire") + } + + return nil +} + +func (q Questionnaire) DeleteQuestionnaire(c echo.Context, questionnaireID int) error { + err := q.ITransaction.Do(c.Request().Context(), nil, func(ctx context.Context) error { + err := q.IQuestionnaire.DeleteQuestionnaire(c.Request().Context(), questionnaireID) + if err != nil { + c.Logger().Errorf("failed to delete questionnaire: %+v", err) + return err + } + + err = q.DeleteTargets(c.Request().Context(), questionnaireID) + if err != nil { + c.Logger().Errorf("failed to delete targets: %+v", err) + return err + } + + err = q.DeleteAdministrators(c.Request().Context(), questionnaireID) + if err != nil { + c.Logger().Errorf("failed to delete administrators: %+v", err) + return err + } + + return nil + }) + if err != nil { + var httpError *echo.HTTPError + if errors.As(err, &httpError) { + return httpError + } + + c.Logger().Errorf("failed to delete questionnaire: %+v", err) + return echo.NewHTTPError(http.StatusInternalServerError, "failed to delete a questionnaire") + } + return nil +} + +func (q Questionnaire) GetQuestionnaireMyRemindStatus(c echo.Context, questionnaireID int) (bool, error) { + // todo: check remind status + return false, nil +} + +func (q Questionnaire) EditQuestionnaireMyRemindStatus(c echo.Context, questionnaireID int) error { + // todo: edit remind status + return nil +} + +func (q Questionnaire) GetQuestionnaireResponses(c echo.Context, questionnaireID int, params openapi.GetQuestionnaireResponsesParams, userID string) (openapi.Responses, error) { + res := []openapi.Response{} + respondentDetails, err := q.GetRespondentDetails(c.Request().Context(), questionnaireID, string(*params.Sort), *params.OnlyMyResponse, userID) + if err != nil { + c.Logger().Errorf("failed to get respondent details: %+v", err) + return res, echo.NewHTTPError(http.StatusInternalServerError, "failed to get respondent details") + } + + for _, respondentDetail := range respondentDetails { + response, err := respondentDetail2Response(c, respondentDetail) + if err != nil { + c.Logger().Errorf("failed to convert respondent detail to response: %+v", err) + return res, echo.NewHTTPError(http.StatusInternalServerError, "failed to convert respondent detail to response") + } + res = append(res, response) + } + + return res, nil +} + +func (q Questionnaire) PostQuestionnaireResponse(c echo.Context, questionnaireID int, params openapi.PostQuestionnaireResponseJSONRequestBody, userID string) (openapi.Response, error) { + res := openapi.Response{} + + limit, err := q.GetQuestionnaireLimit(c.Request().Context(), questionnaireID) + if err != nil { + if errors.Is(err, model.ErrRecordNotFound) { + c.Logger().Info("questionnaire not found") + return res, echo.NewHTTPError(http.StatusNotFound, err) + } + c.Logger().Errorf("failed to get questionnaire limit: %+v", err) + return res, echo.NewHTTPError(http.StatusInternalServerError, err) + } + + // 回答期限を過ぎていたらエラー + if limit.Valid && limit.Time.Before(time.Now()) { + c.Logger().Info("expired questionnaire") + return res, echo.NewHTTPError(http.StatusUnprocessableEntity, err) + } + + var submittedAt, modifiedAt time.Time + //一時保存のときはnull + if params.IsDraft { + submittedAt = time.Time{} + modifiedAt = time.Time{} + } else { + submittedAt = time.Now() + modifiedAt = time.Now() + } + + resopnseID, err := q.InsertRespondent(c.Request().Context(), userID, questionnaireID, null.NewTime(submittedAt, !params.IsDraft)) + if err != nil { + c.Logger().Errorf("failed to insert respondant: %+v", err) + return res, echo.NewHTTPError(http.StatusInternalServerError, err) + } + + res = openapi.Response{ + QuestionnaireId: questionnaireID, + ResponseId: resopnseID, + Respondent: userID, + SubmittedAt: submittedAt, + ModifiedAt: modifiedAt, + IsDraft: params.IsDraft, + Body: params.Body, + } + + return res, nil +} + +func createQuestionnaireMessage(questionnaireID int, title string, description string, administrators []string, resTimeLimit null.Time, targets []string) string { + var resTimeLimitText string + if resTimeLimit.Valid { + resTimeLimitText = resTimeLimit.Time.Local().Format("2006/01/02 15:04") + } else { + resTimeLimitText = "なし" + } + + var targetsMentionText string + if len(targets) == 0 { + targetsMentionText = "なし" + } else { + targetsMentionText = "@" + strings.Join(targets, " @") + } + + return fmt.Sprintf( + `### アンケート『[%s](https://anke-to.trap.jp/questionnaires/%d)』が作成されました +#### 管理者 +%s +#### 説明 +%s +#### 回答期限 +%s +#### 対象者 +%s +#### 回答リンク +https://anke-to.trap.jp/responses/new/%d`, + title, + questionnaireID, + strings.Join(administrators, ","), + description, + resTimeLimitText, + targetsMentionText, + 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 := openapi.ResultItem{ + 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 +} diff --git a/controller/response.go b/controller/response.go new file mode 100644 index 00000000..bb3fd0e3 --- /dev/null +++ b/controller/response.go @@ -0,0 +1,176 @@ +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 + model.IQuestion +} + +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 := openapi.QuestionnaireInfo{ + 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 := openapi.ResponseWithQuestionnaireInfoItem{ + 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 +} + +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/controller/utils.go b/controller/utils.go new file mode 100644 index 00000000..fe9df181 --- /dev/null +++ b/controller/utils.go @@ -0,0 +1,87 @@ +package controller + +import ( + "context" + "slices" + + mapset "github.com/deckarep/golang-set/v2" + "github.com/google/uuid" + "github.com/traPtitech/anke-to/model" + "github.com/traPtitech/anke-to/traq" +) + +func isAllTargetsReponded(targets []model.Targets, respondents []model.Respondents) bool { + respondentsString := []string{} + for _, respondent := range respondents { + respondentsString = append(respondentsString, respondent.UserTraqid) + } + + for _, target := range targets { + if !slices.Contains(respondentsString, target.UserTraqid) { + return false + } + } + return true +} + +func minimizeUsersAndGroups(users []string, groups []uuid.UUID) ([]string, []uuid.UUID, error) { + ctx := context.Background() + client := traq.NewTraqAPIClient() + userSet := mapset.NewSet[string]() + for _, user := range users { + userSet.Add(user) + } + groupUserSet := mapset.NewSet[string]() + for _, group := range groups { + members, err := client.GetGroupMembers(ctx, group.String()) + if err != nil { + return nil, nil, err + } + for _, member := range members { + memberTraqID, err := client.GetUserTraqID(ctx, member.Id) + if err != nil { + return nil, nil, err + } + groupUserSet.Add(memberTraqID) + } + } + userSet = userSet.Difference(groupUserSet) + return userSet.ToSlice(), groups, nil +} + +func rollOutUsersAndGroups(users []string, groups []string) ([]string, error) { + ctx := context.Background() + client := traq.NewTraqAPIClient() + userSet := mapset.NewSet[string]() + for _, user := range users { + userSet.Add(user) + } + for _, group := range groups { + members, err := client.GetGroupMembers(ctx, group) + if err != nil { + return nil, err + } + for _, member := range members { + memberTraqID, err := client.GetUserTraqID(ctx, member.Id) + if err != nil { + return nil, err + } + userSet.Add(memberTraqID) + } + } + return userSet.ToSlice(), nil +} + +func uuid2GroupNames(users []string) ([]string, error) { + ctx := context.Background() + client := traq.NewTraqAPIClient() + groupNames := []string{} + for _, user := range users { + groupName, err := client.GetGroupName(ctx, user) + if err != nil { + return nil, err + } + groupNames = append(groupNames, groupName) + } + return groupNames, nil +} diff --git a/go.mod b/go.mod index 5358018d..1ff36d4d 100644 --- a/go.mod +++ b/go.mod @@ -1,46 +1,46 @@ module github.com/traPtitech/anke-to -go 1.20 +go 1.22.2 require ( github.com/golang/mock v1.6.0 - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/google/subcommands v1.2.0 // indirect github.com/google/wire v0.5.0 - github.com/labstack/echo/v4 v4.11.1 - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/stretchr/testify v1.8.1 - golang.org/x/crypto v0.11.0 // indirect - golang.org/x/mod v0.8.0 // indirect - golang.org/x/net v0.12.0 // indirect - golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f - golang.org/x/sync v0.1.0 - golang.org/x/sys v0.10.0 // indirect - golang.org/x/text v0.11.0 // indirect - golang.org/x/tools v0.6.0 // indirect + github.com/labstack/echo/v4 v4.12.0 + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/stretchr/testify v1.9.0 + golang.org/x/crypto v0.23.0 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/oauth2 v0.10.0 + golang.org/x/sync v0.7.0 + golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect + golang.org/x/tools v0.21.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.27.1 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-playground/validator/v10 v10.10.1 + github.com/go-playground/validator/v10 v10.14.1 github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/jinzhu/inflection v1.0.0 // indirect - github.com/labstack/gommon v0.4.0 // indirect + github.com/labstack/gommon v0.4.2 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - golang.org/x/time v0.3.0 // indirect + golang.org/x/time v0.5.0 // indirect ) require ( - github.com/go-playground/locales v0.14.0 // indirect - github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect github.com/labstack/echo-contrib v0.12.0 - github.com/leodido/go-urn v1.2.1 // indirect + github.com/leodido/go-urn v1.2.4 // indirect ) require ( @@ -65,4 +65,35 @@ require ( gorm.io/plugin/prometheus v0.0.0-20210820101226-2a49866f83ee ) -require github.com/go-gormigrate/gormigrate/v2 v2.1.1 // indirect +require ( + github.com/deepmap/oapi-codegen v1.16.2 + github.com/go-gormigrate/gormigrate/v2 v2.1.1 +) + +require ( + github.com/deckarep/golang-set/v2 v2.6.0 // indirect + github.com/oapi-codegen/oapi-codegen/v2 v2.3.0 // indirect + github.com/traPtitech/go-traq v0.0.0-20240420012203-0152d96098b0 // indirect +) + +require ( + github.com/getkin/kin-openapi v0.124.0 // indirect + github.com/go-openapi/jsonpointer v0.20.2 // indirect + github.com/go-openapi/swag v0.22.8 // indirect + github.com/gorilla/mux v1.8.1 // indirect + github.com/invopop/yaml v0.2.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/oapi-codegen/echo-middleware v1.0.1 + github.com/perimeterx/marshmallow v1.1.5 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) + +require ( + github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gofrs/uuid v4.4.0+incompatible + github.com/google/uuid v1.5.0 // indirect + github.com/oapi-codegen/runtime v1.1.1 // indirect +) diff --git a/go.sum b/go.sum index 83e0cc26..2c369dc4 100644 --- a/go.sum +++ b/go.sum @@ -35,6 +35,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs= github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae/go.mod h1:/cvHQkZ1fst0EmZnA5dFtiQdWCNCFYzb+uE2vqVgvx0= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= @@ -44,12 +45,15 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= +github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/appleboy/gofight/v2 v2.1.2 h1:VOy3jow4vIK8BRQJoC/I9muxyYlJ2yb9ht2hZoS3rf4= github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/casbin/casbin/v2 v2.40.6/go.mod h1:sEL80qBYTbd+BPeL4iyvwYzFT3qwLaESq5aFKVLbLfA= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -67,6 +71,10 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/deepmap/oapi-codegen v1.16.2 h1:xGHx0dNqYfy9gE8a7AVgVM8Sd5oF9SEgePzP+UPAUXI= +github.com/deepmap/oapi-codegen v1.16.2/go.mod h1:rdYoEA2GE+riuZ91DvpmBX9hJbQpuY9wchXpfQ3n+ho= github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= @@ -81,6 +89,12 @@ github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHqu github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/getkin/kin-openapi v0.118.0 h1:z43njxPmJ7TaPpMSCQb7PN0dEYno4tyBPQcrFdHoLuM= +github.com/getkin/kin-openapi v0.118.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc= +github.com/getkin/kin-openapi v0.124.0 h1:VSFNMB9C9rTKBnQ/fpyDU8ytMTr4dWI9QovSKj9kz/M= +github.com/getkin/kin-openapi v0.124.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -93,20 +107,43 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= +github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= +github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.22.8 h1:/9RjDSQ0vbFR+NyjGMkFTsA1IA0fmhKSThmfGZjicbw= +github.com/go-openapi/swag v0.22.8/go.mod h1:6QT22icPLEqAM/z/TChgb4WAveCHF92+2gF0CNjHpPI= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.10.1 h1:uA0+amWMiglNZKZ9FJRKUAe9U3RX91eVn1JYXMWt7ig= github.com/go-playground/validator/v10 v10.10.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k= +github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= @@ -141,6 +178,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -169,12 +208,17 @@ github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3 github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= @@ -183,6 +227,10 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/invopop/yaml v0.1.0 h1:YW3WGUoJEXYfzWBjn00zIlrw7brGVD0fUKRYDPAPhrc= +github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= +github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY= +github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= @@ -197,6 +245,8 @@ github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas= github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -204,6 +254,7 @@ github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= @@ -225,12 +276,24 @@ github.com/labstack/echo-contrib v0.12.0/go.mod h1:kR62TbwsBgmpV2HVab5iQRsQtLuhP github.com/labstack/echo/v4 v4.6.1/go.mod h1:RnjgMWNDB9g/HucVWhQYNQP9PvbYf6adqftqryo7s9k= github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4= github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ= +github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8= +github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8= +github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0= +github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= @@ -243,6 +306,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -250,11 +315,19 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oapi-codegen/echo-middleware v1.0.1 h1:edYGScq1phCcuDoz9AqA9eHX+tEI1LNL5PL1lkkQh1k= +github.com/oapi-codegen/echo-middleware v1.0.1/go.mod h1:DBQKRn+D/vfXOFbaX5GRwFttoJY64JH6yu+pdt7wU3o= +github.com/oapi-codegen/oapi-codegen/v2 v2.3.0 h1:rICjNsHbPP1LttefanBPnwsSwl09SqhCO7Ee623qR84= +github.com/oapi-codegen/oapi-codegen/v2 v2.3.0/go.mod h1:4k+cJeSq5ntkwlcpQSxLxICCxQzCL772o30PxdibRt4= +github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro= +github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= @@ -264,6 +337,10 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.3.0/go.mod h1:4c3sLeE8xjNqehmF5RpAFLPLJxXscc0R4l6Zg0P1tTQ= +github.com/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw= +github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= +github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= +github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -306,6 +383,7 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -320,8 +398,16 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/traPtitech/go-traq v0.0.0-20240420012203-0152d96098b0 h1:qXV2Edt1yRQulqcNv7G9mg+dmkJPX9XXOGSHLuZk+Os= +github.com/traPtitech/go-traq v0.0.0-20240420012203-0152d96098b0/go.mod h1:iac/zAWmOCe6eGomX2U8EeOAM1kwrm5TM19gRMOxJrU= github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= @@ -358,6 +444,15 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -396,6 +491,10 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -439,6 +538,16 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -447,6 +556,8 @@ golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -461,6 +572,9 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -523,6 +637,15 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -540,12 +663,20 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -594,6 +725,10 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= +golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= +golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -686,6 +821,10 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -704,9 +843,11 @@ gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.2.3 h1:cZqzlOfg5Kf1VIdLC1D9hT6Cy9BgxhExLj/2tIgUe7Y= diff --git a/handler/handler.go b/handler/handler.go new file mode 100644 index 00000000..f620ece3 --- /dev/null +++ b/handler/handler.go @@ -0,0 +1,3 @@ +package handler + +type Handler struct{} diff --git a/handler/middleware.go b/handler/middleware.go new file mode 100644 index 00000000..d40ec3af --- /dev/null +++ b/handler/middleware.go @@ -0,0 +1,53 @@ +package handler + +import ( + "errors" + "fmt" + + "github.com/go-playground/validator/v10" + "github.com/labstack/echo/v4" +) + +const ( + validatorKey = "validator" + userIDKey = "userID" + questionnaireIDKey = "questionnaireID" + responseIDKey = "responseID" + questionIDKey = "questionID" +) + +// SetUserIDMiddleware X-Showcase-UserからユーザーIDを取得しセットする +func SetUserIDMiddleware(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + userID := c.Request().Header.Get("X-Showcase-User") + if userID == "" { + userID = "mds_boy" + } + + c.Set(userIDKey, userID) + + return next(c) + } +} + +// getValidator Validatorを設定する +func getValidator(c echo.Context) (*validator.Validate, error) { + rowValidate := c.Get(validatorKey) + validate, ok := rowValidate.(*validator.Validate) + if !ok { + return nil, fmt.Errorf("failed to get validator") + } + + return validate, nil +} + +// getUserID ユーザーIDを取得する +func getUserID(c echo.Context) (string, error) { + rowUserID := c.Get(userIDKey) + userID, ok := rowUserID.(string) + if !ok { + return "", errors.New("invalid context userID") + } + + return userID, nil +} diff --git a/handler/questionnaire.go b/handler/questionnaire.go new file mode 100644 index 00000000..c6fe5dc1 --- /dev/null +++ b/handler/questionnaire.go @@ -0,0 +1,200 @@ +package handler + +import ( + "fmt" + "net/http" + + "github.com/labstack/echo/v4" + "github.com/traPtitech/anke-to/controller" + "github.com/traPtitech/anke-to/openapi" +) + +// (GET /questionnaires) +func (h Handler) GetQuestionnaires(ctx echo.Context, params openapi.GetQuestionnairesParams) error { + res := openapi.QuestionnaireList{} + q := controller.NewQuestionnaire() + 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)) + } + + res, err = q.GetQuestionnaires(ctx, userID, params) + if err != nil { + ctx.Logger().Errorf("failed to get questionnaires: %+v", err) + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get questionnaires: %w", err)) + } + + return ctx.JSON(200, res) +} + +// (POST /questionnaires) +func (h Handler) PostQuestionnaire(ctx echo.Context) error { + params := openapi.PostQuestionnaireJSONRequestBody{} + if err := ctx.Bind(¶ms); err != nil { + ctx.Logger().Errorf("failed to bind request body: %+v", err) + return echo.NewHTTPError(http.StatusBadRequest, fmt.Errorf("failed to bind request body: %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.StructCtx(ctx.Request().Context(), params) + 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)) + } + + res := openapi.QuestionnaireDetail{} + q := controller.NewQuestionnaire() + 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)) + } + + res, err = q.PostQuestionnaire(ctx, userID, params) + if err != nil { + ctx.Logger().Errorf("failed to post questionnaire: %+v", err) + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to post questionnaire: %w", err)) + } + + return ctx.JSON(200, res) +} + +// (GET /questionnaires/{questionnaireID}) +func (h Handler) GetQuestionnaire(ctx echo.Context, questionnaireID openapi.QuestionnaireIDInPath) error { + res := openapi.QuestionnaireDetail{} + q := controller.NewQuestionnaire() + res, err := q.GetQuestionnaire(ctx, questionnaireID) + if err != nil { + ctx.Logger().Errorf("failed to get questionnaire: %+v", err) + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get questionnaire: %w", err)) + } + return ctx.JSON(200, res) +} + +// (PATCH /questionnaires/{questionnaireID}) +func (h Handler) EditQuestionnaire(ctx echo.Context, questionnaireID openapi.QuestionnaireIDInPath) error { + params := openapi.EditQuestionnaireJSONRequestBody{} + if err := ctx.Bind(¶ms); err != nil { + ctx.Logger().Errorf("failed to bind request body: %+v", err) + return echo.NewHTTPError(http.StatusBadRequest, fmt.Errorf("failed to bind request body: %w", err)) + } + + q := controller.NewQuestionnaire() + err := q.EditQuestionnaire(ctx, questionnaireID, params) + if err != nil { + ctx.Logger().Errorf("failed to edit questionnaire: %+v", err) + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to edit questionnaire: %w", err)) + } + + return ctx.NoContent(200) +} + +// (DELETE /questionnaires/{questionnaireID}) +func (h Handler) DeleteQuestionnaire(ctx echo.Context, questionnaireID openapi.QuestionnaireIDInPath) error { + q := controller.NewQuestionnaire() + err := q.DeleteQuestionnaire(ctx, questionnaireID) + if err != nil { + ctx.Logger().Errorf("failed to delete questionnaire: %+v", err) + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to delete questionnaire: %w", err)) + } + + return ctx.NoContent(200) +} + +// (GET /questionnaires/{questionnaireID}/myRemindStatus) +func (h Handler) GetQuestionnaireMyRemindStatus(ctx echo.Context, questionnaireID openapi.QuestionnaireIDInPath) error { + res := openapi.QuestionnaireIsRemindEnabled{} + q := controller.NewQuestionnaire() + status, err := q.GetQuestionnaireMyRemindStatus(ctx, questionnaireID) + if err != nil { + ctx.Logger().Errorf("failed to get questionnaire my remind status: %+v", err) + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to get questionnaire my remind status: %w", err)) + } + res.IsRemindEnabled = status + + return ctx.JSON(200, res) +} + +// (PATCH /questionnaires/{questionnaireID}/myRemindStatus) +func (h Handler) EditQuestionnaireMyRemindStatus(ctx echo.Context, questionnaireID openapi.QuestionnaireIDInPath) error { + q := controller.NewQuestionnaire() + err := q.EditQuestionnaireMyRemindStatus(ctx, questionnaireID) + if err != nil { + ctx.Logger().Errorf("failed to edit questionnaire my remind status: %+v", err) + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to edit questionnaire my remind status: %w", err)) + } + return ctx.NoContent(200) +} + +// (GET /questionnaires/{questionnaireID}/responses) +func (h Handler) GetQuestionnaireResponses(ctx echo.Context, questionnaireID openapi.QuestionnaireIDInPath, params openapi.GetQuestionnaireResponsesParams) 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)) + } + q := controller.NewQuestionnaire() + res, err := q.GetQuestionnaireResponses(ctx, questionnaireID, params, userID) + + return ctx.JSON(200, res) +} + +// (POST /questionnaires/{questionnaireID}/responses) +func (h Handler) PostQuestionnaireResponse(ctx echo.Context, questionnaireID openapi.QuestionnaireIDInPath) error { + res := openapi.Response{} + 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)) + } + + params := openapi.PostQuestionnaireResponseJSONRequestBody{} + if err := ctx.Bind(¶ms); err != nil { + ctx.Logger().Errorf("failed to bind request body: %+v", err) + return echo.NewHTTPError(http.StatusBadRequest, fmt.Errorf("failed to bind request body: %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.StructCtx(ctx.Request().Context(), params) + 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)) + } + + q := controller.NewQuestionnaire() + res, err = q.PostQuestionnaireResponse(ctx, questionnaireID, params, userID) + if err != nil { + ctx.Logger().Errorf("failed to post questionnaire response: %+v", err) + return err + } + + return ctx.JSON(201, res) +} + +// (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) +} diff --git a/handler/response.go b/handler/response.go new file mode 100644 index 00000000..a7dfbfa5 --- /dev/null +++ b/handler/response.go @@ -0,0 +1,81 @@ +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{} + 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) +} + +// (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) +} diff --git a/main.go b/main.go index f5457edc..fe08cd25 100644 --- a/main.go +++ b/main.go @@ -7,7 +7,13 @@ import ( "os" "runtime" + "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" + oapiMiddleware "github.com/oapi-codegen/echo-middleware" + "github.com/traPtitech/anke-to/handler" "github.com/traPtitech/anke-to/model" + "github.com/traPtitech/anke-to/openapi" + "github.com/traPtitech/anke-to/tuning" ) @@ -51,5 +57,17 @@ func main() { panic("no PORT") } - SetRouting(port) + e := echo.New() + swagger, err := openapi.GetSwagger() + if err != nil { + panic(err) + } + e.Use(oapiMiddleware.OapiRequestValidator(swagger)) + e.Use(handler.SetUserIDMiddleware) + e.Use(middleware.Logger()) + e.Use(middleware.Recover()) + openapi.RegisterHandlers(e, handler.Handler{}) + e.Logger.Fatal(e.Start(port)) + + // SetRouting(port) } diff --git a/model/administratorGroups.go b/model/administratorGroups.go new file mode 100644 index 00000000..dfddc73a --- /dev/null +++ b/model/administratorGroups.go @@ -0,0 +1,10 @@ +package model + +import "context" + +// IAdministratorGroup AdministratorGroupのRepository +type IAdministratorGroup interface { + InsertAdministratorGroups(ctx context.Context, questionnaireID int, administratorGroups []string) error + DeleteAdministratorGroups(ctx context.Context, questionnaireID int) error + GetAdministratorGroups(ctx context.Context, questionnaireIDs []int) ([]AdministratorGroups, error) +} diff --git a/model/administratorGroups_impl.go b/model/administratorGroups_impl.go new file mode 100644 index 00000000..a4953d43 --- /dev/null +++ b/model/administratorGroups_impl.go @@ -0,0 +1,83 @@ +package model + +import ( + "context" + "fmt" + + "github.com/gofrs/uuid" +) + +// AdministratorGroup AdministratorGroupRepositoryの実装 +type AdministratorGroup struct{} + +// NewAdministratorGroup AdministratorGroupRepositoryのコンストラクタ +func NewAdministratorGroup() *AdministratorGroup { + return &AdministratorGroup{} +} + +type AdministratorGroups struct { + QuestionnaireID int `gorm:"type:int(11);not null;primaryKey"` + GroupID uuid.UUID `gorm:"type:varchar(36);size:36;not null;primaryKey"` +} + +// InsertAdministratorGroups アンケートの管理者グループを追加 +func (*AdministratorGroup) InsertAdministratorGroups(ctx context.Context, questionnaireID int, groupID []uuid.UUID) error { + db, err := getTx(ctx) + if err != nil { + return fmt.Errorf("failed to get transaction: %w", err) + } + + if len(groupID) == 0 { + return nil + } + + dbAdministratorGroups := make([]AdministratorGroups, 0, len(groupID)) + for _, administratorGroup := range groupID { + dbAdministratorGroups = append(dbAdministratorGroups, AdministratorGroups{ + QuestionnaireID: questionnaireID, + GroupID: administratorGroup, + }) + } + + err = db.Create(&dbAdministratorGroups).Error + if err != nil { + return fmt.Errorf("failed to insert administrator groups: %w", err) + } + + return nil +} + +// DeleteAdministratorGroups アンケートの管理者グループを削除 +func (*AdministratorGroup) DeleteAdministratorGroups(ctx context.Context, questionnaireID int) error { + db, err := getTx(ctx) + if err != nil { + return fmt.Errorf("failed to get transaction: %w", err) + } + + err = db. + Where("questionnaire_id = ?", questionnaireID). + Delete(AdministratorGroups{}).Error + if err != nil { + return fmt.Errorf("failed to delete administrator groups: %w", err) + } + + return nil +} + +// GetAdministratorGroups アンケートの管理者グループを取得 +func (*AdministratorGroup) GetAdministratorGroups(ctx context.Context, questionnaireIDs []int) ([]AdministratorGroups, error) { + db, err := getTx(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get transaction: %w", err) + } + + var administratorGroups []AdministratorGroups + err = db. + Where("questionnaire_id IN ?", questionnaireIDs). + Find(&administratorGroups).Error + if err != nil { + return nil, fmt.Errorf("failed to get administrator groups: %w", err) + } + + return administratorGroups, nil +} diff --git a/model/questionnaires.go b/model/questionnaires.go index ec759d2e..8338abbf 100644 --- a/model/questionnaires.go +++ b/model/questionnaires.go @@ -13,9 +13,9 @@ type IQuestionnaire interface { InsertQuestionnaire(ctx context.Context, title string, description string, resTimeLimit null.Time, resSharedTo string) (int, error) UpdateQuestionnaire(ctx context.Context, title string, description string, resTimeLimit null.Time, resSharedTo string, questionnaireID int) error DeleteQuestionnaire(ctx context.Context, questionnaireID int) error - GetQuestionnaires(ctx context.Context, userID string, sort string, search string, pageNum int, nontargeted bool) ([]QuestionnaireInfo, int, error) + GetQuestionnaires(ctx context.Context, userID string, sort string, search string, pageNum int, onlyTargetingMe bool, onlyAdministratedByMe bool) ([]QuestionnaireInfo, int, error) GetAdminQuestionnaires(ctx context.Context, userID string) ([]Questionnaires, error) - GetQuestionnaireInfo(ctx context.Context, questionnaireID int) (*Questionnaires, []string, []string, []string, error) + GetQuestionnaireInfo(ctx context.Context, questionnaireID int) (*Questionnaires, []string, []string, []string, []string, []string, error) GetTargettedQuestionnaires(ctx context.Context, userID string, answered string, sort string) ([]TargettedQuestionnaire, error) GetQuestionnaireLimit(ctx context.Context, questionnaireID int) (null.Time, error) GetQuestionnaireLimitByResponseID(ctx context.Context, responseID int) (null.Time, error) diff --git a/model/questionnaires_impl.go b/model/questionnaires_impl.go index e7756bc7..da751531 100755 --- a/model/questionnaires_impl.go +++ b/model/questionnaires_impl.go @@ -7,6 +7,7 @@ import ( "regexp" "time" + "github.com/google/uuid" "gopkg.in/guregu/null.v4" "gorm.io/gorm" ) @@ -31,6 +32,7 @@ type Questionnaires struct { ModifiedAt time.Time `json:"modified_at" gorm:"type:timestamp;not null;default:CURRENT_TIMESTAMP"` Administrators []Administrators `json:"-" gorm:"foreignKey:QuestionnaireID"` Targets []Targets `json:"-" gorm:"foreignKey:QuestionnaireID"` + TargetGroups []TargetGroups `json:"-" gorm:"foreignKey:QuestionnaireID"` Questions []Questions `json:"-" gorm:"foreignKey:QuestionnaireID"` Respondents []Respondents `json:"-" gorm:"foreignKey:QuestionnaireID"` } @@ -171,7 +173,7 @@ func (*Questionnaire) DeleteQuestionnaire(ctx context.Context, questionnaireID i GetQuestionnaires アンケートの一覧 2つ目の戻り値はページ数の最大値 */ -func (*Questionnaire) GetQuestionnaires(ctx context.Context, userID string, sort string, search string, pageNum int, nontargeted bool) ([]QuestionnaireInfo, int, error) { +func (*Questionnaire) GetQuestionnaires(ctx context.Context, userID string, sort string, search string, pageNum int, onlyTargetingMe bool, onlyAdministratedByMe bool) ([]QuestionnaireInfo, int, error) { ctx, cancel := context.WithTimeout(ctx, 3*time.Second) defer cancel() @@ -192,9 +194,16 @@ func (*Questionnaire) GetQuestionnaires(ctx context.Context, userID string, sort return nil, 0, fmt.Errorf("failed to set the order of the questionnaire table: %w", err) } - if nontargeted { - query = query.Where("targets.questionnaire_id IS NULL OR (targets.user_traqid != ? AND targets.user_traqid != 'traP')", userID) + if onlyTargetingMe { + query = query.Where("targets.user_traqid = ? OR targets.user_traqid = 'traP'", userID) } + + if onlyAdministratedByMe { + query = query. + Joins("INNER JOIN administrators ON questionnaires.id = administrators.questionnaire_id"). + Where("administrators.user_traqid = ?", userID) + } + if len(search) != 0 { // MySQLでのregexpの構文は少なくともGoのregexpの構文でvalidである必要がある _, err := regexp.Compile(search) @@ -267,25 +276,27 @@ func (*Questionnaire) GetAdminQuestionnaires(ctx context.Context, userID string) } // GetQuestionnaireInfo アンケートの詳細な情報取得 -func (*Questionnaire) GetQuestionnaireInfo(ctx context.Context, questionnaireID int) (*Questionnaires, []string, []string, []string, error) { +func (*Questionnaire) GetQuestionnaireInfo(ctx context.Context, questionnaireID int) (*Questionnaires, []string, []uuid.UUID, []string, []uuid.UUID, []string, error) { db, err := getTx(ctx) if err != nil { - return nil, nil, nil, nil, fmt.Errorf("failed to get tx: %w", err) + return nil, nil, nil, nil, nil, nil, fmt.Errorf("failed to get tx: %w", err) } questionnaire := Questionnaires{} targets := []string{} + targetGroups := []uuid.UUID{} administrators := []string{} + administoratorGroups := []uuid.UUID{} respondents := []string{} err = db. Where("questionnaires.id = ?", questionnaireID). First(&questionnaire).Error if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, nil, nil, nil, ErrRecordNotFound + return nil, nil, nil, nil, nil, nil, ErrRecordNotFound } if err != nil { - return nil, nil, nil, nil, fmt.Errorf("failed to get a questionnaire: %w", err) + return nil, nil, nil, nil, nil, nil, fmt.Errorf("failed to get a questionnaire: %w", err) } err = db. @@ -294,7 +305,7 @@ func (*Questionnaire) GetQuestionnaireInfo(ctx context.Context, questionnaireID Where("questionnaire_id = ?", questionnaire.ID). Pluck("user_traqid", &targets).Error if err != nil { - return nil, nil, nil, nil, fmt.Errorf("failed to get targets: %w", err) + return nil, nil, nil, nil, nil, nil, fmt.Errorf("failed to get targets: %w", err) } err = db. @@ -303,7 +314,7 @@ func (*Questionnaire) GetQuestionnaireInfo(ctx context.Context, questionnaireID Where("questionnaire_id = ?", questionnaire.ID). Pluck("user_traqid", &administrators).Error if err != nil { - return nil, nil, nil, nil, fmt.Errorf("failed to get administrators: %w", err) + return nil, nil, nil, nil, nil, nil, fmt.Errorf("failed to get administrators: %w", err) } err = db. @@ -312,10 +323,10 @@ func (*Questionnaire) GetQuestionnaireInfo(ctx context.Context, questionnaireID Where("questionnaire_id = ? AND deleted_at IS NULL AND submitted_at IS NOT NULL", questionnaire.ID). Pluck("user_traqid", &respondents).Error if err != nil { - return nil, nil, nil, nil, fmt.Errorf("failed to get respondents: %w", err) + return nil, nil, nil, nil, nil, nil, fmt.Errorf("failed to get respondents: %w", err) } - return &questionnaire, targets, administrators, respondents, nil + return &questionnaire, targets, targetGroups, administrators, administoratorGroups, respondents, nil } // GetTargettedQuestionnaires targetになっているアンケートの取得 @@ -409,6 +420,7 @@ func (*Questionnaire) GetQuestionnaireLimitByResponseID(ctx context.Context, res return res.ResTimeLimit, nil } +// GetResponseReadPrivilegeInfoByResponseID 回答のIDから回答の閲覧権限情報を取得 func (*Questionnaire) GetResponseReadPrivilegeInfoByResponseID(ctx context.Context, userID string, responseID int) (*ResponseReadPrivilegeInfo, error) { db, err := getTx(ctx) if err != nil { @@ -434,6 +446,7 @@ func (*Questionnaire) GetResponseReadPrivilegeInfoByResponseID(ctx context.Conte return &responseReadPrivilegeInfo, nil } +// GetResponseReadPrivilegeInfoByQuestionnaireID アンケートのIDから回答の閲覧権限情報を取得 func (*Questionnaire) GetResponseReadPrivilegeInfoByQuestionnaireID(ctx context.Context, userID string, questionnaireID int) (*ResponseReadPrivilegeInfo, error) { db, err := getTx(ctx) if err != nil { diff --git a/model/questionnaires_test.go b/model/questionnaires_test.go index 16b80506..c3b716cf 100644 --- a/model/questionnaires_test.go +++ b/model/questionnaires_test.go @@ -1324,7 +1324,7 @@ func getQuestionnaireInfoTest(t *testing.T) { for _, testCase := range testCases { ctx := context.Background() - actualQuestionnaire, actualTargets, actualAdministrators, actualRespondents, err := questionnaireImpl.GetQuestionnaireInfo(ctx, testCase.questionnaireID) + actualQuestionnaire, actualTargets, actualTargetGroups, actualAdministrators, actualAdministratorGroups, actualRespondents, err := questionnaireImpl.GetQuestionnaireInfo(ctx, testCase.questionnaireID) if !testCase.expect.isErr { assertion.NoError(err, testCase.description, "no error") diff --git a/model/questions_impl.go b/model/questions_impl.go index 0ad5335a..6b48077e 100644 --- a/model/questions_impl.go +++ b/model/questions_impl.go @@ -17,7 +17,7 @@ func NewQuestion() *Question { return new(Question) } -//Questions questionテーブルの構造体 +// Questions questionテーブルの構造体 type Questions struct { ID int `json:"id" gorm:"type:int(11) AUTO_INCREMENT;not null;primaryKey"` QuestionnaireID int `json:"questionnaireID" gorm:"type:int(11);not null"` @@ -41,18 +41,18 @@ func (questionnaire *Questions) BeforeCreate(tx *gorm.DB) error { return nil } -//TableName テーブル名が単数形なのでその対応 +// TableName テーブル名が単数形なのでその対応 func (*Questions) TableName() string { return "question" } -//QuestionIDType 質問のIDと種類の構造体 +// QuestionIDType 質問のIDと種類の構造体 type QuestionIDType struct { ID int Type string } -//InsertQuestion 質問の追加 +// InsertQuestion 質問の追加 func (*Question) InsertQuestion(ctx context.Context, questionnaireID int, pageNum int, questionNum int, questionType string, body string, isRequired bool) (int, error) { db, err := getTx(ctx) if err != nil { @@ -77,7 +77,7 @@ func (*Question) InsertQuestion(ctx context.Context, questionnaireID int, pageNu return question.ID, nil } -//UpdateQuestion 質問の修正 +// UpdateQuestion 質問の修正 func (*Question) UpdateQuestion(ctx context.Context, questionnaireID int, pageNum int, questionNum int, questionType string, body string, isRequired bool, questionID int) error { db, err := getTx(ctx) if err != nil { @@ -104,7 +104,7 @@ func (*Question) UpdateQuestion(ctx context.Context, questionnaireID int, pageNu return nil } -//DeleteQuestion 質問の削除 +// DeleteQuestion 質問の削除 func (*Question) DeleteQuestion(ctx context.Context, questionID int) error { db, err := getTx(ctx) if err != nil { @@ -125,7 +125,7 @@ func (*Question) DeleteQuestion(ctx context.Context, questionID int) error { return nil } -//GetQuestions 質問一覧の取得 +// GetQuestions 質問一覧の取得 func (*Question) GetQuestions(ctx context.Context, questionnaireID int) ([]Questions, error) { db, err := getTx(ctx) if err != nil { diff --git a/model/respondents.go b/model/respondents.go index 67504296..e5cff356 100644 --- a/model/respondents.go +++ b/model/respondents.go @@ -16,7 +16,8 @@ type IRespondent interface { GetRespondent(ctx context.Context, responseID int) (*Respondents, error) 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) ([]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) } diff --git a/model/respondents_impl.go b/model/respondents_impl.go index 29019230..2cbf4aaf 100755 --- a/model/respondents_impl.go +++ b/model/respondents_impl.go @@ -257,7 +257,7 @@ func (*Respondent) GetRespondentDetail(ctx context.Context, responseID int) (Res } // GetRespondentDetails アンケートの回答の詳細情報一覧の取得 -func (*Respondent) GetRespondentDetails(ctx context.Context, questionnaireID int, sort string) ([]RespondentDetail, error) { +func (*Respondent) GetRespondentDetails(ctx context.Context, questionnaireID int, sort string, onlyMyResponse bool, userID string) ([]RespondentDetail, error) { db, err := getTx(ctx) if err != nil { return nil, fmt.Errorf("failed to get tx: %w", err) @@ -306,7 +306,7 @@ func (*Respondent) GetRespondentDetails(ctx context.Context, questionnaireID int } questions := []Questions{} - err = db. + query = db. Preload("Responses", func(db *gorm.DB) *gorm.DB { return db. Select("ResponseID", "QuestionID", "Body"). @@ -314,7 +314,11 @@ func (*Respondent) GetRespondentDetails(ctx context.Context, questionnaireID int }). Where("questionnaire_id = ?", questionnaireID). Order("question_num"). - Select("ID", "Type"). + Select("ID", "Type") + if onlyMyResponse { + query = query.Where("user_traqid = ?", userID) + } + err = query. Find(&questions).Error if err != nil { return nil, fmt.Errorf("failed to get questions: %w", err) @@ -382,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) diff --git a/model/respondents_test.go b/model/respondents_test.go index cafc7dd7..cb38c8e9 100644 --- a/model/respondents_test.go +++ b/model/respondents_test.go @@ -990,6 +990,101 @@ func TestGetRespondentsUserIDs(t *testing.T) { } } +func TestGetMyResponseIDs(t *testing.T) { + t.Parallel() + + assertion := assert.New(t) + ctx := context.Background() + + questionnaireID, err := questionnaireImpl.InsertQuestionnaire(ctx, "第1回集会らん☆ぷろ募集アンケート", "第1回メンバー集会でのらん☆ぷろで発表したい人を募集します らん☆ぷろで発表したい人あつまれー!", null.NewTime(time.Now(), false), "private") + require.NoError(t, err) + + respondents := []Respondents{ + { + QuestionnaireID: questionnaireID, + UserTraqid: userOne, + SubmittedAt: null.NewTime(time.Now(), true), + }, + { + QuestionnaireID: questionnaireID, + UserTraqid: userTwo, + SubmittedAt: null.NewTime(time.Now(), true), + }, + { + QuestionnaireID: questionnaireID, + UserTraqid: userTwo, + SubmittedAt: null.NewTime(time.Now(), true), + }, + } + responseIDs := []int{} + for _, respondent := range respondents { + responseID, err := respondentImpl.InsertRespondent(ctx, respondent.UserTraqid, questionnaireID, respondent.SubmittedAt) + require.NoError(t, err) + responseIDs = append(responseIDs, responseID) + } + + type args struct { + userID string + } + type expect struct { + isErr bool + err error + responseIDs []int + } + type test struct { + description string + args + expect + } + + testCases := []test{ + { + description: "valid user with one resonse", + args: args{ + userID: userOne, + }, + expect: expect{ + responseIDs: []int{responseIDs[1]}, + }, + }, + { + description: "valid user with multiple responses", + args: args{ + userID: userTwo, + }, + expect: expect{ + responseIDs: []int{responseIDs[2], responseIDs[3]}, + }, + }, + { + description: "valid user with no response", + args: args{ + userID: userThree, + }, + expect: expect{ + responseIDs: []int{}, + }, + }, + } + + for _, testCase := range testCases { + MyResponseIDs, err := respondentImpl.GetMyResponseIDs(ctx, testCase.args.userID) + + if !testCase.expect.isErr { + assertion.NoError(err, testCase.description, "no error") + } else if testCase.expect.err != nil { + assertion.Equal(true, errors.Is(err, testCase.expect.err), testCase.description, "errorIs") + } else { + assertion.Error(err, testCase.description, "any error") + } + if err != nil { + continue + } + + assertion.Equal(testCase.expect.responseIDs, MyResponseIDs, testCase.description, "responseIDs") + } +} + func TestTestCheckRespondent(t *testing.T) { t.Parallel() diff --git a/model/targetGroups.go b/model/targetGroups.go new file mode 100644 index 00000000..7217c148 --- /dev/null +++ b/model/targetGroups.go @@ -0,0 +1,12 @@ +package model + +import ( + "context" +) + +// ITargetGroup TargetGroupのRepository +type ITargetGroup interface { + InsertTargetGroups(ctx context.Context, questionnaireID int, groupID []string) error + GetTargetGroups(ctx context.Context, questionnaireIDs []int) ([]TargetGroups, error) + DeleteTargetGroups(ctx context.Context, questionnaireIDs int) error +} diff --git a/model/targetGroups_impl.go b/model/targetGroups_impl.go new file mode 100644 index 00000000..ea04f23d --- /dev/null +++ b/model/targetGroups_impl.go @@ -0,0 +1,84 @@ +package model + +import ( + "context" + "fmt" + + "github.com/gofrs/uuid" +) + +// TargetGroup TargetGroupsRepositoryの実装 +type TargetGroup struct{} + +// NewTargetGroups TargetGroupsのコンストラクター +func NewTargetGroups() *TargetGroups { + return new(TargetGroups) +} + +// TargetGroups targets_groupsテーブルの構造体 +type TargetGroups struct { + QuestionnaireID int `gorm:"type:int(11) AUTO_INCREMENT;not null;primaryKey"` + GroupID uuid.UUID `gorm:"type:char(36);size:36;not null;primaryKey"` +} + +// InsertTargetGroups アンケートの対象としてuser_groupを追加 +func (*TargetGroup) InsertTargetGroups(ctx context.Context, questionnaireID int, groupID []uuid.UUID) error { + db, err := getTx(ctx) + if err != nil { + return fmt.Errorf("failed to get transaction: %w", err) + } + + if len(groupID) == 0 { + return nil + } + + dbTargetGroups := make([]TargetGroups, 0, len(groupID)) + for _, targetGroup := range groupID { + dbTargetGroups = append(dbTargetGroups, TargetGroups{ + QuestionnaireID: questionnaireID, + GroupID: targetGroup, + }) + } + + err = db.Create(&dbTargetGroups).Error + if err != nil { + return fmt.Errorf("failed to insert target groups: %w", err) + } + + return nil +} + +// GetTargetGroups アンケートの対象としてuser_groupを取得 +func (*TargetGroup) GetTargetGroups(ctx context.Context, questionnaireIDs []int) ([]TargetGroups, error) { + db, err := getTx(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get transaction: %w", err) + } + + var targetGroups []TargetGroups + err = db. + Where("questionnaire_id IN ?", questionnaireIDs). + Find(&targetGroups).Error + if err != nil { + return nil, fmt.Errorf("failed to get target groups: %w", err) + } + + return targetGroups, nil +} + +// DeleteTargetGroups アンケートの対象としてuser_groupを削除 +func (*TargetGroup) DeleteTargetGroups(ctx context.Context, questionnaireID int) error { + db, err := getTx(ctx) + if err != nil { + return fmt.Errorf("failed to get transaction: %w", err) + } + + err = db. + Where("questionnaire_id = ?", questionnaireID). + Delete(&TargetGroups{}).Error + if err != nil { + return fmt.Errorf("failed to delete target groups: %w", err) + } + + return nil +} diff --git a/model/targets.go b/model/targets.go index e6557b12..a1bb5506 100644 --- a/model/targets.go +++ b/model/targets.go @@ -9,4 +9,5 @@ type ITarget interface { InsertTargets(ctx context.Context, questionnaireID int, targets []string) error DeleteTargets(ctx context.Context, questionnaireID int) error GetTargets(ctx context.Context, questionnaireIDs []int) ([]Targets, error) + IsTargetingMe(ctx context.Context, quesionnairID int, userID string) (bool, error) } diff --git a/model/targets_impl.go b/model/targets_impl.go index c3d73dd8..6e046217 100644 --- a/model/targets_impl.go +++ b/model/targets_impl.go @@ -13,7 +13,7 @@ func NewTarget() *Target { return new(Target) } -//Targets targetsテーブルの構造体 +// Targets targetsテーブルの構造体 type Targets struct { QuestionnaireID int `gorm:"type:int(11) AUTO_INCREMENT;not null;primaryKey"` UserTraqid string `gorm:"type:varchar(32);size:32;not null;primaryKey"` @@ -80,3 +80,24 @@ func (*Target) GetTargets(ctx context.Context, questionnaireIDs []int) ([]Target return targets, nil } + +func (*Target) IsTargetingMe(ctx context.Context, questionnairID int, userID string) (bool, error) { + db, err := getTx(ctx) + if err != nil { + return false, fmt.Errorf("failed to get transaction: %w", err) + } + + var count int64 + err = db. + Model(&Targets{}). + Where("questionnaire_id = ? AND user_traqid = ?", questionnairID, userID). + Count(&count).Error + if err != nil { + return false, fmt.Errorf("failed to get targets which are targeting me: %w", err) + } + + if count > 0 { + return true, nil + } + return false, nil +} diff --git a/model/targets_test.go b/model/targets_test.go index a00d7487..71404545 100644 --- a/model/targets_test.go +++ b/model/targets_test.go @@ -4,8 +4,11 @@ import ( "context" "errors" "testing" + "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/guregu/null.v4" "gorm.io/gorm" ) @@ -308,3 +311,68 @@ func TestGetTargets(t *testing.T) { }) } } + +func TestIsTargetingMe(t *testing.T) { + t.Parallel() + + assertion := assert.New(t) + ctx := context.Background() + + questionnaireID, err := questionnaireImpl.InsertQuestionnaire(ctx, "第1回集会らん☆ぷろ募集アンケート", "第1回メンバー集会でのらん☆ぷろで発表したい人を募集します らん☆ぷろで発表したい人あつまれー!", null.NewTime(time.Now(), false), "private") + require.NoError(t, err) + + err = targetImpl.InsertTargets(ctx, questionnaireID, []string{userOne}) + require.NoError(t, err) + + type args struct { + userID string + } + type expect struct { + isErr bool + err error + isTargeted bool + } + type test struct { + description string + args + expect + } + + testCases := []test{ + { + description: "is targeted", + args: args{ + userID: userOne, + }, + expect: expect{ + isTargeted: true, + }, + }, + { + description: "not targeted", + args: args{ + userID: userTwo, + }, + expect: expect{ + isTargeted: false, + }, + }, + } + + for _, testCase := range testCases { + isTargeted, err := targetImpl.IsTargetingMe(ctx, questionnaireID, testCase.args.userID) + + if !testCase.expect.isErr { + assertion.NoError(err, testCase.description, "no error") + } else if testCase.expect.err != nil { + assertion.Equal(true, errors.Is(err, testCase.expect.err), testCase.description, "errorIs") + } else { + assertion.Error(err, testCase.description, "any error") + } + if err != nil { + continue + } + + assertion.Equal(testCase.expect.isTargeted, isTargeted, testCase.description, "isTargeted") + } +} diff --git a/openapi/server.go b/openapi/server.go new file mode 100644 index 00000000..177c413d --- /dev/null +++ b/openapi/server.go @@ -0,0 +1,401 @@ +// Package openapi provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT. +package openapi + +import ( + "fmt" + "net/http" + + "github.com/labstack/echo/v4" + "github.com/oapi-codegen/runtime" +) + +// ServerInterface represents all server handlers. +type ServerInterface interface { + + // (GET /questionnaires) + GetQuestionnaires(ctx echo.Context, params GetQuestionnairesParams) error + + // (POST /questionnaires) + PostQuestionnaire(ctx echo.Context) error + + // (DELETE /questionnaires/{questionnaireID}) + DeleteQuestionnaire(ctx echo.Context, questionnaireID QuestionnaireIDInPath) error + + // (GET /questionnaires/{questionnaireID}) + GetQuestionnaire(ctx echo.Context, questionnaireID QuestionnaireIDInPath) error + + // (PATCH /questionnaires/{questionnaireID}) + EditQuestionnaire(ctx echo.Context, questionnaireID QuestionnaireIDInPath) error + + // (GET /questionnaires/{questionnaireID}/myRemindStatus) + GetQuestionnaireMyRemindStatus(ctx echo.Context, questionnaireID QuestionnaireIDInPath) error + + // (PATCH /questionnaires/{questionnaireID}/myRemindStatus) + EditQuestionnaireMyRemindStatus(ctx echo.Context, questionnaireID QuestionnaireIDInPath) error + + // (GET /questionnaires/{questionnaireID}/responses) + GetQuestionnaireResponses(ctx echo.Context, questionnaireID QuestionnaireIDInPath, params GetQuestionnaireResponsesParams) error + + // (POST /questionnaires/{questionnaireID}/responses) + PostQuestionnaireResponse(ctx echo.Context, questionnaireID QuestionnaireIDInPath) error + + // (GET /questionnaires/{questionnaireID}/result) + GetQuestionnaireResult(ctx echo.Context, questionnaireID QuestionnaireIDInPath) error + + // (GET /responses/myResponses) + GetMyResponses(ctx echo.Context, params GetMyResponsesParams) error + + // (DELETE /responses/{responseID}) + DeleteResponse(ctx echo.Context, responseID ResponseIDInPath) error + + // (GET /responses/{responseID}) + GetResponse(ctx echo.Context, responseID ResponseIDInPath) error + + // (PATCH /responses/{responseID}) + EditResponse(ctx echo.Context, responseID ResponseIDInPath) error +} + +// ServerInterfaceWrapper converts echo contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface +} + +// GetQuestionnaires converts echo context to params. +func (w *ServerInterfaceWrapper) GetQuestionnaires(ctx echo.Context) error { + var err error + + ctx.Set(ApplicationScopes, []string{"read", "write"}) + + // Parameter object where we will unmarshal all parameters from the context + var params GetQuestionnairesParams + // ------------- 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 "search" ------------- + + err = runtime.BindQueryParameter("form", true, false, "search", ctx.QueryParams(), ¶ms.Search) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter search: %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 "onlyTargetingMe" ------------- + + err = runtime.BindQueryParameter("form", true, false, "onlyTargetingMe", ctx.QueryParams(), ¶ms.OnlyTargetingMe) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter onlyTargetingMe: %s", err)) + } + + // ------------- Optional query parameter "onlyAdministratedByMe" ------------- + + err = runtime.BindQueryParameter("form", true, false, "onlyAdministratedByMe", ctx.QueryParams(), ¶ms.OnlyAdministratedByMe) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter onlyAdministratedByMe: %s", err)) + } + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.GetQuestionnaires(ctx, params) + return err +} + +// PostQuestionnaire converts echo context to params. +func (w *ServerInterfaceWrapper) PostQuestionnaire(ctx echo.Context) error { + var err error + + ctx.Set(ApplicationScopes, []string{"read", "write"}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.PostQuestionnaire(ctx) + return err +} + +// DeleteQuestionnaire converts echo context to params. +func (w *ServerInterfaceWrapper) DeleteQuestionnaire(ctx echo.Context) error { + var err error + // ------------- Path parameter "questionnaireID" ------------- + var questionnaireID QuestionnaireIDInPath + + err = runtime.BindStyledParameterWithOptions("simple", "questionnaireID", ctx.Param("questionnaireID"), &questionnaireID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter questionnaireID: %s", err)) + } + + ctx.Set(ApplicationScopes, []string{"read", "write"}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.DeleteQuestionnaire(ctx, questionnaireID) + return err +} + +// GetQuestionnaire converts echo context to params. +func (w *ServerInterfaceWrapper) GetQuestionnaire(ctx echo.Context) error { + var err error + // ------------- Path parameter "questionnaireID" ------------- + var questionnaireID QuestionnaireIDInPath + + err = runtime.BindStyledParameterWithOptions("simple", "questionnaireID", ctx.Param("questionnaireID"), &questionnaireID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter questionnaireID: %s", err)) + } + + ctx.Set(ApplicationScopes, []string{"read", "write"}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.GetQuestionnaire(ctx, questionnaireID) + return err +} + +// EditQuestionnaire converts echo context to params. +func (w *ServerInterfaceWrapper) EditQuestionnaire(ctx echo.Context) error { + var err error + // ------------- Path parameter "questionnaireID" ------------- + var questionnaireID QuestionnaireIDInPath + + err = runtime.BindStyledParameterWithOptions("simple", "questionnaireID", ctx.Param("questionnaireID"), &questionnaireID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter questionnaireID: %s", err)) + } + + ctx.Set(ApplicationScopes, []string{"read", "write"}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.EditQuestionnaire(ctx, questionnaireID) + return err +} + +// GetQuestionnaireMyRemindStatus converts echo context to params. +func (w *ServerInterfaceWrapper) GetQuestionnaireMyRemindStatus(ctx echo.Context) error { + var err error + // ------------- Path parameter "questionnaireID" ------------- + var questionnaireID QuestionnaireIDInPath + + err = runtime.BindStyledParameterWithOptions("simple", "questionnaireID", ctx.Param("questionnaireID"), &questionnaireID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter questionnaireID: %s", err)) + } + + ctx.Set(ApplicationScopes, []string{"read", "write"}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.GetQuestionnaireMyRemindStatus(ctx, questionnaireID) + return err +} + +// EditQuestionnaireMyRemindStatus converts echo context to params. +func (w *ServerInterfaceWrapper) EditQuestionnaireMyRemindStatus(ctx echo.Context) error { + var err error + // ------------- Path parameter "questionnaireID" ------------- + var questionnaireID QuestionnaireIDInPath + + err = runtime.BindStyledParameterWithOptions("simple", "questionnaireID", ctx.Param("questionnaireID"), &questionnaireID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter questionnaireID: %s", err)) + } + + ctx.Set(ApplicationScopes, []string{"read", "write"}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.EditQuestionnaireMyRemindStatus(ctx, questionnaireID) + return err +} + +// GetQuestionnaireResponses converts echo context to params. +func (w *ServerInterfaceWrapper) GetQuestionnaireResponses(ctx echo.Context) error { + var err error + // ------------- Path parameter "questionnaireID" ------------- + var questionnaireID QuestionnaireIDInPath + + err = runtime.BindStyledParameterWithOptions("simple", "questionnaireID", ctx.Param("questionnaireID"), &questionnaireID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter questionnaireID: %s", err)) + } + + ctx.Set(ApplicationScopes, []string{"read", "write"}) + + // Parameter object where we will unmarshal all parameters from the context + var params GetQuestionnaireResponsesParams + // ------------- 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 "onlyMyResponse" ------------- + + err = runtime.BindQueryParameter("form", true, false, "onlyMyResponse", ctx.QueryParams(), ¶ms.OnlyMyResponse) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter onlyMyResponse: %s", err)) + } + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.GetQuestionnaireResponses(ctx, questionnaireID, params) + return err +} + +// PostQuestionnaireResponse converts echo context to params. +func (w *ServerInterfaceWrapper) PostQuestionnaireResponse(ctx echo.Context) error { + var err error + // ------------- Path parameter "questionnaireID" ------------- + var questionnaireID QuestionnaireIDInPath + + err = runtime.BindStyledParameterWithOptions("simple", "questionnaireID", ctx.Param("questionnaireID"), &questionnaireID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter questionnaireID: %s", err)) + } + + ctx.Set(ApplicationScopes, []string{"read", "write"}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.PostQuestionnaireResponse(ctx, questionnaireID) + return err +} + +// GetQuestionnaireResult converts echo context to params. +func (w *ServerInterfaceWrapper) GetQuestionnaireResult(ctx echo.Context) error { + var err error + // ------------- Path parameter "questionnaireID" ------------- + var questionnaireID QuestionnaireIDInPath + + err = runtime.BindStyledParameterWithOptions("simple", "questionnaireID", ctx.Param("questionnaireID"), &questionnaireID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter questionnaireID: %s", err)) + } + + ctx.Set(ApplicationScopes, []string{"read", "write"}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.GetQuestionnaireResult(ctx, questionnaireID) + return err +} + +// GetMyResponses converts echo context to params. +func (w *ServerInterfaceWrapper) GetMyResponses(ctx echo.Context) error { + var err error + + ctx.Set(ApplicationScopes, []string{"read", "write"}) + + // 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)) + } + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.GetMyResponses(ctx, params) + return err +} + +// DeleteResponse converts echo context to params. +func (w *ServerInterfaceWrapper) DeleteResponse(ctx echo.Context) error { + var err error + // ------------- Path parameter "responseID" ------------- + var responseID ResponseIDInPath + + err = runtime.BindStyledParameterWithOptions("simple", "responseID", ctx.Param("responseID"), &responseID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter responseID: %s", err)) + } + + ctx.Set(ApplicationScopes, []string{"read", "write"}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.DeleteResponse(ctx, responseID) + return err +} + +// GetResponse converts echo context to params. +func (w *ServerInterfaceWrapper) GetResponse(ctx echo.Context) error { + var err error + // ------------- Path parameter "responseID" ------------- + var responseID ResponseIDInPath + + err = runtime.BindStyledParameterWithOptions("simple", "responseID", ctx.Param("responseID"), &responseID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter responseID: %s", err)) + } + + ctx.Set(ApplicationScopes, []string{"read", "write"}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.GetResponse(ctx, responseID) + return err +} + +// EditResponse converts echo context to params. +func (w *ServerInterfaceWrapper) EditResponse(ctx echo.Context) error { + var err error + // ------------- Path parameter "responseID" ------------- + var responseID ResponseIDInPath + + err = runtime.BindStyledParameterWithOptions("simple", "responseID", ctx.Param("responseID"), &responseID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter responseID: %s", err)) + } + + ctx.Set(ApplicationScopes, []string{"read", "write"}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.EditResponse(ctx, responseID) + return err +} + +// This is a simple interface which specifies echo.Route addition functions which +// are present on both echo.Echo and echo.Group, since we want to allow using +// either of them for path registration +type EchoRouter interface { + CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route + DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route + GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route + HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route + OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route + PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route + POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route + PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route + TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route +} + +// RegisterHandlers adds each server route to the EchoRouter. +func RegisterHandlers(router EchoRouter, si ServerInterface) { + RegisterHandlersWithBaseURL(router, si, "") +} + +// Registers handlers, and prepends BaseURL to the paths, so that the paths +// can be served under a prefix. +func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) { + + wrapper := ServerInterfaceWrapper{ + Handler: si, + } + + router.GET(baseURL+"/questionnaires", wrapper.GetQuestionnaires) + router.POST(baseURL+"/questionnaires", wrapper.PostQuestionnaire) + router.DELETE(baseURL+"/questionnaires/:questionnaireID", wrapper.DeleteQuestionnaire) + router.GET(baseURL+"/questionnaires/:questionnaireID", wrapper.GetQuestionnaire) + router.PATCH(baseURL+"/questionnaires/:questionnaireID", wrapper.EditQuestionnaire) + router.GET(baseURL+"/questionnaires/:questionnaireID/myRemindStatus", wrapper.GetQuestionnaireMyRemindStatus) + router.PATCH(baseURL+"/questionnaires/:questionnaireID/myRemindStatus", wrapper.EditQuestionnaireMyRemindStatus) + router.GET(baseURL+"/questionnaires/:questionnaireID/responses", wrapper.GetQuestionnaireResponses) + router.POST(baseURL+"/questionnaires/:questionnaireID/responses", wrapper.PostQuestionnaireResponse) + router.GET(baseURL+"/questionnaires/:questionnaireID/result", wrapper.GetQuestionnaireResult) + router.GET(baseURL+"/responses/myResponses", wrapper.GetMyResponses) + router.DELETE(baseURL+"/responses/:responseID", wrapper.DeleteResponse) + router.GET(baseURL+"/responses/:responseID", wrapper.GetResponse) + router.PATCH(baseURL+"/responses/:responseID", wrapper.EditResponse) + +} diff --git a/openapi/spec.go b/openapi/spec.go new file mode 100644 index 00000000..6b165df9 --- /dev/null +++ b/openapi/spec.go @@ -0,0 +1,163 @@ +// Package openapi provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT. +package openapi + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "fmt" + "net/url" + "path" + "strings" + + "github.com/getkin/kin-openapi/openapi3" +) + +// Base64 encoded, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/+xd3W8TyZb/V6zefQBtB5swV7rrtzAZXUUa7sIk7D6QyOrYlaTn2t2muw14UaRUG0Ig", + "BiI+woRwCWEyEMjgMBeWzfD5v2ylHftp/4Wrqv6q6g93t2MHuLpShOx2napT5/zOOVWnTjUXubxcKssS", + "kDSVy17kyoIilIAGFPJNlorVoUJJlERVUwQNFI5XT4AR6VQFKFX8ewGoeUUsa6IscVmudeW5sTCPYH2v", + "sb63NN+au4zgFoLPEfwZwScIXiKfLyFdR7BB/j4ZN5eNj/dShzSlAg7zqVBCfdGi0nVjaQvpkDxfQfB3", + "BJ/YnUwJRRUcRnM6ql1BtbtIf4ZqW6i2gOA2+QnN6eMSx3MiZvYsmQPPSUIJcNngmXI8p+ZnQEnAc9Wq", + "ZdxwUpaLQJC42VmeEJ2o/gDUsiyp0XJpGKsP917cCZy5p83uu1+MjeW+ztZlPM40xwRlGmiiNB1H/0j/", + "hGrvkf43VKsRjkKUGSSIuLT9FA012SjZlIXpcIHsfriLavfJdHb2VhsILqYONR88Nxr39z4+w7p+9NpY", + "wlwdpZsdDuEMDxXEjihpYBoohJ2zFaDiwSVBVMDI8Ih0UtBm/Iwh/TGqvUL6b3jQ2sLIsCuOMiZwxvT0", + "x/GcAs5WRAUUuCxWWAQ7im0aoZyYcA9nwO2h27FHZUUL19DOEwRftR/Npw7tfnjQXFhq3vuluaIjWG8u", + "v0TwHoKXUuOcWpksiZoGCjlBG+f4lKepcXPDbDfgbYjBrG9g5NW2EGw0f7qChxrnNFErgoAG7ZXrZoMB", + "p0Vz9XVz+WUgWyW5IE6JzmCeli5XTLtUGLxUWdEYeP2rAqa4LPcvaTdCpM1f1fQPlHDHsOyxxFUgKPmZ", + "UFl7hbHxYO/14zBmSFdBaFc1RZSmzfH2r9m8AoQYemWb/cNqldLmrE1D1gF/UuRKmXwSNVBS/dImDVKn", + "T1uGDC4IpXIRcNmjvFdvzgNBUYQq/v5ncP6U5WZwx0Kx+B9TXPZMZ1ZtiuOCCrhZPl7jUaBhr64er5qz", + "nGBHJ04uOQuEzOGjrMhloGgiIFKy/Scru0690tLwCWuW9oFnqN4n7Lk4MT3rZWVSLlRjc2F3cxwTBehM", + "VHMFRZjScD+Osk2nHBAkaZ4dSt7kaMKhkCd/BHkN9/6Z4ODTnmv2zDy5wcxgZiBzdCBzdCyTyZK/f8v8", + "ezaT4XhuSlZKuD1XEDQwoIklHLN9NmBrLicWmK5de2FDmV/nmJKnOTQhwAjChwHGaC/62RLVnDtWcKg2", + "Pl1uP1pAcBHBZwjOI7hILN6rdc9SJMY8edN/Brv6IAk4HduUPMMwO5tOMPPggOx7QALQ2fRj4IKWGHyY", + "6HuZiD8Z4Z8rpUkit2Rko6I0XQTfzshiPrmlnKgUNbHcNfloXihabjei58SGjzUXwB0Lf7ns98UR4cmD", + "PbsHP5yCJmWpqKvJUOplJ1ESLuTOCcUKCFr38lxJlMJ/no3Ftqmmrri2NBzIdFGYBMVAkceYUgfiiAnT", + "6nPb0oPGUyZjON0Jx2t6nxedxF11NRHH0QUoGUjT5j6vO+w57rBrxhxnGoM5yTKyzrwF+JZs2EIvp1kh", + "BEiVEtaJh3CCjxndzI46hS3KS8RnxyLoMRuOx4jJhdm+10x4DDQuLzRZj1myTSwmK6R5H1iwDSoBG4Sk", + "h6y4m6Tu9ldjZIUXd8FBSIapxWAiQnvzM1wBw4IGxvAavqsO/lME54XJIjheTUY/og5JslQtyRU1MWGx", + "KJ8XpWnb7disJO7oZGWyKKozoJCM0EydqkNSgWTTVdaTkibfmnuWoQDL6NeGywNbetcUhdlhdsvUcT/l", + "Mrz3669HjdWHqLaOaq9QbQnV3rdX53ff30fwKcleX0X67f/7aR7B/0X6dQSf7q28ba1vkiTQGoKXdt++", + "RfotY3GtvTpPHn5EcCUViwzqCG5gAr2Oau///z2MFAc9ixjy0ASx2KUVjwwnQ1Oi7bwHXInITljJtCGt", + "J0mc8AyOnZcu2Adunbo5rQJF7ZD1YTub8JvayHC424+7L4/afUciZkSakg/O6+/befcGQQk8LX3aNBst", + "zQ4u3qdrUc0JVutcyWqeU+j23qT5HHEh9dbGlebdl8bqQ/vI8imC15G+6Mv7JE7+deInzuSdwBg4WfpX", + "T/aq/slYum5PZ9+zcAaKwbMbSoN4LtO/djymQ7BuXP61vbyI4F3s3Z0T0X1Px+UhxnR+ACVRKnwn4ZVN", + "8JQU0iIH3CbBB8VbxjaOa3gKteeo9pAcmrxCtasI1psPrhrXfqenRs5zn5Bj0jf4X1g3tj+2flsn5QJP", + "cdzTr5H2G7aW79FlB9Zh6xxE8DaCDWNuA8E6FpBNXEfwpZ+P9hzc/bRuSVxftI+Oo2XqEUIMwdKOIEis", + "mv17rgT2dfq+b7wwnETO7HtRDVjrlYVpkCsJFwJMdWmhtbmAl0n2qXjz7suwcyUqT8SEpuTBmpCNVkol", + "QalGploc7n3DRoqDihQ+oVCHen1dAdPjRDIcFFJ9nNtePFeogBxmJKeJQTA1bbP5YK29soQtmhijdbyp", + "32rDGwj/rSH9KhN6MIJv4n+JCUqVYpGun2A6xU3v2XbaUwnGExO16wuX0jmrUW6yGuMsbnRGUIBzzk4r", + "MrDDSI3aKD+YVfw/9+5fx97dsxT93NsuoVjM2fuboMWRXfWFHYG7EKhbvmBnAcFPjo9I4ciWQvqt1qc7", + "mBA7nr8ivW7V2cHtFCkMY1qkDjHdvvjJeGDutKnVBNz29Hw4TkDluRlBzZWq7hm6dxm+2FzdIW7PGRev", + "krgOXSnUwX+Qx43TlSNt14HnJqvWaqOLKMPM0s8p71FxwAbWl07yeVTBeR65kx6SClYhC/blZs9JCT0z", + "tHvhbT4iXe+YfcjNTsM5+/blkKy8EZv6sTJD7P4gUh/mIEEsMjEmeh/S2PufpebDB0i/xafacNFYfoPg", + "duvJIuESL5NTh8YtiYxzh/mUxybJHtPXnspljHOHU63nL3Hs13Vfv1JVlsA4Z5malbS25M+mRHirMZ6z", + "K1jrWUBZBl09031gPKAlHT3VKBiPKcLZkQJHlUXGqsig6xn7uh6luWLm5eGBj1q5RhZXOSomzoapc4pd", + "+EFTxSr68BLEKvigiWIWe9AkiQo9aMKERR7MmG6BB/34uKCCEQtVfgcuqefN5xGZR6thiPtiBgs7FvWN", + "RR0AdznUqAno6KFCkB9zqD7Vx7B+vg13mtcetvTH5IjCzIFcQbUa0reR/juCjfbl68bCPeJ3w2brLV2g", + "67s6bahD5eAFU4+KauJCmoKTj5WeFMokYcQ2Ij8nvS9O6YqvhJAal/xT6UFZShLWLfsNZKNHhSj7Zccp", + "y/YtzOywuXdnE8GGKisaXpttNtrrD6mlkSeCDni+28WTA/YHOsTyTKG5vyKA5y4M4HEGzgmKJJSwNzjD", + "jdoDDGlDo99yPP1g+DvyhCyDh9yP1mN3Qzjk+U4a0FL5L1Gb8Z0zjWigFF9j7lqAjzgls46w4q8EMUFQ", + "WVEHN68mrs4OOl50eguUT+IhwqUcPHalqCUZo1LUOneWTKFfwGr8nyvrYJSHOzHb1NAcZKzOdGpI/+Du", + "Or2ejSrk4OlbOn3xak6Oy3RNztd9ezRrc+YTjKYIp1LeGzVcvjyYCYKfWSwQ1/bcDaHX7jwZD9/Cdtp5", + "3ql/N9FSsflKXulgkvL2kH5YkUtn+YoiatVR3JO1GC2Xi2JesKtyporyefN5RZuRFfG/yS/fygXge3ha", + "KXJZbkbTymo2nT57RFOE8pEfy2mhLKbPHUvLuPFg2iYxb2PKZTu1LxSwHIt4uBT+JkrTKQWockXJAzyN", + "84qoAbcJQWCVbYT1If8FxGSENGXCDHluXt+yY1ZeljQhT5yMdSdMU4STHM9VmDGmRW2mMnkkL5fS+HdN", + "1EB+Ji1IfwEDmoz5YrFp/ZAaOjniGJv36TmgqGbro0cyRzIDsqAewz3JZSAJZZHLcsfwc7yZELQZIsS0", + "/wxvGgRmSG8guGClheBa86/ru+/eIP1W8+0cqYRaGczsvnuz++6X3Z1F4kS8CSxUe463NLUFpN8yrw07", + "ZVZoTucIkwrBBLZM7k9AO8VyxjNX5UPiktskTV9WDHOmdHPmLmUMAvoicozmIXe6Y1KGvhMAu36mvmQw", + "k7FBaKWpKOtM/6iaJhrveqL/UJkAnUVG88XPxs4Oglu2Vs3jw49Wjdyc7seCuau1U/gUCmZ57huT/87o", + "q102Hv2GYMP48Nh4fxPB+t7dl+Ss8prZF+7oD0EdeXnRb4Wzv4r02+QrnofZ4zF/j6OnvseMNNZa6/Xm", + "it5evo1g/ZiKJ/fmMmYartmFEPruzjsEt5ovfm49udla39y7+RHBunFjzVh9RGZPsuTTqq/qiwStsqwG", + "2KVzkdU/M/NybUcrOymrrJlZd76BqtkJup4AyXfnc5aNPJpSAbM+IB/tD5CtgspOUA4Xphfc9nOzPmjN", + "T/glQdw3CQ/EO+BvlveGivRFz7sKZk1eikADcbgyrl5rr2x0hOcw6cwL0GRhIPgFDWFuMzYebO69eAjV", + "r98LjgxjrV5aJ1VXT5OoFDbs4etdKZMPjvH+YSwUdhWx+6ypz+IXwkLcfrX+TeabWMWI7pG4pe9+BLrO", + "UUjQ8jPJoLNxtbn6uiN0viuIfcRO78NZKGyiIlpCH2NJ7kB8TBI+ehs20qWqWeE6qglaJXwL0mURa1fO", + "6wTL0tfmyrw1w/8gPo1Vd2vzhdG432/P1j3quvB7fYRdn71gIOL24w775fw+Byz77D8ZqcZc2RmXN61K", + "PrNYLchLBkiFudPRcCr8gw0vhp91j2J6hPXodErQa8piZmH8rx7sq0unylE/i/8+FstQWEiQPTD0gYoB", + "Rn/M0BmzR+Ggc7rFGc2fZfHPwrnctffijnFzu1X7QLhgLsm04Q3jxjvqnZV1e49nphZip3Col0x+ydGD", + "Ob862GwQO26YWXkVHJH5cdr3M+GzL6v5ZnAw4nYIrLvXQWg79ptv5y2EA+E+J5ywL7fOv+OGPVtL7dV5", + "cuUJ8+HU1vpDoNmeFKTbO1q4bSxtWde94X00B6N8IrnsZt4G03WfT1qJGSbxPL+CbYjF6RcTsBzdtpf/", + "1nry1FzBNzefmXC37zBSK5YDycZQ9dy9iFbYVhyNku101ILQefsxc6nDCeKJz+pOVLtfyQUuyPaL0UQ1", + "NyGlO/4KyuSgdmTa6cwrEDMBL7EOUEsMtDjXP7xAuei+67dj7t5dzbEp+5B8fdcLEN/LixNm6X18MsqI", + "G4gdcdv+PjgQH4shp575GhcDTqQmrweo+yJ1WOzP/KHL2B8gzY6uzlVi1ygNOZ7osFMNckn9h+EBLkaT", + "hkxKCzEDpbsy2megjEBi7/duDHJCsnguduJl5XoNnt7vn5JtnuK5zaCU20G6TWv8Tsj7KnzmwblKuiCP", + "wJMpxTtj1sjZhXATGIsqUM7ZWGbZKStyoZK3XuXL1qpZZWZ0VVzA1YOinBeKDG02nSYPZ2RVy/4x88eM", + "STnhzOVi4P97QPr2/H8E3OzE7N8DAAD//wbUgE48ZQAA", +} + +// GetSwagger returns the content of the embedded swagger specification file +// or error if failed to decode +func decodeSpec() ([]byte, error) { + zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, "")) + if err != nil { + return nil, fmt.Errorf("error base64 decoding spec: %w", err) + } + zr, err := gzip.NewReader(bytes.NewReader(zipped)) + if err != nil { + return nil, fmt.Errorf("error decompressing spec: %w", err) + } + var buf bytes.Buffer + _, err = buf.ReadFrom(zr) + if err != nil { + return nil, fmt.Errorf("error decompressing spec: %w", err) + } + + return buf.Bytes(), nil +} + +var rawSpec = decodeSpecCached() + +// a naive cached of a decoded swagger spec +func decodeSpecCached() func() ([]byte, error) { + data, err := decodeSpec() + return func() ([]byte, error) { + return data, err + } +} + +// Constructs a synthetic filesystem for resolving external references when loading openapi specifications. +func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) { + res := make(map[string]func() ([]byte, error)) + if len(pathToFile) > 0 { + res[pathToFile] = rawSpec + } + + return res +} + +// GetSwagger returns the Swagger specification corresponding to the generated code +// in this file. The external references of Swagger specification are resolved. +// The logic of resolving external references is tightly connected to "import-mapping" feature. +// Externally referenced files must be embedded in the corresponding golang packages. +// Urls can be supported but this task was out of the scope. +func GetSwagger() (swagger *openapi3.T, err error) { + resolvePath := PathToRawSpec("") + + loader := openapi3.NewLoader() + loader.IsExternalRefsAllowed = true + loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) { + pathToFile := url.String() + pathToFile = path.Clean(pathToFile) + getSpec, ok := resolvePath[pathToFile] + if !ok { + err1 := fmt.Errorf("path not found: %s", pathToFile) + return nil, err1 + } + return getSpec() + } + var specData []byte + specData, err = rawSpec() + if err != nil { + return + } + swagger, err = loader.LoadFromData(specData) + if err != nil { + return + } + return +} diff --git a/openapi/types.go b/openapi/types.go new file mode 100644 index 00000000..b0ca79bc --- /dev/null +++ b/openapi/types.go @@ -0,0 +1,1533 @@ +// Package openapi provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT. +package openapi + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/oapi-codegen/runtime" +) + +const ( + ApplicationScopes = "application.Scopes" +) + +// Defines values for QuestionSettingsMultipleChoiceQuestionType. +const ( + QuestionSettingsMultipleChoiceQuestionTypeMultipleChoice QuestionSettingsMultipleChoiceQuestionType = "MultipleChoice" +) + +// Defines values for QuestionSettingsNumberQuestionType. +const ( + QuestionSettingsNumberQuestionTypeNumber QuestionSettingsNumberQuestionType = "Number" +) + +// Defines values for QuestionSettingsScaleQuestionType. +const ( + QuestionSettingsScaleQuestionTypeScale QuestionSettingsScaleQuestionType = "Scale" +) + +// Defines values for QuestionSettingsSingleChoiceQuestionType. +const ( + QuestionSettingsSingleChoiceQuestionTypeSingleChoice QuestionSettingsSingleChoiceQuestionType = "SingleChoice" +) + +// Defines values for QuestionSettingsTextQuestionType. +const ( + QuestionSettingsTextQuestionTypeText QuestionSettingsTextQuestionType = "Text" +) + +// Defines values for QuestionSettingsTextLongQuestionType. +const ( + QuestionSettingsTextLongQuestionTypeTextLong QuestionSettingsTextLongQuestionType = "TextLong" +) + +// Defines values for QuestionTypeMultipleChoiceQuestionType. +const ( + QuestionTypeMultipleChoiceQuestionTypeMultipleChoice QuestionTypeMultipleChoiceQuestionType = "MultipleChoice" +) + +// Defines values for QuestionTypeNumberQuestionType. +const ( + QuestionTypeNumberQuestionTypeNumber QuestionTypeNumberQuestionType = "Number" +) + +// Defines values for QuestionTypeScaleQuestionType. +const ( + QuestionTypeScaleQuestionTypeScale QuestionTypeScaleQuestionType = "Scale" +) + +// Defines values for QuestionTypeSingleChoiceQuestionType. +const ( + QuestionTypeSingleChoiceQuestionTypeSingleChoice QuestionTypeSingleChoiceQuestionType = "SingleChoice" +) + +// Defines values for QuestionTypeTextQuestionType. +const ( + QuestionTypeTextQuestionTypeText QuestionTypeTextQuestionType = "Text" +) + +// Defines values for QuestionTypeTextLongQuestionType. +const ( + QuestionTypeTextLongQuestionTypeTextLong QuestionTypeTextLongQuestionType = "TextLong" +) + +// Defines values for ResShareType. +const ( + Admins ResShareType = "admins" + Anyone ResShareType = "anyone" + Respondents ResShareType = "respondents" +) + +// Defines values for ResponseBodyMultipleChoiceQuestionType. +const ( + MultipleChoice ResponseBodyMultipleChoiceQuestionType = "MultipleChoice" +) + +// Defines values for ResponseBodyNumberQuestionType. +const ( + Number ResponseBodyNumberQuestionType = "Number" +) + +// Defines values for ResponseBodyScaleQuestionType. +const ( + Scale ResponseBodyScaleQuestionType = "Scale" +) + +// Defines values for ResponseBodySingleChoiceQuestionType. +const ( + SingleChoice ResponseBodySingleChoiceQuestionType = "SingleChoice" +) + +// Defines values for ResponseBodyTextQuestionType. +const ( + Text ResponseBodyTextQuestionType = "Text" +) + +// Defines values for ResponseBodyTextLongQuestionType. +const ( + TextLong ResponseBodyTextLongQuestionType = "TextLong" +) + +// Defines values for ResponseSortType. +const ( + ResponseSortTypeModifiedAtASC ResponseSortType = "modified_at" + ResponseSortTypeModifiedAtDESC ResponseSortType = "-modified_at" + ResponseSortTypeSubmittedAtASC ResponseSortType = "submitted_at" + ResponseSortTypeSubmittedAtDESC ResponseSortType = "-submitted_at" + ResponseSortTypeTitleASC ResponseSortType = "title" + ResponseSortTypeTitleDESC ResponseSortType = "-title" +) + +// Defines values for SortType. +const ( + SortTypeCreatedAtASC SortType = "created_at" + SortTypeCreatedAtDESC SortType = "-created_at" + SortTypeModifiedAtASC SortType = "modified_at" + SortTypeModifiedAtDESC SortType = "-modified_at" + SortTypeTitleASC SortType = "title" + SortTypeTitleDESC SortType = "-title" +) + +// Groups defines model for Groups. +type Groups = []string + +// NewQuestion defines model for NewQuestion. +type NewQuestion struct { + Description string `json:"description"` + + // IsRequired 回答必須かどうか + IsRequired bool `json:"is_required"` + QuestionnaireId int `json:"questionnaire_id"` + Title string `json:"title"` + union json.RawMessage +} + +// NewQuestionnaire defines model for NewQuestionnaire. +type NewQuestionnaire struct { + Admins UsersAndGroups `json:"admins"` + Description string `json:"description"` + + // IsAllowingMultipleResponses 一人が複数回回答できるかどうか + IsAllowingMultipleResponses bool `json:"is_allowing_multiple_responses"` + + // IsAnonymous 匿名回答かどうか + IsAnonymous bool `json:"is_anonymous"` + + // IsPublished アンケートが公開されているかどうか + IsPublished bool `json:"is_published"` + Questions []NewQuestion `json:"questions"` + + // ResponseDueDateTime 回答期限。この日時を過ぎたら回答できなくなる。nullの場合は回答期限なし。 + ResponseDueDateTime *time.Time `json:"response_due_date_time,omitempty"` + + // ResponseViewableBy アンケートの結果を, 運営は見られる ("admins"), 回答済みの人は見られる ("respondents") 誰でも見られる ("anyone") + ResponseViewableBy ResShareType `json:"response_viewable_by"` + Targets UsersAndGroups `json:"targets"` + Title string `json:"title"` +} + +// NewResponse defines model for NewResponse. +type NewResponse struct { + Body []ResponseBody `json:"body"` + IsDraft bool `json:"is_draft"` +} + +// Question defines model for Question. +type Question struct { + CreatedAt time.Time `json:"created_at"` + Description string `json:"description"` + + // IsRequired 回答必須かどうか + IsRequired bool `json:"is_required"` + QuestionId int `json:"question_id"` + QuestionnaireId int `json:"questionnaire_id"` + Title string `json:"title"` + union json.RawMessage +} + +// QuestionBase defines model for QuestionBase. +type QuestionBase struct { + Description string `json:"description"` + + // IsRequired 回答必須かどうか + IsRequired bool `json:"is_required"` + QuestionnaireId int `json:"questionnaire_id"` + Title string `json:"title"` +} + +// QuestionSettingsByType defines model for QuestionSettingsByType. +type QuestionSettingsByType struct { + union json.RawMessage +} + +// QuestionSettingsMultipleChoice defines model for QuestionSettingsMultipleChoice. +type QuestionSettingsMultipleChoice struct { + Options []string `json:"options"` + QuestionType QuestionSettingsMultipleChoiceQuestionType `json:"question_type"` +} + +// QuestionSettingsMultipleChoiceQuestionType defines model for QuestionSettingsMultipleChoice.QuestionType. +type QuestionSettingsMultipleChoiceQuestionType string + +// QuestionSettingsNumber defines model for QuestionSettingsNumber. +type QuestionSettingsNumber struct { + MaxValue *int `json:"max_value,omitempty"` + MinValue *int `json:"min_value,omitempty"` + QuestionType QuestionSettingsNumberQuestionType `json:"question_type"` +} + +// QuestionSettingsNumberQuestionType defines model for QuestionSettingsNumber.QuestionType. +type QuestionSettingsNumberQuestionType string + +// QuestionSettingsScale defines model for QuestionSettingsScale. +type QuestionSettingsScale struct { + MaxLabel *string `json:"max_label,omitempty"` + MaxValue int `json:"max_value"` + MinLabel *string `json:"min_label,omitempty"` + MinValue int `json:"min_value"` + QuestionType QuestionSettingsScaleQuestionType `json:"question_type"` +} + +// QuestionSettingsScaleQuestionType defines model for QuestionSettingsScale.QuestionType. +type QuestionSettingsScaleQuestionType string + +// QuestionSettingsSingleChoice defines model for QuestionSettingsSingleChoice. +type QuestionSettingsSingleChoice struct { + Options []string `json:"options"` + QuestionType QuestionSettingsSingleChoiceQuestionType `json:"question_type"` +} + +// QuestionSettingsSingleChoiceQuestionType defines model for QuestionSettingsSingleChoice.QuestionType. +type QuestionSettingsSingleChoiceQuestionType string + +// QuestionSettingsText defines model for QuestionSettingsText. +type QuestionSettingsText struct { + MaxLength *int `json:"max_length,omitempty"` + QuestionType QuestionSettingsTextQuestionType `json:"question_type"` +} + +// QuestionSettingsTextQuestionType defines model for QuestionSettingsText.QuestionType. +type QuestionSettingsTextQuestionType string + +// QuestionSettingsTextLong defines model for QuestionSettingsTextLong. +type QuestionSettingsTextLong struct { + MaxLength *float32 `json:"max_length,omitempty"` + QuestionType QuestionSettingsTextLongQuestionType `json:"question_type"` +} + +// QuestionSettingsTextLongQuestionType defines model for QuestionSettingsTextLong.QuestionType. +type QuestionSettingsTextLongQuestionType string + +// QuestionTypeMultipleChoice defines model for QuestionTypeMultipleChoice. +type QuestionTypeMultipleChoice struct { + QuestionType QuestionTypeMultipleChoiceQuestionType `json:"question_type"` +} + +// QuestionTypeMultipleChoiceQuestionType defines model for QuestionTypeMultipleChoice.QuestionType. +type QuestionTypeMultipleChoiceQuestionType string + +// QuestionTypeNumber defines model for QuestionTypeNumber. +type QuestionTypeNumber struct { + QuestionType QuestionTypeNumberQuestionType `json:"question_type"` +} + +// QuestionTypeNumberQuestionType defines model for QuestionTypeNumber.QuestionType. +type QuestionTypeNumberQuestionType string + +// QuestionTypeScale defines model for QuestionTypeScale. +type QuestionTypeScale struct { + QuestionType QuestionTypeScaleQuestionType `json:"question_type"` +} + +// QuestionTypeScaleQuestionType defines model for QuestionTypeScale.QuestionType. +type QuestionTypeScaleQuestionType string + +// QuestionTypeSingleChoice defines model for QuestionTypeSingleChoice. +type QuestionTypeSingleChoice struct { + QuestionType QuestionTypeSingleChoiceQuestionType `json:"question_type"` +} + +// QuestionTypeSingleChoiceQuestionType defines model for QuestionTypeSingleChoice.QuestionType. +type QuestionTypeSingleChoiceQuestionType string + +// QuestionTypeText defines model for QuestionTypeText. +type QuestionTypeText struct { + QuestionType QuestionTypeTextQuestionType `json:"question_type"` +} + +// QuestionTypeTextQuestionType defines model for QuestionTypeText.QuestionType. +type QuestionTypeTextQuestionType string + +// QuestionTypeTextLong defines model for QuestionTypeTextLong. +type QuestionTypeTextLong struct { + QuestionType QuestionTypeTextLongQuestionType `json:"question_type"` +} + +// QuestionTypeTextLongQuestionType defines model for QuestionTypeTextLong.QuestionType. +type QuestionTypeTextLongQuestionType string + +// QuestionnaireBase defines model for QuestionnaireBase. +type QuestionnaireBase struct { + Admins UsersAndGroups `json:"admins"` + Description string `json:"description"` + + // IsAllowingMultipleResponses 一人が複数回回答できるかどうか + IsAllowingMultipleResponses bool `json:"is_allowing_multiple_responses"` + + // IsAnonymous 匿名回答かどうか + IsAnonymous bool `json:"is_anonymous"` + + // IsPublished アンケートが公開されているかどうか + IsPublished bool `json:"is_published"` + + // ResponseDueDateTime 回答期限。この日時を過ぎたら回答できなくなる。nullの場合は回答期限なし。 + ResponseDueDateTime *time.Time `json:"response_due_date_time,omitempty"` + + // ResponseViewableBy アンケートの結果を, 運営は見られる ("admins"), 回答済みの人は見られる ("respondents") 誰でも見られる ("anyone") + ResponseViewableBy ResShareType `json:"response_viewable_by"` + Targets UsersAndGroups `json:"targets"` + Title string `json:"title"` +} + +// QuestionnaireCreatedAt defines model for QuestionnaireCreatedAt. +type QuestionnaireCreatedAt struct { + CreatedAt time.Time `json:"created_at"` +} + +// QuestionnaireDescription defines model for QuestionnaireDescription. +type QuestionnaireDescription struct { + Description string `json:"description"` +} + +// QuestionnaireDetail defines model for QuestionnaireDetail. +type QuestionnaireDetail struct { + Admins UsersAndGroups `json:"admins"` + CreatedAt time.Time `json:"created_at"` + Description string `json:"description"` + + // IsAllowingMultipleResponses 一人が複数回回答できるかどうか + IsAllowingMultipleResponses bool `json:"is_allowing_multiple_responses"` + + // IsAnonymous 匿名回答かどうか + IsAnonymous bool `json:"is_anonymous"` + + // IsPublished アンケートが公開されているかどうか + IsPublished bool `json:"is_published"` + ModifiedAt time.Time `json:"modified_at"` + QuestionnaireId int `json:"questionnaire_id"` + Questions []Question `json:"questions"` + Respondents Users `json:"respondents"` + + // ResponseDueDateTime 回答期限。この日時を過ぎたら回答できなくなる。nullの場合は回答期限なし。 + ResponseDueDateTime *time.Time `json:"response_due_date_time,omitempty"` + + // ResponseViewableBy アンケートの結果を, 運営は見られる ("admins"), 回答済みの人は見られる ("respondents") 誰でも見られる ("anyone") + ResponseViewableBy ResShareType `json:"response_viewable_by"` + Targets UsersAndGroups `json:"targets"` + Title string `json:"title"` +} + +// QuestionnaireID defines model for QuestionnaireID. +type QuestionnaireID struct { + QuestionnaireId int `json:"questionnaire_id"` +} + +// QuestionnaireInfo defines model for QuestionnaireInfo. +type QuestionnaireInfo struct { + CreatedAt time.Time `json:"created_at"` + + // IsTargetingMe 自分がターゲットになっているかどうか + IsTargetingMe bool `json:"is_targeting_me"` + ModifiedAt time.Time `json:"modified_at"` + + // ResponseDueDateTime 回答期限。この日時を過ぎたら回答できなくなる。nullの場合は回答期限なし。 + ResponseDueDateTime *time.Time `json:"response_due_date_time,omitempty"` + Title string `json:"title"` +} + +// QuestionnaireIsAllowingMultipleResponses defines model for QuestionnaireIsAllowingMultipleResponses. +type QuestionnaireIsAllowingMultipleResponses struct { + // IsAllowingMultipleResponses 一人が複数回回答できるかどうか + IsAllowingMultipleResponses bool `json:"is_allowing_multiple_responses"` +} + +// QuestionnaireIsAnonymous defines model for QuestionnaireIsAnonymous. +type QuestionnaireIsAnonymous struct { + // IsAnonymous 匿名回答かどうか + IsAnonymous bool `json:"is_anonymous"` +} + +// QuestionnaireIsPublished defines model for QuestionnaireIsPublished. +type QuestionnaireIsPublished struct { + // IsPublished アンケートが公開されているかどうか + IsPublished bool `json:"is_published"` +} + +// QuestionnaireIsRemindEnabled defines model for QuestionnaireIsRemindEnabled. +type QuestionnaireIsRemindEnabled struct { + // IsRemindEnabled 自分に対するリマインドが有効かどうか。ユーザーが対象者でありかつ回答していない場合、この値がtrueであればリマインドが送信される。 + IsRemindEnabled bool `json:"is_remind_enabled"` +} + +// QuestionnaireIsTargetingMe defines model for QuestionnaireIsTargetingMe. +type QuestionnaireIsTargetingMe struct { + // IsTargetingMe 自分がターゲットになっているかどうか + IsTargetingMe bool `json:"is_targeting_me"` +} + +// QuestionnaireList defines model for QuestionnaireList. +type QuestionnaireList struct { + // PageMax 合計のページ数 + PageMax int `json:"page_max"` + Questionnaires []QuestionnaireSummary `json:"questionnaires"` +} + +// QuestionnaireModifiedAt defines model for QuestionnaireModifiedAt. +type QuestionnaireModifiedAt struct { + ModifiedAt time.Time `json:"modified_at"` +} + +// QuestionnaireResponseDueDateTime defines model for QuestionnaireResponseDueDateTime. +type QuestionnaireResponseDueDateTime struct { + // ResponseDueDateTime 回答期限。この日時を過ぎたら回答できなくなる。nullの場合は回答期限なし。 + ResponseDueDateTime *time.Time `json:"response_due_date_time,omitempty"` +} + +// QuestionnaireResponseViewableBy defines model for QuestionnaireResponseViewableBy. +type QuestionnaireResponseViewableBy struct { + // ResponseViewableBy アンケートの結果を, 運営は見られる ("admins"), 回答済みの人は見られる ("respondents") 誰でも見られる ("anyone") + ResponseViewableBy ResShareType `json:"response_viewable_by"` +} + +// QuestionnaireSummary defines model for QuestionnaireSummary. +type QuestionnaireSummary struct { + // AllResponded すべての対象者が回答済みの場合 true を返す。それ以外は false を返す。 (対象者が存在しない場合は true を返す) + AllResponded bool `json:"all_responded"` + CreatedAt time.Time `json:"created_at"` + Description string `json:"description"` + + // HasMyDraft 下書きが存在する + HasMyDraft bool `json:"has_my_draft"` + + // HasMyResponse 回答が存在する + HasMyResponse bool `json:"has_my_response"` + + // IsAllowingMultipleResponses 一人が複数回回答できるかどうか + IsAllowingMultipleResponses bool `json:"is_allowing_multiple_responses"` + + // IsAnonymous 匿名回答かどうか + IsAnonymous bool `json:"is_anonymous"` + + // IsPublished アンケートが公開されているかどうか + IsPublished bool `json:"is_published"` + + // IsTargetingMe 自分がターゲットになっているかどうか + IsTargetingMe bool `json:"is_targeting_me"` + ModifiedAt time.Time `json:"modified_at"` + QuestionnaireId int `json:"questionnaire_id"` + RespondedDateTimeByMe *time.Time `json:"responded_date_time_by_me,omitempty"` + + // ResponseDueDateTime 回答期限。この日時を過ぎたら回答できなくなる。nullの場合は回答期限なし。 + ResponseDueDateTime *time.Time `json:"response_due_date_time,omitempty"` + + // ResponseViewableBy アンケートの結果を, 運営は見られる ("admins"), 回答済みの人は見られる ("respondents") 誰でも見られる ("anyone") + ResponseViewableBy ResShareType `json:"response_viewable_by"` + Title string `json:"title"` +} + +// QuestionnaireTargetsAndAdmins defines model for QuestionnaireTargetsAndAdmins. +type QuestionnaireTargetsAndAdmins struct { + Admins UsersAndGroups `json:"admins"` + Targets UsersAndGroups `json:"targets"` +} + +// QuestionnaireTitle defines model for QuestionnaireTitle. +type QuestionnaireTitle struct { + Title string `json:"title"` +} + +// ResShareType アンケートの結果を, 運営は見られる ("admins"), 回答済みの人は見られる ("respondents") 誰でも見られる ("anyone") +type ResShareType string + +// Response defines model for Response. +type Response struct { + Body []ResponseBody `json:"body"` + IsDraft bool `json:"is_draft"` + ModifiedAt time.Time `json:"modified_at"` + QuestionnaireId int `json:"questionnaire_id"` + + // Respondent traQ ID + Respondent TraqId `json:"respondent"` + ResponseId int `json:"response_id"` + SubmittedAt time.Time `json:"submitted_at"` +} + +// ResponseBody defines model for ResponseBody. +type ResponseBody struct { + union json.RawMessage +} + +// ResponseBodyBaseInteger defines model for ResponseBodyBaseInteger. +type ResponseBodyBaseInteger struct { + Answer int `json:"answer"` +} + +// ResponseBodyBaseNumber defines model for ResponseBodyBaseNumber. +type ResponseBodyBaseNumber struct { + Answer float32 `json:"answer"` +} + +// ResponseBodyBaseString defines model for ResponseBodyBaseString. +type ResponseBodyBaseString struct { + Answer string `json:"answer"` +} + +// ResponseBodyMultipleChoice defines model for ResponseBodyMultipleChoice. +type ResponseBodyMultipleChoice struct { + Answer []int `json:"answer"` + QuestionType ResponseBodyMultipleChoiceQuestionType `json:"question_type"` +} + +// ResponseBodyMultipleChoiceQuestionType defines model for ResponseBodyMultipleChoice.QuestionType. +type ResponseBodyMultipleChoiceQuestionType string + +// ResponseBodyNumber defines model for ResponseBodyNumber. +type ResponseBodyNumber struct { + Answer float32 `json:"answer"` + QuestionType ResponseBodyNumberQuestionType `json:"question_type"` +} + +// ResponseBodyNumberQuestionType defines model for ResponseBodyNumber.QuestionType. +type ResponseBodyNumberQuestionType string + +// ResponseBodyScale defines model for ResponseBodyScale. +type ResponseBodyScale struct { + Answer int `json:"answer"` + QuestionType ResponseBodyScaleQuestionType `json:"question_type"` +} + +// ResponseBodyScaleQuestionType defines model for ResponseBodyScale.QuestionType. +type ResponseBodyScaleQuestionType string + +// ResponseBodySingleChoice defines model for ResponseBodySingleChoice. +type ResponseBodySingleChoice struct { + Answer int `json:"answer"` + QuestionType ResponseBodySingleChoiceQuestionType `json:"question_type"` +} + +// ResponseBodySingleChoiceQuestionType defines model for ResponseBodySingleChoice.QuestionType. +type ResponseBodySingleChoiceQuestionType string + +// ResponseBodyText defines model for ResponseBodyText. +type ResponseBodyText struct { + Answer string `json:"answer"` + QuestionType ResponseBodyTextQuestionType `json:"question_type"` +} + +// ResponseBodyTextQuestionType defines model for ResponseBodyText.QuestionType. +type ResponseBodyTextQuestionType string + +// ResponseBodyTextLong defines model for ResponseBodyTextLong. +type ResponseBodyTextLong struct { + Answer string `json:"answer"` + QuestionType ResponseBodyTextLongQuestionType `json:"question_type"` +} + +// ResponseBodyTextLongQuestionType defines model for ResponseBodyTextLong.QuestionType. +type ResponseBodyTextLongQuestionType string + +// ResponseSortType response用のsortの種類 +type ResponseSortType string + +// ResponseWithQuestionnaireInfoItem defines model for ResponseWithQuestionnaireInfoItem. +type ResponseWithQuestionnaireInfoItem struct { + Body []ResponseBody `json:"body"` + IsDraft bool `json:"is_draft"` + ModifiedAt time.Time `json:"modified_at"` + QuestionnaireId int `json:"questionnaire_id"` + QuestionnaireInfo *QuestionnaireInfo `json:"questionnaire_info,omitempty"` + + // Respondent traQ ID + Respondent TraqId `json:"respondent"` + ResponseId int `json:"response_id"` + SubmittedAt time.Time `json:"submitted_at"` +} + +// Responses defines model for Responses. +type Responses = []Response + +// ResponsesWithQuestionnaireInfo defines model for ResponsesWithQuestionnaireInfo. +type ResponsesWithQuestionnaireInfo = []ResponseWithQuestionnaireInfoItem + +// Result defines model for Result. +type Result = []ResultItem + +// ResultItem defines model for ResultItem. +type ResultItem struct { + Body []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"` +} + +// SortType question、questionnaire用のソートの種類 +type SortType string + +// TraqId traQ ID +type TraqId = string + +// Users defines model for Users. +type Users = []TraqId + +// UsersAndGroups defines model for UsersAndGroups. +type UsersAndGroups struct { + Groups Groups `json:"groups"` + Users Users `json:"users"` +} + +// OnlyAdministratedByMeInQuery defines model for onlyAdministratedByMeInQuery. +type OnlyAdministratedByMeInQuery = bool + +// OnlyMyResponseInQuery defines model for onlyMyResponseInQuery. +type OnlyMyResponseInQuery = bool + +// OnlyTargetingMeInQuery defines model for onlyTargetingMeInQuery. +type OnlyTargetingMeInQuery = bool + +// PageInQuery defines model for pageInQuery. +type PageInQuery = int + +// QuestionnaireIDInPath defines model for questionnaireIDInPath. +type QuestionnaireIDInPath = int + +// ResponseIDInPath defines model for responseIDInPath. +type ResponseIDInPath = int + +// ResponseSortInQuery response用のsortの種類 +type ResponseSortInQuery = ResponseSortType + +// SearchInQuery defines model for searchInQuery. +type SearchInQuery = string + +// SortInQuery question、questionnaire用のソートの種類 +type SortInQuery = SortType + +// GetQuestionnairesParams defines parameters for GetQuestionnaires. +type GetQuestionnairesParams struct { + // Sort 並び順 (作成日時が新しい "created_at", 作成日時が古い "-created_at", タイトルの昇順 "title", タイトルの降順 "-title", 更新日時が新しい "modified_at", 更新日時が古い "-modified_at" ) + Sort *SortInQuery `form:"sort,omitempty" json:"sort,omitempty"` + + // Search タイトルの検索 + Search *SearchInQuery `form:"search,omitempty" json:"search,omitempty"` + + // Page 何ページ目か (未定義の場合は1ページ目) + Page *PageInQuery `form:"page,omitempty" json:"page,omitempty"` + + // OnlyTargetingMe 自分がターゲットになっているもののみ取得 (true), ターゲットになっているものも含めてすべて取得 (false)。デフォルトはfalse。 + OnlyTargetingMe *OnlyTargetingMeInQuery `form:"onlyTargetingMe,omitempty" json:"onlyTargetingMe,omitempty"` + + // OnlyAdministratedByMe 自分が管理者になっていないもののみ取得 (true), 管理者になっているものも含めてすべて取得 (false)。デフォルトはfalse。 + OnlyAdministratedByMe *OnlyAdministratedByMeInQuery `form:"onlyAdministratedByMe,omitempty" json:"onlyAdministratedByMe,omitempty"` +} + +// GetQuestionnaireResponsesParams defines parameters for GetQuestionnaireResponses. +type GetQuestionnaireResponsesParams struct { + // Sort 並び順 (作成日時が新しい "submitted_at", 作成日時が古い "-submitted_at", タイトルの昇順 "title", タイトルの降順 "-title", 更新日時が新しい "modified_at", 更新日時が古い "-modified_at" ) + Sort *ResponseSortInQuery `form:"sort,omitempty" json:"sort,omitempty"` + + // OnlyMyResponse 自分の回答のみ取得 (true), 自分の回答以外も含めてすべて取得 (false)。デフォルトはfalse。 + OnlyMyResponse *OnlyMyResponseInQuery `form:"onlyMyResponse,omitempty" json:"onlyMyResponse,omitempty"` +} + +// GetMyResponsesParams defines parameters for GetMyResponses. +type GetMyResponsesParams struct { + // Sort 並び順 (作成日時が新しい "submitted_at", 作成日時が古い "-submitted_at", タイトルの昇順 "title", タイトルの降順 "-title", 更新日時が新しい "modified_at", 更新日時が古い "-modified_at" ) + Sort *ResponseSortInQuery `form:"sort,omitempty" json:"sort,omitempty"` +} + +// PostQuestionnaireJSONRequestBody defines body for PostQuestionnaire for application/json ContentType. +type PostQuestionnaireJSONRequestBody = NewQuestionnaire + +// EditQuestionnaireJSONRequestBody defines body for EditQuestionnaire for application/json ContentType. +type EditQuestionnaireJSONRequestBody = QuestionnaireDetail + +// EditQuestionnaireMyRemindStatusJSONRequestBody defines body for EditQuestionnaireMyRemindStatus for application/json ContentType. +type EditQuestionnaireMyRemindStatusJSONRequestBody = QuestionnaireIsRemindEnabled + +// PostQuestionnaireResponseJSONRequestBody defines body for PostQuestionnaireResponse for application/json ContentType. +type PostQuestionnaireResponseJSONRequestBody = NewResponse + +// EditResponseJSONRequestBody defines body for EditResponse for application/json ContentType. +type EditResponseJSONRequestBody = Response + +// AsQuestionSettingsText returns the union data inside the NewQuestion as a QuestionSettingsText +func (t NewQuestion) AsQuestionSettingsText() (QuestionSettingsText, error) { + var body QuestionSettingsText + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsText overwrites any union data inside the NewQuestion as the provided QuestionSettingsText +func (t *NewQuestion) FromQuestionSettingsText(v QuestionSettingsText) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsText performs a merge with any union data inside the NewQuestion, using the provided QuestionSettingsText +func (t *NewQuestion) MergeQuestionSettingsText(v QuestionSettingsText) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsQuestionSettingsTextLong returns the union data inside the NewQuestion as a QuestionSettingsTextLong +func (t NewQuestion) AsQuestionSettingsTextLong() (QuestionSettingsTextLong, error) { + var body QuestionSettingsTextLong + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsTextLong overwrites any union data inside the NewQuestion as the provided QuestionSettingsTextLong +func (t *NewQuestion) FromQuestionSettingsTextLong(v QuestionSettingsTextLong) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsTextLong performs a merge with any union data inside the NewQuestion, using the provided QuestionSettingsTextLong +func (t *NewQuestion) MergeQuestionSettingsTextLong(v QuestionSettingsTextLong) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsQuestionSettingsNumber returns the union data inside the NewQuestion as a QuestionSettingsNumber +func (t NewQuestion) AsQuestionSettingsNumber() (QuestionSettingsNumber, error) { + var body QuestionSettingsNumber + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsNumber overwrites any union data inside the NewQuestion as the provided QuestionSettingsNumber +func (t *NewQuestion) FromQuestionSettingsNumber(v QuestionSettingsNumber) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsNumber performs a merge with any union data inside the NewQuestion, using the provided QuestionSettingsNumber +func (t *NewQuestion) MergeQuestionSettingsNumber(v QuestionSettingsNumber) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsQuestionSettingsSingleChoice returns the union data inside the NewQuestion as a QuestionSettingsSingleChoice +func (t NewQuestion) AsQuestionSettingsSingleChoice() (QuestionSettingsSingleChoice, error) { + var body QuestionSettingsSingleChoice + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsSingleChoice overwrites any union data inside the NewQuestion as the provided QuestionSettingsSingleChoice +func (t *NewQuestion) FromQuestionSettingsSingleChoice(v QuestionSettingsSingleChoice) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsSingleChoice performs a merge with any union data inside the NewQuestion, using the provided QuestionSettingsSingleChoice +func (t *NewQuestion) MergeQuestionSettingsSingleChoice(v QuestionSettingsSingleChoice) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsQuestionSettingsMultipleChoice returns the union data inside the NewQuestion as a QuestionSettingsMultipleChoice +func (t NewQuestion) AsQuestionSettingsMultipleChoice() (QuestionSettingsMultipleChoice, error) { + var body QuestionSettingsMultipleChoice + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsMultipleChoice overwrites any union data inside the NewQuestion as the provided QuestionSettingsMultipleChoice +func (t *NewQuestion) FromQuestionSettingsMultipleChoice(v QuestionSettingsMultipleChoice) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsMultipleChoice performs a merge with any union data inside the NewQuestion, using the provided QuestionSettingsMultipleChoice +func (t *NewQuestion) MergeQuestionSettingsMultipleChoice(v QuestionSettingsMultipleChoice) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsQuestionSettingsScale returns the union data inside the NewQuestion as a QuestionSettingsScale +func (t NewQuestion) AsQuestionSettingsScale() (QuestionSettingsScale, error) { + var body QuestionSettingsScale + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsScale overwrites any union data inside the NewQuestion as the provided QuestionSettingsScale +func (t *NewQuestion) FromQuestionSettingsScale(v QuestionSettingsScale) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsScale performs a merge with any union data inside the NewQuestion, using the provided QuestionSettingsScale +func (t *NewQuestion) MergeQuestionSettingsScale(v QuestionSettingsScale) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +func (t NewQuestion) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + if err != nil { + return nil, err + } + object := make(map[string]json.RawMessage) + if t.union != nil { + err = json.Unmarshal(b, &object) + if err != nil { + return nil, err + } + } + + object["description"], err = json.Marshal(t.Description) + if err != nil { + return nil, fmt.Errorf("error marshaling 'description': %w", err) + } + + object["is_required"], err = json.Marshal(t.IsRequired) + if err != nil { + return nil, fmt.Errorf("error marshaling 'is_required': %w", err) + } + + object["questionnaire_id"], err = json.Marshal(t.QuestionnaireId) + if err != nil { + return nil, fmt.Errorf("error marshaling 'questionnaire_id': %w", err) + } + + object["title"], err = json.Marshal(t.Title) + if err != nil { + return nil, fmt.Errorf("error marshaling 'title': %w", err) + } + + b, err = json.Marshal(object) + return b, err +} + +func (t *NewQuestion) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + if err != nil { + return err + } + object := make(map[string]json.RawMessage) + err = json.Unmarshal(b, &object) + if err != nil { + return err + } + + if raw, found := object["description"]; found { + err = json.Unmarshal(raw, &t.Description) + if err != nil { + return fmt.Errorf("error reading 'description': %w", err) + } + } + + if raw, found := object["is_required"]; found { + err = json.Unmarshal(raw, &t.IsRequired) + if err != nil { + return fmt.Errorf("error reading 'is_required': %w", err) + } + } + + if raw, found := object["questionnaire_id"]; found { + err = json.Unmarshal(raw, &t.QuestionnaireId) + if err != nil { + return fmt.Errorf("error reading 'questionnaire_id': %w", err) + } + } + + if raw, found := object["title"]; found { + err = json.Unmarshal(raw, &t.Title) + if err != nil { + return fmt.Errorf("error reading 'title': %w", err) + } + } + + return err +} + +// AsQuestionSettingsText returns the union data inside the Question as a QuestionSettingsText +func (t Question) AsQuestionSettingsText() (QuestionSettingsText, error) { + var body QuestionSettingsText + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsText overwrites any union data inside the Question as the provided QuestionSettingsText +func (t *Question) FromQuestionSettingsText(v QuestionSettingsText) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsText performs a merge with any union data inside the Question, using the provided QuestionSettingsText +func (t *Question) MergeQuestionSettingsText(v QuestionSettingsText) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsQuestionSettingsTextLong returns the union data inside the Question as a QuestionSettingsTextLong +func (t Question) AsQuestionSettingsTextLong() (QuestionSettingsTextLong, error) { + var body QuestionSettingsTextLong + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsTextLong overwrites any union data inside the Question as the provided QuestionSettingsTextLong +func (t *Question) FromQuestionSettingsTextLong(v QuestionSettingsTextLong) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsTextLong performs a merge with any union data inside the Question, using the provided QuestionSettingsTextLong +func (t *Question) MergeQuestionSettingsTextLong(v QuestionSettingsTextLong) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsQuestionSettingsNumber returns the union data inside the Question as a QuestionSettingsNumber +func (t Question) AsQuestionSettingsNumber() (QuestionSettingsNumber, error) { + var body QuestionSettingsNumber + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsNumber overwrites any union data inside the Question as the provided QuestionSettingsNumber +func (t *Question) FromQuestionSettingsNumber(v QuestionSettingsNumber) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsNumber performs a merge with any union data inside the Question, using the provided QuestionSettingsNumber +func (t *Question) MergeQuestionSettingsNumber(v QuestionSettingsNumber) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsQuestionSettingsSingleChoice returns the union data inside the Question as a QuestionSettingsSingleChoice +func (t Question) AsQuestionSettingsSingleChoice() (QuestionSettingsSingleChoice, error) { + var body QuestionSettingsSingleChoice + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsSingleChoice overwrites any union data inside the Question as the provided QuestionSettingsSingleChoice +func (t *Question) FromQuestionSettingsSingleChoice(v QuestionSettingsSingleChoice) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsSingleChoice performs a merge with any union data inside the Question, using the provided QuestionSettingsSingleChoice +func (t *Question) MergeQuestionSettingsSingleChoice(v QuestionSettingsSingleChoice) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsQuestionSettingsMultipleChoice returns the union data inside the Question as a QuestionSettingsMultipleChoice +func (t Question) AsQuestionSettingsMultipleChoice() (QuestionSettingsMultipleChoice, error) { + var body QuestionSettingsMultipleChoice + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsMultipleChoice overwrites any union data inside the Question as the provided QuestionSettingsMultipleChoice +func (t *Question) FromQuestionSettingsMultipleChoice(v QuestionSettingsMultipleChoice) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsMultipleChoice performs a merge with any union data inside the Question, using the provided QuestionSettingsMultipleChoice +func (t *Question) MergeQuestionSettingsMultipleChoice(v QuestionSettingsMultipleChoice) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsQuestionSettingsScale returns the union data inside the Question as a QuestionSettingsScale +func (t Question) AsQuestionSettingsScale() (QuestionSettingsScale, error) { + var body QuestionSettingsScale + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsScale overwrites any union data inside the Question as the provided QuestionSettingsScale +func (t *Question) FromQuestionSettingsScale(v QuestionSettingsScale) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsScale performs a merge with any union data inside the Question, using the provided QuestionSettingsScale +func (t *Question) MergeQuestionSettingsScale(v QuestionSettingsScale) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +func (t Question) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + if err != nil { + return nil, err + } + object := make(map[string]json.RawMessage) + if t.union != nil { + err = json.Unmarshal(b, &object) + if err != nil { + return nil, err + } + } + + object["created_at"], err = json.Marshal(t.CreatedAt) + if err != nil { + return nil, fmt.Errorf("error marshaling 'created_at': %w", err) + } + + object["description"], err = json.Marshal(t.Description) + if err != nil { + return nil, fmt.Errorf("error marshaling 'description': %w", err) + } + + object["is_required"], err = json.Marshal(t.IsRequired) + if err != nil { + return nil, fmt.Errorf("error marshaling 'is_required': %w", err) + } + + object["question_id"], err = json.Marshal(t.QuestionId) + if err != nil { + return nil, fmt.Errorf("error marshaling 'question_id': %w", err) + } + + object["questionnaire_id"], err = json.Marshal(t.QuestionnaireId) + if err != nil { + return nil, fmt.Errorf("error marshaling 'questionnaire_id': %w", err) + } + + object["title"], err = json.Marshal(t.Title) + if err != nil { + return nil, fmt.Errorf("error marshaling 'title': %w", err) + } + + b, err = json.Marshal(object) + return b, err +} + +func (t *Question) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + if err != nil { + return err + } + object := make(map[string]json.RawMessage) + err = json.Unmarshal(b, &object) + if err != nil { + return err + } + + if raw, found := object["created_at"]; found { + err = json.Unmarshal(raw, &t.CreatedAt) + if err != nil { + return fmt.Errorf("error reading 'created_at': %w", err) + } + } + + if raw, found := object["description"]; found { + err = json.Unmarshal(raw, &t.Description) + if err != nil { + return fmt.Errorf("error reading 'description': %w", err) + } + } + + if raw, found := object["is_required"]; found { + err = json.Unmarshal(raw, &t.IsRequired) + if err != nil { + return fmt.Errorf("error reading 'is_required': %w", err) + } + } + + if raw, found := object["question_id"]; found { + err = json.Unmarshal(raw, &t.QuestionId) + if err != nil { + return fmt.Errorf("error reading 'question_id': %w", err) + } + } + + if raw, found := object["questionnaire_id"]; found { + err = json.Unmarshal(raw, &t.QuestionnaireId) + if err != nil { + return fmt.Errorf("error reading 'questionnaire_id': %w", err) + } + } + + if raw, found := object["title"]; found { + err = json.Unmarshal(raw, &t.Title) + if err != nil { + return fmt.Errorf("error reading 'title': %w", err) + } + } + + return err +} + +// AsQuestionSettingsText returns the union data inside the QuestionSettingsByType as a QuestionSettingsText +func (t QuestionSettingsByType) AsQuestionSettingsText() (QuestionSettingsText, error) { + var body QuestionSettingsText + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsText overwrites any union data inside the QuestionSettingsByType as the provided QuestionSettingsText +func (t *QuestionSettingsByType) FromQuestionSettingsText(v QuestionSettingsText) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsText performs a merge with any union data inside the QuestionSettingsByType, using the provided QuestionSettingsText +func (t *QuestionSettingsByType) MergeQuestionSettingsText(v QuestionSettingsText) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsQuestionSettingsTextLong returns the union data inside the QuestionSettingsByType as a QuestionSettingsTextLong +func (t QuestionSettingsByType) AsQuestionSettingsTextLong() (QuestionSettingsTextLong, error) { + var body QuestionSettingsTextLong + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsTextLong overwrites any union data inside the QuestionSettingsByType as the provided QuestionSettingsTextLong +func (t *QuestionSettingsByType) FromQuestionSettingsTextLong(v QuestionSettingsTextLong) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsTextLong performs a merge with any union data inside the QuestionSettingsByType, using the provided QuestionSettingsTextLong +func (t *QuestionSettingsByType) MergeQuestionSettingsTextLong(v QuestionSettingsTextLong) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsQuestionSettingsNumber returns the union data inside the QuestionSettingsByType as a QuestionSettingsNumber +func (t QuestionSettingsByType) AsQuestionSettingsNumber() (QuestionSettingsNumber, error) { + var body QuestionSettingsNumber + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsNumber overwrites any union data inside the QuestionSettingsByType as the provided QuestionSettingsNumber +func (t *QuestionSettingsByType) FromQuestionSettingsNumber(v QuestionSettingsNumber) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsNumber performs a merge with any union data inside the QuestionSettingsByType, using the provided QuestionSettingsNumber +func (t *QuestionSettingsByType) MergeQuestionSettingsNumber(v QuestionSettingsNumber) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsQuestionSettingsSingleChoice returns the union data inside the QuestionSettingsByType as a QuestionSettingsSingleChoice +func (t QuestionSettingsByType) AsQuestionSettingsSingleChoice() (QuestionSettingsSingleChoice, error) { + var body QuestionSettingsSingleChoice + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsSingleChoice overwrites any union data inside the QuestionSettingsByType as the provided QuestionSettingsSingleChoice +func (t *QuestionSettingsByType) FromQuestionSettingsSingleChoice(v QuestionSettingsSingleChoice) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsSingleChoice performs a merge with any union data inside the QuestionSettingsByType, using the provided QuestionSettingsSingleChoice +func (t *QuestionSettingsByType) MergeQuestionSettingsSingleChoice(v QuestionSettingsSingleChoice) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsQuestionSettingsMultipleChoice returns the union data inside the QuestionSettingsByType as a QuestionSettingsMultipleChoice +func (t QuestionSettingsByType) AsQuestionSettingsMultipleChoice() (QuestionSettingsMultipleChoice, error) { + var body QuestionSettingsMultipleChoice + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsMultipleChoice overwrites any union data inside the QuestionSettingsByType as the provided QuestionSettingsMultipleChoice +func (t *QuestionSettingsByType) FromQuestionSettingsMultipleChoice(v QuestionSettingsMultipleChoice) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsMultipleChoice performs a merge with any union data inside the QuestionSettingsByType, using the provided QuestionSettingsMultipleChoice +func (t *QuestionSettingsByType) MergeQuestionSettingsMultipleChoice(v QuestionSettingsMultipleChoice) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsQuestionSettingsScale returns the union data inside the QuestionSettingsByType as a QuestionSettingsScale +func (t QuestionSettingsByType) AsQuestionSettingsScale() (QuestionSettingsScale, error) { + var body QuestionSettingsScale + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuestionSettingsScale overwrites any union data inside the QuestionSettingsByType as the provided QuestionSettingsScale +func (t *QuestionSettingsByType) FromQuestionSettingsScale(v QuestionSettingsScale) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuestionSettingsScale performs a merge with any union data inside the QuestionSettingsByType, using the provided QuestionSettingsScale +func (t *QuestionSettingsByType) MergeQuestionSettingsScale(v QuestionSettingsScale) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +func (t QuestionSettingsByType) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *QuestionSettingsByType) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + +// AsResponseBodyText returns the union data inside the ResponseBody as a ResponseBodyText +func (t ResponseBody) AsResponseBodyText() (ResponseBodyText, error) { + var body ResponseBodyText + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromResponseBodyText overwrites any union data inside the ResponseBody as the provided ResponseBodyText +func (t *ResponseBody) FromResponseBodyText(v ResponseBodyText) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeResponseBodyText performs a merge with any union data inside the ResponseBody, using the provided ResponseBodyText +func (t *ResponseBody) MergeResponseBodyText(v ResponseBodyText) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsResponseBodyTextLong returns the union data inside the ResponseBody as a ResponseBodyTextLong +func (t ResponseBody) AsResponseBodyTextLong() (ResponseBodyTextLong, error) { + var body ResponseBodyTextLong + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromResponseBodyTextLong overwrites any union data inside the ResponseBody as the provided ResponseBodyTextLong +func (t *ResponseBody) FromResponseBodyTextLong(v ResponseBodyTextLong) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeResponseBodyTextLong performs a merge with any union data inside the ResponseBody, using the provided ResponseBodyTextLong +func (t *ResponseBody) MergeResponseBodyTextLong(v ResponseBodyTextLong) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsResponseBodyNumber returns the union data inside the ResponseBody as a ResponseBodyNumber +func (t ResponseBody) AsResponseBodyNumber() (ResponseBodyNumber, error) { + var body ResponseBodyNumber + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromResponseBodyNumber overwrites any union data inside the ResponseBody as the provided ResponseBodyNumber +func (t *ResponseBody) FromResponseBodyNumber(v ResponseBodyNumber) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeResponseBodyNumber performs a merge with any union data inside the ResponseBody, using the provided ResponseBodyNumber +func (t *ResponseBody) MergeResponseBodyNumber(v ResponseBodyNumber) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsResponseBodySingleChoice returns the union data inside the ResponseBody as a ResponseBodySingleChoice +func (t ResponseBody) AsResponseBodySingleChoice() (ResponseBodySingleChoice, error) { + var body ResponseBodySingleChoice + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromResponseBodySingleChoice overwrites any union data inside the ResponseBody as the provided ResponseBodySingleChoice +func (t *ResponseBody) FromResponseBodySingleChoice(v ResponseBodySingleChoice) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeResponseBodySingleChoice performs a merge with any union data inside the ResponseBody, using the provided ResponseBodySingleChoice +func (t *ResponseBody) MergeResponseBodySingleChoice(v ResponseBodySingleChoice) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsResponseBodyMultipleChoice returns the union data inside the ResponseBody as a ResponseBodyMultipleChoice +func (t ResponseBody) AsResponseBodyMultipleChoice() (ResponseBodyMultipleChoice, error) { + var body ResponseBodyMultipleChoice + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromResponseBodyMultipleChoice overwrites any union data inside the ResponseBody as the provided ResponseBodyMultipleChoice +func (t *ResponseBody) FromResponseBodyMultipleChoice(v ResponseBodyMultipleChoice) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeResponseBodyMultipleChoice performs a merge with any union data inside the ResponseBody, using the provided ResponseBodyMultipleChoice +func (t *ResponseBody) MergeResponseBodyMultipleChoice(v ResponseBodyMultipleChoice) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsResponseBodyScale returns the union data inside the ResponseBody as a ResponseBodyScale +func (t ResponseBody) AsResponseBodyScale() (ResponseBodyScale, error) { + var body ResponseBodyScale + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromResponseBodyScale overwrites any union data inside the ResponseBody as the provided ResponseBodyScale +func (t *ResponseBody) FromResponseBodyScale(v ResponseBodyScale) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeResponseBodyScale performs a merge with any union data inside the ResponseBody, using the provided ResponseBodyScale +func (t *ResponseBody) MergeResponseBodyScale(v ResponseBodyScale) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +func (t ResponseBody) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *ResponseBody) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} diff --git a/tools.go b/tools.go index a73f8352..005b37f2 100644 --- a/tools.go +++ b/tools.go @@ -6,4 +6,5 @@ package main import ( _ "github.com/golang/mock/mockgen" _ "github.com/google/wire/cmd/wire" + _ "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen" ) diff --git a/traq/traq.go b/traq/traq.go new file mode 100644 index 00000000..6f08b8ac --- /dev/null +++ b/traq/traq.go @@ -0,0 +1,45 @@ +package traq + +import ( + "context" + + traq "github.com/traPtitech/go-traq" +) + +const TOKEN = "/* your token */" + +type TraqAPIClient struct { + client *traq.APIClient + auth context.Context +} + +func NewTraqAPIClient() *TraqAPIClient { + return &TraqAPIClient{ + client: traq.NewAPIClient(traq.NewConfiguration()), + auth: context.WithValue(context.Background(), traq.ContextAccessToken, TOKEN), + } +} + +func (t *TraqAPIClient) GetGroupMembers(ctx context.Context, groupID string) ([]traq.UserGroupMember, error) { + v, _, err := t.client.GroupApi.GetUserGroupMembers(ctx, groupID).Execute() + if err != nil { + return nil, err + } + return v, nil +} + +func (t *TraqAPIClient) GetUserTraqID(ctx context.Context, userUUID string) (string, error) { + v, _, err := t.client.UserApi.GetUser(ctx, userUUID).Execute() + if err != nil { + return "", err + } + return v.Name, nil +} + +func (t *TraqAPIClient) GetGroupName(ctx context.Context, groupID string) (string, error) { + v, _, err := t.client.GroupApi.GetUserGroup(ctx, groupID).Execute() + if err != nil { + return "", err + } + return v.Name, nil +}