Skip to content

Commit

Permalink
Merge pull request #1278 from traPtitech/fix/openapi-duplicate_response
Browse files Browse the repository at this point in the history
feat: add support for restricting duplicate responses
  • Loading branch information
Eraxyso authored Jan 6, 2025
2 parents 95ebb76 + 3eb25c3 commit 1d982df
Show file tree
Hide file tree
Showing 16 changed files with 691 additions and 300 deletions.
42 changes: 21 additions & 21 deletions controller/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ import (

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,
AllResponded: allResponded,
CreatedAt: questionnaireInfo.CreatedAt,
Description: questionnaireInfo.Description,
HasMyDraft: hasMyDraft,
HasMyResponse: hasMyResponse,
IsDuplicateAnswerAllowed: questionnaireInfo.IsDuplicateAnswerAllowed,
// IsAnonymous: questionnaireInfo.IsAnonymous,
// IsPublished: questionnaireInfo.IsPublished,
IsPublished: questionnaireInfo.IsPublished,
IsTargetingMe: questionnaireInfo.IsTargeted,
ModifiedAt: questionnaireInfo.ModifiedAt,
QuestionnaireId: questionnaireInfo.ID,
Expand Down Expand Up @@ -150,20 +150,20 @@ func convertRespondents(respondents []model.Respondents) []string {

func questionnaire2QuestionnaireDetail(questionnaires model.Questionnaires, adminUsers []string, adminGroups []uuid.UUID, targetUsers []string, targetGroups []uuid.UUID, 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,
Admins: createUsersAndGroups(adminUsers, adminGroups),
CreatedAt: questionnaires.CreatedAt,
Description: questionnaires.Description,
IsDuplicateAnswerAllowed: questionnaires.IsDuplicateAnswerAllowed,
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
}
Expand Down
4 changes: 2 additions & 2 deletions controller/questionnaire.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ func (q Questionnaire) PostQuestionnaire(c echo.Context, userID string, params o
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), params.IsPublished, params.IsAnonymous)
questionnaireID, err := q.InsertQuestionnaire(ctx, params.Title, params.Description, responseDueDateTime, convertResponseViewableBy(params.ResponseViewableBy), params.IsPublished, params.IsAnonymous, params.IsDuplicateAnswerAllowed)
if err != nil {
c.Logger().Errorf("failed to insert questionnaire: %+v", err)
return err
Expand Down Expand Up @@ -359,7 +359,7 @@ func (q Questionnaire) EditQuestionnaire(c echo.Context, questionnaireID int, pa
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, params.IsPublished, params.IsAnonymous)
err := q.UpdateQuestionnaire(ctx, params.Title, params.Description, responseDueDateTime, string(params.ResponseViewableBy), questionnaireID, params.IsPublished, params.IsAnonymous, params.IsDuplicateAnswerAllowed)
if err != nil && !errors.Is(err, model.ErrNoRecordUpdated) {
c.Logger().Errorf("failed to update questionnaire: %+v", err)
return err
Expand Down
10 changes: 5 additions & 5 deletions docs/swagger/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ components:
- $ref: "#/components/schemas/QuestionnaireResponseDueDateTime"
- $ref: "#/components/schemas/QuestionnaireResponseViewableBy"
- $ref: "#/components/schemas/QuestionnaireIsAnonymous"
- $ref: "#/components/schemas/QuestionnaireIsAllowingMultipleResponses"
- $ref: "#/components/schemas/QuestionnaireIsDuplicateAnswerAllowed"
- $ref: "#/components/schemas/QuestionnaireIsPublished"
- $ref: "#/components/schemas/QuestionnaireTargetsAndAdmins"
NewQuestionnaire:
Expand Down Expand Up @@ -496,7 +496,7 @@ components:
- $ref: "#/components/schemas/QuestionnaireResponseDueDateTime"
- $ref: "#/components/schemas/QuestionnaireResponseViewableBy"
- $ref: "#/components/schemas/QuestionnaireIsAnonymous"
- $ref: "#/components/schemas/QuestionnaireIsAllowingMultipleResponses"
- $ref: "#/components/schemas/QuestionnaireIsDuplicateAnswerAllowed"
- $ref: "#/components/schemas/QuestionnaireIsPublished"
- $ref: "#/components/schemas/QuestionnaireIsTargetingMe"
- $ref: "#/components/schemas/QuestionnaireCreatedAt"
Expand Down Expand Up @@ -585,16 +585,16 @@ components:
匿名回答かどうか
required:
- is_anonymous
QuestionnaireIsAllowingMultipleResponses:
QuestionnaireIsDuplicateAnswerAllowed:
type: object
properties:
is_allowing_multiple_responses:
is_duplicate_answer_allowed:
type: boolean
example: true
description: |
一人が複数回回答できるかどうか
required:
- is_allowing_multiple_responses
- is_duplicate_answer_allowed
QuestionnaireIsPublished:
type: object
properties:
Expand Down
2 changes: 2 additions & 0 deletions model/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ var (
ErrInvalidTx = errors.New("invalid tx")
// ErrDeadlineExceeded deadline exceeded
ErrDeadlineExceeded = errors.New("deadline exceeded")
// ErrDuplicatedAnswered
ErrDuplicatedAnswered = errors.New("duplicated answered is not allowed")
)
4 changes: 2 additions & 2 deletions model/questionnaires.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import (

// IQuestionnaire QuestionnaireのRepository
type IQuestionnaire interface {
InsertQuestionnaire(ctx context.Context, title string, description string, resTimeLimit null.Time, resSharedTo string, isPublished bool, isAnonymous bool) (int, error)
UpdateQuestionnaire(ctx context.Context, title string, description string, resTimeLimit null.Time, resSharedTo string, questionnaireID int, isPublished bool, isAnonymous bool) error
InsertQuestionnaire(ctx context.Context, title string, description string, resTimeLimit null.Time, resSharedTo string, isPublished bool, isAnonymous bool, IsDuplicateAnswerAllowed bool) (int, error)
UpdateQuestionnaire(ctx context.Context, title string, description string, resTimeLimit null.Time, resSharedTo string, questionnaireID int, isPublished bool, isAnonymous bool, IsDuplicateAnswerAllowed bool) error
DeleteQuestionnaire(ctx context.Context, questionnaireID 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)
Expand Down
85 changes: 45 additions & 40 deletions model/questionnaires_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,22 @@ func NewQuestionnaire() *Questionnaire {

// Questionnaires questionnairesテーブルの構造体
type Questionnaires struct {
ID int `json:"questionnaireID" gorm:"type:int(11) AUTO_INCREMENT;not null;primaryKey"`
Title string `json:"title" gorm:"type:char(50);size:50;not null"`
Description string `json:"description" gorm:"type:text;not null"`
ResTimeLimit null.Time `json:"res_time_limit,omitempty" gorm:"type:TIMESTAMP NULL;default:NULL;"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"type:TIMESTAMP NULL;default:NULL;"`
ResSharedTo string `json:"res_shared_to" gorm:"type:char(30);size:30;not null;default:administrators"`
IsAnonymous bool `json:"is_anonymous" gorm:"type:boolean;not null;default:false"`
CreatedAt time.Time `json:"created_at" gorm:"type:timestamp;not null;default:CURRENT_TIMESTAMP"`
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"`
IsPublished bool `json:"is_published" gorm:"type:boolean;default:false"`
ID int `json:"questionnaireID" gorm:"type:int(11) AUTO_INCREMENT;not null;primaryKey"`
Title string `json:"title" gorm:"type:char(50);size:50;not null"`
Description string `json:"description" gorm:"type:text;not null"`
ResTimeLimit null.Time `json:"res_time_limit,omitempty" gorm:"type:TIMESTAMP NULL;default:NULL;"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"type:TIMESTAMP NULL;default:NULL;"`
ResSharedTo string `json:"res_shared_to" gorm:"type:char(30);size:30;not null;default:administrators"`
CreatedAt time.Time `json:"created_at" gorm:"type:timestamp;not null;default:CURRENT_TIMESTAMP"`
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"`
IsPublished bool `json:"is_published" gorm:"type:boolean;default:false"`
IsAnonymous bool `json:"is_anonymous" gorm:"type:boolean;not null;default:false"`
IsDuplicateAnswerAllowed bool `json:"is_duplicate_answer_allowed" gorm:"type:tinyint(4);size:4;not null;default:0"`
}

// BeforeCreate Update時に自動でmodified_atを現在時刻に
Expand Down Expand Up @@ -83,7 +84,7 @@ type ResponseReadPrivilegeInfo struct {
}

// InsertQuestionnaire アンケートの追加
func (*Questionnaire) InsertQuestionnaire(ctx context.Context, title string, description string, resTimeLimit null.Time, resSharedTo string, isPublished bool, isAnonymous bool) (int, error) {
func (*Questionnaire) InsertQuestionnaire(ctx context.Context, title string, description string, resTimeLimit null.Time, resSharedTo string, isPublished bool, isAnonymous bool, isDuplicateAnswerAllowed bool) (int, error) {
db, err := getTx(ctx)
if err != nil {
return 0, fmt.Errorf("failed to get tx: %w", err)
Expand All @@ -92,20 +93,22 @@ func (*Questionnaire) InsertQuestionnaire(ctx context.Context, title string, des
var questionnaire Questionnaires
if !resTimeLimit.Valid {
questionnaire = Questionnaires{
Title: title,
Description: description,
ResSharedTo: resSharedTo,
IsPublished: isPublished,
IsAnonymous: isAnonymous,
Title: title,
Description: description,
ResSharedTo: resSharedTo,
IsPublished: isPublished,
IsAnonymous: isAnonymous,
IsDuplicateAnswerAllowed: isDuplicateAnswerAllowed,
}
} else {
questionnaire = Questionnaires{
Title: title,
Description: description,
ResTimeLimit: resTimeLimit,
ResSharedTo: resSharedTo,
IsPublished: isPublished,
IsAnonymous: isAnonymous,
Title: title,
Description: description,
ResTimeLimit: resTimeLimit,
ResSharedTo: resSharedTo,
IsPublished: isPublished,
IsAnonymous: isAnonymous,
IsDuplicateAnswerAllowed: isDuplicateAnswerAllowed,
}
}

Expand All @@ -118,7 +121,7 @@ func (*Questionnaire) InsertQuestionnaire(ctx context.Context, title string, des
}

// UpdateQuestionnaire アンケートの更新
func (*Questionnaire) UpdateQuestionnaire(ctx context.Context, title string, description string, resTimeLimit null.Time, resSharedTo string, questionnaireID int, isPublished bool, isAnonymous bool) error {
func (*Questionnaire) UpdateQuestionnaire(ctx context.Context, title string, description string, resTimeLimit null.Time, resSharedTo string, questionnaireID int, isPublished bool, isAnonymous bool, isDuplicateAnswerAllowed bool) error {
db, err := getTx(ctx)
if err != nil {
return fmt.Errorf("failed to get tx: %w", err)
Expand All @@ -127,21 +130,23 @@ func (*Questionnaire) UpdateQuestionnaire(ctx context.Context, title string, des
var questionnaire interface{}
if resTimeLimit.Valid {
questionnaire = Questionnaires{
Title: title,
Description: description,
ResTimeLimit: resTimeLimit,
ResSharedTo: resSharedTo,
IsPublished: isPublished,
IsAnonymous: isAnonymous,
Title: title,
Description: description,
ResTimeLimit: resTimeLimit,
ResSharedTo: resSharedTo,
IsPublished: isPublished,
IsAnonymous: isAnonymous,
IsDuplicateAnswerAllowed: isDuplicateAnswerAllowed,
}
} else {
questionnaire = map[string]interface{}{
"title": title,
"description": description,
"res_time_limit": gorm.Expr("NULL"),
"res_shared_to": resSharedTo,
"is_published": isPublished,
"is_anonymous": isAnonymous,
"title": title,
"description": description,
"res_time_limit": gorm.Expr("NULL"),
"res_shared_to": resSharedTo,
"is_published": isPublished,
"is_anonymous": isAnonymous,
"is_duplicate_answer_allowed": isDuplicateAnswerAllowed,
}
}

Expand Down
Loading

0 comments on commit 1d982df

Please sign in to comment.