package admin import ( "net/http" "time" "github.com/gin-gonic/gin" "github.com/gothinkster/golang-gin-realworld-example-app/common" "github.com/gothinkster/golang-gin-realworld-example-app/models" ) // ContractEntry is the contract address entry returned to the frontend. type ContractEntry struct { Name string `json:"name"` ChainID int `json:"chain_id"` Address string `json:"address"` } // GetContracts is a public endpoint that returns all active contract addresses. // Merges infrastructure contracts (system_contracts) and token contracts (assets). func GetContracts(c *gin.Context) { db := common.GetDB() // Infrastructure contracts from system_contracts var sysContracts []models.SystemContract db.Where("is_active = ?", true).Find(&sysContracts) // Token contracts from assets var assets []models.Asset db.Where("is_active = ? AND contract_address != ''", true).Find(&assets) entries := make([]ContractEntry, 0, len(sysContracts)+len(assets)) for _, sc := range sysContracts { if sc.Address != "" { entries = append(entries, ContractEntry{Name: sc.Name, ChainID: sc.ChainID, Address: sc.Address}) } } for _, a := range assets { entries = append(entries, ContractEntry{Name: a.AssetCode, ChainID: a.ChainID, Address: a.ContractAddress}) } c.JSON(http.StatusOK, gin.H{"contracts": entries}) } // --- Admin CRUD for system_contracts --- func ListSystemContracts(c *gin.Context) { db := common.GetDB() p := ParsePagination(c) query := db.Model(&models.SystemContract{}) if v := c.Query("name"); v != "" { query = query.Where("name LIKE ?", "%"+v+"%") } if v := c.Query("chain_id"); v != "" { query = query.Where("chain_id = ?", v) } if v := c.Query("is_active"); v != "" { query = query.Where("is_active = ?", v == "true") } var total int64 query.Count(&total) var items []models.SystemContract if err := query.Order("chain_id ASC, name ASC").Offset(p.Offset()).Limit(p.PageSize).Find(&items).Error; err != nil { Fail(c, http.StatusInternalServerError, "Failed to fetch system contracts") return } OKList(c, items, total) } func GetSystemContract(c *gin.Context) { db := common.GetDB() var item models.SystemContract if err := db.First(&item, c.Param("id")).Error; err != nil { Fail(c, http.StatusNotFound, "System contract not found") return } OK(c, item) } func CreateSystemContract(c *gin.Context) { db := common.GetDB() var item models.SystemContract if err := c.ShouldBindJSON(&item); err != nil { Fail(c, http.StatusBadRequest, err.Error()) return } item.ID = 0 now := time.Now() item.CreatedAt = now item.UpdatedAt = now if err := db.Create(&item).Error; err != nil { Fail(c, http.StatusInternalServerError, err.Error()) return } LogOp(c, "create", "system_contract", "create_system_contract", &item.ID, item) OK(c, item) } func UpdateSystemContract(c *gin.Context) { db := common.GetDB() var existing models.SystemContract if err := db.First(&existing, c.Param("id")).Error; err != nil { Fail(c, http.StatusNotFound, "System contract not found") return } var item models.SystemContract if err := c.ShouldBindJSON(&item); err != nil { Fail(c, http.StatusBadRequest, err.Error()) return } item.ID = existing.ID item.CreatedAt = existing.CreatedAt item.UpdatedAt = time.Now() if err := db.Save(&item).Error; err != nil { Fail(c, http.StatusInternalServerError, err.Error()) return } LogOp(c, "update", "system_contract", "update_system_contract", &item.ID, item) OK(c, item) } func DeleteSystemContract(c *gin.Context) { db := common.GetDB() var item models.SystemContract if err := db.First(&item, c.Param("id")).Error; err != nil { Fail(c, http.StatusNotFound, "System contract not found") return } if err := db.Delete(&item).Error; err != nil { Fail(c, http.StatusInternalServerError, err.Error()) return } LogOp(c, "delete", "system_contract", "delete_system_contract", &item.ID, nil) OK(c, gin.H{"message": "deleted"}) }