From 783ddb1df7769e5c3cf23b5122d03400904dd064 Mon Sep 17 00:00:00 2001 From: GabllaGit Date: Sun, 1 Mar 2026 15:16:05 -0800 Subject: [PATCH 01/11] dto models --- internal/dto/request/announcements.go | 17 +++++++++++++++++ internal/dto/request/event.go | 19 +++++++++++++++++++ internal/dto/request/officer.go | 17 +++++++++++++++++ internal/dto/request/position.go | 19 +++++++++++++++++++ internal/dto/request/tier.go | 15 +++++++++++++++ internal/dto/response/announcements.go | 9 +++++++++ internal/dto/response/event.go | 10 ++++++++++ internal/dto/response/officer.go | 9 +++++++++ internal/dto/response/position.go | 10 ++++++++++ internal/dto/response/tier.go | 8 ++++++++ 10 files changed, 133 insertions(+) create mode 100644 internal/dto/request/announcements.go create mode 100644 internal/dto/request/event.go create mode 100644 internal/dto/request/officer.go create mode 100644 internal/dto/request/position.go create mode 100644 internal/dto/request/tier.go create mode 100644 internal/dto/response/announcements.go create mode 100644 internal/dto/response/event.go create mode 100644 internal/dto/response/officer.go create mode 100644 internal/dto/response/position.go create mode 100644 internal/dto/response/tier.go diff --git a/internal/dto/request/announcements.go b/internal/dto/request/announcements.go new file mode 100644 index 00000000..c6e30afe --- /dev/null +++ b/internal/dto/request/announcements.go @@ -0,0 +1,17 @@ +package dto_request + +type Announcement struct { + Uuid string `json:"uuid"` + Visibility string `json:"visibility"` + AnnounceAt int64 `json:"announce_at"` + DiscordChannelID *string `json:"discord_channel_id"` + DiscordMessageID *string `json:"discord_message_id"` +} + +type UpdateAnnouncement struct { + Uuid string `json:"uuid"` + Visibility *string `json:"visibility"` + AnnounceAt *int64 `json:"announce_at"` + DiscordChannelID *string `json:"discord_channel_id"` + DiscordMessageID *string `json:"discord_message_id"` +} diff --git a/internal/dto/request/event.go b/internal/dto/request/event.go new file mode 100644 index 00000000..102f3439 --- /dev/null +++ b/internal/dto/request/event.go @@ -0,0 +1,19 @@ +package dto_request + +type Event struct { + Uuid string `json:"uuid"` + Location string `json:"location"` + StartAt int64 `json:"start_at"` + EndAt int64 `json:"end_at"` + IsAllDay bool `json:"is_all_day"` + Host string `json:"host"` +} + +type UpdateEvent struct { + Uuid string `json:"uuid"` + Location *string `json:"location"` + StartAt *int64 `json:"start_at"` + EndAt *int64 `json:"end_at"` + IsAllDay *bool `json:"is_all_day"` + Host *string `json:"host"` +} diff --git a/internal/dto/request/officer.go b/internal/dto/request/officer.go new file mode 100644 index 00000000..be1ca31e --- /dev/null +++ b/internal/dto/request/officer.go @@ -0,0 +1,17 @@ +package dto_request + +type Officer struct { + Uuid string `json:"uuid"` + FullName string `json:"full_name"` + Picture *string `json:"picture"` + Github *string `json:"github"` + Discord *string `json:"discord"` +} + +type UpdateOfficer struct { + Uuid string `json:"uuid"` + FullName *string `json:"full_name"` + Picture *string `json:"picture"` + Github *string `json:"github"` + Discord *string `json:"discord"` +} diff --git a/internal/dto/request/position.go b/internal/dto/request/position.go new file mode 100644 index 00000000..9ab4a4dd --- /dev/null +++ b/internal/dto/request/position.go @@ -0,0 +1,19 @@ +package dto_request + +type Position struct { + Oid string `json:"oid"` + Semester string `json:"semester"` + Tier int `json:"tier"` + FullName string `json:"full_name"` + Title *string `json:"title"` + Team *string `json:"team"` +} + +type UpdatePosition struct { + Oid string `json:"oid"` + Semester string `json:"semester"` + Tier int `json:"tier"` + FullName string `json:"full_name"` + Title *string `json:"title"` + Team *string `json:"team"` +} diff --git a/internal/dto/request/tier.go b/internal/dto/request/tier.go new file mode 100644 index 00000000..1f6c62a6 --- /dev/null +++ b/internal/dto/request/tier.go @@ -0,0 +1,15 @@ +package dto_request + +type Tier struct { + Tier int `json:"tier"` + Title *string `json:"title"` + Tindex *int `json:"t_index"` + Team *string `json:"team"` +} + +type UpdateTier struct { + Tier int `json:"tier"` + Title *string `json:"title"` + Tindex *int `json:"t_index"` + Team *string `json:"team"` +} diff --git a/internal/dto/response/announcements.go b/internal/dto/response/announcements.go new file mode 100644 index 00000000..af348a6b --- /dev/null +++ b/internal/dto/response/announcements.go @@ -0,0 +1,9 @@ +package dto_response + +type Announcement struct { + Uuid string `json:"uuid"` + Visibility string `json:"visibility"` + AnnounceAt int64 `json:"announce_at"` + DiscordChannelID string `json:"discord_channel_id"` + DiscordMessageID string `json:"discord_message_id"` +} diff --git a/internal/dto/response/event.go b/internal/dto/response/event.go new file mode 100644 index 00000000..adbef018 --- /dev/null +++ b/internal/dto/response/event.go @@ -0,0 +1,10 @@ +package dto_response + +type Event struct { + Uuid string `json:"uuid"` + Location string `json:"location"` + StartAt int64 `json:"start_at"` + EndAt int64 `json:"end_at"` + IsAllDay bool `json:"is_all_day"` + Host string `json:"host"` +} diff --git a/internal/dto/response/officer.go b/internal/dto/response/officer.go new file mode 100644 index 00000000..f0fbd76e --- /dev/null +++ b/internal/dto/response/officer.go @@ -0,0 +1,9 @@ +package dto_response + +type Officer struct { + Uuid string `json:"uuid"` + FullName string `json:"full_name"` + Picture string `json:"picture"` + Github string `json:"github"` + Discord string `json:"discord"` +} diff --git a/internal/dto/response/position.go b/internal/dto/response/position.go new file mode 100644 index 00000000..5d061ff9 --- /dev/null +++ b/internal/dto/response/position.go @@ -0,0 +1,10 @@ +package dto_response + +type Position struct { + Oid string `json:"oid"` + Semester string `json:"semester"` + Tier int `json:"tier"` + FullName string `json:"tier"` + Title *string `json:"title"` + Team *string `json:"team"` +} diff --git a/internal/dto/response/tier.go b/internal/dto/response/tier.go new file mode 100644 index 00000000..db901827 --- /dev/null +++ b/internal/dto/response/tier.go @@ -0,0 +1,8 @@ +package dto_response + +type Tier struct { + Tier int `json:"tier"` + Title string `json:"title"` + Tindex int `json:"t_index"` + Team string `json:"team"` +} From 3137d0b2535f6cf9bb0ce1c99a81f8409fb651b6 Mon Sep 17 00:00:00 2001 From: GabllaGit Date: Sun, 1 Mar 2026 15:22:13 -0800 Subject: [PATCH 02/11] Make check and test a bit more pretty --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 28b2eab3..a85bb6d9 100644 --- a/Makefile +++ b/Makefile @@ -47,9 +47,13 @@ fmt: ## Format all go files @go fmt ./... check: ## Run static analysis on all go files - staticcheck ./... + @printf "[\t\033[1;34mBuilding project\033[0m\t]\n" + @go build ./... 2>&1 || (printf "\033[1;31;1mError building\033[0m: "; exit 1) + @printf "[\t\033[1;34mRunning staticcheck\033[0m\t]\n" + staticcheck -f stylish ./... test: check ## Run all tests + @printf "[\t\033[1;34mRunning go tests\033[0m\t]\n" go test ./... check-sql: ## Lint all sql files From 1a4d1685c8108d7f9b66fd7596dd5f04850edd7b Mon Sep 17 00:00:00 2001 From: Mark Gaballa Date: Mon, 2 Mar 2026 10:41:18 -0800 Subject: [PATCH 03/11] revert most makefile changes --- Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Makefile b/Makefile index a85bb6d9..c387c8c9 100644 --- a/Makefile +++ b/Makefile @@ -47,13 +47,9 @@ fmt: ## Format all go files @go fmt ./... check: ## Run static analysis on all go files - @printf "[\t\033[1;34mBuilding project\033[0m\t]\n" - @go build ./... 2>&1 || (printf "\033[1;31;1mError building\033[0m: "; exit 1) - @printf "[\t\033[1;34mRunning staticcheck\033[0m\t]\n" staticcheck -f stylish ./... test: check ## Run all tests - @printf "[\t\033[1;34mRunning go tests\033[0m\t]\n" go test ./... check-sql: ## Lint all sql files From a006538a68bf570ef94725e14ca9686cf8840a72 Mon Sep 17 00:00:00 2001 From: Mark Gaballa Date: Mon, 2 Mar 2026 10:49:00 -0800 Subject: [PATCH 04/11] change DTO directories and model names --- internal/dto/{request => }/announcements.go | 2 +- internal/dto/{request => }/event.go | 2 +- internal/dto/{request => }/officer.go | 2 +- internal/dto/{request => }/position.go | 2 +- internal/dto/response/announcements.go | 9 --------- internal/dto/response/event.go | 10 ---------- internal/dto/response/officer.go | 9 --------- internal/dto/response/position.go | 10 ---------- internal/dto/response/tier.go | 8 -------- internal/dto/{request => }/tier.go | 2 +- 10 files changed, 5 insertions(+), 51 deletions(-) rename internal/dto/{request => }/announcements.go (94%) rename internal/dto/{request => }/event.go (95%) rename internal/dto/{request => }/officer.go (94%) rename internal/dto/{request => }/position.go (94%) delete mode 100644 internal/dto/response/announcements.go delete mode 100644 internal/dto/response/event.go delete mode 100644 internal/dto/response/officer.go delete mode 100644 internal/dto/response/position.go delete mode 100644 internal/dto/response/tier.go rename internal/dto/{request => }/tier.go (93%) diff --git a/internal/dto/request/announcements.go b/internal/dto/announcements.go similarity index 94% rename from internal/dto/request/announcements.go rename to internal/dto/announcements.go index c6e30afe..72db7937 100644 --- a/internal/dto/request/announcements.go +++ b/internal/dto/announcements.go @@ -1,6 +1,6 @@ package dto_request -type Announcement struct { +type AnnouncementDto struct { Uuid string `json:"uuid"` Visibility string `json:"visibility"` AnnounceAt int64 `json:"announce_at"` diff --git a/internal/dto/request/event.go b/internal/dto/event.go similarity index 95% rename from internal/dto/request/event.go rename to internal/dto/event.go index 102f3439..1af8529d 100644 --- a/internal/dto/request/event.go +++ b/internal/dto/event.go @@ -1,6 +1,6 @@ package dto_request -type Event struct { +type EventDto struct { Uuid string `json:"uuid"` Location string `json:"location"` StartAt int64 `json:"start_at"` diff --git a/internal/dto/request/officer.go b/internal/dto/officer.go similarity index 94% rename from internal/dto/request/officer.go rename to internal/dto/officer.go index be1ca31e..c1334c80 100644 --- a/internal/dto/request/officer.go +++ b/internal/dto/officer.go @@ -1,6 +1,6 @@ package dto_request -type Officer struct { +type OfficerDto struct { Uuid string `json:"uuid"` FullName string `json:"full_name"` Picture *string `json:"picture"` diff --git a/internal/dto/request/position.go b/internal/dto/position.go similarity index 94% rename from internal/dto/request/position.go rename to internal/dto/position.go index 9ab4a4dd..8a934a04 100644 --- a/internal/dto/request/position.go +++ b/internal/dto/position.go @@ -1,6 +1,6 @@ package dto_request -type Position struct { +type PositionDto struct { Oid string `json:"oid"` Semester string `json:"semester"` Tier int `json:"tier"` diff --git a/internal/dto/response/announcements.go b/internal/dto/response/announcements.go deleted file mode 100644 index af348a6b..00000000 --- a/internal/dto/response/announcements.go +++ /dev/null @@ -1,9 +0,0 @@ -package dto_response - -type Announcement struct { - Uuid string `json:"uuid"` - Visibility string `json:"visibility"` - AnnounceAt int64 `json:"announce_at"` - DiscordChannelID string `json:"discord_channel_id"` - DiscordMessageID string `json:"discord_message_id"` -} diff --git a/internal/dto/response/event.go b/internal/dto/response/event.go deleted file mode 100644 index adbef018..00000000 --- a/internal/dto/response/event.go +++ /dev/null @@ -1,10 +0,0 @@ -package dto_response - -type Event struct { - Uuid string `json:"uuid"` - Location string `json:"location"` - StartAt int64 `json:"start_at"` - EndAt int64 `json:"end_at"` - IsAllDay bool `json:"is_all_day"` - Host string `json:"host"` -} diff --git a/internal/dto/response/officer.go b/internal/dto/response/officer.go deleted file mode 100644 index f0fbd76e..00000000 --- a/internal/dto/response/officer.go +++ /dev/null @@ -1,9 +0,0 @@ -package dto_response - -type Officer struct { - Uuid string `json:"uuid"` - FullName string `json:"full_name"` - Picture string `json:"picture"` - Github string `json:"github"` - Discord string `json:"discord"` -} diff --git a/internal/dto/response/position.go b/internal/dto/response/position.go deleted file mode 100644 index 5d061ff9..00000000 --- a/internal/dto/response/position.go +++ /dev/null @@ -1,10 +0,0 @@ -package dto_response - -type Position struct { - Oid string `json:"oid"` - Semester string `json:"semester"` - Tier int `json:"tier"` - FullName string `json:"tier"` - Title *string `json:"title"` - Team *string `json:"team"` -} diff --git a/internal/dto/response/tier.go b/internal/dto/response/tier.go deleted file mode 100644 index db901827..00000000 --- a/internal/dto/response/tier.go +++ /dev/null @@ -1,8 +0,0 @@ -package dto_response - -type Tier struct { - Tier int `json:"tier"` - Title string `json:"title"` - Tindex int `json:"t_index"` - Team string `json:"team"` -} diff --git a/internal/dto/request/tier.go b/internal/dto/tier.go similarity index 93% rename from internal/dto/request/tier.go rename to internal/dto/tier.go index 1f6c62a6..d148d7b3 100644 --- a/internal/dto/request/tier.go +++ b/internal/dto/tier.go @@ -1,6 +1,6 @@ package dto_request -type Tier struct { +type TierDto struct { Tier int `json:"tier"` Title *string `json:"title"` Tindex *int `json:"t_index"` From 3ff786e2a68da26da98433dc35a538dcbe5e6bd2 Mon Sep 17 00:00:00 2001 From: Josh Holman Date: Tue, 3 Mar 2026 13:34:06 -0800 Subject: [PATCH 05/11] consistent naming --- internal/dto/{announcements.go => announcement.go} | 4 ++-- internal/dto/event.go | 4 ++-- internal/dto/officer.go | 4 ++-- internal/dto/position.go | 4 ++-- internal/dto/tier.go | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) rename internal/dto/{announcements.go => announcement.go} (91%) diff --git a/internal/dto/announcements.go b/internal/dto/announcement.go similarity index 91% rename from internal/dto/announcements.go rename to internal/dto/announcement.go index 72db7937..26124232 100644 --- a/internal/dto/announcements.go +++ b/internal/dto/announcement.go @@ -1,6 +1,6 @@ -package dto_request +package dto -type AnnouncementDto struct { +type Announcement struct { Uuid string `json:"uuid"` Visibility string `json:"visibility"` AnnounceAt int64 `json:"announce_at"` diff --git a/internal/dto/event.go b/internal/dto/event.go index 1af8529d..30ad285e 100644 --- a/internal/dto/event.go +++ b/internal/dto/event.go @@ -1,6 +1,6 @@ -package dto_request +package dto -type EventDto struct { +type Event struct { Uuid string `json:"uuid"` Location string `json:"location"` StartAt int64 `json:"start_at"` diff --git a/internal/dto/officer.go b/internal/dto/officer.go index c1334c80..c22a6f5e 100644 --- a/internal/dto/officer.go +++ b/internal/dto/officer.go @@ -1,6 +1,6 @@ -package dto_request +package dto -type OfficerDto struct { +type Officer struct { Uuid string `json:"uuid"` FullName string `json:"full_name"` Picture *string `json:"picture"` diff --git a/internal/dto/position.go b/internal/dto/position.go index 8a934a04..52181991 100644 --- a/internal/dto/position.go +++ b/internal/dto/position.go @@ -1,6 +1,6 @@ -package dto_request +package dto -type PositionDto struct { +type Position struct { Oid string `json:"oid"` Semester string `json:"semester"` Tier int `json:"tier"` diff --git a/internal/dto/tier.go b/internal/dto/tier.go index d148d7b3..41b2cb89 100644 --- a/internal/dto/tier.go +++ b/internal/dto/tier.go @@ -1,6 +1,6 @@ -package dto_request +package dto -type TierDto struct { +type Tier struct { Tier int `json:"tier"` Title *string `json:"title"` Tindex *int `json:"t_index"` From d3f3ff788cebc6842097a41bf36fa374f929b92d Mon Sep 17 00:00:00 2001 From: Josh Holman Date: Tue, 3 Mar 2026 13:50:35 -0800 Subject: [PATCH 06/11] implment dto for announcement get --- internal/api/handlers/announcement.go | 29 ++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/internal/api/handlers/announcement.go b/internal/api/handlers/announcement.go index 2fc804eb..56bf9b27 100644 --- a/internal/api/handlers/announcement.go +++ b/internal/api/handlers/announcement.go @@ -3,10 +3,14 @@ package handlers import ( + "database/sql" + "errors" + "log" "net/http" "github.com/acmcsufoss/api.acmcsuf.com/internal/api/dbmodels" "github.com/acmcsufoss/api.acmcsuf.com/internal/api/services" + "github.com/acmcsufoss/api.acmcsuf.com/internal/dto" "github.com/gin-gonic/gin" ) @@ -26,7 +30,7 @@ func NewAnnouncementHandler(announcementService services.AnnouncementServicer) * // @Accept json // @Produce json // @Param id path string true "Announcement ID" -// @Success 200 {object} dbmodels.Announcement "Announcement details" +// @Success 200 {object} dto.Announcement "Announcement details" // @Failure 404 {object} map[string]string // @Failure 500 {object} map[string]string // @Router /v1/announcements/{id} [get] @@ -37,7 +41,7 @@ func (h *AnnouncementHandler) GetAnnouncement(c *gin.Context) { announcement, err := h.announcementService.Get(ctx, id) if err != nil { - if err.Error() == "sql: no rows in result set" { + if errors.Is(err, sql.ErrNoRows) { c.JSON(http.StatusNotFound, gin.H{ "error": "Announcement not found", }) @@ -46,9 +50,28 @@ func (h *AnnouncementHandler) GetAnnouncement(c *gin.Context) { c.JSON(http.StatusInternalServerError, gin.H{ "error": "Failed to retrieve announcement", }) + log.Println("Failed to retrieve announcement:", err) + return + } + + // NOTE: We won't have to do this once implement domain models + var discordChannelID *string + if announcement.DiscordChannelID.Valid { + discordChannelID = &announcement.DiscordChannelID.String + } + var discordMessageID *string + if announcement.DiscordMessageID.Valid { + discordMessageID = &announcement.DiscordMessageID.String + } + dto := dto.Announcement{ + Uuid: announcement.Uuid, + Visibility: announcement.Visibility, + AnnounceAt: announcement.AnnounceAt, + DiscordChannelID: discordChannelID, + DiscordMessageID: discordMessageID, } - c.JSON(http.StatusOK, announcement) + c.JSON(http.StatusOK, dto) } func (h *AnnouncementHandler) GetAnnouncements(c *gin.Context) { From a5753b759cbfd092360b79113e98cbe319e6f94b Mon Sep 17 00:00:00 2001 From: Josh Holman Date: Tue, 3 Mar 2026 14:02:55 -0800 Subject: [PATCH 07/11] rengenerate swagger dosc --- internal/api/docs/docs.go | 42 +++++++++++++++++----------------- internal/api/docs/swagger.json | 42 +++++++++++++++++----------------- internal/api/docs/swagger.yaml | 28 +++++++++++------------ 3 files changed, 56 insertions(+), 56 deletions(-) diff --git a/internal/api/docs/docs.go b/internal/api/docs/docs.go index 808210d4..bcc721b6 100644 --- a/internal/api/docs/docs.go +++ b/internal/api/docs/docs.go @@ -94,7 +94,7 @@ const docTemplate = `{ "200": { "description": "Announcement details", "schema": { - "$ref": "#/definitions/dbmodels.Announcement" + "$ref": "#/definitions/dto.Announcement" } }, "404": { @@ -1294,26 +1294,6 @@ const docTemplate = `{ } }, "definitions": { - "dbmodels.Announcement": { - "type": "object", - "properties": { - "announce_at": { - "type": "integer" - }, - "discord_channel_id": { - "$ref": "#/definitions/sql.NullString" - }, - "discord_message_id": { - "$ref": "#/definitions/sql.NullString" - }, - "uuid": { - "type": "string" - }, - "visibility": { - "type": "string" - } - } - }, "dbmodels.CreateAnnouncementParams": { "type": "object", "properties": { @@ -1608,6 +1588,26 @@ const docTemplate = `{ } } }, + "dto.Announcement": { + "type": "object", + "properties": { + "announce_at": { + "type": "integer" + }, + "discord_channel_id": { + "type": "string" + }, + "discord_message_id": { + "type": "string" + }, + "uuid": { + "type": "string" + }, + "visibility": { + "type": "string" + } + } + }, "sql.NullBool": { "type": "object", "properties": { diff --git a/internal/api/docs/swagger.json b/internal/api/docs/swagger.json index 08f86682..edda95ca 100644 --- a/internal/api/docs/swagger.json +++ b/internal/api/docs/swagger.json @@ -83,7 +83,7 @@ "200": { "description": "Announcement details", "schema": { - "$ref": "#/definitions/dbmodels.Announcement" + "$ref": "#/definitions/dto.Announcement" } }, "404": { @@ -1283,26 +1283,6 @@ } }, "definitions": { - "dbmodels.Announcement": { - "type": "object", - "properties": { - "announce_at": { - "type": "integer" - }, - "discord_channel_id": { - "$ref": "#/definitions/sql.NullString" - }, - "discord_message_id": { - "$ref": "#/definitions/sql.NullString" - }, - "uuid": { - "type": "string" - }, - "visibility": { - "type": "string" - } - } - }, "dbmodels.CreateAnnouncementParams": { "type": "object", "properties": { @@ -1597,6 +1577,26 @@ } } }, + "dto.Announcement": { + "type": "object", + "properties": { + "announce_at": { + "type": "integer" + }, + "discord_channel_id": { + "type": "string" + }, + "discord_message_id": { + "type": "string" + }, + "uuid": { + "type": "string" + }, + "visibility": { + "type": "string" + } + } + }, "sql.NullBool": { "type": "object", "properties": { diff --git a/internal/api/docs/swagger.yaml b/internal/api/docs/swagger.yaml index c7679583..b2293a94 100644 --- a/internal/api/docs/swagger.yaml +++ b/internal/api/docs/swagger.yaml @@ -1,17 +1,4 @@ definitions: - dbmodels.Announcement: - properties: - announce_at: - type: integer - discord_channel_id: - $ref: '#/definitions/sql.NullString' - discord_message_id: - $ref: '#/definitions/sql.NullString' - uuid: - type: string - visibility: - type: string - type: object dbmodels.CreateAnnouncementParams: properties: announce_at: @@ -203,6 +190,19 @@ definitions: title: $ref: '#/definitions/sql.NullString' type: object + dto.Announcement: + properties: + announce_at: + type: integer + discord_channel_id: + type: string + discord_message_id: + type: string + uuid: + type: string + visibility: + type: string + type: object sql.NullBool: properties: bool: @@ -317,7 +317,7 @@ paths: "200": description: Announcement details schema: - $ref: '#/definitions/dbmodels.Announcement' + $ref: '#/definitions/dto.Announcement' "404": description: Not Found schema: From 1a4f4473811e1ab1e443c71643cfadc2b579c1c8 Mon Sep 17 00:00:00 2001 From: GabllaGit Date: Tue, 3 Mar 2026 14:42:07 -0800 Subject: [PATCH 08/11] Implement DTO to Post Announcement handler/cli (sponsered by nano) --- internal/api/dbmodels/board.sql.go | 25 +++++++++++++++++++------ internal/api/docs/docs.go | 9 +++++++++ internal/api/docs/swagger.json | 9 +++++++++ internal/api/docs/swagger.yaml | 6 ++++++ internal/api/handlers/announcement.go | 24 ++++++++++++++++++++++-- internal/cli/announcements/post.go | 12 +++++++----- 6 files changed, 72 insertions(+), 13 deletions(-) diff --git a/internal/api/dbmodels/board.sql.go b/internal/api/dbmodels/board.sql.go index 1ce78a0d..217ce3d2 100644 --- a/internal/api/dbmodels/board.sql.go +++ b/internal/api/dbmodels/board.sql.go @@ -56,21 +56,34 @@ INSERT INTO position ( oid, semester, - tier + tier, + full_name, + title, + team ) VALUES -(?, ?, ?) +(?, ?, ?, ?, ?, ?) RETURNING oid, semester, tier, full_name, title, team ` type CreatePositionParams struct { - Oid string `json:"oid"` - Semester string `json:"semester"` - Tier int64 `json:"tier"` + Oid string `json:"oid"` + Semester string `json:"semester"` + Tier int64 `json:"tier"` + FullName string `json:"full_name"` + Title sql.NullString `json:"title"` + Team sql.NullString `json:"team"` } func (q *Queries) CreatePosition(ctx context.Context, arg CreatePositionParams) (Position, error) { - row := q.db.QueryRowContext(ctx, createPosition, arg.Oid, arg.Semester, arg.Tier) + row := q.db.QueryRowContext(ctx, createPosition, + arg.Oid, + arg.Semester, + arg.Tier, + arg.FullName, + arg.Title, + arg.Team, + ) var i Position err := row.Scan( &i.Oid, diff --git a/internal/api/docs/docs.go b/internal/api/docs/docs.go index bcc721b6..7e410d65 100644 --- a/internal/api/docs/docs.go +++ b/internal/api/docs/docs.go @@ -1360,14 +1360,23 @@ const docTemplate = `{ "dbmodels.CreatePositionParams": { "type": "object", "properties": { + "full_name": { + "type": "string" + }, "oid": { "type": "string" }, "semester": { "type": "string" }, + "team": { + "$ref": "#/definitions/sql.NullString" + }, "tier": { "type": "integer" + }, + "title": { + "$ref": "#/definitions/sql.NullString" } } }, diff --git a/internal/api/docs/swagger.json b/internal/api/docs/swagger.json index edda95ca..b26c6f34 100644 --- a/internal/api/docs/swagger.json +++ b/internal/api/docs/swagger.json @@ -1349,14 +1349,23 @@ "dbmodels.CreatePositionParams": { "type": "object", "properties": { + "full_name": { + "type": "string" + }, "oid": { "type": "string" }, "semester": { "type": "string" }, + "team": { + "$ref": "#/definitions/sql.NullString" + }, "tier": { "type": "integer" + }, + "title": { + "$ref": "#/definitions/sql.NullString" } } }, diff --git a/internal/api/docs/swagger.yaml b/internal/api/docs/swagger.yaml index b2293a94..8d0bf9b0 100644 --- a/internal/api/docs/swagger.yaml +++ b/internal/api/docs/swagger.yaml @@ -42,12 +42,18 @@ definitions: type: object dbmodels.CreatePositionParams: properties: + full_name: + type: string oid: type: string semester: type: string + team: + $ref: '#/definitions/sql.NullString' tier: type: integer + title: + $ref: '#/definitions/sql.NullString' type: object dbmodels.CreateTierParams: properties: diff --git a/internal/api/handlers/announcement.go b/internal/api/handlers/announcement.go index 56bf9b27..c66cb45a 100644 --- a/internal/api/handlers/announcement.go +++ b/internal/api/handlers/announcement.go @@ -7,6 +7,7 @@ import ( "errors" "log" "net/http" + "fmt" "github.com/acmcsufoss/api.acmcsuf.com/internal/api/dbmodels" "github.com/acmcsufoss/api.acmcsuf.com/internal/api/services" @@ -103,7 +104,7 @@ func (h *AnnouncementHandler) GetAnnouncements(c *gin.Context) { // @Router /v1/announcements [post] func (h *AnnouncementHandler) CreateAnnouncement(c *gin.Context) { ctx := c.Request.Context() - var params dbmodels.CreateAnnouncementParams + var params dto.Announcement if err := c.ShouldBindJSON(¶ms); err != nil { c.JSON(http.StatusBadRequest, gin.H{ @@ -112,8 +113,27 @@ func (h *AnnouncementHandler) CreateAnnouncement(c *gin.Context) { return } + var chanID sql.NullString + if params.DiscordChannelID != nil { + chanID = sql.NullString{String: *params.DiscordChannelID, Valid: true} + } + + + var msgID sql.NullString + if params.DiscordMessageID != nil { + msgID = sql.NullString{String: *params.DiscordMessageID, Valid: true} + } + dbParams := dbmodels.CreateAnnouncementParams{ + Uuid: params.Uuid, + Visibility: params.Visibility, + AnnounceAt: params.AnnounceAt, + DiscordChannelID: chanID, + DiscordMessageID: msgID, + } + + fmt.Println("DTO ->", params, "\nDBMODEL->", dbParams) // TODO: error out if required fields aren't provided - if err := h.announcementService.Create(ctx, params); err != nil { + if err := h.announcementService.Create(ctx, dbParams); err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": "Failed to create announcement", }) diff --git a/internal/cli/announcements/post.go b/internal/cli/announcements/post.go index fbb2330a..c11332a1 100644 --- a/internal/cli/announcements/post.go +++ b/internal/cli/announcements/post.go @@ -7,10 +7,11 @@ import ( "net/http" "strings" + "github.com/charmbracelet/huh" "github.com/spf13/cobra" - "github.com/acmcsufoss/api.acmcsuf.com/internal/api/dbmodels" + "github.com/acmcsufoss/api.acmcsuf.com/internal/dto" "github.com/acmcsufoss/api.acmcsuf.com/internal/cli/config" "github.com/acmcsufoss/api.acmcsuf.com/internal/cli/forms" "github.com/acmcsufoss/api.acmcsuf.com/internal/cli/oauth" @@ -68,8 +69,8 @@ func postAnnouncement(cfg *config.Config) { } // TODO: Use DTO models instaad of dbmodels -func postForm() (*dbmodels.CreateAnnouncementParams, error) { - var payload dbmodels.CreateAnnouncementParams +func postForm() (*dto.Announcement, error) { + var payload dto.Announcement var err error var ( announceAtStr string @@ -106,12 +107,13 @@ func postForm() (*dbmodels.CreateAnnouncementParams, error) { } // HACK: These conversions won't be necessary once we start using DTO models here + payload.AnnounceAt, err = utils.ByteSlicetoUnix([]byte(announceAtStr)) if err != nil { return nil, err } - payload.DiscordChannelID = utils.StringtoNullString(channelIDStr) - payload.DiscordMessageID = utils.StringtoNullString(messageIDStr) + payload.DiscordChannelID = &channelIDStr + payload.DiscordMessageID = &messageIDStr return &payload, err } From 9b49859455b5d0da7f8bd3c083d9c323b19e13da Mon Sep 17 00:00:00 2001 From: GabllaGit Date: Tue, 3 Mar 2026 19:08:14 -0800 Subject: [PATCH 09/11] fmt --- internal/api/handlers/announcement.go | 9 ++++----- internal/cli/announcements/post.go | 5 ++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/internal/api/handlers/announcement.go b/internal/api/handlers/announcement.go index c66cb45a..a7bf606d 100644 --- a/internal/api/handlers/announcement.go +++ b/internal/api/handlers/announcement.go @@ -5,9 +5,9 @@ package handlers import ( "database/sql" "errors" + "fmt" "log" "net/http" - "fmt" "github.com/acmcsufoss/api.acmcsuf.com/internal/api/dbmodels" "github.com/acmcsufoss/api.acmcsuf.com/internal/api/services" @@ -113,13 +113,12 @@ func (h *AnnouncementHandler) CreateAnnouncement(c *gin.Context) { return } - var chanID sql.NullString + var chanID sql.NullString if params.DiscordChannelID != nil { chanID = sql.NullString{String: *params.DiscordChannelID, Valid: true} } - - var msgID sql.NullString + var msgID sql.NullString if params.DiscordMessageID != nil { msgID = sql.NullString{String: *params.DiscordMessageID, Valid: true} } @@ -130,7 +129,7 @@ func (h *AnnouncementHandler) CreateAnnouncement(c *gin.Context) { DiscordChannelID: chanID, DiscordMessageID: msgID, } - + fmt.Println("DTO ->", params, "\nDBMODEL->", dbParams) // TODO: error out if required fields aren't provided if err := h.announcementService.Create(ctx, dbParams); err != nil { diff --git a/internal/cli/announcements/post.go b/internal/cli/announcements/post.go index c11332a1..96cd7764 100644 --- a/internal/cli/announcements/post.go +++ b/internal/cli/announcements/post.go @@ -7,14 +7,13 @@ import ( "net/http" "strings" - "github.com/charmbracelet/huh" "github.com/spf13/cobra" - "github.com/acmcsufoss/api.acmcsuf.com/internal/dto" "github.com/acmcsufoss/api.acmcsuf.com/internal/cli/config" "github.com/acmcsufoss/api.acmcsuf.com/internal/cli/forms" "github.com/acmcsufoss/api.acmcsuf.com/internal/cli/oauth" + "github.com/acmcsufoss/api.acmcsuf.com/internal/dto" "github.com/acmcsufoss/api.acmcsuf.com/utils" ) @@ -107,7 +106,7 @@ func postForm() (*dto.Announcement, error) { } // HACK: These conversions won't be necessary once we start using DTO models here - + payload.AnnounceAt, err = utils.ByteSlicetoUnix([]byte(announceAtStr)) if err != nil { return nil, err From cde96177623a295c8d33c02881869726ea6d982f Mon Sep 17 00:00:00 2001 From: Mark Gaballa Date: Wed, 4 Mar 2026 12:50:17 -0800 Subject: [PATCH 10/11] Put handler for announcements --- internal/api/handlers/announcement.go | 32 ++++++++++++++++++++++++--- internal/cli/announcements/put.go | 24 +++++++++----------- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/internal/api/handlers/announcement.go b/internal/api/handlers/announcement.go index a7bf606d..98caf443 100644 --- a/internal/api/handlers/announcement.go +++ b/internal/api/handlers/announcement.go @@ -40,7 +40,6 @@ func (h *AnnouncementHandler) GetAnnouncement(c *gin.Context) { id := c.Param("id") announcement, err := h.announcementService.Get(ctx, id) - if err != nil { if errors.Is(err, sql.ErrNoRows) { c.JSON(http.StatusNotFound, gin.H{ @@ -161,7 +160,7 @@ func (h *AnnouncementHandler) CreateAnnouncement(c *gin.Context) { // @Router /v1/announcements/{id} [put] func (h *AnnouncementHandler) UpdateAnnouncement(c *gin.Context) { ctx := c.Request.Context() - var params dbmodels.UpdateAnnouncementParams + var params dto.UpdateAnnouncement id := c.Param("id") if err := c.ShouldBindJSON(¶ms); err != nil { @@ -170,7 +169,34 @@ func (h *AnnouncementHandler) UpdateAnnouncement(c *gin.Context) { }) } - if err := h.announcementService.Update(ctx, id, params); err != nil { + var chanID sql.NullString + if params.DiscordChannelID != nil { + chanID = sql.NullString{String: *params.DiscordChannelID, Valid: true} + } + + var msgID sql.NullString + if params.DiscordMessageID != nil { + msgID = sql.NullString{String: *params.DiscordMessageID, Valid: true} + } + + var vis sql.NullString + if params.Visibility != nil { + vis = sql.NullString{String: *params.Visibility, Valid: true} + } + + var announceAt sql.NullInt64 + if params.AnnounceAt != nil { + announceAt = sql.NullInt64{Int64: *params.AnnounceAt, Valid: true} + } + dbParams := dbmodels.UpdateAnnouncementParams{ + Uuid: params.Uuid, + Visibility: vis, + AnnounceAt: announceAt, + DiscordChannelID: chanID, + DiscordMessageID: msgID, + } + + if err := h.announcementService.Update(ctx, id, dbParams); err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": "Failed to update announcement", }) diff --git a/internal/cli/announcements/put.go b/internal/cli/announcements/put.go index e4ab8047..14651e28 100644 --- a/internal/cli/announcements/put.go +++ b/internal/cli/announcements/put.go @@ -10,9 +10,9 @@ import ( "github.com/charmbracelet/huh" "github.com/spf13/cobra" - "github.com/acmcsufoss/api.acmcsuf.com/internal/api/dbmodels" "github.com/acmcsufoss/api.acmcsuf.com/internal/cli/config" "github.com/acmcsufoss/api.acmcsuf.com/internal/cli/oauth" + "github.com/acmcsufoss/api.acmcsuf.com/internal/dto" "github.com/acmcsufoss/api.acmcsuf.com/utils" ) @@ -58,7 +58,7 @@ func putAnnouncements(id string, cfg *config.Config) { } // ----- Update found announceement ----- - var oldPayload dbmodels.CreateAnnouncementParams + var oldPayload dto.UpdateAnnouncement err = json.Unmarshal(body, &oldPayload) if err != nil { fmt.Println("Error: failed to unmarshal response body:", err) @@ -99,8 +99,8 @@ func putAnnouncements(id string, cfg *config.Config) { } // TODO: Use DTO models instaad of dbmodels -func putForm(uuid string) (*dbmodels.UpdateAnnouncementParams, error) { - var payload dbmodels.UpdateAnnouncementParams +func putForm(uuid string) (*dto.UpdateAnnouncement, error) { + var payload dto.UpdateAnnouncement var err error var ( visibilityStr string @@ -133,21 +133,17 @@ func putForm(uuid string) (*dbmodels.UpdateAnnouncementParams, error) { payload.Uuid = uuid // HACK: These conversions won't be necessary once we start using DTO models here - if visibilityStr != "" { - payload.Visibility = utils.StringtoNullString(visibilityStr) - } + payload.Visibility = &visibilityStr if announceAtStr != "" { timestamp, err := utils.ByteSlicetoUnix([]byte(announceAtStr)) if err != nil { return nil, err } - payload.AnnounceAt = utils.Int64toNullInt64(timestamp) - } - if channelIDStr != "" { - payload.DiscordChannelID = utils.StringtoNullString(channelIDStr) - } - if messageIDStr != "" { - payload.DiscordMessageID = utils.StringtoNullString(messageIDStr) + payload.AnnounceAt = ×tamp } + + payload.DiscordChannelID = &channelIDStr + payload.DiscordMessageID = &messageIDStr + return &payload, nil } From 2bddaef8990859c0ae0e51a90a90f3874c2c90a1 Mon Sep 17 00:00:00 2001 From: Josh Holman Date: Fri, 6 Mar 2026 16:11:54 -0800 Subject: [PATCH 11/11] rm artifacts from dbmodels --- internal/cli/announcements/post.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/internal/cli/announcements/post.go b/internal/cli/announcements/post.go index 96cd7764..a1fa018f 100644 --- a/internal/cli/announcements/post.go +++ b/internal/cli/announcements/post.go @@ -67,7 +67,6 @@ func postAnnouncement(cfg *config.Config) { utils.PrettyPrintJSON(body) } -// TODO: Use DTO models instaad of dbmodels func postForm() (*dto.Announcement, error) { var payload dto.Announcement var err error @@ -105,8 +104,6 @@ func postForm() (*dto.Announcement, error) { return nil, err } - // HACK: These conversions won't be necessary once we start using DTO models here - payload.AnnounceAt, err = utils.ByteSlicetoUnix([]byte(announceAtStr)) if err != nil { return nil, err