Squashed commit of the following:
commita394259f0a
Author: Sense T <me@sense-t.eu.org> Date: Fri Apr 19 15:10:08 2024 +0800 done commitaf9d966376
Author: Sense T <me@sense-t.eu.org> Date: Fri Apr 19 13:52:33 2024 +0800 debug done. commit47335ca5e9
Author: Sense T <me@sense-t.eu.org> Date: Fri Apr 19 12:47:00 2024 +0800 swagger done commit34fb2a478b
Author: Sense T <me@sense-t.eu.org> Date: Fri Apr 19 10:05:19 2024 +0800 stage 2, not completed commit88b2255f8b
Author: Sense T <me@sense-t.eu.org> Date: Fri Apr 19 09:44:37 2024 +0800 test stage 1 commitb583720223
Author: Sense T <me@sense-t.eu.org> Date: Mon Apr 15 21:53:09 2024 +0800 Squashed commit of the following: commit 1e92328a0fc570fe9419ad5dbaaef77f7dc9ad2e Author: Sense T <me@sense-t.eu.org> Date: Mon Apr 15 21:52:44 2024 +0800 yes, react it! commit 09fffff6139b4cecb81cb1444139f225e95e8917 Author: Sense T <me@sense-t.eu.org> Date: Mon Apr 15 17:33:26 2024 +0800 actions to be done commit 1611b0b338cfd965d15f43fb10308bc56015895f Author: Sense T <me@sense-t.eu.org> Date: Mon Apr 15 15:22:08 2024 +0800 modal needed. commit 88453e7382618fb6774ff1cc4c0f7045d4dfcf46 Author: Sense T <me@sense-t.eu.org> Date: Mon Apr 15 10:52:13 2024 +0800 Domain View done commit 8cedca27c79ca2ba69c8777dfcb6019799875e31 Author: Sense T <me@sense-t.eu.org> Date: Sun Apr 14 21:24:14 2024 +0800 domain delete modal done commit 60cd00c0cad0774bae5b57bcfc4723a29d28d221 Author: Sense T <me@sense-t.eu.org> Date: Sun Apr 14 07:55:11 2024 +0800 1 commit 285853e988db6e6a6371135869da0129fd73afd7 Author: Sense T <me@sense-t.eu.org> Date: Sat Apr 13 17:29:43 2024 +0800 eslint commit 8f0ffbf744fd85a612daacd7bd6cbc45d58907d3 Author: Sense T <me@sense-t.eu.org> Date: Sat Apr 13 17:20:50 2024 +0800 f commit 9762b632225f185d83388e58d93ed49f62fe6b3f Author: Sense T <me@sense-t.eu.org> Date: Sat Apr 13 17:08:37 2024 +0800 views, components to be done commit 321e5255f2b1e705844179dd910d5f5a1ae58298 Author: Sense T <me@sense-t.eu.org> Date: Sat Apr 13 14:29:04 2024 +0800 prepare for react commit3305d8d618
Author: Sense T <me@sense-t.eu.org> Date: Sat Apr 13 10:30:02 2024 +0800 swagger to be done commit2c754e7eec
Author: Sense T <me@sense-t.eu.org> Date: Sat Apr 13 10:14:45 2024 +0800 validate 'em ! commit7b529ad8f6
Author: Sense T <me@sense-t.eu.org> Date: Sat Apr 13 09:22:27 2024 +0800 try to avoid nil point panic commit0012a697cb
Author: Sense T <me@sense-t.eu.org> Date: Fri Apr 12 22:26:35 2024 +0800 fix some bug commita098d3056c
Author: Sense T <me@sense-t.eu.org> Date: Fri Apr 12 20:03:34 2024 +0800 web debug done commit01765c4e7f
Author: Sense T <me@sense-t.eu.org> Date: Fri Apr 12 15:16:52 2024 +0800 all tsx used, no vue SFC commit731504ae82
Author: Sense T <me@sense-t.eu.org> Date: Thu Apr 11 22:05:58 2024 +0800 tsx used - stage 2 commitb669a3e68e
Author: Sense T <me@sense-t.eu.org> Date: Thu Apr 11 16:18:11 2024 +0800 use tsx for compoents stage 1 commit2ab1b0bf1b
Author: Sense T <me@sense-t.eu.org> Date: Thu Apr 11 12:10:57 2024 +0800 rr validation commit58c66fc3a8
Author: Sense T <me@sense-t.eu.org> Date: Thu Apr 11 11:41:33 2024 +0800 stage 1 commit7a5fcf1972
Author: Sense T <me@sense-t.eu.org> Date: Thu Apr 11 10:51:50 2024 +0800 long options supported commitc3b80093d2
Author: Sense T <me@sense-t.eu.org> Date: Thu Apr 11 10:51:33 2024 +0800 for develop use commit7f52707323
Author: Sense T <me@sense-t.eu.org> Date: Thu Apr 11 10:51:24 2024 +0800 fix typo commit9cc2696bbe
Author: Sense T <me@sense-t.eu.org> Date: Wed Apr 10 16:53:03 2024 +0800 record data validate done commit5e2ae637a0
Author: Sense T <me@sense-t.eu.org> Date: Wed Apr 10 14:56:15 2024 +0800 end with dot. commited4fee935d
Author: Sense T <me@sense-t.eu.org> Date: Wed Apr 10 13:41:32 2024 +0800 content safety commit29f75938bb
Author: Sense T <me@sense-t.eu.org> Date: Wed Apr 10 13:24:01 2024 +0800 cmd is ok commit9465bb885d
Author: Sense T <me@sense-t.eu.org> Date: Wed Apr 10 11:00:47 2024 +0800 web done commit65bf461d44
Author: Sense T <me@sense-t.eu.org> Date: Wed Apr 10 11:00:38 2024 +0800 use tokei for stat commit61395ab61b
Author: Sense T <me@sense-t.eu.org> Date: Tue Apr 9 21:53:12 2024 +0800 errors handler commit9752e7d9ae
Author: Sense T <me@sense-t.eu.org> Date: Tue Apr 9 21:16:19 2024 +0800 model with generics done commit7dd3af3707
Author: Sense T <me@sense-t.eu.org> Date: Tue Apr 9 16:28:18 2024 +0800 use DAO commit2369734230
Author: Sense T <me@sense-t.eu.org> Date: Tue Apr 9 13:06:31 2024 +0800 dao for future commite18781ba25
Author: Sense T <me@sense-t.eu.org> Date: Tue Apr 9 11:36:34 2024 +0800 DotEnd commit613ef7fdd9
Author: Sense T <me@sense-t.eu.org> Date: Tue Apr 9 10:16:06 2024 +0800 record should endwith . commitc93e8107dc
Author: Sense T <me@sense-t.eu.org> Date: Tue Apr 9 10:06:47 2024 +0800 update regexp commit84e9961f4b
Author: Sense T <me@sense-t.eu.org> Date: Tue Apr 9 08:30:32 2024 +0800 error log commitdb77b0fdb2
Author: Sense T <me@sense-t.eu.org> Date: Tue Apr 9 08:25:25 2024 +0800 no console log commit0c197820a0
Author: Sense T <me@sense-t.eu.org> Date: Tue Apr 9 08:25:01 2024 +0800 use flags for validate commit33c9050653
Author: Sense T <me@sense-t.eu.org> Date: Tue Apr 9 07:58:27 2024 +0800 SOA Email Format commitfb9c78efed
Author: Sense T <me@sense-t.eu.org> Date: Tue Apr 9 00:19:03 2024 +0800 no debug commit1a7bf83cb9
Author: Sense T <me@sense-t.eu.org> Date: Tue Apr 9 00:18:18 2024 +0800 1 commite72de14797
Author: Sense T <me@sense-t.eu.org> Date: Mon Apr 8 17:30:25 2024 +0800 last modal commite884840b7d
Author: Sense T <me@sense-t.eu.org> Date: Mon Apr 8 15:56:03 2024 +0800 add commit36b0384319
Author: Sense T <me@sense-t.eu.org> Date: Mon Apr 8 15:02:55 2024 +0800 delete domain modal done commit753e950fae
Author: Sense T <me@sense-t.eu.org> Date: Mon Apr 8 13:49:11 2024 +0800 add domainRemovemodal commit69613f9b6e
Author: Sense T <me@sense-t.eu.org> Date: Mon Apr 8 13:32:01 2024 +0800 modal needed for edit commit8c0b79066f
Author: Sense T <me@sense-t.eu.org> Date: Mon Apr 8 09:37:32 2024 +0800 base UI commita67b2d7724
Author: Sense T <me@sense-t.eu.org> Date: Sun Apr 7 21:07:20 2024 +0800 route update commit5a266e9e6c
Author: Sense T <me@sense-t.eu.org> Date: Sun Apr 7 14:36:55 2024 +0800 ui base data struct commit3449df913c
Author: Sense T <me@sense-t.eu.org> Date: Sun Apr 7 13:08:45 2024 +0800 web store for dev commit156bf651dd
Author: Sense T <me@sense-t.eu.org> Date: Sun Apr 7 13:08:30 2024 +0800 store friendly commitd90e949472
Author: Sense T <me@sense-t.eu.org> Date: Sun Apr 7 10:08:02 2024 +0800 base code update commit0a20b5a670
Author: Sense T <me@sense-t.eu.org> Date: Sun Apr 7 10:07:26 2024 +0800 metrics commitbdd4866c10
Author: Sense T <me@sense-t.eu.org> Date: Wed Apr 3 22:37:15 2024 +0800 all api done commit8a8ea59b71
Author: Sense T <me@sense-t.eu.org> Date: Wed Apr 3 17:05:12 2024 +0800 1
This commit is contained in:
1
server/.gitignore
vendored
Normal file
1
server/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
dist/
|
129
server/handlers_domains.go
Normal file
129
server/handlers_domains.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reCoreD-UI/controllers"
|
||||
"reCoreD-UI/models"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
_ "reCoreD-UI/docs"
|
||||
)
|
||||
|
||||
// GetDomains godoc
|
||||
//
|
||||
// @Router /domains/ [get]
|
||||
// @Summary List all domains
|
||||
// @Description List all domains
|
||||
// @Tags domains
|
||||
// @Accept json
|
||||
// @Product json
|
||||
// @Success 200 {object} Response{data=[]models.Domain}
|
||||
// @Failure 401 {object} Response{data=nil}
|
||||
// @Failure 500 {object} Response{data=nil}
|
||||
func getDomains(c *gin.Context) {
|
||||
domains, err := controllers.GetDomains("")
|
||||
if err != nil {
|
||||
errorHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, Response{
|
||||
Succeed: true,
|
||||
Data: domains,
|
||||
})
|
||||
}
|
||||
|
||||
// CreateDomain godoc
|
||||
//
|
||||
// @Router /domains/ [post]
|
||||
// @Summary Create a domain
|
||||
// @Description Create a domain
|
||||
// @Tags domains
|
||||
// @Product json
|
||||
// @Param object body models.Domain true "content"
|
||||
// @Success 201 {object} Response{data=models.Domain}
|
||||
// @Failure 400 {object} Response{data=nil}
|
||||
// @Failure 401 {object} Response{data=nil}
|
||||
// @Failure 500 {object} Response{data=nil}
|
||||
func createDomain(c *gin.Context) {
|
||||
domain := &models.Domain{}
|
||||
|
||||
if err := c.BindJSON(domain); err != nil {
|
||||
c.JSON(http.StatusBadRequest, Response{
|
||||
Succeed: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
domain, err := controllers.CreateDomain(domain)
|
||||
if err != nil {
|
||||
errorHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, Response{
|
||||
Succeed: true,
|
||||
Data: domain,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateDomain godoc
|
||||
//
|
||||
// @Router /domains/ [put]
|
||||
// @Summary Update a domain
|
||||
// @Description Update a domain
|
||||
// @Tags domains
|
||||
// @Accept json
|
||||
// @Product json
|
||||
// @Param object body models.Domain true "content"
|
||||
// @Success 200 {object} Response{data=models.Domain}
|
||||
// @Failure 400 {object} Response{data=nil}
|
||||
// @Failure 401 {object} Response{data=nil}
|
||||
// @Failure 404 {object} Response{data=nil}
|
||||
// @Failure 500 {object} Response{data=nil}
|
||||
func updateDomain(c *gin.Context) {
|
||||
domain := &models.Domain{}
|
||||
|
||||
if err := c.BindJSON(domain); err != nil {
|
||||
c.JSON(http.StatusBadRequest, Response{
|
||||
Succeed: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := controllers.UpdateDomain(domain); err != nil {
|
||||
errorHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, Response{
|
||||
Succeed: true,
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteDomain godoc
|
||||
//
|
||||
// @Router /domains/{id} [delete]
|
||||
// @Summary Delete a domain
|
||||
// @Description Delete a domain
|
||||
// @Tags domains
|
||||
// @Product json
|
||||
// @Param id path int true "Domain ID"
|
||||
// @Success 204 {object} Response{data=nil}
|
||||
// @Failure 401 {object} Response{data=nil}
|
||||
// @Failure 404 {object} Response{data=nil}
|
||||
// @Failure 500 {object} Response{data=nil}
|
||||
func deleteDomain(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
if err := controllers.DeleteDomain(id); err != nil {
|
||||
errorHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusNoContent, Response{
|
||||
Succeed: true,
|
||||
})
|
||||
}
|
281
server/handlers_records.go
Normal file
281
server/handlers_records.go
Normal file
@@ -0,0 +1,281 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reCoreD-UI/controllers"
|
||||
"reCoreD-UI/models"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func validateRecord(r models.IRecord) error {
|
||||
switch r.GetType() {
|
||||
case models.RecordTypeA:
|
||||
record := &models.Record[models.ARecord]{}
|
||||
if err := record.FromEntity(r); err != nil {
|
||||
return err
|
||||
}
|
||||
return record.Content.Validate()
|
||||
case models.RecordTypeAAAA:
|
||||
record := &models.Record[models.AAAARecord]{}
|
||||
if err := record.FromEntity(r); err != nil {
|
||||
return err
|
||||
}
|
||||
return record.Content.Validate()
|
||||
case models.RecordTypeCNAME:
|
||||
record := &models.Record[models.CNAMERecord]{}
|
||||
if err := record.FromEntity(r); err != nil {
|
||||
return err
|
||||
}
|
||||
return record.Content.Validate()
|
||||
case models.RecordTypeCAA:
|
||||
record := &models.Record[models.CAARecord]{}
|
||||
if err := record.FromEntity(r); err != nil {
|
||||
return err
|
||||
}
|
||||
return record.Content.Validate()
|
||||
case models.RecordTypeMX:
|
||||
record := &models.Record[models.MXRecord]{}
|
||||
if err := record.FromEntity(r); err != nil {
|
||||
return err
|
||||
}
|
||||
return record.Content.Validate()
|
||||
case models.RecordTypeNS:
|
||||
record := &models.Record[models.NSRecord]{}
|
||||
if err := record.FromEntity(r); err != nil {
|
||||
return err
|
||||
}
|
||||
return record.Content.Validate()
|
||||
case models.RecordTypeSOA:
|
||||
record := &models.Record[models.SOARecord]{}
|
||||
if err := record.FromEntity(r); err != nil {
|
||||
return err
|
||||
}
|
||||
return record.Content.Validate()
|
||||
case models.RecordTypeSRV:
|
||||
record := &models.Record[models.SRVRecord]{}
|
||||
if err := record.FromEntity(r); err != nil {
|
||||
return err
|
||||
}
|
||||
return record.Content.Validate()
|
||||
case models.RecordTypeTXT:
|
||||
record := &models.Record[models.TXTRecord]{}
|
||||
if err := record.FromEntity(r); err != nil {
|
||||
return err
|
||||
}
|
||||
return record.Content.Validate()
|
||||
default:
|
||||
return models.ErrInvalidType
|
||||
}
|
||||
}
|
||||
|
||||
// GetRecords godoc
|
||||
//
|
||||
// @Router /records/{domain} [get]
|
||||
// @Summary List all records of a domain
|
||||
// @Description List all records of a domain
|
||||
// @Tags records
|
||||
// @Product json
|
||||
// @Param domain path string true "domain"
|
||||
// @Success 200 {object} Response{data=[]models.Record[models.RecordContentDefault]}
|
||||
// @Failure 401 {object} Response{data=nil}
|
||||
// @Failure 404 {object} Response{data=nil}
|
||||
// @Failure 500 {object} Response{data=nil}
|
||||
func getRecords(c *gin.Context) {
|
||||
query := &models.Record[models.RecordContentDefault]{Content: make(models.RecordContentDefault)}
|
||||
if err := c.BindQuery(query); err != nil {
|
||||
c.JSON(http.StatusBadRequest, Response{
|
||||
Succeed: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
domain := c.Param("domain")
|
||||
query.Zone = fmt.Sprintf("%s.", domain)
|
||||
|
||||
records, err := controllers.GetRecords(query)
|
||||
if err != nil {
|
||||
errorHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, Response{
|
||||
Succeed: true,
|
||||
Data: records,
|
||||
})
|
||||
}
|
||||
|
||||
// CreateRecord godoc
|
||||
//
|
||||
// @Router /records/{domain} [post]
|
||||
// @Summary Create a record of a domain
|
||||
// @Description Create a record of a domain
|
||||
// @Tags records
|
||||
// @Accept json
|
||||
// @Product json
|
||||
// @Param domain path string true "domain"
|
||||
// @Param object body models.Record[models.RecordContentDefault] true "content"
|
||||
// @Success 201 {object} Response{data=models.Record[models.RecordContentDefault]}
|
||||
// @Failure 400 {object} Response{data=nil}
|
||||
// @Failure 401 {object} Response{data=nil}
|
||||
// @Failure 404 {object} Response{data=nil}
|
||||
// @Failure 500 {object} Response{data=nil}
|
||||
func createRecord(c *gin.Context) {
|
||||
record := &models.Record[models.RecordContentDefault]{Content: make(models.RecordContentDefault)}
|
||||
if err := c.BindJSON(record); err != nil {
|
||||
c.JSON(http.StatusBadRequest, Response{
|
||||
Succeed: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
domain := c.Param("domain")
|
||||
if domain != record.WithOutDotTail() {
|
||||
c.JSON(http.StatusBadRequest, Response{
|
||||
Succeed: false,
|
||||
Message: "request body doesn't match URI",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := validateRecord(record); err != nil {
|
||||
c.JSON(http.StatusBadRequest, Response{
|
||||
Succeed: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
irecord, err := controllers.CreateRecord(record)
|
||||
if err != nil {
|
||||
errorHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, Response{
|
||||
Succeed: true,
|
||||
Data: irecord,
|
||||
})
|
||||
}
|
||||
|
||||
// CreateRecords godoc
|
||||
//
|
||||
// @Router /records/{domain}/bulk [post]
|
||||
// @Summary Create some records of a domain
|
||||
// @Description Create some records of a domain
|
||||
// @Tags records
|
||||
// @Accept json
|
||||
// @Product json
|
||||
// @Param domain path string true "domain"
|
||||
// @Param object body []models.Record[models.RecordContentDefault] true "content"
|
||||
// @Success 201 {object} Response{data=models.Record[models.RecordContentDefault]}
|
||||
// @Failure 400 {object} Response{data=nil}
|
||||
// @Failure 401 {object} Response{data=nil}
|
||||
// @Failure 404 {object} Response{data=nil}
|
||||
// @Failure 500 {object} Response{data=nil}
|
||||
func createRecords(c *gin.Context) {
|
||||
var records []models.Record[models.RecordContentDefault]
|
||||
if err := c.BindJSON(&records); err != nil {
|
||||
c.JSON(http.StatusBadRequest, Response{
|
||||
Succeed: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var iRecords []models.IRecord
|
||||
for _, v := range records {
|
||||
iRecords = append(iRecords, &v)
|
||||
}
|
||||
|
||||
if err := controllers.CreateRecords(iRecords); err != nil {
|
||||
errorHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, Response{
|
||||
Succeed: true,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateRecord godoc
|
||||
//
|
||||
// @Router /records/{domain} [put]
|
||||
// @Summary Update a record of a domain
|
||||
// @Description Update a record of a domain
|
||||
// @Tags records
|
||||
// @Accept json
|
||||
// @Product json
|
||||
// @Param domain path string true "domain"
|
||||
// @Param object body models.Record[models.RecordContentDefault] true "content"
|
||||
// @Success 200 {object} Response{data=models.Record[models.RecordContentDefault]}
|
||||
// @Failure 400 {object} Response{data=nil}
|
||||
// @Failure 401 {object} Response{data=nil}
|
||||
// @Failure 404 {object} Response{data=nil}
|
||||
// @Failure 500 {object} Response{data=nil}
|
||||
func updateRecord(c *gin.Context) {
|
||||
record := &models.Record[models.RecordContentDefault]{Content: make(models.RecordContentDefault)}
|
||||
if err := c.BindJSON(record); err != nil {
|
||||
c.JSON(http.StatusBadRequest, Response{
|
||||
Succeed: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := validateRecord(record); err != nil {
|
||||
c.JSON(http.StatusBadRequest, Response{
|
||||
Succeed: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
domain := c.Param("domain")
|
||||
if domain != record.WithOutDotTail() {
|
||||
c.JSON(http.StatusBadRequest, Response{
|
||||
Succeed: false,
|
||||
Message: "request body doesn't match URI",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := controllers.UpdateRecord(record); err != nil {
|
||||
errorHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, Response{
|
||||
Succeed: true,
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteRecord godoc
|
||||
//
|
||||
// @Router /records/{domain}/{id} [delete]
|
||||
// @Summary Delete a record of a domain
|
||||
// @Description Delete a record of a domain, except SOA record.
|
||||
// @Tags records
|
||||
// @Product json
|
||||
// @Param domain path string true "domain"
|
||||
// @Param id path int true "Record ID"
|
||||
// @Success 204 {object} Response{data=nil}
|
||||
// @Failure 400 {object} Response{data=nil}
|
||||
// @Failure 401 {object} Response{data=nil}
|
||||
// @Failure 404 {object} Response{data=nil}
|
||||
// @Failure 500 {object} Response{data=nil}
|
||||
func deleteRecord(c *gin.Context) {
|
||||
domain := c.Param("domain")
|
||||
id := c.Param("id")
|
||||
|
||||
if err := controllers.DeleteRecord(domain, id); err != nil {
|
||||
errorHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusNoContent, Response{
|
||||
Succeed: true,
|
||||
})
|
||||
}
|
44
server/response.go
Normal file
44
server/response.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"reCoreD-UI/models"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Response common http response
|
||||
type Response struct {
|
||||
// `true` for 2xx, else `false`
|
||||
Succeed bool `json:"succeed"`
|
||||
|
||||
// error message
|
||||
Message string `json:"message"`
|
||||
|
||||
// payload here
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func errorHandler(c *gin.Context, err error) {
|
||||
logrus.Error(err)
|
||||
switch {
|
||||
case errors.Is(err, gorm.ErrRecordNotFound):
|
||||
c.JSON(http.StatusNotFound, Response{
|
||||
Succeed: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
case errors.Is(err, models.ErrorZoneNotEndWithDot):
|
||||
c.JSON(http.StatusBadRequest, Response{
|
||||
Succeed: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
default:
|
||||
c.JSON(http.StatusInternalServerError, Response{
|
||||
Succeed: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
}
|
||||
}
|
99
server/route.go
Normal file
99
server/route.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"path"
|
||||
"reCoreD-UI/controllers"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/sirupsen/logrus"
|
||||
swaggerfiles "github.com/swaggo/files"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
)
|
||||
|
||||
const (
|
||||
apiPrefix = "/api"
|
||||
metricPrefix = "/metrics"
|
||||
swaggerPrefix = "/swagger"
|
||||
)
|
||||
|
||||
|
||||
func (s *Server) setupRoute() {
|
||||
username, password, err := controllers.GetAdmin()
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
logrus.Debugf("got %s:%s", username, password)
|
||||
|
||||
server := s.webServer.Group(s.prefix)
|
||||
|
||||
swaggerHandler := server
|
||||
if s.debug {
|
||||
swaggerHandler.GET(path.Join(swaggerPrefix, "*any"), ginSwagger.WrapHandler(swaggerfiles.Handler))
|
||||
} else {
|
||||
swaggerHandler.GET(path.Join(swaggerPrefix, "*any"), func(ctx *gin.Context) {
|
||||
ctx.HTML(http.StatusNotFound, "", nil)
|
||||
})
|
||||
}
|
||||
|
||||
controllers.RegisterMetrics()
|
||||
metricHandler := server
|
||||
metricHandler.GET(metricPrefix, func(ctx *gin.Context) {
|
||||
if err := controllers.RefreshMetrics(); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
promhttp.Handler().ServeHTTP(ctx.Writer, ctx.Request)
|
||||
})
|
||||
|
||||
apiHandler := server
|
||||
|
||||
groupV1 := apiHandler.Group(apiPrefix, gin.BasicAuth(gin.Accounts{
|
||||
username: password,
|
||||
}), func(ctx *gin.Context) {
|
||||
_, ok := ctx.Get(gin.AuthUserKey)
|
||||
if !ok {
|
||||
ctx.AbortWithStatusJSON(http.StatusUnauthorized, Response{
|
||||
Succeed: false,
|
||||
})
|
||||
}
|
||||
}).Group("/v1")
|
||||
|
||||
domains := groupV1.Group("/domains")
|
||||
domains.
|
||||
GET("/", getDomains).
|
||||
POST("/", createDomain).
|
||||
PUT("/", updateDomain).
|
||||
DELETE("/:id", deleteDomain)
|
||||
|
||||
records := groupV1.Group("/records")
|
||||
records.
|
||||
GET("/:domain", getRecords).
|
||||
POST("/:domain", createRecord).
|
||||
POST("/:domain/bulk", createRecords).
|
||||
PUT("/:domain", updateRecord).
|
||||
DELETE("/:domain/:id", deleteRecord)
|
||||
|
||||
/*server := s.webServer.Group(s.prefix)
|
||||
server.Use(apiHandler.HandleContext, metricHandler.HandleContext, func(ctx *gin.Context) {
|
||||
uri := ctx.Request.RequestURI
|
||||
logrus.Debug(uri)
|
||||
switch {
|
||||
case strings.HasPrefix(uri, path.Join(s.prefix, apiPrefix)):
|
||||
//apiHandler.HandleContext(ctx)
|
||||
case strings.HasPrefix(uri, path.Join(s.prefix, metricPrefix)):
|
||||
//metricHandler.HandleContext(ctx)
|
||||
case strings.HasPrefix(uri, path.Join(s.prefix, swaggerPrefix)):
|
||||
if s.debug {
|
||||
swaggerHandler.HandleContext(ctx)
|
||||
} else {
|
||||
ctx.HTML(http.StatusNotFound, "", nil)
|
||||
}
|
||||
default:
|
||||
staticFileHandler()(ctx)
|
||||
}
|
||||
})*/
|
||||
|
||||
server.GET("/", staticFileHandler())
|
||||
server.GET("/assets/*any", staticFileHandler())
|
||||
}
|
48
server/server.go
Normal file
48
server/server.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net"
|
||||
"reCoreD-UI/database"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
webServer *gin.Engine
|
||||
listen string
|
||||
prefix string
|
||||
debug bool
|
||||
}
|
||||
|
||||
func NewServer(c *cli.Context) (*Server, error) {
|
||||
if err := database.Connect(c.String("mysql-dsn")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if c.Bool("debug") {
|
||||
database.Client = database.Client.Debug()
|
||||
gin.SetMode(gin.DebugMode)
|
||||
} else {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
}
|
||||
|
||||
return &Server{
|
||||
webServer: gin.New(),
|
||||
listen: net.JoinHostPort(
|
||||
c.String("listen"),
|
||||
c.String("port"),
|
||||
),
|
||||
prefix: c.String("prefix"),
|
||||
debug: c.Bool("debug"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) Run() error {
|
||||
logrus.Debug("server running")
|
||||
defer logrus.Debug("server exit")
|
||||
|
||||
s.setupRoute()
|
||||
|
||||
return s.webServer.Run(s.listen)
|
||||
}
|
35
server/static.go
Normal file
35
server/static.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
//go:generate cp -r ../web/dist ./
|
||||
//go:embed dist
|
||||
var staticFiles embed.FS
|
||||
|
||||
func staticFileHandler() gin.HandlerFunc {
|
||||
sf, err := fs.Sub(staticFiles, "dist")
|
||||
if err != nil {
|
||||
logrus.Fatal("compile error: ", err)
|
||||
}
|
||||
|
||||
fs := http.FileServer(http.FS(sf))
|
||||
|
||||
return func(ctx *gin.Context) {
|
||||
defer ctx.Abort()
|
||||
filename := strings.TrimLeft(ctx.Request.RequestURI, "/")
|
||||
|
||||
if filename == "" {
|
||||
filename = "index.html"
|
||||
}
|
||||
|
||||
fs.ServeHTTP(ctx.Writer, ctx.Request)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user