748 lines
24 KiB
Go
748 lines
24 KiB
Go
package controllers
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"gorm.io/gorm"
|
|
|
|
"goaresv3/app/settings/models"
|
|
"goaresv3/config"
|
|
)
|
|
|
|
type UpsertSettingRequest struct {
|
|
Title string `json:"title" binding:"required,max=254"`
|
|
MetaTitle string `json:"meta_title" binding:"required,max=254"`
|
|
MetaDescription string `json:"meta_description" binding:"required,max=254"`
|
|
Phone string `json:"phone" binding:"required,max=254"`
|
|
URL string `json:"url" binding:"required,max=254"`
|
|
Email string `json:"email" binding:"required,email,max=254"`
|
|
Facebook string `json:"facebook" binding:"omitempty,max=254"`
|
|
X string `json:"x" binding:"omitempty,max=254"`
|
|
Instagram string `json:"instagram" binding:"omitempty,max=254"`
|
|
Whatsapp string `json:"whatsapp" binding:"omitempty,max=254"`
|
|
Pinterest string `json:"pinterest" binding:"omitempty,max=254"`
|
|
Linkedin string `json:"linkedin" binding:"omitempty,max=254"`
|
|
Slogan string `json:"slogan" binding:"omitempty,max=254"`
|
|
Address string `json:"address"`
|
|
Copyright string `json:"copyright" binding:"omitempty,max=254"`
|
|
MapEmbed string `json:"map_embed"`
|
|
WLogo string `json:"w_logo"`
|
|
BLogo string `json:"b_logo"`
|
|
IsActive bool `json:"is_active"`
|
|
WWidth int `json:"w_width"`
|
|
WHeight int `json:"w_height"`
|
|
WQuality int `json:"w_quality"`
|
|
WFormat string `json:"w_format" binding:"omitempty,max=10"`
|
|
BWidth int `json:"b_width"`
|
|
BHeight int `json:"b_height"`
|
|
BQuality int `json:"b_quality"`
|
|
BFormat string `json:"b_format" binding:"omitempty,max=10"`
|
|
}
|
|
|
|
type UpsertHeroRequest struct {
|
|
Color string `json:"color" binding:"required,max=32"`
|
|
Title string `json:"title" binding:"omitempty,max=254"`
|
|
Text1 string `json:"text1" binding:"omitempty,max=254"`
|
|
Text2 string `json:"text2" binding:"omitempty,max=254"`
|
|
Text4 string `json:"text4" binding:"omitempty,max=254"`
|
|
Text5 string `json:"text5" binding:"omitempty,max=254"`
|
|
Image string `json:"image" binding:"omitempty,max=254"`
|
|
IsActive bool `json:"is_active"`
|
|
Width int `json:"width"`
|
|
Height int `json:"height"`
|
|
Quality int `json:"quality"`
|
|
Format string `json:"format" binding:"omitempty,max=10"`
|
|
}
|
|
|
|
type UpsertCorsWhitelistRequest struct {
|
|
Origin string `json:"origin" binding:"required,max=255"`
|
|
Description string `json:"description" binding:"omitempty,max=255"`
|
|
IsActive bool `json:"is_active"`
|
|
CreatedBy string `json:"created_by" binding:"omitempty,max=255"`
|
|
}
|
|
|
|
type UpsertCorsBlacklistRequest struct {
|
|
Origin string `json:"origin" binding:"required,max=255"`
|
|
Reason string `json:"reason" binding:"omitempty,max=255"`
|
|
IsActive bool `json:"is_active"`
|
|
CreatedBy string `json:"created_by" binding:"omitempty,max=255"`
|
|
}
|
|
|
|
type UpsertRateLimitRequest struct {
|
|
Name string `json:"name" binding:"required,max=100"`
|
|
Description string `json:"description" binding:"omitempty,max=255"`
|
|
MaxRequests int64 `json:"max_requests" binding:"required,min=1"`
|
|
WindowSeconds int `json:"window_seconds" binding:"required,min=1"`
|
|
IsActive bool `json:"is_active"`
|
|
UpdatedBy string `json:"updated_by" binding:"omitempty,max=255"`
|
|
}
|
|
|
|
func parseID(c *gin.Context) (uint64, bool) {
|
|
id, err := strconv.ParseUint(strings.TrimSpace(c.Param("id")), 10, 64)
|
|
if err != nil || id == 0 {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
|
return 0, false
|
|
}
|
|
return id, true
|
|
}
|
|
|
|
// GetSetting godoc
|
|
// @Summary Get global setting
|
|
// @Description Returns the latest settings record.
|
|
// @Tags Settings
|
|
// @Produce json
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Failure 404 {object} map[string]string
|
|
// @Failure 500 {object} map[string]string
|
|
// @Router /api/v1/settings [get]
|
|
func GetSetting(c *gin.Context) {
|
|
var setting models.Setting
|
|
err := config.DB.Order("id DESC").First(&setting).Error
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "setting not found"})
|
|
return
|
|
}
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch setting"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, setting)
|
|
}
|
|
|
|
// UpsertSetting godoc
|
|
// @Summary Create or update global setting
|
|
// @Description Creates the first setting record if none exists, otherwise updates the latest one.
|
|
// @Tags Settings
|
|
// @Security BearerAuth
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body UpsertSettingRequest true "setting payload"
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Success 201 {object} map[string]interface{}
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 500 {object} map[string]string
|
|
// @Router /api/v1/settings [put]
|
|
func UpsertSetting(c *gin.Context) {
|
|
var req UpsertSettingRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
var setting models.Setting
|
|
err := config.DB.Order("id DESC").First(&setting).Error
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
setting = models.Setting{
|
|
Title: req.Title,
|
|
MetaTitle: req.MetaTitle,
|
|
MetaDescription: req.MetaDescription,
|
|
Phone: req.Phone,
|
|
URL: req.URL,
|
|
Email: req.Email,
|
|
Facebook: req.Facebook,
|
|
X: req.X,
|
|
Instagram: req.Instagram,
|
|
Whatsapp: req.Whatsapp,
|
|
Pinterest: req.Pinterest,
|
|
Linkedin: req.Linkedin,
|
|
Slogan: req.Slogan,
|
|
Address: req.Address,
|
|
Copyright: req.Copyright,
|
|
MapEmbed: req.MapEmbed,
|
|
WLogo: req.WLogo,
|
|
BLogo: req.BLogo,
|
|
IsActive: req.IsActive,
|
|
WWidth: req.WWidth,
|
|
WHeight: req.WHeight,
|
|
WQuality: req.WQuality,
|
|
WFormat: req.WFormat,
|
|
BWidth: req.BWidth,
|
|
BHeight: req.BHeight,
|
|
BQuality: req.BQuality,
|
|
BFormat: req.BFormat,
|
|
}
|
|
if createErr := config.DB.Create(&setting).Error; createErr != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create setting"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusCreated, setting)
|
|
return
|
|
}
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch setting"})
|
|
return
|
|
}
|
|
|
|
updates := map[string]any{
|
|
"title": req.Title,
|
|
"meta_title": req.MetaTitle,
|
|
"meta_description": req.MetaDescription,
|
|
"phone": req.Phone,
|
|
"url": req.URL,
|
|
"email": req.Email,
|
|
"facebook": req.Facebook,
|
|
"x": req.X,
|
|
"instagram": req.Instagram,
|
|
"whatsapp": req.Whatsapp,
|
|
"pinterest": req.Pinterest,
|
|
"linkedin": req.Linkedin,
|
|
"slogan": req.Slogan,
|
|
"address": req.Address,
|
|
"copyright": req.Copyright,
|
|
"map_embed": req.MapEmbed,
|
|
"w_logo": req.WLogo,
|
|
"b_logo": req.BLogo,
|
|
"is_active": req.IsActive,
|
|
"w_width": req.WWidth,
|
|
"w_height": req.WHeight,
|
|
"w_quality": req.WQuality,
|
|
"w_format": req.WFormat,
|
|
"b_width": req.BWidth,
|
|
"b_height": req.BHeight,
|
|
"b_quality": req.BQuality,
|
|
"b_format": req.BFormat,
|
|
}
|
|
if err := config.DB.Model(&setting).Updates(updates).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to update setting"})
|
|
return
|
|
}
|
|
|
|
if err := config.DB.First(&setting, setting.ID).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch updated setting"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, setting)
|
|
}
|
|
|
|
// ListHeroes godoc
|
|
// @Summary List heroes
|
|
// @Description Returns all hero records ordered by id desc.
|
|
// @Tags Settings
|
|
// @Produce json
|
|
// @Success 200 {array} map[string]interface{}
|
|
// @Failure 500 {object} map[string]string
|
|
// @Router /api/v1/settings/heroes [get]
|
|
func ListHeroes(c *gin.Context) {
|
|
var heroes []models.Hero
|
|
if err := config.DB.Order("id DESC").Find(&heroes).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch heroes"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, heroes)
|
|
}
|
|
|
|
// CreateHero godoc
|
|
// @Summary Create hero
|
|
// @Description Creates a new hero record.
|
|
// @Tags Settings
|
|
// @Security BearerAuth
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body UpsertHeroRequest true "hero payload"
|
|
// @Success 201 {object} map[string]interface{}
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 500 {object} map[string]string
|
|
// @Router /api/v1/settings/heroes [post]
|
|
func CreateHero(c *gin.Context) {
|
|
var req UpsertHeroRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
hero := models.Hero{
|
|
Color: req.Color,
|
|
Title: req.Title,
|
|
Text1: req.Text1,
|
|
Text2: req.Text2,
|
|
Text4: req.Text4,
|
|
Text5: req.Text5,
|
|
Image: req.Image,
|
|
IsActive: req.IsActive,
|
|
Width: req.Width,
|
|
Height: req.Height,
|
|
Quality: req.Quality,
|
|
Format: req.Format,
|
|
}
|
|
if err := config.DB.Create(&hero).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create hero"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusCreated, hero)
|
|
}
|
|
|
|
// UpdateHero godoc
|
|
// @Summary Update hero
|
|
// @Description Updates a hero by id.
|
|
// @Tags Settings
|
|
// @Security BearerAuth
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path int true "hero id"
|
|
// @Param request body UpsertHeroRequest true "hero payload"
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 404 {object} map[string]string
|
|
// @Failure 500 {object} map[string]string
|
|
// @Router /api/v1/settings/heroes/{id} [put]
|
|
func UpdateHero(c *gin.Context) {
|
|
id, ok := parseID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
var req UpsertHeroRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
var hero models.Hero
|
|
if err := config.DB.First(&hero, id).Error; errors.Is(err, gorm.ErrRecordNotFound) {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "hero not found"})
|
|
return
|
|
} else if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch hero"})
|
|
return
|
|
}
|
|
|
|
if err := config.DB.Model(&hero).Updates(map[string]any{
|
|
"color": req.Color,
|
|
"title": req.Title,
|
|
"text1": req.Text1,
|
|
"text2": req.Text2,
|
|
"text4": req.Text4,
|
|
"text5": req.Text5,
|
|
"image": req.Image,
|
|
"is_active": req.IsActive,
|
|
"width": req.Width,
|
|
"height": req.Height,
|
|
"quality": req.Quality,
|
|
"format": req.Format,
|
|
}).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to update hero"})
|
|
return
|
|
}
|
|
|
|
if err := config.DB.First(&hero, id).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch updated hero"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, hero)
|
|
}
|
|
|
|
// DeleteHero godoc
|
|
// @Summary Delete hero
|
|
// @Description Deletes a hero by id.
|
|
// @Tags Settings
|
|
// @Security BearerAuth
|
|
// @Produce json
|
|
// @Param id path int true "hero id"
|
|
// @Success 200 {object} map[string]string
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 404 {object} map[string]string
|
|
// @Failure 500 {object} map[string]string
|
|
// @Router /api/v1/settings/heroes/{id} [delete]
|
|
func DeleteHero(c *gin.Context) {
|
|
id, ok := parseID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
res := config.DB.Delete(&models.Hero{}, id)
|
|
if res.Error != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete hero"})
|
|
return
|
|
}
|
|
if res.RowsAffected == 0 {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "hero not found"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"message": "hero deleted"})
|
|
}
|
|
|
|
// ListCorsWhitelists godoc
|
|
// @Summary List CORS whitelist items
|
|
// @Description Returns all CORS whitelist records.
|
|
// @Tags Settings
|
|
// @Security BearerAuth
|
|
// @Produce json
|
|
// @Success 200 {array} map[string]interface{}
|
|
// @Failure 500 {object} map[string]string
|
|
// @Router /api/v1/settings/cors/whitelist [get]
|
|
func ListCorsWhitelists(c *gin.Context) {
|
|
var items []models.CorsWhitelist
|
|
if err := config.DB.Order("id DESC").Find(&items).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch cors whitelists"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, items)
|
|
}
|
|
|
|
// CreateCorsWhitelist godoc
|
|
// @Summary Create CORS whitelist item
|
|
// @Description Creates a new whitelist origin.
|
|
// @Tags Settings
|
|
// @Security BearerAuth
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body UpsertCorsWhitelistRequest true "cors whitelist payload"
|
|
// @Success 201 {object} map[string]interface{}
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 409 {object} map[string]string
|
|
// @Router /api/v1/settings/cors/whitelist [post]
|
|
func CreateCorsWhitelist(c *gin.Context) {
|
|
var req UpsertCorsWhitelistRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
item := models.CorsWhitelist{
|
|
Origin: req.Origin,
|
|
Description: req.Description,
|
|
IsActive: req.IsActive,
|
|
CreatedBy: req.CreatedBy,
|
|
}
|
|
if err := config.DB.Create(&item).Error; err != nil {
|
|
c.JSON(http.StatusConflict, gin.H{"error": "failed to create cors whitelist"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusCreated, item)
|
|
}
|
|
|
|
// UpdateCorsWhitelist godoc
|
|
// @Summary Update CORS whitelist item
|
|
// @Description Updates a whitelist origin by id.
|
|
// @Tags Settings
|
|
// @Security BearerAuth
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path int true "whitelist id"
|
|
// @Param request body UpsertCorsWhitelistRequest true "cors whitelist payload"
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 404 {object} map[string]string
|
|
// @Failure 409 {object} map[string]string
|
|
// @Router /api/v1/settings/cors/whitelist/{id} [put]
|
|
func UpdateCorsWhitelist(c *gin.Context) {
|
|
id, ok := parseID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
var req UpsertCorsWhitelistRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
var item models.CorsWhitelist
|
|
if err := config.DB.First(&item, id).Error; errors.Is(err, gorm.ErrRecordNotFound) {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "cors whitelist not found"})
|
|
return
|
|
} else if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch cors whitelist"})
|
|
return
|
|
}
|
|
if err := config.DB.Model(&item).Updates(map[string]any{
|
|
"origin": req.Origin,
|
|
"description": req.Description,
|
|
"is_active": req.IsActive,
|
|
"created_by": req.CreatedBy,
|
|
}).Error; err != nil {
|
|
c.JSON(http.StatusConflict, gin.H{"error": "failed to update cors whitelist"})
|
|
return
|
|
}
|
|
if err := config.DB.First(&item, id).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch updated cors whitelist"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, item)
|
|
}
|
|
|
|
// DeleteCorsWhitelist godoc
|
|
// @Summary Delete CORS whitelist item
|
|
// @Description Deletes a whitelist origin by id.
|
|
// @Tags Settings
|
|
// @Security BearerAuth
|
|
// @Produce json
|
|
// @Param id path int true "whitelist id"
|
|
// @Success 200 {object} map[string]string
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 404 {object} map[string]string
|
|
// @Failure 500 {object} map[string]string
|
|
// @Router /api/v1/settings/cors/whitelist/{id} [delete]
|
|
func DeleteCorsWhitelist(c *gin.Context) {
|
|
id, ok := parseID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
res := config.DB.Delete(&models.CorsWhitelist{}, id)
|
|
if res.Error != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete cors whitelist"})
|
|
return
|
|
}
|
|
if res.RowsAffected == 0 {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "cors whitelist not found"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"message": "cors whitelist deleted"})
|
|
}
|
|
|
|
// ListCorsBlacklists godoc
|
|
// @Summary List CORS blacklist items
|
|
// @Description Returns all CORS blacklist records.
|
|
// @Tags Settings
|
|
// @Security BearerAuth
|
|
// @Produce json
|
|
// @Success 200 {array} map[string]interface{}
|
|
// @Failure 500 {object} map[string]string
|
|
// @Router /api/v1/settings/cors/blacklist [get]
|
|
func ListCorsBlacklists(c *gin.Context) {
|
|
var items []models.CorsBlacklist
|
|
if err := config.DB.Order("id DESC").Find(&items).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch cors blacklists"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, items)
|
|
}
|
|
|
|
// CreateCorsBlacklist godoc
|
|
// @Summary Create CORS blacklist item
|
|
// @Description Creates a new blacklist origin.
|
|
// @Tags Settings
|
|
// @Security BearerAuth
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body UpsertCorsBlacklistRequest true "cors blacklist payload"
|
|
// @Success 201 {object} map[string]interface{}
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 409 {object} map[string]string
|
|
// @Router /api/v1/settings/cors/blacklist [post]
|
|
func CreateCorsBlacklist(c *gin.Context) {
|
|
var req UpsertCorsBlacklistRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
item := models.CorsBlacklist{
|
|
Origin: req.Origin,
|
|
Reason: req.Reason,
|
|
IsActive: req.IsActive,
|
|
CreatedBy: req.CreatedBy,
|
|
}
|
|
if err := config.DB.Create(&item).Error; err != nil {
|
|
c.JSON(http.StatusConflict, gin.H{"error": "failed to create cors blacklist"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusCreated, item)
|
|
}
|
|
|
|
// UpdateCorsBlacklist godoc
|
|
// @Summary Update CORS blacklist item
|
|
// @Description Updates a blacklist origin by id.
|
|
// @Tags Settings
|
|
// @Security BearerAuth
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path int true "blacklist id"
|
|
// @Param request body UpsertCorsBlacklistRequest true "cors blacklist payload"
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 404 {object} map[string]string
|
|
// @Failure 409 {object} map[string]string
|
|
// @Router /api/v1/settings/cors/blacklist/{id} [put]
|
|
func UpdateCorsBlacklist(c *gin.Context) {
|
|
id, ok := parseID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
var req UpsertCorsBlacklistRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
var item models.CorsBlacklist
|
|
if err := config.DB.First(&item, id).Error; errors.Is(err, gorm.ErrRecordNotFound) {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "cors blacklist not found"})
|
|
return
|
|
} else if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch cors blacklist"})
|
|
return
|
|
}
|
|
if err := config.DB.Model(&item).Updates(map[string]any{
|
|
"origin": req.Origin,
|
|
"reason": req.Reason,
|
|
"is_active": req.IsActive,
|
|
"created_by": req.CreatedBy,
|
|
}).Error; err != nil {
|
|
c.JSON(http.StatusConflict, gin.H{"error": "failed to update cors blacklist"})
|
|
return
|
|
}
|
|
if err := config.DB.First(&item, id).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch updated cors blacklist"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, item)
|
|
}
|
|
|
|
// DeleteCorsBlacklist godoc
|
|
// @Summary Delete CORS blacklist item
|
|
// @Description Deletes a blacklist origin by id.
|
|
// @Tags Settings
|
|
// @Security BearerAuth
|
|
// @Produce json
|
|
// @Param id path int true "blacklist id"
|
|
// @Success 200 {object} map[string]string
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 404 {object} map[string]string
|
|
// @Failure 500 {object} map[string]string
|
|
// @Router /api/v1/settings/cors/blacklist/{id} [delete]
|
|
func DeleteCorsBlacklist(c *gin.Context) {
|
|
id, ok := parseID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
res := config.DB.Delete(&models.CorsBlacklist{}, id)
|
|
if res.Error != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete cors blacklist"})
|
|
return
|
|
}
|
|
if res.RowsAffected == 0 {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "cors blacklist not found"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"message": "cors blacklist deleted"})
|
|
}
|
|
|
|
// ListRateLimits godoc
|
|
// @Summary List rate limits
|
|
// @Description Returns all rate-limit settings.
|
|
// @Tags Settings
|
|
// @Security BearerAuth
|
|
// @Produce json
|
|
// @Success 200 {array} map[string]interface{}
|
|
// @Failure 500 {object} map[string]string
|
|
// @Router /api/v1/settings/rate-limits [get]
|
|
func ListRateLimits(c *gin.Context) {
|
|
var items []models.RateLimitSetting
|
|
if err := config.DB.Order("id DESC").Find(&items).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch rate limits"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, items)
|
|
}
|
|
|
|
// CreateRateLimit godoc
|
|
// @Summary Create rate limit
|
|
// @Description Creates a new rate-limit setting.
|
|
// @Tags Settings
|
|
// @Security BearerAuth
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body UpsertRateLimitRequest true "rate limit payload"
|
|
// @Success 201 {object} map[string]interface{}
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 409 {object} map[string]string
|
|
// @Router /api/v1/settings/rate-limits [post]
|
|
func CreateRateLimit(c *gin.Context) {
|
|
var req UpsertRateLimitRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
item := models.RateLimitSetting{
|
|
Name: req.Name,
|
|
Description: req.Description,
|
|
MaxRequests: req.MaxRequests,
|
|
WindowSeconds: req.WindowSeconds,
|
|
IsActive: req.IsActive,
|
|
UpdatedBy: req.UpdatedBy,
|
|
}
|
|
if err := config.DB.Create(&item).Error; err != nil {
|
|
c.JSON(http.StatusConflict, gin.H{"error": "failed to create rate limit"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusCreated, item)
|
|
}
|
|
|
|
// UpdateRateLimit godoc
|
|
// @Summary Update rate limit
|
|
// @Description Updates a rate-limit setting by id.
|
|
// @Tags Settings
|
|
// @Security BearerAuth
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path int true "rate limit id"
|
|
// @Param request body UpsertRateLimitRequest true "rate limit payload"
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 404 {object} map[string]string
|
|
// @Failure 409 {object} map[string]string
|
|
// @Router /api/v1/settings/rate-limits/{id} [put]
|
|
func UpdateRateLimit(c *gin.Context) {
|
|
id, ok := parseID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
var req UpsertRateLimitRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
var item models.RateLimitSetting
|
|
if err := config.DB.First(&item, id).Error; errors.Is(err, gorm.ErrRecordNotFound) {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "rate limit not found"})
|
|
return
|
|
} else if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch rate limit"})
|
|
return
|
|
}
|
|
if err := config.DB.Model(&item).Updates(map[string]any{
|
|
"name": req.Name,
|
|
"description": req.Description,
|
|
"max_requests": req.MaxRequests,
|
|
"window_seconds": req.WindowSeconds,
|
|
"is_active": req.IsActive,
|
|
"updated_by": req.UpdatedBy,
|
|
}).Error; err != nil {
|
|
c.JSON(http.StatusConflict, gin.H{"error": "failed to update rate limit"})
|
|
return
|
|
}
|
|
if err := config.DB.First(&item, id).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch updated rate limit"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, item)
|
|
}
|
|
|
|
// DeleteRateLimit godoc
|
|
// @Summary Delete rate limit
|
|
// @Description Deletes a rate-limit setting by id.
|
|
// @Tags Settings
|
|
// @Security BearerAuth
|
|
// @Produce json
|
|
// @Param id path int true "rate limit id"
|
|
// @Success 200 {object} map[string]string
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 404 {object} map[string]string
|
|
// @Failure 500 {object} map[string]string
|
|
// @Router /api/v1/settings/rate-limits/{id} [delete]
|
|
func DeleteRateLimit(c *gin.Context) {
|
|
id, ok := parseID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
res := config.DB.Delete(&models.RateLimitSetting{}, id)
|
|
if res.Error != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete rate limit"})
|
|
return
|
|
}
|
|
if res.RowsAffected == 0 {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "rate limit not found"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"message": "rate limit deleted"})
|
|
}
|