From a999117361ee1bee2e1e197cab348d5dd43b94b8 Mon Sep 17 00:00:00 2001 From: Nagata Kuren Date: Fri, 5 Jun 2026 12:01:56 +0900 Subject: [PATCH 01/14] =?UTF-8?q?userid=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/openapi/academic/openapi.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/api/openapi/academic/openapi.yaml b/api/openapi/academic/openapi.yaml index f0ad80b..d6262f6 100644 --- a/api/openapi/academic/openapi.yaml +++ b/api/openapi/academic/openapi.yaml @@ -938,6 +938,13 @@ paths: items: $ref: '#/components/schemas/DottoFoundationV1.CulturalSubjectCategory' explode: false + - name: userId + in: query + required: false + description: ユーザーID; 指定した場合はユーザーのコース・学年に近い順にソートする + schema: + type: string + explode: false responses: '200': description: 科目のリスト From 493952b39e740881e9a037b47d1b14684f9e4985 Mon Sep 17 00:00:00 2001 From: Nagata Kuren Date: Fri, 5 Jun 2026 12:02:42 +0900 Subject: [PATCH 02/14] =?UTF-8?q?oapi-codegen=20=E3=81=A7=E5=86=8D?= =?UTF-8?q?=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gen/academic/api.gen.go | 975 +++++++++++++++++++++++++++------------- 1 file changed, 668 insertions(+), 307 deletions(-) diff --git a/gen/academic/api.gen.go b/gen/academic/api.gen.go index bc6cb3c..0f92c1d 100644 --- a/gen/academic/api.gen.go +++ b/gen/academic/api.gen.go @@ -1,9 +1,10 @@ // Package api provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.7.0 DO NOT EDIT. package api import ( + "bytes" "context" "encoding/json" "fmt" @@ -12,7 +13,6 @@ import ( "github.com/gin-gonic/gin" "github.com/oapi-codegen/runtime" - strictgin "github.com/oapi-codegen/runtime/strictmiddleware/gin" openapi_types "github.com/oapi-codegen/runtime/types" ) @@ -32,6 +32,38 @@ const ( L DottoFoundationV1Class = "L" ) +// Valid indicates whether the value is a known member of the DottoFoundationV1Class enum. +func (e DottoFoundationV1Class) Valid() bool { + switch e { + case A: + return true + case B: + return true + case C: + return true + case D: + return true + case E: + return true + case F: + return true + case G: + return true + case H: + return true + case I: + return true + case J: + return true + case K: + return true + case L: + return true + default: + return false + } +} + // Defines values for DottoFoundationV1Course. const ( AdvancedICT DottoFoundationV1Course = "AdvancedICT" @@ -41,6 +73,24 @@ const ( IntelligentSystem DottoFoundationV1Course = "IntelligentSystem" ) +// Valid indicates whether the value is a known member of the DottoFoundationV1Course enum. +func (e DottoFoundationV1Course) Valid() bool { + switch e { + case AdvancedICT: + return true + case ComplexSystem: + return true + case InformationDesign: + return true + case InformationSystem: + return true + case IntelligentSystem: + return true + default: + return false + } +} + // Defines values for DottoFoundationV1CourseSemester. const ( AllYear DottoFoundationV1CourseSemester = "AllYear" @@ -54,6 +104,32 @@ const ( WinterIntensive DottoFoundationV1CourseSemester = "WinterIntensive" ) +// Valid indicates whether the value is a known member of the DottoFoundationV1CourseSemester enum. +func (e DottoFoundationV1CourseSemester) Valid() bool { + switch e { + case AllYear: + return true + case H1: + return true + case H2: + return true + case Q1: + return true + case Q2: + return true + case Q3: + return true + case Q4: + return true + case SummerIntensive: + return true + case WinterIntensive: + return true + default: + return false + } +} + // Defines values for DottoFoundationV1CulturalSubjectCategory. const ( Communication DottoFoundationV1CulturalSubjectCategory = "Communication" @@ -63,6 +139,24 @@ const ( Society DottoFoundationV1CulturalSubjectCategory = "Society" ) +// Valid indicates whether the value is a known member of the DottoFoundationV1CulturalSubjectCategory enum. +func (e DottoFoundationV1CulturalSubjectCategory) Valid() bool { + switch e { + case Communication: + return true + case Health: + return true + case Human: + return true + case Science: + return true + case Society: + return true + default: + return false + } +} + // Defines values for DottoFoundationV1DayOfWeek. const ( Friday DottoFoundationV1DayOfWeek = "Friday" @@ -74,6 +168,28 @@ const ( Wednesday DottoFoundationV1DayOfWeek = "Wednesday" ) +// Valid indicates whether the value is a known member of the DottoFoundationV1DayOfWeek enum. +func (e DottoFoundationV1DayOfWeek) Valid() bool { + switch e { + case Friday: + return true + case Monday: + return true + case Saturday: + return true + case Sunday: + return true + case Thursday: + return true + case Tuesday: + return true + case Wednesday: + return true + default: + return false + } +} + // Defines values for DottoFoundationV1Floor. const ( Floor1 DottoFoundationV1Floor = "Floor1" @@ -86,6 +202,30 @@ const ( Virtual DottoFoundationV1Floor = "Virtual" ) +// Valid indicates whether the value is a known member of the DottoFoundationV1Floor enum. +func (e DottoFoundationV1Floor) Valid() bool { + switch e { + case Floor1: + return true + case Floor2: + return true + case Floor3: + return true + case Floor4: + return true + case Floor5: + return true + case Floor6: + return true + case Floor7: + return true + case Virtual: + return true + default: + return false + } +} + // Defines values for DottoFoundationV1Grade. const ( B1 DottoFoundationV1Grade = "B1" @@ -99,6 +239,32 @@ const ( M2 DottoFoundationV1Grade = "M2" ) +// Valid indicates whether the value is a known member of the DottoFoundationV1Grade enum. +func (e DottoFoundationV1Grade) Valid() bool { + switch e { + case B1: + return true + case B2: + return true + case B3: + return true + case B4: + return true + case D1: + return true + case D2: + return true + case D3: + return true + case M1: + return true + case M2: + return true + default: + return false + } +} + // Defines values for DottoFoundationV1Period. const ( Period1 DottoFoundationV1Period = "Period1" @@ -109,6 +275,26 @@ const ( Period6 DottoFoundationV1Period = "Period6" ) +// Valid indicates whether the value is a known member of the DottoFoundationV1Period enum. +func (e DottoFoundationV1Period) Valid() bool { + switch e { + case Period1: + return true + case Period2: + return true + case Period3: + return true + case Period4: + return true + case Period5: + return true + case Period6: + return true + default: + return false + } +} + // Defines values for DottoFoundationV1PersonalCalendarItemStatus. const ( Cancelled DottoFoundationV1PersonalCalendarItemStatus = "Cancelled" @@ -117,6 +303,22 @@ const ( RoomChanged DottoFoundationV1PersonalCalendarItemStatus = "RoomChanged" ) +// Valid indicates whether the value is a known member of the DottoFoundationV1PersonalCalendarItemStatus enum. +func (e DottoFoundationV1PersonalCalendarItemStatus) Valid() bool { + switch e { + case Cancelled: + return true + case Makeup: + return true + case Normal: + return true + case RoomChanged: + return true + default: + return false + } +} + // Defines values for DottoFoundationV1SubjectClassification. const ( Cultural DottoFoundationV1SubjectClassification = "Cultural" @@ -124,6 +326,20 @@ const ( Specialized DottoFoundationV1SubjectClassification = "Specialized" ) +// Valid indicates whether the value is a known member of the DottoFoundationV1SubjectClassification enum. +func (e DottoFoundationV1SubjectClassification) Valid() bool { + switch e { + case Cultural: + return true + case ResearchInstruction: + return true + case Specialized: + return true + default: + return false + } +} + // Defines values for DottoFoundationV1SubjectRequirementType. const ( Optional DottoFoundationV1SubjectRequirementType = "Optional" @@ -131,6 +347,20 @@ const ( Required DottoFoundationV1SubjectRequirementType = "Required" ) +// Valid indicates whether the value is a known member of the DottoFoundationV1SubjectRequirementType enum. +func (e DottoFoundationV1SubjectRequirementType) Valid() bool { + switch e { + case Optional: + return true + case OptionalRequired: + return true + case Required: + return true + default: + return false + } +} + // CancelledClass 休講 type CancelledClass struct { Comment string `json:"comment"` @@ -587,6 +817,9 @@ type SubjectsV1ListParams struct { // CulturalSubjectCategories 教養科目カテゴリ CulturalSubjectCategories *[]DottoFoundationV1CulturalSubjectCategory `form:"culturalSubjectCategories,omitempty" json:"culturalSubjectCategories,omitempty"` + + // UserId ユーザーID; 指定した場合はユーザーのコース・学年に近い順にソートする + UserId *string `form:"userId,omitempty" json:"userId,omitempty"` } // TimetableItemsV1ListParams defines parameters for TimetableItemsV1List. @@ -756,13 +989,14 @@ type MiddlewareFunc func(c *gin.Context) func (siw *ServerInterfaceWrapper) CancelledClassesV1List(c *gin.Context) { var err error + _ = err // Parameter object where we will unmarshal all parameters from the context var params CancelledClassesV1ListParams // ------------- Optional query parameter "subjectIds" ------------- - err = runtime.BindQueryParameter("form", false, false, "subjectIds", c.Request.URL.Query(), ¶ms.SubjectIds) + err = runtime.BindQueryParameterWithOptions("form", false, false, "subjectIds", c.Request.URL.Query(), ¶ms.SubjectIds, runtime.BindQueryParameterOptions{Type: "array", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter subjectIds: %w", err), http.StatusBadRequest) return @@ -770,7 +1004,7 @@ func (siw *ServerInterfaceWrapper) CancelledClassesV1List(c *gin.Context) { // ------------- Optional query parameter "from" ------------- - err = runtime.BindQueryParameter("form", true, false, "from", c.Request.URL.Query(), ¶ms.From) + err = runtime.BindQueryParameterWithOptions("form", true, false, "from", c.Request.URL.Query(), ¶ms.From, runtime.BindQueryParameterOptions{Type: "string", Format: "date"}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter from: %w", err), http.StatusBadRequest) return @@ -778,7 +1012,7 @@ func (siw *ServerInterfaceWrapper) CancelledClassesV1List(c *gin.Context) { // ------------- Optional query parameter "until" ------------- - err = runtime.BindQueryParameter("form", true, false, "until", c.Request.URL.Query(), ¶ms.Until) + err = runtime.BindQueryParameterWithOptions("form", true, false, "until", c.Request.URL.Query(), ¶ms.Until, runtime.BindQueryParameterOptions{Type: "string", Format: "date"}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter until: %w", err), http.StatusBadRequest) return @@ -811,11 +1045,12 @@ func (siw *ServerInterfaceWrapper) CancelledClassesV1Create(c *gin.Context) { func (siw *ServerInterfaceWrapper) CancelledClassesV1Delete(c *gin.Context) { var err error + _ = err // ------------- Path parameter "id" ------------- var id string - err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest) return @@ -835,20 +1070,14 @@ func (siw *ServerInterfaceWrapper) CancelledClassesV1Delete(c *gin.Context) { func (siw *ServerInterfaceWrapper) CourseRegistrationsV1List(c *gin.Context) { var err error + _ = err // Parameter object where we will unmarshal all parameters from the context var params CourseRegistrationsV1ListParams // ------------- Required query parameter "userId" ------------- - if paramValue := c.Query("userId"); paramValue != "" { - - } else { - siw.ErrorHandler(c, fmt.Errorf("Query argument userId is required, but not found"), http.StatusBadRequest) - return - } - - err = runtime.BindQueryParameter("form", false, true, "userId", c.Request.URL.Query(), ¶ms.UserId) + err = runtime.BindQueryParameterWithOptions("form", false, true, "userId", c.Request.URL.Query(), ¶ms.UserId, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter userId: %w", err), http.StatusBadRequest) return @@ -856,7 +1085,7 @@ func (siw *ServerInterfaceWrapper) CourseRegistrationsV1List(c *gin.Context) { // ------------- Optional query parameter "year" ------------- - err = runtime.BindQueryParameter("form", false, false, "year", c.Request.URL.Query(), ¶ms.Year) + err = runtime.BindQueryParameterWithOptions("form", false, false, "year", c.Request.URL.Query(), ¶ms.Year, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter year: %w", err), http.StatusBadRequest) return @@ -864,14 +1093,7 @@ func (siw *ServerInterfaceWrapper) CourseRegistrationsV1List(c *gin.Context) { // ------------- Required query parameter "semesters" ------------- - if paramValue := c.Query("semesters"); paramValue != "" { - - } else { - siw.ErrorHandler(c, fmt.Errorf("Query argument semesters is required, but not found"), http.StatusBadRequest) - return - } - - err = runtime.BindQueryParameter("form", false, true, "semesters", c.Request.URL.Query(), ¶ms.Semesters) + err = runtime.BindQueryParameterWithOptions("form", false, true, "semesters", c.Request.URL.Query(), ¶ms.Semesters, runtime.BindQueryParameterOptions{Type: "array", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter semesters: %w", err), http.StatusBadRequest) return @@ -904,11 +1126,12 @@ func (siw *ServerInterfaceWrapper) CourseRegistrationsV1Create(c *gin.Context) { func (siw *ServerInterfaceWrapper) CourseRegistrationsV1Delete(c *gin.Context) { var err error + _ = err // ------------- Path parameter "id" ------------- var id string - err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest) return @@ -928,13 +1151,14 @@ func (siw *ServerInterfaceWrapper) CourseRegistrationsV1Delete(c *gin.Context) { func (siw *ServerInterfaceWrapper) FacultiesV1List(c *gin.Context) { var err error + _ = err // Parameter object where we will unmarshal all parameters from the context var params FacultiesV1ListParams // ------------- Optional query parameter "q" ------------- - err = runtime.BindQueryParameter("form", false, false, "q", c.Request.URL.Query(), ¶ms.Q) + err = runtime.BindQueryParameterWithOptions("form", false, false, "q", c.Request.URL.Query(), ¶ms.Q, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter q: %w", err), http.StatusBadRequest) return @@ -967,11 +1191,12 @@ func (siw *ServerInterfaceWrapper) FacultiesV1Create(c *gin.Context) { func (siw *ServerInterfaceWrapper) FacultiesV1Delete(c *gin.Context) { var err error + _ = err // ------------- Path parameter "id" ------------- var id string - err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest) return @@ -991,11 +1216,12 @@ func (siw *ServerInterfaceWrapper) FacultiesV1Delete(c *gin.Context) { func (siw *ServerInterfaceWrapper) FacultiesV1Detail(c *gin.Context) { var err error + _ = err // ------------- Path parameter "id" ------------- var id string - err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest) return @@ -1015,11 +1241,12 @@ func (siw *ServerInterfaceWrapper) FacultiesV1Detail(c *gin.Context) { func (siw *ServerInterfaceWrapper) FacultiesV1Update(c *gin.Context) { var err error + _ = err // ------------- Path parameter "id" ------------- var id string - err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest) return @@ -1039,13 +1266,14 @@ func (siw *ServerInterfaceWrapper) FacultiesV1Update(c *gin.Context) { func (siw *ServerInterfaceWrapper) FacultyRoomsV1List(c *gin.Context) { var err error + _ = err // Parameter object where we will unmarshal all parameters from the context var params FacultyRoomsV1ListParams // ------------- Optional query parameter "year" ------------- - err = runtime.BindQueryParameter("form", false, false, "year", c.Request.URL.Query(), ¶ms.Year) + err = runtime.BindQueryParameterWithOptions("form", false, false, "year", c.Request.URL.Query(), ¶ms.Year, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter year: %w", err), http.StatusBadRequest) return @@ -1078,11 +1306,12 @@ func (siw *ServerInterfaceWrapper) FacultyRoomsV1Create(c *gin.Context) { func (siw *ServerInterfaceWrapper) FacultyRoomsV1Delete(c *gin.Context) { var err error + _ = err // ------------- Path parameter "id" ------------- var id string - err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest) return @@ -1102,13 +1331,14 @@ func (siw *ServerInterfaceWrapper) FacultyRoomsV1Delete(c *gin.Context) { func (siw *ServerInterfaceWrapper) MakeupClassesV1List(c *gin.Context) { var err error + _ = err // Parameter object where we will unmarshal all parameters from the context var params MakeupClassesV1ListParams // ------------- Optional query parameter "subjectIds" ------------- - err = runtime.BindQueryParameter("form", false, false, "subjectIds", c.Request.URL.Query(), ¶ms.SubjectIds) + err = runtime.BindQueryParameterWithOptions("form", false, false, "subjectIds", c.Request.URL.Query(), ¶ms.SubjectIds, runtime.BindQueryParameterOptions{Type: "array", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter subjectIds: %w", err), http.StatusBadRequest) return @@ -1116,7 +1346,7 @@ func (siw *ServerInterfaceWrapper) MakeupClassesV1List(c *gin.Context) { // ------------- Optional query parameter "from" ------------- - err = runtime.BindQueryParameter("form", true, false, "from", c.Request.URL.Query(), ¶ms.From) + err = runtime.BindQueryParameterWithOptions("form", true, false, "from", c.Request.URL.Query(), ¶ms.From, runtime.BindQueryParameterOptions{Type: "string", Format: "date"}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter from: %w", err), http.StatusBadRequest) return @@ -1124,7 +1354,7 @@ func (siw *ServerInterfaceWrapper) MakeupClassesV1List(c *gin.Context) { // ------------- Optional query parameter "until" ------------- - err = runtime.BindQueryParameter("form", true, false, "until", c.Request.URL.Query(), ¶ms.Until) + err = runtime.BindQueryParameterWithOptions("form", true, false, "until", c.Request.URL.Query(), ¶ms.Until, runtime.BindQueryParameterOptions{Type: "string", Format: "date"}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter until: %w", err), http.StatusBadRequest) return @@ -1157,11 +1387,12 @@ func (siw *ServerInterfaceWrapper) MakeupClassesV1Create(c *gin.Context) { func (siw *ServerInterfaceWrapper) MakeupClassesV1Delete(c *gin.Context) { var err error + _ = err // ------------- Path parameter "id" ------------- var id string - err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest) return @@ -1181,20 +1412,14 @@ func (siw *ServerInterfaceWrapper) MakeupClassesV1Delete(c *gin.Context) { func (siw *ServerInterfaceWrapper) PersonalCalendarItemsV1List(c *gin.Context) { var err error + _ = err // Parameter object where we will unmarshal all parameters from the context var params PersonalCalendarItemsV1ListParams // ------------- Required query parameter "userId" ------------- - if paramValue := c.Query("userId"); paramValue != "" { - - } else { - siw.ErrorHandler(c, fmt.Errorf("Query argument userId is required, but not found"), http.StatusBadRequest) - return - } - - err = runtime.BindQueryParameter("form", false, true, "userId", c.Request.URL.Query(), ¶ms.UserId) + err = runtime.BindQueryParameterWithOptions("form", false, true, "userId", c.Request.URL.Query(), ¶ms.UserId, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter userId: %w", err), http.StatusBadRequest) return @@ -1202,14 +1427,7 @@ func (siw *ServerInterfaceWrapper) PersonalCalendarItemsV1List(c *gin.Context) { // ------------- Required query parameter "dates" ------------- - if paramValue := c.Query("dates"); paramValue != "" { - - } else { - siw.ErrorHandler(c, fmt.Errorf("Query argument dates is required, but not found"), http.StatusBadRequest) - return - } - - err = runtime.BindQueryParameter("form", false, true, "dates", c.Request.URL.Query(), ¶ms.Dates) + err = runtime.BindQueryParameterWithOptions("form", false, true, "dates", c.Request.URL.Query(), ¶ms.Dates, runtime.BindQueryParameterOptions{Type: "array", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter dates: %w", err), http.StatusBadRequest) return @@ -1229,13 +1447,14 @@ func (siw *ServerInterfaceWrapper) PersonalCalendarItemsV1List(c *gin.Context) { func (siw *ServerInterfaceWrapper) ReservationsV1List(c *gin.Context) { var err error + _ = err // Parameter object where we will unmarshal all parameters from the context var params ReservationsV1ListParams // ------------- Optional query parameter "roomIds" ------------- - err = runtime.BindQueryParameter("form", false, false, "roomIds", c.Request.URL.Query(), ¶ms.RoomIds) + err = runtime.BindQueryParameterWithOptions("form", false, false, "roomIds", c.Request.URL.Query(), ¶ms.RoomIds, runtime.BindQueryParameterOptions{Type: "array", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter roomIds: %w", err), http.StatusBadRequest) return @@ -1243,7 +1462,7 @@ func (siw *ServerInterfaceWrapper) ReservationsV1List(c *gin.Context) { // ------------- Optional query parameter "from" ------------- - err = runtime.BindQueryParameter("form", true, false, "from", c.Request.URL.Query(), ¶ms.From) + err = runtime.BindQueryParameterWithOptions("form", true, false, "from", c.Request.URL.Query(), ¶ms.From, runtime.BindQueryParameterOptions{Type: "string", Format: "date-time"}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter from: %w", err), http.StatusBadRequest) return @@ -1251,7 +1470,7 @@ func (siw *ServerInterfaceWrapper) ReservationsV1List(c *gin.Context) { // ------------- Optional query parameter "until" ------------- - err = runtime.BindQueryParameter("form", true, false, "until", c.Request.URL.Query(), ¶ms.Until) + err = runtime.BindQueryParameterWithOptions("form", true, false, "until", c.Request.URL.Query(), ¶ms.Until, runtime.BindQueryParameterOptions{Type: "string", Format: "date-time"}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter until: %w", err), http.StatusBadRequest) return @@ -1284,11 +1503,12 @@ func (siw *ServerInterfaceWrapper) ReservationsV1Create(c *gin.Context) { func (siw *ServerInterfaceWrapper) ReservationsV1Delete(c *gin.Context) { var err error + _ = err // ------------- Path parameter "id" ------------- var id string - err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest) return @@ -1308,13 +1528,14 @@ func (siw *ServerInterfaceWrapper) ReservationsV1Delete(c *gin.Context) { func (siw *ServerInterfaceWrapper) RoomChangesV1List(c *gin.Context) { var err error + _ = err // Parameter object where we will unmarshal all parameters from the context var params RoomChangesV1ListParams // ------------- Optional query parameter "subjectIds" ------------- - err = runtime.BindQueryParameter("form", false, false, "subjectIds", c.Request.URL.Query(), ¶ms.SubjectIds) + err = runtime.BindQueryParameterWithOptions("form", false, false, "subjectIds", c.Request.URL.Query(), ¶ms.SubjectIds, runtime.BindQueryParameterOptions{Type: "array", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter subjectIds: %w", err), http.StatusBadRequest) return @@ -1322,7 +1543,7 @@ func (siw *ServerInterfaceWrapper) RoomChangesV1List(c *gin.Context) { // ------------- Optional query parameter "from" ------------- - err = runtime.BindQueryParameter("form", true, false, "from", c.Request.URL.Query(), ¶ms.From) + err = runtime.BindQueryParameterWithOptions("form", true, false, "from", c.Request.URL.Query(), ¶ms.From, runtime.BindQueryParameterOptions{Type: "string", Format: "date"}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter from: %w", err), http.StatusBadRequest) return @@ -1330,7 +1551,7 @@ func (siw *ServerInterfaceWrapper) RoomChangesV1List(c *gin.Context) { // ------------- Optional query parameter "until" ------------- - err = runtime.BindQueryParameter("form", true, false, "until", c.Request.URL.Query(), ¶ms.Until) + err = runtime.BindQueryParameterWithOptions("form", true, false, "until", c.Request.URL.Query(), ¶ms.Until, runtime.BindQueryParameterOptions{Type: "string", Format: "date"}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter until: %w", err), http.StatusBadRequest) return @@ -1363,11 +1584,12 @@ func (siw *ServerInterfaceWrapper) RoomChangesV1Create(c *gin.Context) { func (siw *ServerInterfaceWrapper) RoomChangesV1Delete(c *gin.Context) { var err error + _ = err // ------------- Path parameter "id" ------------- var id string - err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest) return @@ -1387,13 +1609,14 @@ func (siw *ServerInterfaceWrapper) RoomChangesV1Delete(c *gin.Context) { func (siw *ServerInterfaceWrapper) RoomsV1List(c *gin.Context) { var err error + _ = err // Parameter object where we will unmarshal all parameters from the context var params RoomsV1ListParams // ------------- Optional query parameter "q" ------------- - err = runtime.BindQueryParameter("form", false, false, "q", c.Request.URL.Query(), ¶ms.Q) + err = runtime.BindQueryParameterWithOptions("form", false, false, "q", c.Request.URL.Query(), ¶ms.Q, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter q: %w", err), http.StatusBadRequest) return @@ -1401,7 +1624,7 @@ func (siw *ServerInterfaceWrapper) RoomsV1List(c *gin.Context) { // ------------- Optional query parameter "floors" ------------- - err = runtime.BindQueryParameter("form", false, false, "floors", c.Request.URL.Query(), ¶ms.Floors) + err = runtime.BindQueryParameterWithOptions("form", false, false, "floors", c.Request.URL.Query(), ¶ms.Floors, runtime.BindQueryParameterOptions{Type: "array", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter floors: %w", err), http.StatusBadRequest) return @@ -1434,11 +1657,12 @@ func (siw *ServerInterfaceWrapper) RoomsV1Create(c *gin.Context) { func (siw *ServerInterfaceWrapper) RoomsV1Delete(c *gin.Context) { var err error + _ = err // ------------- Path parameter "id" ------------- var id string - err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest) return @@ -1458,11 +1682,12 @@ func (siw *ServerInterfaceWrapper) RoomsV1Delete(c *gin.Context) { func (siw *ServerInterfaceWrapper) RoomsV1Detail(c *gin.Context) { var err error + _ = err // ------------- Path parameter "id" ------------- var id string - err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest) return @@ -1482,11 +1707,12 @@ func (siw *ServerInterfaceWrapper) RoomsV1Detail(c *gin.Context) { func (siw *ServerInterfaceWrapper) RoomsV1Update(c *gin.Context) { var err error + _ = err // ------------- Path parameter "id" ------------- var id string - err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest) return @@ -1506,13 +1732,14 @@ func (siw *ServerInterfaceWrapper) RoomsV1Update(c *gin.Context) { func (siw *ServerInterfaceWrapper) SubjectsV1List(c *gin.Context) { var err error + _ = err // Parameter object where we will unmarshal all parameters from the context var params SubjectsV1ListParams // ------------- Optional query parameter "ids" ------------- - err = runtime.BindQueryParameter("form", false, false, "ids", c.Request.URL.Query(), ¶ms.Ids) + err = runtime.BindQueryParameterWithOptions("form", false, false, "ids", c.Request.URL.Query(), ¶ms.Ids, runtime.BindQueryParameterOptions{Type: "array", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter ids: %w", err), http.StatusBadRequest) return @@ -1520,7 +1747,7 @@ func (siw *ServerInterfaceWrapper) SubjectsV1List(c *gin.Context) { // ------------- Optional query parameter "q" ------------- - err = runtime.BindQueryParameter("form", false, false, "q", c.Request.URL.Query(), ¶ms.Q) + err = runtime.BindQueryParameterWithOptions("form", false, false, "q", c.Request.URL.Query(), ¶ms.Q, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter q: %w", err), http.StatusBadRequest) return @@ -1528,7 +1755,7 @@ func (siw *ServerInterfaceWrapper) SubjectsV1List(c *gin.Context) { // ------------- Optional query parameter "grades" ------------- - err = runtime.BindQueryParameter("form", false, false, "grades", c.Request.URL.Query(), ¶ms.Grades) + err = runtime.BindQueryParameterWithOptions("form", false, false, "grades", c.Request.URL.Query(), ¶ms.Grades, runtime.BindQueryParameterOptions{Type: "array", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter grades: %w", err), http.StatusBadRequest) return @@ -1536,7 +1763,7 @@ func (siw *ServerInterfaceWrapper) SubjectsV1List(c *gin.Context) { // ------------- Optional query parameter "courses" ------------- - err = runtime.BindQueryParameter("form", false, false, "courses", c.Request.URL.Query(), ¶ms.Courses) + err = runtime.BindQueryParameterWithOptions("form", false, false, "courses", c.Request.URL.Query(), ¶ms.Courses, runtime.BindQueryParameterOptions{Type: "array", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter courses: %w", err), http.StatusBadRequest) return @@ -1544,7 +1771,7 @@ func (siw *ServerInterfaceWrapper) SubjectsV1List(c *gin.Context) { // ------------- Optional query parameter "classes" ------------- - err = runtime.BindQueryParameter("form", false, false, "classes", c.Request.URL.Query(), ¶ms.Classes) + err = runtime.BindQueryParameterWithOptions("form", false, false, "classes", c.Request.URL.Query(), ¶ms.Classes, runtime.BindQueryParameterOptions{Type: "array", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter classes: %w", err), http.StatusBadRequest) return @@ -1552,7 +1779,7 @@ func (siw *ServerInterfaceWrapper) SubjectsV1List(c *gin.Context) { // ------------- Optional query parameter "classifications" ------------- - err = runtime.BindQueryParameter("form", false, false, "classifications", c.Request.URL.Query(), ¶ms.Classifications) + err = runtime.BindQueryParameterWithOptions("form", false, false, "classifications", c.Request.URL.Query(), ¶ms.Classifications, runtime.BindQueryParameterOptions{Type: "array", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter classifications: %w", err), http.StatusBadRequest) return @@ -1560,7 +1787,7 @@ func (siw *ServerInterfaceWrapper) SubjectsV1List(c *gin.Context) { // ------------- Optional query parameter "year" ------------- - err = runtime.BindQueryParameter("form", false, false, "year", c.Request.URL.Query(), ¶ms.Year) + err = runtime.BindQueryParameterWithOptions("form", false, false, "year", c.Request.URL.Query(), ¶ms.Year, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter year: %w", err), http.StatusBadRequest) return @@ -1568,7 +1795,7 @@ func (siw *ServerInterfaceWrapper) SubjectsV1List(c *gin.Context) { // ------------- Optional query parameter "semesters" ------------- - err = runtime.BindQueryParameter("form", false, false, "semesters", c.Request.URL.Query(), ¶ms.Semesters) + err = runtime.BindQueryParameterWithOptions("form", false, false, "semesters", c.Request.URL.Query(), ¶ms.Semesters, runtime.BindQueryParameterOptions{Type: "array", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter semesters: %w", err), http.StatusBadRequest) return @@ -1576,7 +1803,7 @@ func (siw *ServerInterfaceWrapper) SubjectsV1List(c *gin.Context) { // ------------- Optional query parameter "requirementTypes" ------------- - err = runtime.BindQueryParameter("form", false, false, "requirementTypes", c.Request.URL.Query(), ¶ms.RequirementTypes) + err = runtime.BindQueryParameterWithOptions("form", false, false, "requirementTypes", c.Request.URL.Query(), ¶ms.RequirementTypes, runtime.BindQueryParameterOptions{Type: "array", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter requirementTypes: %w", err), http.StatusBadRequest) return @@ -1584,12 +1811,20 @@ func (siw *ServerInterfaceWrapper) SubjectsV1List(c *gin.Context) { // ------------- Optional query parameter "culturalSubjectCategories" ------------- - err = runtime.BindQueryParameter("form", false, false, "culturalSubjectCategories", c.Request.URL.Query(), ¶ms.CulturalSubjectCategories) + err = runtime.BindQueryParameterWithOptions("form", false, false, "culturalSubjectCategories", c.Request.URL.Query(), ¶ms.CulturalSubjectCategories, runtime.BindQueryParameterOptions{Type: "array", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter culturalSubjectCategories: %w", err), http.StatusBadRequest) return } + // ------------- Optional query parameter "userId" ------------- + + err = runtime.BindQueryParameterWithOptions("form", false, false, "userId", c.Request.URL.Query(), ¶ms.UserId, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter userId: %w", err), http.StatusBadRequest) + return + } + for _, middleware := range siw.HandlerMiddlewares { middleware(c) if c.IsAborted() { @@ -1604,11 +1839,12 @@ func (siw *ServerInterfaceWrapper) SubjectsV1List(c *gin.Context) { func (siw *ServerInterfaceWrapper) SubjectsV1Delete(c *gin.Context) { var err error + _ = err // ------------- Path parameter "id" ------------- var id string - err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest) return @@ -1628,11 +1864,12 @@ func (siw *ServerInterfaceWrapper) SubjectsV1Delete(c *gin.Context) { func (siw *ServerInterfaceWrapper) SubjectsV1Detail(c *gin.Context) { var err error + _ = err // ------------- Path parameter "id" ------------- var id string - err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest) return @@ -1652,11 +1889,12 @@ func (siw *ServerInterfaceWrapper) SubjectsV1Detail(c *gin.Context) { func (siw *ServerInterfaceWrapper) SyllabusV1Detail(c *gin.Context) { var err error + _ = err // ------------- Path parameter "id" ------------- var id string - err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest) return @@ -1676,13 +1914,14 @@ func (siw *ServerInterfaceWrapper) SyllabusV1Detail(c *gin.Context) { func (siw *ServerInterfaceWrapper) TimetableItemsV1List(c *gin.Context) { var err error + _ = err // Parameter object where we will unmarshal all parameters from the context var params TimetableItemsV1ListParams // ------------- Optional query parameter "year" ------------- - err = runtime.BindQueryParameter("form", false, false, "year", c.Request.URL.Query(), ¶ms.Year) + err = runtime.BindQueryParameterWithOptions("form", false, false, "year", c.Request.URL.Query(), ¶ms.Year, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter year: %w", err), http.StatusBadRequest) return @@ -1690,14 +1929,7 @@ func (siw *ServerInterfaceWrapper) TimetableItemsV1List(c *gin.Context) { // ------------- Required query parameter "semesters" ------------- - if paramValue := c.Query("semesters"); paramValue != "" { - - } else { - siw.ErrorHandler(c, fmt.Errorf("Query argument semesters is required, but not found"), http.StatusBadRequest) - return - } - - err = runtime.BindQueryParameter("form", false, true, "semesters", c.Request.URL.Query(), ¶ms.Semesters) + err = runtime.BindQueryParameterWithOptions("form", false, true, "semesters", c.Request.URL.Query(), ¶ms.Semesters, runtime.BindQueryParameterOptions{Type: "array", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter semesters: %w", err), http.StatusBadRequest) return @@ -1730,11 +1962,12 @@ func (siw *ServerInterfaceWrapper) TimetableItemsV1Create(c *gin.Context) { func (siw *ServerInterfaceWrapper) TimetableItemsV1Delete(c *gin.Context) { var err error + _ = err // ------------- Path parameter "id" ------------- var id string - err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest) return @@ -1828,10 +2061,15 @@ type CancelledClassesV1List200JSONResponse struct { } func (response CancelledClassesV1List200JSONResponse) VisitCancelledClassesV1ListResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type CancelledClassesV1CreateRequestObject struct { @@ -1848,10 +2086,15 @@ type CancelledClassesV1Create201JSONResponse struct { } func (response CancelledClassesV1Create201JSONResponse) VisitCancelledClassesV1CreateResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(201) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type CancelledClassesV1DeleteRequestObject struct { @@ -1891,10 +2134,15 @@ type CourseRegistrationsV1List200JSONResponse struct { } func (response CourseRegistrationsV1List200JSONResponse) VisitCourseRegistrationsV1ListResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type CourseRegistrationsV1List404Response struct { @@ -1918,10 +2166,15 @@ type CourseRegistrationsV1Create201JSONResponse struct { } func (response CourseRegistrationsV1Create201JSONResponse) VisitCourseRegistrationsV1CreateResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(201) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type CourseRegistrationsV1Create400Response struct { @@ -1969,10 +2222,15 @@ type FacultiesV1List200JSONResponse struct { } func (response FacultiesV1List200JSONResponse) VisitFacultiesV1ListResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type FacultiesV1CreateRequestObject struct { @@ -1988,10 +2246,15 @@ type FacultiesV1Create201JSONResponse struct { } func (response FacultiesV1Create201JSONResponse) VisitFacultiesV1CreateResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(201) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type FacultiesV1DeleteRequestObject struct { @@ -2039,10 +2302,15 @@ type FacultiesV1Detail200JSONResponse struct { } func (response FacultiesV1Detail200JSONResponse) VisitFacultiesV1DetailResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type FacultiesV1Detail404Response struct { @@ -2067,10 +2335,15 @@ type FacultiesV1Update200JSONResponse struct { } func (response FacultiesV1Update200JSONResponse) VisitFacultiesV1UpdateResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type FacultiesV1Update404Response struct { @@ -2094,10 +2367,15 @@ type FacultyRoomsV1List200JSONResponse struct { } func (response FacultyRoomsV1List200JSONResponse) VisitFacultyRoomsV1ListResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type FacultyRoomsV1CreateRequestObject struct { @@ -2113,10 +2391,15 @@ type FacultyRoomsV1Create201JSONResponse struct { } func (response FacultyRoomsV1Create201JSONResponse) VisitFacultyRoomsV1CreateResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(201) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type FacultyRoomsV1Create409Response struct { @@ -2164,10 +2447,15 @@ type MakeupClassesV1List200JSONResponse struct { } func (response MakeupClassesV1List200JSONResponse) VisitMakeupClassesV1ListResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type MakeupClassesV1CreateRequestObject struct { @@ -2184,10 +2472,15 @@ type MakeupClassesV1Create201JSONResponse struct { } func (response MakeupClassesV1Create201JSONResponse) VisitMakeupClassesV1CreateResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(201) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type MakeupClassesV1DeleteRequestObject struct { @@ -2227,10 +2520,15 @@ type PersonalCalendarItemsV1List200JSONResponse struct { } func (response PersonalCalendarItemsV1List200JSONResponse) VisitPersonalCalendarItemsV1ListResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type ReservationsV1ListRequestObject struct { @@ -2246,10 +2544,15 @@ type ReservationsV1List200JSONResponse struct { } func (response ReservationsV1List200JSONResponse) VisitReservationsV1ListResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type ReservationsV1CreateRequestObject struct { @@ -2265,10 +2568,15 @@ type ReservationsV1Create201JSONResponse struct { } func (response ReservationsV1Create201JSONResponse) VisitReservationsV1CreateResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(201) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type ReservationsV1DeleteRequestObject struct { @@ -2308,10 +2616,15 @@ type RoomChangesV1List200JSONResponse struct { } func (response RoomChangesV1List200JSONResponse) VisitRoomChangesV1ListResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type RoomChangesV1CreateRequestObject struct { @@ -2328,10 +2641,15 @@ type RoomChangesV1Create201JSONResponse struct { } func (response RoomChangesV1Create201JSONResponse) VisitRoomChangesV1CreateResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(201) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type RoomChangesV1DeleteRequestObject struct { @@ -2371,10 +2689,15 @@ type RoomsV1List200JSONResponse struct { } func (response RoomsV1List200JSONResponse) VisitRoomsV1ListResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type RoomsV1CreateRequestObject struct { @@ -2390,10 +2713,15 @@ type RoomsV1Create201JSONResponse struct { } func (response RoomsV1Create201JSONResponse) VisitRoomsV1CreateResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(201) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type RoomsV1DeleteRequestObject struct { @@ -2441,10 +2769,15 @@ type RoomsV1Detail200JSONResponse struct { } func (response RoomsV1Detail200JSONResponse) VisitRoomsV1DetailResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type RoomsV1Detail404Response struct { @@ -2469,10 +2802,15 @@ type RoomsV1Update200JSONResponse struct { } func (response RoomsV1Update200JSONResponse) VisitRoomsV1UpdateResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type RoomsV1Update404Response struct { @@ -2496,10 +2834,15 @@ type SubjectsV1List200JSONResponse struct { } func (response SubjectsV1List200JSONResponse) VisitSubjectsV1ListResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type SubjectsV1DeleteRequestObject struct { @@ -2547,10 +2890,15 @@ type SubjectsV1Detail200JSONResponse struct { } func (response SubjectsV1Detail200JSONResponse) VisitSubjectsV1DetailResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type SubjectsV1Detail404Response struct { @@ -2574,10 +2922,15 @@ type SyllabusV1Detail200JSONResponse struct { } func (response SyllabusV1Detail200JSONResponse) VisitSyllabusV1DetailResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type SyllabusV1Detail404Response struct { @@ -2601,10 +2954,15 @@ type TimetableItemsV1List200JSONResponse struct { } func (response TimetableItemsV1List200JSONResponse) VisitTimetableItemsV1ListResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type TimetableItemsV1CreateRequestObject struct { @@ -2620,10 +2978,15 @@ type TimetableItemsV1Create201JSONResponse struct { } func (response TimetableItemsV1Create201JSONResponse) VisitTimetableItemsV1CreateResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(201) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type TimetableItemsV1DeleteRequestObject struct { @@ -2762,16 +3125,61 @@ type StrictServerInterface interface { TimetableItemsV1Delete(ctx context.Context, request TimetableItemsV1DeleteRequestObject) (TimetableItemsV1DeleteResponseObject, error) } -type StrictHandlerFunc = strictgin.StrictGinHandlerFunc -type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc +type StrictHandlerFunc func(ctx *gin.Context, request any) (any, error) +type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc + +type StrictGinServerOptions struct { + // RequestErrorHandlerFunc is called when a request cannot be parsed or + // decoded. It is invoked for JSON bind failures, form parse/bind errors, + // multipart reader errors, media type parse errors, missing multipart + // boundaries, and request body read errors. The default returns 400. + RequestErrorHandlerFunc func(ctx *gin.Context, err error) + // HandlerErrorFunc is called when the application handler (or any + // middleware wrapping it) returns a non-nil error. The default returns 500. + HandlerErrorFunc func(ctx *gin.Context, err error) + // ResponseErrorHandlerFunc is called when the response object fails to + // serialize (Visit*Response returns an error) or when the handler returns + // an unexpected response type. The default returns 500. + ResponseErrorHandlerFunc func(ctx *gin.Context, err error) +} func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface { - return &strictHandler{ssi: ssi, middlewares: middlewares} + return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictGinServerOptions{ + RequestErrorHandlerFunc: func(ctx *gin.Context, err error) { + ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()}) + }, + HandlerErrorFunc: func(ctx *gin.Context, err error) { + ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()}) + }, + ResponseErrorHandlerFunc: func(ctx *gin.Context, err error) { + ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()}) + }, + }} +} + +func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictGinServerOptions) ServerInterface { + if options.RequestErrorHandlerFunc == nil { + options.RequestErrorHandlerFunc = func(ctx *gin.Context, err error) { + ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()}) + } + } + if options.HandlerErrorFunc == nil { + options.HandlerErrorFunc = func(ctx *gin.Context, err error) { + ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()}) + } + } + if options.ResponseErrorHandlerFunc == nil { + options.ResponseErrorHandlerFunc = func(ctx *gin.Context, err error) { + ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()}) + } + } + return &strictHandler{ssi: ssi, middlewares: middlewares, options: options} } type strictHandler struct { ssi StrictServerInterface middlewares []StrictMiddlewareFunc + options StrictGinServerOptions } // CancelledClassesV1List operation middleware @@ -2790,14 +3198,13 @@ func (sh *strictHandler) CancelledClassesV1List(ctx *gin.Context, params Cancell response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(CancelledClassesV1ListResponseObject); ok { if err := validResponse.VisitCancelledClassesV1ListResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -2807,8 +3214,7 @@ func (sh *strictHandler) CancelledClassesV1Create(ctx *gin.Context) { var body CancelledClassesV1CreateJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } request.Body = &body @@ -2823,14 +3229,13 @@ func (sh *strictHandler) CancelledClassesV1Create(ctx *gin.Context) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(CancelledClassesV1CreateResponseObject); ok { if err := validResponse.VisitCancelledClassesV1CreateResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -2850,14 +3255,13 @@ func (sh *strictHandler) CancelledClassesV1Delete(ctx *gin.Context, id string) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(CancelledClassesV1DeleteResponseObject); ok { if err := validResponse.VisitCancelledClassesV1DeleteResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -2877,14 +3281,13 @@ func (sh *strictHandler) CourseRegistrationsV1List(ctx *gin.Context, params Cour response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(CourseRegistrationsV1ListResponseObject); ok { if err := validResponse.VisitCourseRegistrationsV1ListResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -2894,8 +3297,7 @@ func (sh *strictHandler) CourseRegistrationsV1Create(ctx *gin.Context) { var body CourseRegistrationsV1CreateJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } request.Body = &body @@ -2910,14 +3312,13 @@ func (sh *strictHandler) CourseRegistrationsV1Create(ctx *gin.Context) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(CourseRegistrationsV1CreateResponseObject); ok { if err := validResponse.VisitCourseRegistrationsV1CreateResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -2937,14 +3338,13 @@ func (sh *strictHandler) CourseRegistrationsV1Delete(ctx *gin.Context, id string response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(CourseRegistrationsV1DeleteResponseObject); ok { if err := validResponse.VisitCourseRegistrationsV1DeleteResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -2964,14 +3364,13 @@ func (sh *strictHandler) FacultiesV1List(ctx *gin.Context, params FacultiesV1Lis response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(FacultiesV1ListResponseObject); ok { if err := validResponse.VisitFacultiesV1ListResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -2981,8 +3380,7 @@ func (sh *strictHandler) FacultiesV1Create(ctx *gin.Context) { var body FacultiesV1CreateJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } request.Body = &body @@ -2997,14 +3395,13 @@ func (sh *strictHandler) FacultiesV1Create(ctx *gin.Context) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(FacultiesV1CreateResponseObject); ok { if err := validResponse.VisitFacultiesV1CreateResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3024,14 +3421,13 @@ func (sh *strictHandler) FacultiesV1Delete(ctx *gin.Context, id string) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(FacultiesV1DeleteResponseObject); ok { if err := validResponse.VisitFacultiesV1DeleteResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3051,14 +3447,13 @@ func (sh *strictHandler) FacultiesV1Detail(ctx *gin.Context, id string) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(FacultiesV1DetailResponseObject); ok { if err := validResponse.VisitFacultiesV1DetailResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3070,8 +3465,7 @@ func (sh *strictHandler) FacultiesV1Update(ctx *gin.Context, id string) { var body FacultiesV1UpdateJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } request.Body = &body @@ -3086,14 +3480,13 @@ func (sh *strictHandler) FacultiesV1Update(ctx *gin.Context, id string) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(FacultiesV1UpdateResponseObject); ok { if err := validResponse.VisitFacultiesV1UpdateResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3113,14 +3506,13 @@ func (sh *strictHandler) FacultyRoomsV1List(ctx *gin.Context, params FacultyRoom response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(FacultyRoomsV1ListResponseObject); ok { if err := validResponse.VisitFacultyRoomsV1ListResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3130,8 +3522,7 @@ func (sh *strictHandler) FacultyRoomsV1Create(ctx *gin.Context) { var body FacultyRoomsV1CreateJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } request.Body = &body @@ -3146,14 +3537,13 @@ func (sh *strictHandler) FacultyRoomsV1Create(ctx *gin.Context) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(FacultyRoomsV1CreateResponseObject); ok { if err := validResponse.VisitFacultyRoomsV1CreateResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3173,14 +3563,13 @@ func (sh *strictHandler) FacultyRoomsV1Delete(ctx *gin.Context, id string) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(FacultyRoomsV1DeleteResponseObject); ok { if err := validResponse.VisitFacultyRoomsV1DeleteResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3200,14 +3589,13 @@ func (sh *strictHandler) MakeupClassesV1List(ctx *gin.Context, params MakeupClas response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(MakeupClassesV1ListResponseObject); ok { if err := validResponse.VisitMakeupClassesV1ListResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3217,8 +3605,7 @@ func (sh *strictHandler) MakeupClassesV1Create(ctx *gin.Context) { var body MakeupClassesV1CreateJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } request.Body = &body @@ -3233,14 +3620,13 @@ func (sh *strictHandler) MakeupClassesV1Create(ctx *gin.Context) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(MakeupClassesV1CreateResponseObject); ok { if err := validResponse.VisitMakeupClassesV1CreateResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3260,14 +3646,13 @@ func (sh *strictHandler) MakeupClassesV1Delete(ctx *gin.Context, id string) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(MakeupClassesV1DeleteResponseObject); ok { if err := validResponse.VisitMakeupClassesV1DeleteResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3287,14 +3672,13 @@ func (sh *strictHandler) PersonalCalendarItemsV1List(ctx *gin.Context, params Pe response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(PersonalCalendarItemsV1ListResponseObject); ok { if err := validResponse.VisitPersonalCalendarItemsV1ListResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3314,14 +3698,13 @@ func (sh *strictHandler) ReservationsV1List(ctx *gin.Context, params Reservation response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(ReservationsV1ListResponseObject); ok { if err := validResponse.VisitReservationsV1ListResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3331,8 +3714,7 @@ func (sh *strictHandler) ReservationsV1Create(ctx *gin.Context) { var body ReservationsV1CreateJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } request.Body = &body @@ -3347,14 +3729,13 @@ func (sh *strictHandler) ReservationsV1Create(ctx *gin.Context) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(ReservationsV1CreateResponseObject); ok { if err := validResponse.VisitReservationsV1CreateResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3374,14 +3755,13 @@ func (sh *strictHandler) ReservationsV1Delete(ctx *gin.Context, id string) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(ReservationsV1DeleteResponseObject); ok { if err := validResponse.VisitReservationsV1DeleteResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3401,14 +3781,13 @@ func (sh *strictHandler) RoomChangesV1List(ctx *gin.Context, params RoomChangesV response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(RoomChangesV1ListResponseObject); ok { if err := validResponse.VisitRoomChangesV1ListResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3418,8 +3797,7 @@ func (sh *strictHandler) RoomChangesV1Create(ctx *gin.Context) { var body RoomChangesV1CreateJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } request.Body = &body @@ -3434,14 +3812,13 @@ func (sh *strictHandler) RoomChangesV1Create(ctx *gin.Context) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(RoomChangesV1CreateResponseObject); ok { if err := validResponse.VisitRoomChangesV1CreateResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3461,14 +3838,13 @@ func (sh *strictHandler) RoomChangesV1Delete(ctx *gin.Context, id string) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(RoomChangesV1DeleteResponseObject); ok { if err := validResponse.VisitRoomChangesV1DeleteResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3488,14 +3864,13 @@ func (sh *strictHandler) RoomsV1List(ctx *gin.Context, params RoomsV1ListParams) response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(RoomsV1ListResponseObject); ok { if err := validResponse.VisitRoomsV1ListResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3505,8 +3880,7 @@ func (sh *strictHandler) RoomsV1Create(ctx *gin.Context) { var body RoomsV1CreateJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } request.Body = &body @@ -3521,14 +3895,13 @@ func (sh *strictHandler) RoomsV1Create(ctx *gin.Context) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(RoomsV1CreateResponseObject); ok { if err := validResponse.VisitRoomsV1CreateResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3548,14 +3921,13 @@ func (sh *strictHandler) RoomsV1Delete(ctx *gin.Context, id string) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(RoomsV1DeleteResponseObject); ok { if err := validResponse.VisitRoomsV1DeleteResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3575,14 +3947,13 @@ func (sh *strictHandler) RoomsV1Detail(ctx *gin.Context, id string) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(RoomsV1DetailResponseObject); ok { if err := validResponse.VisitRoomsV1DetailResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3594,8 +3965,7 @@ func (sh *strictHandler) RoomsV1Update(ctx *gin.Context, id string) { var body RoomsV1UpdateJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } request.Body = &body @@ -3610,14 +3980,13 @@ func (sh *strictHandler) RoomsV1Update(ctx *gin.Context, id string) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(RoomsV1UpdateResponseObject); ok { if err := validResponse.VisitRoomsV1UpdateResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3637,14 +4006,13 @@ func (sh *strictHandler) SubjectsV1List(ctx *gin.Context, params SubjectsV1ListP response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(SubjectsV1ListResponseObject); ok { if err := validResponse.VisitSubjectsV1ListResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3664,14 +4032,13 @@ func (sh *strictHandler) SubjectsV1Delete(ctx *gin.Context, id string) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(SubjectsV1DeleteResponseObject); ok { if err := validResponse.VisitSubjectsV1DeleteResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3691,14 +4058,13 @@ func (sh *strictHandler) SubjectsV1Detail(ctx *gin.Context, id string) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(SubjectsV1DetailResponseObject); ok { if err := validResponse.VisitSubjectsV1DetailResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3718,14 +4084,13 @@ func (sh *strictHandler) SyllabusV1Detail(ctx *gin.Context, id string) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(SyllabusV1DetailResponseObject); ok { if err := validResponse.VisitSyllabusV1DetailResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3745,14 +4110,13 @@ func (sh *strictHandler) TimetableItemsV1List(ctx *gin.Context, params Timetable response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(TimetableItemsV1ListResponseObject); ok { if err := validResponse.VisitTimetableItemsV1ListResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3762,8 +4126,7 @@ func (sh *strictHandler) TimetableItemsV1Create(ctx *gin.Context) { var body TimetableItemsV1CreateJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } request.Body = &body @@ -3778,14 +4141,13 @@ func (sh *strictHandler) TimetableItemsV1Create(ctx *gin.Context) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(TimetableItemsV1CreateResponseObject); ok { if err := validResponse.VisitTimetableItemsV1CreateResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } @@ -3805,13 +4167,12 @@ func (sh *strictHandler) TimetableItemsV1Delete(ctx *gin.Context, id string) { response, err := handler(ctx, request) if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) + sh.options.HandlerErrorFunc(ctx, err) } else if validResponse, ok := response.(TimetableItemsV1DeleteResponseObject); ok { if err := validResponse.VisitTimetableItemsV1DeleteResponse(ctx.Writer); err != nil { - ctx.Error(err) + sh.options.ResponseErrorHandlerFunc(ctx, err) } } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response)) } } From 6ad65de21dda73b2cb64ee0e1ffd972c2894b921 Mon Sep 17 00:00:00 2001 From: Nagata Kuren Date: Fri, 5 Jun 2026 12:03:22 +0900 Subject: [PATCH 03/14] =?UTF-8?q?=09UserRepository=20=E3=82=92=E7=94=9F?= =?UTF-8?q?=E6=88=90=E3=81=97=E3=81=A6=20NewHandler=20=E3=81=AB=E6=B8=A1?= =?UTF-8?q?=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/academic-api/main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/academic-api/main.go b/cmd/academic-api/main.go index ba70def..cd0afd4 100644 --- a/cmd/academic-api/main.go +++ b/cmd/academic-api/main.go @@ -74,6 +74,7 @@ func main() { makeupClassRepo := repository.NewMakeupClassRepository(conn) roomChangeRepo := repository.NewRoomChangeRepository(conn) facultyRoomRepo := repository.NewFacultyRoomRepository(conn) + userRepo := repository.NewUserRepository(conn) // Events substituteDayMap, err := event.LoadSubstituteDayMap(assets.EventsJSON) if err != nil { @@ -98,7 +99,7 @@ func main() { facultyRoomSvc := service.NewFacultyRoomService(facultyRoomRepo) // Handler + Router - h := handler.NewHandler(subjectSvc, facultySvc, roomSvc, timetableItemSvc, courseRegistrationSvc, personalCalendarItemSvc, cancelledClassSvc, makeupClassSvc, roomChangeSvc, facultyRoomSvc) + h := handler.NewHandler(subjectSvc, facultySvc, roomSvc, timetableItemSvc, courseRegistrationSvc, personalCalendarItemSvc, cancelledClassSvc, makeupClassSvc, roomChangeSvc, facultyRoomSvc, userRepo) strictHandler := api.NewStrictHandler(h, []api.StrictMiddlewareFunc{ middleware.DeadlineErrorMapper(), }) From a332a8536fcbbfc395c1feece3e49e27bf39ab1c Mon Sep 17 00:00:00 2001 From: Nagata Kuren Date: Fri, 5 Jun 2026 12:03:44 +0900 Subject: [PATCH 04/14] =?UTF-8?q?sortSubjects=20=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/modules/academic/domain/subject.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/modules/academic/domain/subject.go b/internal/modules/academic/domain/subject.go index 603625a..f3ea90c 100644 --- a/internal/modules/academic/domain/subject.go +++ b/internal/modules/academic/domain/subject.go @@ -40,4 +40,7 @@ type SubjectListFilter struct { Semester []CourseSemester RequirementType []SubjectRequirementType CulturalSubjectCategory []CulturalSubjectCategory + + SortByUserAttribute bool + SortCourse *CourseType } From 7d81b262f8fcdec143b828089c8a560335ce267e Mon Sep 17 00:00:00 2001 From: Nagata Kuren Date: Fri, 5 Jun 2026 12:04:06 +0900 Subject: [PATCH 05/14] =?UTF-8?q?user=E3=82=92=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/modules/academic/domain/user.go | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 internal/modules/academic/domain/user.go diff --git a/internal/modules/academic/domain/user.go b/internal/modules/academic/domain/user.go new file mode 100644 index 0000000..020933a --- /dev/null +++ b/internal/modules/academic/domain/user.go @@ -0,0 +1,7 @@ +package domain + +type User struct { + ID string + Course *CourseType + Grade *Grade +} From b02cc87a06317564184f323ef265c033011b62de Mon Sep 17 00:00:00 2001 From: Nagata Kuren Date: Fri, 5 Jun 2026 12:04:28 +0900 Subject: [PATCH 06/14] =?UTF-8?q?=E3=82=A4=E3=83=B3=E3=82=BF=E3=83=BC?= =?UTF-8?q?=E3=83=95=E3=82=A7=E3=83=BC=E3=82=B9=E3=83=BB=E3=83=95=E3=82=A3?= =?UTF-8?q?=E3=83=BC=E3=83=AB=E3=83=89=E3=83=BB=E3=82=B3=E3=83=B3=E3=82=B9?= =?UTF-8?q?=E3=83=88=E3=83=A9=E3=82=AF=E3=82=BF=E5=BC=95=E6=95=B0=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/modules/academic/handler/handler.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/internal/modules/academic/handler/handler.go b/internal/modules/academic/handler/handler.go index 1c77390..a5f9fce 100644 --- a/internal/modules/academic/handler/handler.go +++ b/internal/modules/academic/handler/handler.go @@ -76,6 +76,10 @@ type facultyRoomService interface { Delete(ctx context.Context, id string) error } +type userRepository interface { + FindByID(ctx context.Context, id string) (domain.User, bool, error) +} + type Handler struct { subjectSvc subjectService facultySvc facultyService @@ -87,6 +91,7 @@ type Handler struct { makeupClassSvc makeupClassService roomChangeSvc roomChangeService facultyRoomSvc facultyRoomService + userRepo userRepository } func NewHandler( @@ -100,6 +105,7 @@ func NewHandler( makeupClassSvc makeupClassService, roomChangeSvc roomChangeService, facultyRoomSvc facultyRoomService, + userRepo userRepository, ) *Handler { return &Handler{ subjectSvc: subjectSvc, @@ -112,5 +118,6 @@ func NewHandler( makeupClassSvc: makeupClassSvc, roomChangeSvc: roomChangeSvc, facultyRoomSvc: facultyRoomSvc, + userRepo: userRepo, } } From 84c8743baa77ff68b8f7c43e51f4ae8abd6d52fb Mon Sep 17 00:00:00 2001 From: Nagata Kuren Date: Fri, 5 Jun 2026 12:04:56 +0900 Subject: [PATCH 07/14] =?UTF-8?q?userID=E3=82=92=E5=8F=96=E5=BE=97?= =?UTF-8?q?=E3=81=97sort=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/modules/academic/handler/subject_list.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/internal/modules/academic/handler/subject_list.go b/internal/modules/academic/handler/subject_list.go index a3cab33..e9c7042 100644 --- a/internal/modules/academic/handler/subject_list.go +++ b/internal/modules/academic/handler/subject_list.go @@ -9,6 +9,17 @@ import ( func (h *Handler) SubjectsV1List(ctx context.Context, request api.SubjectsV1ListRequestObject) (api.SubjectsV1ListResponseObject, error) { filter := buildSubjectListFilter(request.Params) + if request.Params.UserId != nil { + user, found, err := h.userRepo.FindByID(ctx, *request.Params.UserId) + if err != nil { + return nil, err + } + if found { + filter.SortByUserAttribute = true + filter.SortCourse = user.Course + } + } + subjects, err := h.subjectSvc.List(ctx, filter) if err != nil { return nil, err From af46e6851920561f9cada297a5f3db21025497a1 Mon Sep 17 00:00:00 2001 From: Nagata Kuren Date: Fri, 5 Jun 2026 12:05:15 +0900 Subject: [PATCH 08/14] =?UTF-8?q?SortByUserAttribute,=20SortCourse=20?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/modules/academic/service/subject.go | 75 +++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/internal/modules/academic/service/subject.go b/internal/modules/academic/service/subject.go index 859e0f8..2b87b51 100644 --- a/internal/modules/academic/service/subject.go +++ b/internal/modules/academic/service/subject.go @@ -1,7 +1,10 @@ package service import ( + "cmp" "context" + "math" + "slices" "github.com/fun-dotto/server/internal/modules/academic/domain" ) @@ -26,7 +29,14 @@ func NewSubjectService(repo subjectRepository, syllabusRepo syllabusRepository) } func (s *SubjectService) List(ctx context.Context, filter domain.SubjectListFilter) ([]domain.Subject, error) { - return s.repo.List(ctx, filter) + subjects, err := s.repo.List(ctx, filter) + if err != nil { + return nil, err + } + if filter.SortByUserAttribute { + sortSubjects(subjects, filter.SortCourse) + } + return subjects, nil } func (s *SubjectService) GetByID(ctx context.Context, id string) (domain.Subject, error) { @@ -45,3 +55,66 @@ func (s *SubjectService) GetSyllabus(ctx context.Context, subjectID string) (dom return s.syllabusRepo.GetByID(ctx, subject.SyllabusID) } +var courseOrder = map[domain.CourseType]int{ + domain.CourseTypeInformationSystem: 0, + domain.CourseTypeInformationDesign: 1, + domain.CourseTypeAdvancedICT: 2, + domain.CourseTypeComplexSystem: 3, + domain.CourseTypeIntelligentSystem: 4, +} + +var gradeOrder = map[domain.Grade]int{ + domain.GradeB1: 0, + domain.GradeB2: 1, + domain.GradeB3: 2, + domain.GradeB4: 3, + domain.GradeM1: 4, + domain.GradeM2: 5, + domain.GradeD1: 6, + domain.GradeD2: 7, + domain.GradeD3: 8, +} + +// courseRank はソートキーを返す。 +// ユーザーのコースと一致する場合は -1(最優先)、 +// それ以外は enum 定義順、Requirements が空なら math.MaxInt(最後)。 +func courseRank(s domain.Subject, userCourse *domain.CourseType) int { + if len(s.Requirements) == 0 { + return math.MaxInt + } + best := math.MaxInt + for _, r := range s.Requirements { + if userCourse != nil && r.Course == *userCourse { + return -1 + } + if rank, ok := courseOrder[r.Course]; ok && rank < best { + best = rank + } + } + return best +} + +// gradeRank はソートキーを返す。 +// EligibleAttributes の中で最も若い学年の順位を返す。 +// EligibleAttributes が空なら math.MaxInt(最後)。 +func gradeRank(s domain.Subject) int { + if len(s.EligibleAttributes) == 0 { + return math.MaxInt + } + best := math.MaxInt + for _, a := range s.EligibleAttributes { + if rank, ok := gradeOrder[a.Grade]; ok && rank < best { + best = rank + } + } + return best +} + +func sortSubjects(subjects []domain.Subject, userCourse *domain.CourseType) { + slices.SortStableFunc(subjects, func(a, b domain.Subject) int { + if c := cmp.Compare(courseRank(a, userCourse), courseRank(b, userCourse)); c != 0 { + return c + } + return cmp.Compare(gradeRank(a), gradeRank(b)) + }) +} From 0f6d9cdcbbd6cb8a4f27f92f15ba38f7acd729d3 Mon Sep 17 00:00:00 2001 From: Nagata Kuren Date: Fri, 5 Jun 2026 12:05:33 +0900 Subject: [PATCH 09/14] =?UTF-8?q?User=E3=82=92=E6=96=B0=E8=A6=8F=E4=BD=9C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/modules/academic/repository/user.go | 43 ++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 internal/modules/academic/repository/user.go diff --git a/internal/modules/academic/repository/user.go b/internal/modules/academic/repository/user.go new file mode 100644 index 0000000..59537d3 --- /dev/null +++ b/internal/modules/academic/repository/user.go @@ -0,0 +1,43 @@ +package repository + +import ( + "context" + "errors" + + "github.com/fun-dotto/server/internal/modules/academic/domain" + "github.com/fun-dotto/server/internal/shared/model" + "gorm.io/gorm" +) + +type UserRepository struct { + db *gorm.DB +} + +func NewUserRepository(db *gorm.DB) *UserRepository { + return &UserRepository{db: db} +} + +// FindByID はユーザーを取得する。見つからない場合は found=false を返す。 +func (r *UserRepository) FindByID(ctx context.Context, id string) (domain.User, bool, error) { + var record model.User + if err := r.db.WithContext(ctx).First(&record, "id = ?", id).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return domain.User{}, false, nil + } + return domain.User{}, false, err + } + return userToDomain(record), true, nil +} + +func userToDomain(m model.User) domain.User { + u := domain.User{ID: m.ID} + if m.Course != nil { + c := domain.CourseType(*m.Course) + u.Course = &c + } + if m.Grade != nil { + g := domain.Grade(*m.Grade) + u.Grade = &g + } + return u +} From 85cc5464e74647159dc038e29805d8b29aec32e9 Mon Sep 17 00:00:00 2001 From: Nagata Kuren Date: Fri, 5 Jun 2026 12:46:57 +0900 Subject: [PATCH 10/14] =?UTF-8?q?=E5=AD=A6=E5=B9=B4=E3=82=BD=E3=83=BC?= =?UTF-8?q?=E3=83=88=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/modules/academic/domain/subject.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/modules/academic/domain/subject.go b/internal/modules/academic/domain/subject.go index f3ea90c..e941438 100644 --- a/internal/modules/academic/domain/subject.go +++ b/internal/modules/academic/domain/subject.go @@ -43,4 +43,5 @@ type SubjectListFilter struct { SortByUserAttribute bool SortCourse *CourseType + SortGrade *Grade } From 76d36f0c625ed67a63e459c5bb205a83f1d65378 Mon Sep 17 00:00:00 2001 From: Nagata Kuren Date: Fri, 5 Jun 2026 12:48:15 +0900 Subject: [PATCH 11/14] =?UTF-8?q?=E8=87=AA=E5=88=86=E3=81=AE=E5=AD=A6?= =?UTF-8?q?=E5=B9=B4=E3=81=8C=E6=9C=80=E5=84=AA=E5=85=88=E3=81=AB=E3=81=AA?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/academic/handler/subject_list.go | 1 + internal/modules/academic/service/subject.go | 33 +++++++++++++++---- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/internal/modules/academic/handler/subject_list.go b/internal/modules/academic/handler/subject_list.go index e9c7042..62ef57f 100644 --- a/internal/modules/academic/handler/subject_list.go +++ b/internal/modules/academic/handler/subject_list.go @@ -17,6 +17,7 @@ func (h *Handler) SubjectsV1List(ctx context.Context, request api.SubjectsV1List if found { filter.SortByUserAttribute = true filter.SortCourse = user.Course + filter.SortGrade = user.Grade } } diff --git a/internal/modules/academic/service/subject.go b/internal/modules/academic/service/subject.go index 2b87b51..a577915 100644 --- a/internal/modules/academic/service/subject.go +++ b/internal/modules/academic/service/subject.go @@ -34,7 +34,7 @@ func (s *SubjectService) List(ctx context.Context, filter domain.SubjectListFilt return nil, err } if filter.SortByUserAttribute { - sortSubjects(subjects, filter.SortCourse) + sortSubjects(subjects, filter.SortCourse, filter.SortGrade) } return subjects, nil } @@ -55,6 +55,12 @@ func (s *SubjectService) GetSyllabus(ctx context.Context, subjectID string) (dom return s.syllabusRepo.GetByID(ctx, subject.SyllabusID) } +var classificationOrder = map[domain.SubjectClassification]int{ + domain.SubjectClassificationSpecialized: 0, + domain.SubjectClassificationResearchInstruction: 1, + domain.SubjectClassificationCultural: 2, +} + var courseOrder = map[domain.CourseType]int{ domain.CourseTypeInformationSystem: 0, domain.CourseTypeInformationDesign: 1, @@ -75,6 +81,15 @@ var gradeOrder = map[domain.Grade]int{ domain.GradeD3: 8, } +// classificationRank は科目区分のソートキーを返す。 +// 専門 → 研究指導 → 教養 の順。 +func classificationRank(s domain.Subject) int { + if rank, ok := classificationOrder[s.Classification]; ok { + return rank + } + return math.MaxInt +} + // courseRank はソートキーを返す。 // ユーザーのコースと一致する場合は -1(最優先)、 // それ以外は enum 定義順、Requirements が空なら math.MaxInt(最後)。 @@ -95,14 +110,17 @@ func courseRank(s domain.Subject, userCourse *domain.CourseType) int { } // gradeRank はソートキーを返す。 -// EligibleAttributes の中で最も若い学年の順位を返す。 -// EligibleAttributes が空なら math.MaxInt(最後)。 -func gradeRank(s domain.Subject) int { +// ユーザーの学年と一致する場合は -1(最優先)、 +// それ以外は学年の昇順(B1=0, B2=1, ...)、EligibleAttributes が空なら math.MaxInt(最後)。 +func gradeRank(s domain.Subject, userGrade *domain.Grade) int { if len(s.EligibleAttributes) == 0 { return math.MaxInt } best := math.MaxInt for _, a := range s.EligibleAttributes { + if userGrade != nil && a.Grade == *userGrade { + return -1 + } if rank, ok := gradeOrder[a.Grade]; ok && rank < best { best = rank } @@ -110,11 +128,14 @@ func gradeRank(s domain.Subject) int { return best } -func sortSubjects(subjects []domain.Subject, userCourse *domain.CourseType) { +func sortSubjects(subjects []domain.Subject, userCourse *domain.CourseType, userGrade *domain.Grade) { slices.SortStableFunc(subjects, func(a, b domain.Subject) int { + if c := cmp.Compare(classificationRank(a), classificationRank(b)); c != 0 { + return c + } if c := cmp.Compare(courseRank(a, userCourse), courseRank(b, userCourse)); c != 0 { return c } - return cmp.Compare(gradeRank(a), gradeRank(b)) + return cmp.Compare(gradeRank(a, userGrade), gradeRank(b, userGrade)) }) } From 0de6fd55b8f2a2cb125c526174902cb88238b05c Mon Sep 17 00:00:00 2001 From: Nagata Kuren Date: Fri, 24 Jul 2026 15:55:54 +0900 Subject: [PATCH 12/14] =?UTF-8?q?PR=E3=81=AE=E3=82=B3=E3=83=A1=E3=83=B3?= =?UTF-8?q?=E3=83=88=E3=82=92=E5=8F=8D=E6=98=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/openapi/academic/openapi.yaml | 7 --- cmd/academic-api/main.go | 44 ++++++++++++++++++- gen/academic/api.gen.go | 12 +++++ internal/modules/academic/handler/handler.go | 8 ++-- .../modules/academic/handler/subject_list.go | 2 +- .../modules/academic/repository/convert.go | 13 ++++++ internal/modules/academic/repository/user.go | 13 ------ internal/modules/academic/service/user.go | 24 ++++++++++ 8 files changed, 96 insertions(+), 27 deletions(-) create mode 100644 internal/modules/academic/service/user.go diff --git a/api/openapi/academic/openapi.yaml b/api/openapi/academic/openapi.yaml index d6262f6..f0ad80b 100644 --- a/api/openapi/academic/openapi.yaml +++ b/api/openapi/academic/openapi.yaml @@ -938,13 +938,6 @@ paths: items: $ref: '#/components/schemas/DottoFoundationV1.CulturalSubjectCategory' explode: false - - name: userId - in: query - required: false - description: ユーザーID; 指定した場合はユーザーのコース・学年に近い順にソートする - schema: - type: string - explode: false responses: '200': description: 科目のリスト diff --git a/cmd/academic-api/main.go b/cmd/academic-api/main.go index db32de9..50107ce 100644 --- a/cmd/academic-api/main.go +++ b/cmd/academic-api/main.go @@ -2,6 +2,7 @@ package main import ( "log" + "net/http" "time" api "github.com/fun-dotto/server/gen/academic" @@ -86,11 +87,16 @@ func main() { makeupClassSvc := service.NewMakeupClassService(makeupClassRepo) roomChangeSvc := service.NewRoomChangeService(roomChangeRepo) facultyRoomSvc := service.NewFacultyRoomService(facultyRoomRepo) + userSvc := service.NewUserService(userRepo) // Handler + Router - h := handler.NewHandler(subjectSvc, facultySvc, roomSvc, timetableItemSvc, courseRegistrationSvc, personalCalendarItemSvc, cancelledClassSvc, makeupClassSvc, roomChangeSvc, facultyRoomSvc, userRepo) - strictHandler := api.NewStrictHandler(h, []api.StrictMiddlewareFunc{ + h := handler.NewHandler(subjectSvc, facultySvc, roomSvc, timetableItemSvc, courseRegistrationSvc, personalCalendarItemSvc, cancelledClassSvc, makeupClassSvc, roomChangeSvc, facultyRoomSvc, userSvc) + strictHandler := api.NewStrictHandlerWithOptions(h, []api.StrictMiddlewareFunc{ middleware.DeadlineErrorMapper(), + }, api.StrictGinServerOptions{ + RequestErrorHandlerFunc: requestErrorHandler, + HandlerErrorFunc: handlerErrorHandler, + ResponseErrorHandlerFunc: responseErrorHandler, }) api.RegisterHandlers(router, strictHandler) @@ -98,3 +104,37 @@ func main() { log.Fatalf("Server exited with error: %v", err) } } + +// oapi-codegen が生成する strict handler の既定のエラーハンドラは err.Error() を +// そのままレスポンス本文に載せるため、SQL 文やドライバのエラーメッセージといった +// 内部実装の詳細がクライアントへ露出し得る。本文は固定文言に差し替え、 +// 詳細はサーバー側のログにのみ出力する。 + +const ( + badRequestMessage = "invalid request" + internalErrorMessage = "internal server error" +) + +// requestErrorHandler はリクエストのパース・デコードに失敗した場合に 400 を返す。 +func requestErrorHandler(c *gin.Context, err error) { + logStrictError(c, "request error", err) + c.JSON(http.StatusBadRequest, gin.H{"msg": badRequestMessage}) +} + +// handlerErrorHandler はハンドラ(および strict middleware)が non-nil error を +// 返した場合に 500 を返す。 +func handlerErrorHandler(c *gin.Context, err error) { + logStrictError(c, "handler error", err) + c.JSON(http.StatusInternalServerError, gin.H{"msg": internalErrorMessage}) +} + +// responseErrorHandler はレスポンスのシリアライズに失敗した場合、あるいは想定外の +// レスポンス型が返された場合に 500 を返す。 +func responseErrorHandler(c *gin.Context, err error) { + logStrictError(c, "response error", err) + c.JSON(http.StatusInternalServerError, gin.H{"msg": internalErrorMessage}) +} + +func logStrictError(c *gin.Context, kind string, err error) { + log.Printf("%s: %s %s: %v", kind, c.Request.Method, c.Request.URL.Path, err) +} diff --git a/gen/academic/api.gen.go b/gen/academic/api.gen.go index 45239c4..bf7e051 100644 --- a/gen/academic/api.gen.go +++ b/gen/academic/api.gen.go @@ -3159,6 +3159,18 @@ func NewSubjectsV1ListRequest(server string, params *SubjectsV1ListParams) (*htt } + if params.UserId != nil { + + if queryFrag, err := runtime.StyleParamWithOptions("form", false, "userId", *params.UserId, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "string", Format: ""}); err != nil { + return nil, err + } else { + for _, qp := range strings.Split(queryFrag, "&") { + rawQueryFragments = append(rawQueryFragments, qp) + } + } + + } + if encoded := queryValues.Encode(); encoded != "" { rawQueryFragments = append(rawQueryFragments, encoded) } diff --git a/internal/modules/academic/handler/handler.go b/internal/modules/academic/handler/handler.go index a5f9fce..0f98c07 100644 --- a/internal/modules/academic/handler/handler.go +++ b/internal/modules/academic/handler/handler.go @@ -76,7 +76,7 @@ type facultyRoomService interface { Delete(ctx context.Context, id string) error } -type userRepository interface { +type userService interface { FindByID(ctx context.Context, id string) (domain.User, bool, error) } @@ -91,7 +91,7 @@ type Handler struct { makeupClassSvc makeupClassService roomChangeSvc roomChangeService facultyRoomSvc facultyRoomService - userRepo userRepository + userSvc userService } func NewHandler( @@ -105,7 +105,7 @@ func NewHandler( makeupClassSvc makeupClassService, roomChangeSvc roomChangeService, facultyRoomSvc facultyRoomService, - userRepo userRepository, + userSvc userService, ) *Handler { return &Handler{ subjectSvc: subjectSvc, @@ -118,6 +118,6 @@ func NewHandler( makeupClassSvc: makeupClassSvc, roomChangeSvc: roomChangeSvc, facultyRoomSvc: facultyRoomSvc, - userRepo: userRepo, + userSvc: userSvc, } } diff --git a/internal/modules/academic/handler/subject_list.go b/internal/modules/academic/handler/subject_list.go index 62ef57f..a96addb 100644 --- a/internal/modules/academic/handler/subject_list.go +++ b/internal/modules/academic/handler/subject_list.go @@ -10,7 +10,7 @@ func (h *Handler) SubjectsV1List(ctx context.Context, request api.SubjectsV1List filter := buildSubjectListFilter(request.Params) if request.Params.UserId != nil { - user, found, err := h.userRepo.FindByID(ctx, *request.Params.UserId) + user, found, err := h.userSvc.FindByID(ctx, *request.Params.UserId) if err != nil { return nil, err } diff --git a/internal/modules/academic/repository/convert.go b/internal/modules/academic/repository/convert.go index a6a1908..03f20c7 100644 --- a/internal/modules/academic/repository/convert.go +++ b/internal/modules/academic/repository/convert.go @@ -408,3 +408,16 @@ func timetableItemFromDomain(d domain.TimetableItem) model.TimetableItem { } return m } + +func userToDomain(m model.User) domain.User { + d := domain.User{ID: m.ID} + if m.Course != nil { + c := domain.CourseType(*m.Course) + d.Course = &c + } + if m.Grade != nil { + g := domain.Grade(*m.Grade) + d.Grade = &g + } + return d +} diff --git a/internal/modules/academic/repository/user.go b/internal/modules/academic/repository/user.go index 59537d3..02f8df3 100644 --- a/internal/modules/academic/repository/user.go +++ b/internal/modules/academic/repository/user.go @@ -28,16 +28,3 @@ func (r *UserRepository) FindByID(ctx context.Context, id string) (domain.User, } return userToDomain(record), true, nil } - -func userToDomain(m model.User) domain.User { - u := domain.User{ID: m.ID} - if m.Course != nil { - c := domain.CourseType(*m.Course) - u.Course = &c - } - if m.Grade != nil { - g := domain.Grade(*m.Grade) - u.Grade = &g - } - return u -} diff --git a/internal/modules/academic/service/user.go b/internal/modules/academic/service/user.go new file mode 100644 index 0000000..c9421c3 --- /dev/null +++ b/internal/modules/academic/service/user.go @@ -0,0 +1,24 @@ +package service + +import ( + "context" + + "github.com/fun-dotto/server/internal/modules/academic/domain" +) + +type userRepository interface { + FindByID(ctx context.Context, id string) (domain.User, bool, error) +} + +type UserService struct { + repo userRepository +} + +func NewUserService(repo userRepository) *UserService { + return &UserService{repo: repo} +} + +// FindByID はユーザーを取得する。見つからない場合は found=false を返す。 +func (s *UserService) FindByID(ctx context.Context, id string) (domain.User, bool, error) { + return s.repo.FindByID(ctx, id) +} From de0908a866721a6da3c699dbbc40f783d1abd166 Mon Sep 17 00:00:00 2001 From: Nagata Kuren Date: Fri, 24 Jul 2026 16:23:57 +0900 Subject: [PATCH 13/14] =?UTF-8?q?test=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/academic/service/subject_test.go | 291 ++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 internal/modules/academic/service/subject_test.go diff --git a/internal/modules/academic/service/subject_test.go b/internal/modules/academic/service/subject_test.go new file mode 100644 index 0000000..a89563b --- /dev/null +++ b/internal/modules/academic/service/subject_test.go @@ -0,0 +1,291 @@ +package service + +import ( + "math" + "testing" + + "github.com/fun-dotto/server/internal/modules/academic/domain" +) + +func coursePtr(c domain.CourseType) *domain.CourseType { return &c } + +func gradePtr(g domain.Grade) *domain.Grade { return &g } + +func TestClassificationRank(t *testing.T) { + tests := []struct { + name string + subject domain.Subject + want int + }{ + { + name: "専門が最優先", + subject: domain.Subject{Classification: domain.SubjectClassificationSpecialized}, + want: 0, + }, + { + name: "研究指導は専門の次", + subject: domain.Subject{Classification: domain.SubjectClassificationResearchInstruction}, + want: 1, + }, + { + name: "教養は最後", + subject: domain.Subject{Classification: domain.SubjectClassificationCultural}, + want: 2, + }, + { + name: "未知の区分は最後尾", + subject: domain.Subject{Classification: domain.SubjectClassification("Unknown")}, + want: math.MaxInt, + }, + { + name: "空文字も最後尾", + subject: domain.Subject{}, + want: math.MaxInt, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := classificationRank(tt.subject); got != tt.want { + t.Errorf("classificationRank() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestCourseRank(t *testing.T) { + subjectWith := func(courses ...domain.CourseType) domain.Subject { + reqs := make([]domain.SubjectRequirement, len(courses)) + for i, c := range courses { + reqs[i] = domain.SubjectRequirement{Course: c} + } + return domain.Subject{Requirements: reqs} + } + + tests := []struct { + name string + subject domain.Subject + userCourse *domain.CourseType + want int + }{ + { + name: "ユーザーのコースと一致すれば最優先", + subject: subjectWith(domain.CourseTypeComplexSystem), + userCourse: coursePtr(domain.CourseTypeComplexSystem), + want: -1, + }, + { + name: "複数コースのうち1つでも一致すれば最優先", + subject: subjectWith(domain.CourseTypeInformationSystem, domain.CourseTypeIntelligentSystem), + userCourse: coursePtr(domain.CourseTypeIntelligentSystem), + want: -1, + }, + { + name: "一致しなければ enum 定義順のうち最小", + subject: subjectWith(domain.CourseTypeIntelligentSystem, domain.CourseTypeInformationDesign), + userCourse: coursePtr(domain.CourseTypeComplexSystem), + want: 1, // InformationDesign + }, + { + name: "ユーザーのコースが未設定なら enum 定義順のみ", + subject: subjectWith(domain.CourseTypeAdvancedICT), + userCourse: nil, + want: 2, + }, + { + name: "Requirements が空なら最後尾", + subject: domain.Subject{}, + userCourse: coursePtr(domain.CourseTypeComplexSystem), + want: math.MaxInt, + }, + { + name: "未知のコースのみなら最後尾", + subject: subjectWith(domain.CourseType("Unknown")), + userCourse: coursePtr(domain.CourseTypeComplexSystem), + want: math.MaxInt, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := courseRank(tt.subject, tt.userCourse); got != tt.want { + t.Errorf("courseRank() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestGradeRank(t *testing.T) { + subjectWith := func(grades ...domain.Grade) domain.Subject { + attrs := make([]domain.SubjectTargetClass, len(grades)) + for i, g := range grades { + attrs[i] = domain.SubjectTargetClass{Grade: g} + } + return domain.Subject{EligibleAttributes: attrs} + } + + tests := []struct { + name string + subject domain.Subject + userGrade *domain.Grade + want int + }{ + { + name: "ユーザーの学年と一致すれば最優先", + subject: subjectWith(domain.GradeB3), + userGrade: gradePtr(domain.GradeB3), + want: -1, + }, + { + name: "複数学年のうち1つでも一致すれば最優先", + subject: subjectWith(domain.GradeB1, domain.GradeB4), + userGrade: gradePtr(domain.GradeB4), + want: -1, + }, + { + name: "一致しなければ最も低い学年", + subject: subjectWith(domain.GradeM1, domain.GradeB2), + userGrade: gradePtr(domain.GradeB4), + want: 1, // B2 + }, + { + name: "ユーザーの学年が未設定なら学年昇順のみ", + subject: subjectWith(domain.GradeD1), + userGrade: nil, + want: 6, + }, + { + name: "EligibleAttributes が空なら最後尾", + subject: domain.Subject{}, + userGrade: gradePtr(domain.GradeB1), + want: math.MaxInt, + }, + { + name: "未知の学年のみなら最後尾", + subject: subjectWith(domain.Grade("B9")), + userGrade: gradePtr(domain.GradeB1), + want: math.MaxInt, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := gradeRank(tt.subject, tt.userGrade); got != tt.want { + t.Errorf("gradeRank() = %v, want %v", got, tt.want) + } + }) + } +} + +// newSubject はソート対象の科目を組み立てるヘルパー。 +func newSubject(id string, classification domain.SubjectClassification, course domain.CourseType, grade domain.Grade) domain.Subject { + return domain.Subject{ + ID: id, + Classification: classification, + Requirements: []domain.SubjectRequirement{{Course: course}}, + EligibleAttributes: []domain.SubjectTargetClass{{Grade: grade}}, + } +} + +func TestSortSubjects(t *testing.T) { + tests := []struct { + name string + subjects []domain.Subject + userCourse *domain.CourseType + userGrade *domain.Grade + wantIDs []string + }{ + { + name: "第1キー: 専門 → 研究指導 → 教養", + subjects: []domain.Subject{ + newSubject("cultural", domain.SubjectClassificationCultural, domain.CourseTypeComplexSystem, domain.GradeB1), + newSubject("research", domain.SubjectClassificationResearchInstruction, domain.CourseTypeComplexSystem, domain.GradeB1), + newSubject("specialized", domain.SubjectClassificationSpecialized, domain.CourseTypeComplexSystem, domain.GradeB1), + }, + userCourse: coursePtr(domain.CourseTypeComplexSystem), + userGrade: gradePtr(domain.GradeB1), + wantIDs: []string{"specialized", "research", "cultural"}, + }, + { + name: "第2キー: 同一区分ならユーザーのコースが最優先", + subjects: []domain.Subject{ + newSubject("other", domain.SubjectClassificationSpecialized, domain.CourseTypeIntelligentSystem, domain.GradeB1), + newSubject("mine", domain.SubjectClassificationSpecialized, domain.CourseTypeComplexSystem, domain.GradeB1), + }, + userCourse: coursePtr(domain.CourseTypeComplexSystem), + userGrade: gradePtr(domain.GradeB1), + wantIDs: []string{"mine", "other"}, + }, + { + name: "第3キー: 区分もコースも同じならユーザーの学年が最優先", + subjects: []domain.Subject{ + newSubject("b1", domain.SubjectClassificationSpecialized, domain.CourseTypeComplexSystem, domain.GradeB1), + newSubject("b3", domain.SubjectClassificationSpecialized, domain.CourseTypeComplexSystem, domain.GradeB3), + }, + userCourse: coursePtr(domain.CourseTypeComplexSystem), + userGrade: gradePtr(domain.GradeB3), + wantIDs: []string{"b3", "b1"}, + }, + { + name: "区分がコースより優先される(教養かつ一致コースは専門の後)", + subjects: []domain.Subject{ + newSubject("cultural-mine", domain.SubjectClassificationCultural, domain.CourseTypeComplexSystem, domain.GradeB1), + newSubject("specialized-other", domain.SubjectClassificationSpecialized, domain.CourseTypeIntelligentSystem, domain.GradeB4), + }, + userCourse: coursePtr(domain.CourseTypeComplexSystem), + userGrade: gradePtr(domain.GradeB1), + wantIDs: []string{"specialized-other", "cultural-mine"}, + }, + { + name: "Requirements / EligibleAttributes が空の科目は最後尾", + subjects: []domain.Subject{ + {ID: "empty", Classification: domain.SubjectClassificationSpecialized}, + newSubject("filled", domain.SubjectClassificationSpecialized, domain.CourseTypeIntelligentSystem, domain.GradeB1), + }, + userCourse: coursePtr(domain.CourseTypeComplexSystem), + userGrade: gradePtr(domain.GradeB4), + wantIDs: []string{"filled", "empty"}, + }, + { + name: "全キー同順位なら元の順序を維持する(stable)", + subjects: []domain.Subject{ + newSubject("first", domain.SubjectClassificationSpecialized, domain.CourseTypeComplexSystem, domain.GradeB1), + newSubject("second", domain.SubjectClassificationSpecialized, domain.CourseTypeComplexSystem, domain.GradeB1), + newSubject("third", domain.SubjectClassificationSpecialized, domain.CourseTypeComplexSystem, domain.GradeB1), + }, + userCourse: coursePtr(domain.CourseTypeComplexSystem), + userGrade: gradePtr(domain.GradeB1), + wantIDs: []string{"first", "second", "third"}, + }, + { + name: "コース・学年が未設定のユーザーでも区分と定義順で並ぶ", + subjects: []domain.Subject{ + newSubject("cultural", domain.SubjectClassificationCultural, domain.CourseTypeInformationSystem, domain.GradeB1), + newSubject("specialized", domain.SubjectClassificationSpecialized, domain.CourseTypeIntelligentSystem, domain.GradeB4), + }, + userCourse: nil, + userGrade: nil, + wantIDs: []string{"specialized", "cultural"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sortSubjects(tt.subjects, tt.userCourse, tt.userGrade) + + got := make([]string, len(tt.subjects)) + for i, s := range tt.subjects { + got[i] = s.ID + } + if len(got) != len(tt.wantIDs) { + t.Fatalf("sortSubjects() = %v, want %v", got, tt.wantIDs) + } + for i := range got { + if got[i] != tt.wantIDs[i] { + t.Errorf("sortSubjects() = %v, want %v", got, tt.wantIDs) + break + } + } + }) + } +} From c32b3b19e181e16f40a5b8acb1dcd74e9eb08a72 Mon Sep 17 00:00:00 2001 From: Nagata Kuren Date: Fri, 24 Jul 2026 16:45:01 +0900 Subject: [PATCH 14/14] =?UTF-8?q?copilot=E3=81=AE=E6=8C=87=E6=91=98?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../academic/handler/subject_list_test.go | 167 ++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 internal/modules/academic/handler/subject_list_test.go diff --git a/internal/modules/academic/handler/subject_list_test.go b/internal/modules/academic/handler/subject_list_test.go new file mode 100644 index 0000000..795fc67 --- /dev/null +++ b/internal/modules/academic/handler/subject_list_test.go @@ -0,0 +1,167 @@ +package handler + +import ( + "context" + "errors" + "testing" + + api "github.com/fun-dotto/server/gen/academic" + "github.com/fun-dotto/server/internal/modules/academic/domain" +) + +// fakeSubjectService は List に渡された filter を記録するだけのスタブ。 +type fakeSubjectService struct { + gotFilter domain.SubjectListFilter + called bool +} + +func (f *fakeSubjectService) List(_ context.Context, filter domain.SubjectListFilter) ([]domain.Subject, error) { + f.gotFilter = filter + f.called = true + return nil, nil +} + +func (f *fakeSubjectService) GetByID(context.Context, string) (domain.Subject, error) { + return domain.Subject{}, nil +} + +func (f *fakeSubjectService) Delete(context.Context, string) error { return nil } + +func (f *fakeSubjectService) GetSyllabus(context.Context, string) (domain.Syllabus, error) { + return domain.Syllabus{}, nil +} + +type fakeUserService struct { + user domain.User + found bool + err error + gotID string + called bool +} + +func (f *fakeUserService) FindByID(_ context.Context, id string) (domain.User, bool, error) { + f.gotID = id + f.called = true + return f.user, f.found, f.err +} + +func TestSubjectsV1List_UserAttributeSort(t *testing.T) { + course := domain.CourseTypeComplexSystem + grade := domain.GradeB3 + userID := "firebase-uid-001" + + tests := []struct { + name string + // 入力 + paramUserID *string + userSvc *fakeUserService + // 期待値 + wantUserSvcCalled bool + wantSortEnabled bool + wantSortCourse *domain.CourseType + wantSortGrade *domain.Grade + wantErr bool + }{ + { + name: "userId 未指定ならソートせず UserService も呼ばない", + paramUserID: nil, + userSvc: &fakeUserService{}, + wantUserSvcCalled: false, + wantSortEnabled: false, + }, + { + name: "userId 指定かつユーザーが存在すればソート条件が立つ", + paramUserID: &userID, + userSvc: &fakeUserService{ + user: domain.User{ID: userID, Course: &course, Grade: &grade}, + found: true, + }, + wantUserSvcCalled: true, + wantSortEnabled: true, + wantSortCourse: &course, + wantSortGrade: &grade, + }, + { + name: "ユーザーが存在しなければエラーにせず現行順にフォールバックする", + paramUserID: &userID, + userSvc: &fakeUserService{found: false}, + wantUserSvcCalled: true, + wantSortEnabled: false, + }, + { + name: "コース・学年が未設定のユーザーでもソートは有効になる", + paramUserID: &userID, + userSvc: &fakeUserService{ + user: domain.User{ID: userID}, + found: true, + }, + wantUserSvcCalled: true, + wantSortEnabled: true, + wantSortCourse: nil, + wantSortGrade: nil, + }, + { + name: "UserService がエラーを返せばハンドラもエラーを返す", + paramUserID: &userID, + userSvc: &fakeUserService{err: errors.New("db is down")}, + wantUserSvcCalled: true, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + subjectSvc := &fakeSubjectService{} + h := &Handler{subjectSvc: subjectSvc, userSvc: tt.userSvc} + + _, err := h.SubjectsV1List(context.Background(), api.SubjectsV1ListRequestObject{ + Params: api.SubjectsV1ListParams{UserId: tt.paramUserID}, + }) + + if tt.wantErr { + if err == nil { + t.Fatal("エラーを期待したが nil だった") + } + if subjectSvc.called { + t.Error("エラー時は SubjectService.List を呼ぶべきではない") + } + return + } + if err != nil { + t.Fatalf("予期しないエラー: %v", err) + } + + if tt.userSvc.called != tt.wantUserSvcCalled { + t.Errorf("UserService.FindByID called = %v, want %v", tt.userSvc.called, tt.wantUserSvcCalled) + } + if tt.wantUserSvcCalled && tt.userSvc.gotID != userID { + t.Errorf("FindByID に渡された id = %q, want %q", tt.userSvc.gotID, userID) + } + + got := subjectSvc.gotFilter + if got.SortByUserAttribute != tt.wantSortEnabled { + t.Errorf("SortByUserAttribute = %v, want %v", got.SortByUserAttribute, tt.wantSortEnabled) + } + if !equalCourse(got.SortCourse, tt.wantSortCourse) { + t.Errorf("SortCourse = %v, want %v", got.SortCourse, tt.wantSortCourse) + } + if !equalGrade(got.SortGrade, tt.wantSortGrade) { + t.Errorf("SortGrade = %v, want %v", got.SortGrade, tt.wantSortGrade) + } + }) + } +} + +func equalCourse(a, b *domain.CourseType) bool { + if a == nil || b == nil { + return a == b + } + return *a == *b +} + +func equalGrade(a, b *domain.Grade) bool { + if a == nil || b == nil { + return a == b + } + return *a == *b +}