Skip to content

Commit

Permalink
Merge branch 'fix/openapi' into fix/openapi-duplicate_response
Browse files Browse the repository at this point in the history
  • Loading branch information
Eraxyso authored Dec 19, 2024
2 parents 84a33d2 + 95ebb76 commit 3eb25c3
Show file tree
Hide file tree
Showing 46 changed files with 1,063 additions and 9,577 deletions.
36 changes: 22 additions & 14 deletions controller/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package controller
import (
"strconv"

"github.com/google/uuid"
"github.com/labstack/echo/v4"
"github.com/traPtitech/anke-to/model"
"github.com/traPtitech/anke-to/openapi"
Expand Down Expand Up @@ -64,10 +65,10 @@ func convertResSharedTo(resSharedTo string) openapi.ResShareType {

}

func createUsersAndGroups(users []string, groups []string) openapi.UsersAndGroups {
func createUsersAndGroups(users []string, groups uuid.UUIDs) openapi.UsersAndGroups {
res := openapi.UsersAndGroups{
Users: users,
Groups: groups,
Groups: groups.Strings(),
}
return res
}
Expand Down Expand Up @@ -147,22 +148,22 @@ func convertRespondents(respondents []model.Respondents) []string {
return res
}

func questionnaire2QuestionnaireDetail(questionnaires model.Questionnaires, adminUsers []string, adminGroups []string, targetUsers []string, targetGroups []string, respondents []string) openapi.QuestionnaireDetail {
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,
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,
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 Expand Up @@ -264,14 +265,21 @@ func respondentDetail2Response(ctx echo.Context, respondentDetail model.Responde
oResponseBodies = append(oResponseBodies, oResponseBody)
}

isAnonymous, err := model.NewQuestionnaire().GetResponseIsAnonymousByQuestionnaireID(ctx.Request().Context(), respondentDetail.QuestionnaireID)
if err != nil {
ctx.Logger().Errorf("failed to get response is anonymous: %+v", err)
return openapi.Response{}, err
}

res := openapi.Response{
Body: oResponseBodies,
IsDraft: respondentDetail.SubmittedAt.Valid,
ModifiedAt: respondentDetail.ModifiedAt,
QuestionnaireId: respondentDetail.QuestionnaireID,
Respondent: respondentDetail.TraqID,
Respondent: &respondentDetail.TraqID,
ResponseId: respondentDetail.ResponseID,
SubmittedAt: respondentDetail.SubmittedAt.Time,
IsAnonymous: &isAnonymous,
}

return res, nil
Expand Down
224 changes: 189 additions & 35 deletions controller/questionnaire.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package controller

import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
Expand Down Expand Up @@ -32,8 +33,28 @@ type Questionnaire struct {
Response
}

func NewQuestionnaire() *Questionnaire {
return &Questionnaire{}
func NewQuestionnaire(
questionnaire model.IQuestionnaire,
target model.ITarget,
administrator model.IAdministrator,
question model.IQuestion,
option model.IOption,
scaleLabel model.IScaleLabel,
validation model.IValidation,
transaction model.ITransaction,
webhook traq.IWebhook,
) *Questionnaire {
return &Questionnaire{
IQuestionnaire: questionnaire,
ITarget: target,
IAdministrator: administrator,
IQuestion: question,
IOption: option,
IScaleLabel: scaleLabel,
IValidation: validation,
ITransaction: transaction,
IWebhook: webhook,
}
}

const MaxTitleLength = 50
Expand Down Expand Up @@ -111,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.IsDuplicateAnswerAllowed)
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 @@ -156,6 +177,25 @@ func (q Questionnaire) PostQuestionnaire(c echo.Context, userID string, params o
c.Logger().Errorf("failed to insert administrator groups: %+v", err)
return err
}
for questoinNum, question := range params.Questions {
b, err := question.MarshalJSON()
if err != nil {
c.Logger().Errorf("failed to marshal new question: %+v", err)
return err
}
var questionParsed map[string]interface{}
err = json.Unmarshal([]byte(b), &questionParsed)
if err != nil {
c.Logger().Errorf("failed to unmarshal new question: %+v", err)
return err
}
questionType := questionParsed["question_type"].(string)
_, err = q.InsertQuestion(ctx, questionnaireID, 1, questoinNum+1, questionType, question.Body, question.IsRequired)
if err != nil {
c.Logger().Errorf("failed to insert question: %+v", err)
return err
}
}

message := createQuestionnaireMessage(
questionnaireID,
Expand All @@ -171,6 +211,12 @@ func (q Questionnaire) PostQuestionnaire(c echo.Context, userID string, params o
return err
}

Jq.PushReminder(questionnaireID, params.ResponseDueDateTime)
if err != nil {
c.Logger().Errorf("failed to push reminder: %+v", err)
return err
}

return nil
})
if err != nil {
Expand Down Expand Up @@ -296,13 +342,24 @@ func (q Questionnaire) GetQuestionnaire(ctx echo.Context, questionnaireID int) (
}

func (q Questionnaire) EditQuestionnaire(c echo.Context, questionnaireID int, params openapi.EditQuestionnaireJSONRequestBody) error {
// unable to change the questionnaire from anoymous to non-anonymous
isAnonymous, err := q.GetResponseIsAnonymousByQuestionnaireID(c.Request().Context(), questionnaireID)
if err != nil {
c.Logger().Errorf("failed to get anonymous info: %+v", err)
return echo.NewHTTPError(http.StatusInternalServerError, "failed to get anonymous info")
}
if isAnonymous && !params.IsAnonymous {
c.Logger().Info("unable to change the questionnaire from anoymous to non-anonymous")
return echo.NewHTTPError(http.StatusBadRequest, "unable to change the questionnaire from anoymous to non-anonymous")
}

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, params.IsPublished, params.IsDuplicateAnswerAllowed)
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, params.IsDuplicateAnswerAllowed)
if err != nil && !errors.Is(err, model.ErrNoRecordUpdated) {
c.Logger().Errorf("failed to update questionnaire: %+v", err)
return err
Expand Down Expand Up @@ -357,6 +414,44 @@ func (q Questionnaire) EditQuestionnaire(c echo.Context, questionnaireID int, pa
c.Logger().Errorf("failed to insert administrator groups: %+v", err)
return err
}
for questoinNum, question := range params.Questions {
b, err := question.MarshalJSON()
if err != nil {
c.Logger().Errorf("failed to marshal new question: %+v", err)
return err
}
var questionParsed map[string]interface{}
err = json.Unmarshal([]byte(b), &questionParsed)
if err != nil {
c.Logger().Errorf("failed to unmarshal new question: %+v", err)
return err
}
questionType := questionParsed["question_type"].(string)
if question.QuestionId == nil {
_, err = q.InsertQuestion(ctx, questionnaireID, 1, questoinNum+1, questionType, question.Body, question.IsRequired)
if err != nil {
c.Logger().Errorf("failed to insert question: %+v", err)
return err
}
} else {
err = q.UpdateQuestion(ctx, questionnaireID, 1, questoinNum+1, questionType, question.Body, question.IsRequired, *question.QuestionId)
if err != nil {
c.Logger().Errorf("failed to update question: %+v", err)
return err
}
}
}

err = Jq.DeleteReminder(questionnaireID)
if err != nil {
c.Logger().Errorf("failed to delete reminder: %+v", err)
return err
}
err = Jq.PushReminder(questionnaireID, params.ResponseDueDateTime)
if err != nil {
c.Logger().Errorf("failed to push reminder: %+v", err)
return err
}

return nil
})
Expand Down Expand Up @@ -483,6 +578,25 @@ func (q Questionnaire) DeleteQuestionnaire(c echo.Context, questionnaireID int)
return err
}

questions, err := q.GetQuestions(c.Request().Context(), questionnaireID)
if err != nil {
c.Logger().Errorf("failed to get questions: %+v", err)
return err
}
for _, question := range questions {
err = q.DeleteQuestion(c.Request().Context(), question.ID)
if err != nil {
c.Logger().Errorf("failed to delete administrators: %+v", err)
return err
}
}

err = Jq.DeleteReminder(questionnaireID)
if err != nil {
c.Logger().Errorf("failed to delete reminder: %+v", err)
return err
}

return nil
})
if err != nil {
Expand All @@ -498,12 +612,48 @@ func (q Questionnaire) DeleteQuestionnaire(c echo.Context, questionnaireID int)
}

func (q Questionnaire) GetQuestionnaireMyRemindStatus(c echo.Context, questionnaireID int) (bool, error) {
// todo: check remind status
return false, nil
status, err := Jq.CheckRemindStatus(questionnaireID)
if err != nil {
c.Logger().Errorf("failed to check remind status: %+v", err)
return false, echo.NewHTTPError(http.StatusInternalServerError, "failed to check remind status")
}

return status, nil
}

func (q Questionnaire) EditQuestionnaireMyRemindStatus(c echo.Context, questionnaireID int) error {
// todo: edit remind status
func (q Questionnaire) EditQuestionnaireMyRemindStatus(c echo.Context, questionnaireID int, isRemindEnabled bool) error {
if isRemindEnabled {
status, err := Jq.CheckRemindStatus(questionnaireID)
if err != nil {
c.Logger().Errorf("failed to check remind status: %+v", err)
return echo.NewHTTPError(http.StatusInternalServerError, "failed to check remind status")
}
if status {
return nil
}

questionnaire, _, _, _, _, _, err := q.GetQuestionnaireInfo(c.Request().Context(), questionnaireID)
if err != nil {
if errors.Is(err, model.ErrRecordNotFound) {
c.Logger().Info("questionnaire not found")
return echo.NewHTTPError(http.StatusNotFound, "questionnaire not found")
}
c.Logger().Errorf("failed to get questionnaire: %+v", err)
return echo.NewHTTPError(http.StatusInternalServerError, "failed to get questionnaire")
}

err = Jq.PushReminder(questionnaireID, &questionnaire.ResTimeLimit.Time)
if err != nil {
c.Logger().Errorf("failed to push reminder: %+v", err)
return echo.NewHTTPError(http.StatusInternalServerError, "failed to push reminder")
}
} else {
err := Jq.DeleteReminder(questionnaireID)
if err != nil {
c.Logger().Errorf("failed to delete reminder: %+v", err)
return echo.NewHTTPError(http.StatusInternalServerError, "failed to delete reminder")
}
}
return nil
}

Expand Down Expand Up @@ -656,13 +806,16 @@ func (q Questionnaire) PostQuestionnaireResponse(c echo.Context, questionnaireID
}
}

isAnonymous, err := q.GetResponseIsAnonymousByQuestionnaireID(c.Request().Context(), questionnaireID)

res = openapi.Response{
QuestionnaireId: questionnaireID,
ResponseId: resopnseID,
Respondent: userID,
Respondent: &userID,
SubmittedAt: submittedAt,
ModifiedAt: modifiedAt,
IsDraft: params.IsDraft,
IsAnonymous: &isAnonymous,
Body: params.Body,
}

Expand Down Expand Up @@ -706,30 +859,31 @@ https://anke-to.trap.jp/responses/new/%d`,
)
}

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 {
if errors.Is(echo.ErrNotFound, err) {
return openapi.Result{}, err
}
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)
}
func createReminderMessage(questionnaireID int, title string, description string, administrators []string, resTimeLimit time.Time, targets []string, leftTimeText string) string {
resTimeLimitText := resTimeLimit.Local().Format("2006/01/02 15:04")
targetsMentionText := "@" + strings.Join(targets, " @")

return res, nil
return fmt.Sprintf(
`### アンケート『[%s](https://anke-to.trap.jp/questionnaires/%d)』の回答期限が迫っています!
==残り%sです!==
#### 管理者
%s
#### 説明
%s
#### 回答期限
%s
#### 対象者
%s
#### 回答リンク
https://anke-to.trap.jp/responses/new/%d
`,
title,
questionnaireID,
leftTimeText,
strings.Join(administrators, ","),
description,
resTimeLimitText,
targetsMentionText,
questionnaireID,
)
}
Loading

0 comments on commit 3eb25c3

Please sign in to comment.