소스 검색

feat: 友情链接列表

runningwater 5 달 전
부모
커밋
16a1b2bbeb

+ 17 - 0
app/http/controllers/api/v1/links_controller.go

@@ -0,0 +1,17 @@
+package v1
+
+import (
+	"github.com/runningwater/gohub/app/models/link"
+	"github.com/runningwater/gohub/pkg/response"
+
+	"github.com/gin-gonic/gin"
+)
+
+type LinksController struct {
+	BaseApiController
+}
+
+func (ctrl *LinksController) Index(c *gin.Context) {
+	links := link.All()
+	response.Data(c, links)
+}

+ 11 - 0
app/models/link/link_hooks.go

@@ -0,0 +1,11 @@
+package link
+
+// func (link *Link) BeforeSave(tx *gorm.DB) (err error) {}
+// func (link *Link) BeforeCreate(tx *gorm.DB) (err error) {}
+// func (link *Link) AfterCreate(tx *gorm.DB) (err error) {}
+// func (link *Link) BeforeUpdate(tx *gorm.DB) (err error) {}
+// func (link *Link) AfterUpdate(tx *gorm.DB) (err error) {}
+// func (link *Link) AfterSave(tx *gorm.DB) (err error) {}
+// func (link *Link) BeforeDelete(tx *gorm.DB) (err error) {}
+// func (link *Link) AfterDelete(tx *gorm.DB) (err error) {}
+// func (link *Link) AfterFind(tx *gorm.DB) (err error) {}

+ 30 - 0
app/models/link/link_model.go

@@ -0,0 +1,30 @@
+// Package link 模型
+package link
+
+import (
+	"github.com/runningwater/gohub/app/models"
+	"github.com/runningwater/gohub/pkg/database"
+)
+
+type Link struct {
+	models.BaseModel
+
+	Name string `json:"name,omitempty"`
+	URL  string `json:"url,omitempty"`
+
+	models.CommonTimestampsField
+}
+
+func (link *Link) Create() {
+	database.DB.Create(&link)
+}
+
+func (link *Link) Save() (rowsAffected int64) {
+	result := database.DB.Save(&link)
+	return result.RowsAffected
+}
+
+func (link *Link) Delete() (rowsAffected int64) {
+	result := database.DB.Delete(&link)
+	return result.RowsAffected
+}

+ 42 - 0
app/models/link/link_util.go

@@ -0,0 +1,42 @@
+package link
+
+import (
+	"github.com/gin-gonic/gin"
+
+	"github.com/runningwater/gohub/pkg/app"
+	"github.com/runningwater/gohub/pkg/database"
+	"github.com/runningwater/gohub/pkg/paginator"
+)
+
+func Get(idStr string) (link Link) {
+	database.DB.Where("id", idStr).First(&link)
+	return
+}
+
+func GetBy(field, value string) (link Link) {
+	database.DB.Where("? = ?", field, value).First(&link)
+	return
+}
+
+func All() (links []Link) {
+	database.DB.Find(&links)
+	return
+}
+
+func IsExist(field, value string) bool {
+	var count int64
+	database.DB.Model(Link{}).Where("? = ?", field, value).Count(&count)
+	return count > 0
+}
+
+// Paginate 分页内容
+func Paginate(c *gin.Context, pageSize int) (links []Link, paging paginator.Paging) {
+	paging = paginator.Paginate(
+		c,
+		database.DB.Model(Link{}),
+		&links,
+		app.V1URL(database.TableName(&Link{})),
+		pageSize,
+	)
+	return
+}

+ 24 - 0
database/factories/link_factory.go

@@ -0,0 +1,24 @@
+// Package factories 存放 link 工厂方法
+package factories
+
+import (
+	"github.com/bxcodec/faker/v4"
+
+	"github.com/runningwater/gohub/app/models/link"
+)
+
+func MakeLinks(times int) []link.Link {
+	var objs []link.Link
+
+	// 设置唯一值, 如 Link 模型中的某个字段需要唯一
+	faker.SetGenerateUniqueValues(true)
+
+	for range times {
+		model := link.Link{
+			Name: faker.Username(),
+			URL:  faker.URL(),
+		}
+		objs = append(objs, model)
+	}
+	return objs
+}

+ 30 - 0
database/migrations/2025_07_21_091558_add_links_table.go

@@ -0,0 +1,30 @@
+package migrations
+
+import (
+	"gorm.io/gorm"
+
+	"github.com/runningwater/gohub/app/models"
+	"github.com/runningwater/gohub/pkg/migrate"
+)
+
+func init() {
+
+	type Link struct {
+		models.BaseModel
+
+		Name string `gorm:"type:varchar(255);not null"`
+		URL  string `gorm:"type:varchar(255);default:null"`
+
+		models.CommonTimestampsField
+	}
+
+	up := func(migrator gorm.Migrator, DB *gorm.DB) {
+		_ = DB.Set("gorm:table_options", "ENGINE=InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci comment='友情链接'").AutoMigrate(&Link{})
+	}
+
+	down := func(migrator gorm.Migrator, DB *gorm.DB) {
+		_ = migrator.DropTable(&Link{})
+	}
+
+	migrate.Add(up, down, "2025_07_21_091558_add_links_table")
+}

+ 1 - 0
database/seeders/init.go

@@ -11,5 +11,6 @@ func Initialize() {
 		"UsersTableSeeder",
 		"CategoriesTableSeeder",
 		"TopicsTableSeeder",
+		"LinksTableSeeder",
 	})
 }

+ 31 - 0
database/seeders/link_seeder.go

@@ -0,0 +1,31 @@
+package seeders
+
+import (
+	"fmt"
+
+	"gorm.io/gorm"
+
+	"github.com/runningwater/gohub/database/factories"
+	"github.com/runningwater/gohub/pkg/console"
+	"github.com/runningwater/gohub/pkg/logger"
+	"github.com/runningwater/gohub/pkg/seed"
+)
+
+func init() {
+	// 添加 Seeder
+	seed.Add("LinksTableSeeder", func(db *gorm.DB) {
+		// 创建 10 个用户对象
+		links := factories.MakeLinks(5)
+
+		// 批量插入到数据库
+		result := db.Table("links").Create(&links)
+
+		if err := result.Error; err != nil {
+			logger.LogIf(err)
+			return
+		}
+
+		// 打印成功信息
+		console.Success(fmt.Sprintf("Table [%v] %v rows seeded", result.Statement.Table, result.RowsAffected))
+	})
+}

+ 8 - 0
gohub.http

@@ -159,3 +159,11 @@ Content-Type: application/json
 DELETE {{base_url}}/v1/topics/1 HTTP/1.1
 Authorization: Bearer {{access_token}}
 Content-Type: application/json
+
+### 话题列表
+GET {{base_url}}/v1/topics HTTP/1.1
+Content-Type: application/json
+
+### 友情链接列表
+GET {{base_url}}/v1/links HTTP/1.1
+Content-Type: application/json

+ 5 - 0
routes/api.go

@@ -75,5 +75,10 @@ func RegisterAPIRoutes(router *gin.Engine) {
 			tpcGroup.DELETE("/:id", middlewares.AuthJWT(), tpc.Delete)
 			tpcGroup.GET("/:id", tpc.Show)
 		}
+		lsc := new(controllers.LinksController)
+		linksGroup := v1.Group("/links")
+		{
+			linksGroup.GET("", lsc.Index)
+		}
 	}
 }