Files
rill/internal/note/note.go
T
kevin 84768e94ed Swagger 文档改为按权限分组
- @Tags 由功能维度改为 public/user/admin 权限维度
- main.go 增加全局 tag 声明与权限说明(需放在 @securitydefinitions 之前,否则会被解析器吞掉)
- 重新生成 docs/,公开 4 个、需登录 7 个、管理员 11 个接口
2026-09-21 16:24:19 +08:00

206 lines
6.5 KiB
Go

// Package note 提供便签接口。
package note
import (
"net/http"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"rill/internal/httpx"
"rill/internal/model"
)
// Request 创建/更新便签请求。
type Request struct {
Title string `json:"title" binding:"required,max=200" example:"Shopping list"`
Content string `json:"content" example:"Milk, eggs"`
}
// ListResponse 便签分页列表响应。
type ListResponse struct {
Items []model.Note `json:"items"`
Total int64 `json:"total" example:"42"`
Page int `json:"page" example:"1"`
PageSize int `json:"page_size" example:"20"`
}
// @Summary List notes
// @Description List notes ordered by id DESC. page starts at 1; page_size is 1-100, default 20.
// @Tags user
// @Produce json
// @Param page query int false "Page number, default 1" example(1)
// @Param page_size query int false "Page size, default 20, max 100" example(20)
// @Success 200 {object} note.ListResponse
// @Failure 500 {object} httpx.ErrorResponse
// @Security BearerAuth
// @Failure 401 {object} httpx.ErrorResponse "unauthorized or session expired"
// @Failure 403 {object} httpx.ErrorResponse "account disabled"
// @Router /notes [get]
func List(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
page, pageSize := httpx.ParsePagination(c)
ctx := c.Request.Context()
var total int64
if err := db.WithContext(ctx).Model(&model.Note{}).Count(&total).Error; err != nil {
httpx.RespondDBError(c, err)
return
}
var notes []model.Note
if err := db.WithContext(ctx).
Order("id DESC").
Offset((page - 1) * pageSize).
Limit(pageSize).
Find(&notes).Error; err != nil {
httpx.RespondDBError(c, err)
return
}
c.JSON(http.StatusOK, ListResponse{
Items: notes,
Total: total,
Page: page,
PageSize: pageSize,
})
}
}
// @Summary Create a note
// @Description Create a note. title is required (max 200 chars); content is optional.
// @Tags user
// @Accept json
// @Produce json
// @Param note body note.Request true "Note payload"
// @Success 201 {object} model.Note
// @Failure 400 {object} httpx.ErrorResponse "invalid request"
// @Failure 500 {object} httpx.ErrorResponse
// @Security BearerAuth
// @Failure 401 {object} httpx.ErrorResponse "unauthorized or session expired"
// @Failure 403 {object} httpx.ErrorResponse "account disabled"
// @Router /notes [post]
func Create(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
var req Request
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, httpx.ErrorResponse{Error: "invalid request: " + err.Error()})
return
}
note := model.Note{Title: req.Title, Content: req.Content}
if err := db.WithContext(c.Request.Context()).Create(&note).Error; err != nil {
httpx.RespondDBError(c, err)
return
}
c.JSON(http.StatusCreated, note)
}
}
// @Summary Get a note
// @Description Get a note by id.
// @Tags user
// @Produce json
// @Param id path int true "Note ID" example(1)
// @Success 200 {object} model.Note
// @Failure 400 {object} httpx.ErrorResponse "invalid id"
// @Failure 404 {object} httpx.ErrorResponse "record not found"
// @Failure 500 {object} httpx.ErrorResponse
// @Security BearerAuth
// @Failure 401 {object} httpx.ErrorResponse "unauthorized or session expired"
// @Failure 403 {object} httpx.ErrorResponse "account disabled"
// @Router /notes/{id} [get]
func Get(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
id, ok := httpx.ParseID(c)
if !ok {
return
}
var note model.Note
if err := db.WithContext(c.Request.Context()).First(&note, id).Error; err != nil {
httpx.RespondGetError(c, err)
return
}
c.JSON(http.StatusOK, note)
}
}
// @Summary Update a note
// @Description Update title and content; validation is the same as create.
// @Tags user
// @Accept json
// @Produce json
// @Param id path int true "Note ID" example(1)
// @Param note body note.Request true "Note payload"
// @Success 200 {object} model.Note
// @Failure 400 {object} httpx.ErrorResponse "invalid request or id"
// @Failure 404 {object} httpx.ErrorResponse "record not found"
// @Failure 500 {object} httpx.ErrorResponse
// @Security BearerAuth
// @Failure 401 {object} httpx.ErrorResponse "unauthorized or session expired"
// @Failure 403 {object} httpx.ErrorResponse "account disabled"
// @Router /notes/{id} [put]
func Update(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
id, ok := httpx.ParseID(c)
if !ok {
return
}
var req Request
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, httpx.ErrorResponse{Error: "invalid request: " + err.Error()})
return
}
ctx := c.Request.Context()
var note model.Note
if err := db.WithContext(ctx).First(&note, id).Error; err != nil {
httpx.RespondGetError(c, err)
return
}
note.Title = req.Title
note.Content = req.Content
if err := db.WithContext(ctx).Save(&note).Error; err != nil {
httpx.RespondDBError(c, err)
return
}
c.JSON(http.StatusOK, note)
}
}
// @Summary Delete a note
// @Description Delete a note by id; returns 204 with no body on success.
// @Tags user
// @Produce json
// @Param id path int true "Note ID" example(1)
// @Success 204 "Deleted"
// @Failure 400 {object} httpx.ErrorResponse "invalid id"
// @Failure 404 {object} httpx.ErrorResponse "record not found"
// @Failure 500 {object} httpx.ErrorResponse
// @Security BearerAuth
// @Failure 401 {object} httpx.ErrorResponse "unauthorized or session expired"
// @Failure 403 {object} httpx.ErrorResponse "account disabled"
// @Router /notes/{id} [delete]
func Delete(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
id, ok := httpx.ParseID(c)
if !ok {
return
}
result := db.WithContext(c.Request.Context()).Delete(&model.Note{}, id)
if result.Error != nil {
httpx.RespondDBError(c, result.Error)
return
}
if result.RowsAffected == 0 {
c.JSON(http.StatusNotFound, httpx.ErrorResponse{Error: "record not found"})
return
}
c.Status(http.StatusNoContent)
}
}