test stage 1
This commit is contained in:
parent
b583720223
commit
88b2255f8b
13
.nixd.json
Normal file
13
.nixd.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"formatting": {
|
||||
"command": "nixpkgs-fmt"
|
||||
},
|
||||
"eval": {
|
||||
"target": {
|
||||
"args": [
|
||||
"--expr",
|
||||
"with import <nixpkgs> { };"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
17
.vscode/settings.json
vendored
Normal file
17
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"sqltools.connections": [
|
||||
{
|
||||
"mysqlOptions": {
|
||||
"authProtocol": "default",
|
||||
"enableSsl": "Disabled"
|
||||
},
|
||||
"previewLimit": 50,
|
||||
"server": "mysql.dev",
|
||||
"port": 3306,
|
||||
"driver": "MySQL",
|
||||
"name": "recored-ui",
|
||||
"database": "recoredui",
|
||||
"username": "recoredui"
|
||||
}
|
||||
]
|
||||
}
|
1
TODO
1
TODO
@ -2,6 +2,7 @@
|
||||
- [x] Web UI
|
||||
- [x] i18n
|
||||
- [x] modals
|
||||
- [] debug
|
||||
- [] swagger
|
||||
- [] Nix Module
|
||||
- [] RBAC
|
||||
|
@ -18,12 +18,12 @@ var Command = &cli.Command{
|
||||
}),
|
||||
altsrc.NewStringFlag(&cli.StringFlag{
|
||||
Name: "listen",
|
||||
Value: "[::]",
|
||||
Value: "::",
|
||||
Usage: "IP for listen at",
|
||||
}),
|
||||
altsrc.NewIntFlag(&cli.IntFlag{
|
||||
Name: "port",
|
||||
Value: 8080,
|
||||
Value: 3000,
|
||||
Usage: "Port for listen at",
|
||||
}),
|
||||
},
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"reCoreD-UI/database"
|
||||
"reCoreD-UI/models"
|
||||
"strconv"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type domainsDAO struct {
|
||||
@ -28,6 +30,7 @@ func CreateDomain(d *models.Domain) (*models.Domain, error) {
|
||||
r.Name = "@"
|
||||
r.RecordType = models.RecordTypeSOA
|
||||
r.Content = d.GenerateSOA()
|
||||
logrus.Debug(r)
|
||||
if err := r.CheckZone(); err != nil {
|
||||
tx.Rollback()
|
||||
return nil, err
|
||||
@ -41,7 +44,7 @@ func CreateDomain(d *models.Domain) (*models.Domain, error) {
|
||||
for i, ns := range nss {
|
||||
record := &models.Record[models.NSRecord]{
|
||||
Zone: d.WithDotEnd(),
|
||||
RecordType: models.RecordTypeSOA,
|
||||
RecordType: models.RecordTypeNS,
|
||||
Name: fmt.Sprintf("ns%d", i+1),
|
||||
}
|
||||
record.Content.Host = ns
|
||||
@ -123,13 +126,13 @@ func DeleteDomain(id string) error {
|
||||
}
|
||||
|
||||
tx := database.Client.Begin()
|
||||
domain, err := (domainsDAO{}).GetOne(tx, &models.Domain{ID: ID})
|
||||
domain, err := (domainsDAO{}).GetOne(tx, &models.Domain{ID: uint(ID)})
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := (domainsDAO{}).Delete(tx, &models.Domain{ID: ID}); err != nil {
|
||||
if err := (domainsDAO{}).Delete(tx, &models.Domain{ID: uint(ID)}); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ func RegisterMetrics() {
|
||||
|
||||
GinMetrics := ginprometheus.NewPrometheus("recoredui")
|
||||
for _, v := range GinMetrics.MetricsList {
|
||||
prometheus.MustRegister(v.MetricCollector)
|
||||
prometheus.Register(v.MetricCollector)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ func CreateRecords(rs []models.IRecord) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return tx.Commit().Error
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ func DeleteRecord(domain, id string) error {
|
||||
}
|
||||
|
||||
tx := database.Client.Begin()
|
||||
record, err := (recordsDAO{}).GetOne(tx, &models.Record[models.RecordContentDefault]{ID: ID, Zone: fmt.Sprintf("%s.", domain)})
|
||||
record, err := (recordsDAO{}).GetOne(tx, &models.Record[models.RecordContentDefault]{ID: uint(ID), Zone: fmt.Sprintf("%s.", domain)})
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
|
@ -3,6 +3,7 @@ package database
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/huandu/go-clone"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@ -14,41 +15,40 @@ func (b BaseDAO[T]) Migrate(db *gorm.DB, e T) error {
|
||||
|
||||
func (BaseDAO[T]) GetAll(db *gorm.DB, e T, cond ...T) ([]T, error) {
|
||||
var r []T
|
||||
tx := db
|
||||
tx := db.Model(e)
|
||||
for _, c := range cond {
|
||||
tx = tx.Where(c)
|
||||
}
|
||||
|
||||
if err := tx.Find(&r, e).Error; err != nil {
|
||||
rows, err := tx.Rows()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
if err := db.ScanRows(rows, e); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
i := clone.Clone(e).(T)
|
||||
|
||||
r = append(r, i)
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (BaseDAO[T]) GetOne(db *gorm.DB, e T, cond ...T) (T, error) {
|
||||
var r T
|
||||
tx := db
|
||||
for _, c := range cond {
|
||||
tx = tx.Where(c)
|
||||
}
|
||||
|
||||
if err := tx.First(&r, e).Error; err != nil {
|
||||
return r, err
|
||||
if err := tx.First(e).Error; err != nil {
|
||||
return e, err
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (BaseDAO[T]) GetSome(db *gorm.DB, e T, limit, offset int, cond ...T) ([]T, error) {
|
||||
var r []T
|
||||
tx := db
|
||||
for _, c := range cond {
|
||||
tx = tx.Where(c)
|
||||
}
|
||||
|
||||
if err := tx.Find(&r, e).Limit(limit).Offset(offset).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r, nil
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (BaseDAO[T]) Create(db *gorm.DB, e T) (T, error) {
|
||||
|
36
flake.lock
generated
36
flake.lock
generated
@ -1,39 +1,6 @@
|
||||
{
|
||||
"nodes": {
|
||||
"naersk": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1698420672,
|
||||
"narHash": "sha256-/TdeHMPRjjdJub7p7+w55vyABrsJlt5QkznPYy55vKA=",
|
||||
"owner": "nix-community",
|
||||
"repo": "naersk",
|
||||
"rev": "aeb58d5e8faead8980a807c840232697982d47b9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"ref": "master",
|
||||
"repo": "naersk",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1711715736,
|
||||
"narHash": "sha256-9slQ609YqT9bT/MNX9+5k5jltL9zgpn36DpFB7TkttM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "807c549feabce7eddbf259dbdcec9e0600a0660d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1711715736,
|
||||
"narHash": "sha256-9slQ609YqT9bT/MNX9+5k5jltL9zgpn36DpFB7TkttM=",
|
||||
@ -51,8 +18,7 @@
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"naersk": "naersk",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"utils": "utils"
|
||||
}
|
||||
},
|
||||
|
12
flake.nix
12
flake.nix
@ -20,29 +20,23 @@
|
||||
};
|
||||
|
||||
inputs = {
|
||||
naersk.url = "github:nix-community/naersk/master";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, utils, naersk }:
|
||||
outputs = { self, nixpkgs, utils }:
|
||||
utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
naersk-lib = pkgs.callPackage naersk { };
|
||||
in
|
||||
{
|
||||
defaultPackage = naersk-lib.buildPackage {
|
||||
src = ./.;
|
||||
buildInputs = with pkgs; [
|
||||
|
||||
];
|
||||
};
|
||||
defaultPackage = {};
|
||||
|
||||
devShell = with pkgs; mkShell {
|
||||
buildInputs = [
|
||||
go
|
||||
nodejs
|
||||
dig
|
||||
tokei
|
||||
];
|
||||
GOPATH = "/home/coder/.cache/go";
|
||||
|
1
go.mod
1
go.mod
@ -35,6 +35,7 @@ require (
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect
|
||||
github.com/huandu/go-clone v1.7.2 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
|
3
go.sum
3
go.sum
@ -354,6 +354,9 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U=
|
||||
github.com/huandu/go-clone v1.7.2 h1:3+Aq0Ed8XK+zKkLjE2dfHg0XrpIfcohBE1K+c8Usxoo=
|
||||
github.com/huandu/go-clone v1.7.2/go.mod h1:ReGivhG6op3GYr+UY3lS6mxjKp7MIGTknuU5TbTVaXE=
|
||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
|
@ -6,17 +6,17 @@ import (
|
||||
)
|
||||
|
||||
type Domain struct {
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
DomainName string `gorm:"unique,not null,size:255" json:"domain_name"`
|
||||
|
||||
//SOA Info
|
||||
MainDNS string `gorm:"not null;size:255" json:"main_dns"`
|
||||
AdminEmail string `gorm:"not null;size:255" json:"admin_email"`
|
||||
SerialNumber int64 `gorm:"not null;default:1" json:"serial_number"`
|
||||
RefreshInterval uint32 `gorm:"not null;size:255,default:\"86400\"" json:"refresh_interval"`
|
||||
RetryInterval uint32 `gorm:"not null;size:255,default:\"7200\"" json:"retry_interval"`
|
||||
ExpiryPeriod uint32 `gorm:"not null;size:255,default:\"3600000\"" json:"expiry_period"`
|
||||
NegativeTtl uint32 `gorm:"not null;size:255,default:\"86400\"" json:"negative_ttl"`
|
||||
RefreshInterval uint32 `gorm:"type:uint;not null;default:86400" json:"refresh_interval"`
|
||||
RetryInterval uint32 `gorm:"type:uint;not null;default:7200" json:"retry_interval"`
|
||||
ExpiryPeriod uint32 `gorm:"type:uint;not null;default:3600000" json:"expiry_period"`
|
||||
NegativeTtl uint32 `gorm:"type:uint;not null;default:86400" json:"negative_ttl"`
|
||||
}
|
||||
|
||||
func (d *Domain) EmailSOAForamt() string {
|
||||
@ -53,8 +53,13 @@ func (d *Domain) GenerateSOA() SOARecord {
|
||||
return r
|
||||
}
|
||||
|
||||
func (d *Domain) GetValue() Domain {
|
||||
return *d
|
||||
}
|
||||
|
||||
type IDomain interface {
|
||||
EmailSOAForamt() string
|
||||
WithDotEnd() string
|
||||
GenerateSOA() SOARecord
|
||||
GetValue() Domain
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ type recordContentTypes interface {
|
||||
}
|
||||
|
||||
type Record[T recordContentTypes] struct {
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Zone string `gorm:"not null;size:255" json:"zone"`
|
||||
Name string `gorm:"not null;size:255" json:"name"`
|
||||
Ttl int `json:"ttl"`
|
||||
@ -34,11 +34,11 @@ type Record[T recordContentTypes] struct {
|
||||
}
|
||||
|
||||
func (*Record[T]) TableName() string {
|
||||
return "coredns_record"
|
||||
return "coredns_records"
|
||||
}
|
||||
|
||||
func (r *Record[T]) CheckZone() error {
|
||||
if strings.HasSuffix(r.Zone, ".") {
|
||||
if !strings.HasSuffix(r.Zone, ".") {
|
||||
return ErrorZoneNotEndWithDot
|
||||
}
|
||||
return nil
|
||||
@ -65,6 +65,10 @@ func (r *Record[T]) GetType() string {
|
||||
return r.RecordType
|
||||
}
|
||||
|
||||
func (r *Record[T]) GetValue() IRecord {
|
||||
return r.ToEntity()
|
||||
}
|
||||
|
||||
type IRecord interface {
|
||||
TableName() string
|
||||
CheckZone() error
|
||||
@ -72,4 +76,5 @@ type IRecord interface {
|
||||
ToEntity() IRecord
|
||||
FromEntity(any) error
|
||||
GetType() string
|
||||
GetValue() IRecord
|
||||
}
|
||||
|
@ -2,8 +2,6 @@ package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -13,7 +11,7 @@ const (
|
||||
)
|
||||
|
||||
type Settings struct {
|
||||
gorm.Model
|
||||
ID uint `gorm:"primaryKey"`
|
||||
Key string `gorm:"unique;not null;size:255"`
|
||||
Value string `gorm:"not null;size:255"`
|
||||
}
|
||||
@ -22,6 +20,11 @@ func (s *Settings) String() string {
|
||||
return fmt.Sprintf("%s: %s", s.Key, s.Value)
|
||||
}
|
||||
|
||||
func (s *Settings) GetValue() Settings {
|
||||
return *s
|
||||
}
|
||||
|
||||
type ISettings interface {
|
||||
String() string
|
||||
GetValue() Settings
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import (
|
||||
"net/http"
|
||||
"path"
|
||||
"reCoreD-UI/controllers"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
@ -24,11 +23,21 @@ func (s *Server) setupRoute() {
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
logrus.Debugf("got %s:%s", username, password)
|
||||
|
||||
swaggerHandler := gin.New()
|
||||
swaggerHandler.GET(path.Join(swaggerPrefix, "*any"), ginSwagger.WrapHandler(swaggerfiles.Handler))
|
||||
server := s.webServer.Group(s.prefix)
|
||||
|
||||
metricHandler := gin.New()
|
||||
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)
|
||||
@ -36,11 +45,18 @@ func (s *Server) setupRoute() {
|
||||
promhttp.Handler().ServeHTTP(ctx.Writer, ctx.Request)
|
||||
})
|
||||
|
||||
apiHandler := gin.New()
|
||||
apiHandler := server
|
||||
|
||||
groupV1 := apiHandler.Group(apiPrefix, gin.BasicAuth(gin.Accounts{
|
||||
username: password,
|
||||
})).Group("/v1")
|
||||
}), 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.
|
||||
@ -57,15 +73,15 @@ func (s *Server) setupRoute() {
|
||||
PUT("/:domain", updateRecord).
|
||||
DELETE("/:domain/:id", deleteRecord)
|
||||
|
||||
server := s.webServer.Group(s.prefix)
|
||||
server.Use(func(ctx *gin.Context) {
|
||||
/*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)
|
||||
//apiHandler.HandleContext(ctx)
|
||||
case strings.HasPrefix(uri, path.Join(s.prefix, metricPrefix)):
|
||||
metricHandler.HandleContext(ctx)
|
||||
//metricHandler.HandleContext(ctx)
|
||||
case strings.HasPrefix(uri, path.Join(s.prefix, swaggerPrefix)):
|
||||
if s.debug {
|
||||
swaggerHandler.HandleContext(ctx)
|
||||
@ -75,5 +91,8 @@ func (s *Server) setupRoute() {
|
||||
default:
|
||||
staticFileHandler()(ctx)
|
||||
}
|
||||
})
|
||||
})*/
|
||||
|
||||
server.GET("/", staticFileHandler())
|
||||
server.GET("/assets/*any", staticFileHandler())
|
||||
}
|
||||
|
@ -22,6 +22,9 @@ func NewServer(c *cli.Context) (*Server, error) {
|
||||
}
|
||||
if c.Bool("debug") {
|
||||
database.Client = database.Client.Debug()
|
||||
gin.SetMode(gin.DebugMode)
|
||||
} else {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
}
|
||||
|
||||
return &Server{
|
||||
|
@ -91,7 +91,8 @@ export default {
|
||||
dotAndMinus: 'should not start or end with "." "-"',
|
||||
doubleDots: 'should have no contianus "."',
|
||||
logerThan63: 'should not longer than 63 characters splited by "."'
|
||||
}
|
||||
},
|
||||
tooLong: 'too long'
|
||||
}
|
||||
}
|
||||
}
|
@ -91,7 +91,8 @@ export default {
|
||||
dotAndMinus: '资源记录不能以 "."、"-" 开头或结尾',
|
||||
doubleDots: '资源记录不能有连续的 "."',
|
||||
logerThan63: '资源记录以 "." 分割的每个字符串长度不能超过63字符'
|
||||
}
|
||||
},
|
||||
tooLong: '记录值过长'
|
||||
}
|
||||
}
|
||||
}
|
@ -35,6 +35,7 @@ export class TXTRecord {
|
||||
|
||||
static validate(v: TXTRecord): true | Error {
|
||||
if (!v.text || v.text === '') return new Error(t('common.mandatory'))
|
||||
if (v.text.length > 512) return new Error('records.errors.tooLong')
|
||||
return true
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user