mirror of
https://github.com/jc21/nginx-proxy-manager.git
synced 2024-08-30 18:22:48 +00:00
Convert db backend to use Gorm, with basis for support
for Mysql and Postgres in addition to existing Sqlite
This commit is contained in:
@ -1,25 +0,0 @@
|
||||
package accesslist
|
||||
|
||||
import (
|
||||
"npm/internal/entity"
|
||||
)
|
||||
|
||||
var filterMapFunctions = make(map[string]entity.FilterMapFunction)
|
||||
|
||||
// getFilterMapFunctions is a map of functions that should be executed
|
||||
// during the filtering process, if a field is defined here then the value in
|
||||
// the filter will be given to the defined function and it will return a new
|
||||
// value for use in the sql query.
|
||||
func getFilterMapFunctions() map[string]entity.FilterMapFunction {
|
||||
// if len(filterMapFunctions) == 0 {
|
||||
// TODO: See internal/model/file_item.go:620 for an example
|
||||
// }
|
||||
|
||||
return filterMapFunctions
|
||||
}
|
||||
|
||||
// GetFilterSchema returns filter schema
|
||||
func GetFilterSchema() string {
|
||||
var m Model
|
||||
return entity.GetFilterSchema(m)
|
||||
}
|
@ -1,122 +1,41 @@
|
||||
package accesslist
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/errors"
|
||||
"npm/internal/logger"
|
||||
"npm/internal/model"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
// GetByID finds a row by ID
|
||||
func GetByID(id int) (Model, error) {
|
||||
func GetByID(id uint) (Model, error) {
|
||||
var m Model
|
||||
err := m.LoadByID(id)
|
||||
return m, err
|
||||
}
|
||||
|
||||
// Create will create a row from this model
|
||||
func Create(m *Model) (int, error) {
|
||||
if m.ID != 0 {
|
||||
return 0, eris.New("Cannot create access list when model already has an ID")
|
||||
}
|
||||
|
||||
m.Touch(true)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
result, err := db.NamedExec(`INSERT INTO `+fmt.Sprintf("`%s`", tableName)+` (
|
||||
created_on,
|
||||
modified_on,
|
||||
user_id,
|
||||
name,
|
||||
meta,
|
||||
is_deleted
|
||||
) VALUES (
|
||||
:created_on,
|
||||
:modified_on,
|
||||
:user_id,
|
||||
:name,
|
||||
:meta,
|
||||
:is_deleted
|
||||
)`, m)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
last, lastErr := result.LastInsertId()
|
||||
if lastErr != nil {
|
||||
return 0, lastErr
|
||||
}
|
||||
|
||||
return int(last), nil
|
||||
}
|
||||
|
||||
// Update will Update a row from this model
|
||||
func Update(m *Model) error {
|
||||
if m.ID == 0 {
|
||||
return eris.New("Cannot update access list when model doesn't have an ID")
|
||||
}
|
||||
|
||||
m.Touch(false)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
_, err := db.NamedExec(`UPDATE `+fmt.Sprintf("`%s`", tableName)+` SET
|
||||
created_on = :created_on,
|
||||
modified_on = :modified_on,
|
||||
user_id = :user_id,
|
||||
name = :name,
|
||||
meta = :meta,
|
||||
is_deleted = :is_deleted
|
||||
WHERE id = :id`, m)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// List will return a list of access lists
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter) (ListResponse, error) {
|
||||
var result ListResponse
|
||||
var exampleModel Model
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse, error) {
|
||||
var result entity.ListResponse
|
||||
|
||||
defaultSort := model.Sort{
|
||||
Field: "name",
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
db := database.GetInstance()
|
||||
if db == nil {
|
||||
return result, errors.ErrDatabaseUnavailable
|
||||
}
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
|
||||
// Get count of items in this search
|
||||
query, params := entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), true)
|
||||
countRow := db.QueryRowx(query, params...)
|
||||
var totalRows int
|
||||
queryErr := countRow.Scan(&totalRows)
|
||||
if queryErr != nil && queryErr != sql.ErrNoRows {
|
||||
logger.Error("ListAccessListsError", queryErr)
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, queryErr
|
||||
var totalRows int64
|
||||
if res := dbo.Model(&Model{}).Count(&totalRows); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
// Get rows
|
||||
items := make([]Model, 0)
|
||||
query, params = entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), false)
|
||||
err := db.Select(&items, query, params...)
|
||||
if err != nil {
|
||||
logger.Error("ListAccessListsError", err)
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, err
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
result = ListResponse{
|
||||
result = entity.ListResponse{
|
||||
Items: items,
|
||||
Total: totalRows,
|
||||
Limit: pageInfo.Limit,
|
||||
|
@ -1,77 +1,54 @@
|
||||
package accesslist
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/entity/user"
|
||||
"npm/internal/types"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
const (
|
||||
tableName = "access_list"
|
||||
)
|
||||
|
||||
// Model is the access list model
|
||||
// Model is the model
|
||||
type Model struct {
|
||||
ID int `json:"id" db:"id" filter:"id,integer"`
|
||||
CreatedOn types.DBDate `json:"created_on" db:"created_on" filter:"created_on,integer"`
|
||||
ModifiedOn types.DBDate `json:"modified_on" db:"modified_on" filter:"modified_on,integer"`
|
||||
UserID int `json:"user_id" db:"user_id" filter:"user_id,integer"`
|
||||
Name string `json:"name" db:"name" filter:"name,string"`
|
||||
Meta types.JSONB `json:"meta" db:"meta"`
|
||||
IsDeleted bool `json:"is_deleted,omitempty" db:"is_deleted"`
|
||||
entity.ModelBase
|
||||
UserID int `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"`
|
||||
Name string `json:"name" gorm:"column:name" filter:"name,string"`
|
||||
Meta types.JSONB `json:"meta" gorm:"column:meta"`
|
||||
// Expansions
|
||||
User *user.Model `json:"user,omitempty"`
|
||||
User *user.Model `json:"user,omitempty" gorm:"-"`
|
||||
}
|
||||
|
||||
func (m *Model) getByQuery(query string, params []interface{}) error {
|
||||
return database.GetByQuery(m, query, params)
|
||||
// TableName overrides the table name used by gorm
|
||||
func (Model) TableName() string {
|
||||
return "access_list"
|
||||
}
|
||||
|
||||
// LoadByID will load from an ID
|
||||
func (m *Model) LoadByID(id int) error {
|
||||
query := fmt.Sprintf("SELECT * FROM `%s` WHERE id = ? AND is_deleted = ? LIMIT 1", tableName)
|
||||
params := []interface{}{id, 0}
|
||||
return m.getByQuery(query, params)
|
||||
}
|
||||
|
||||
// Touch will update model's timestamp(s)
|
||||
func (m *Model) Touch(created bool) {
|
||||
var d types.DBDate
|
||||
d.Time = time.Now()
|
||||
if created {
|
||||
m.CreatedOn = d
|
||||
}
|
||||
m.ModifiedOn = d
|
||||
func (m *Model) LoadByID(id uint) error {
|
||||
db := database.GetDB()
|
||||
result := db.First(&m, id)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Save will save this model to the DB
|
||||
func (m *Model) Save() error {
|
||||
var err error
|
||||
|
||||
if m.UserID == 0 {
|
||||
return eris.Errorf("User ID must be specified")
|
||||
}
|
||||
|
||||
if m.ID == 0 {
|
||||
m.ID, err = Create(m)
|
||||
} else {
|
||||
err = Update(m)
|
||||
}
|
||||
|
||||
return err
|
||||
db := database.GetDB()
|
||||
result := db.Save(m)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Delete will mark a access list as deleted
|
||||
// Delete will mark row as deleted
|
||||
func (m *Model) Delete() bool {
|
||||
m.Touch(false)
|
||||
m.IsDeleted = true
|
||||
if err := m.Save(); err != nil {
|
||||
if m.ID == 0 {
|
||||
// Can't delete a new object
|
||||
return false
|
||||
}
|
||||
return true
|
||||
db := database.GetDB()
|
||||
result := db.Delete(m)
|
||||
return result.Error == nil
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
package accesslist
|
||||
|
||||
import (
|
||||
"npm/internal/model"
|
||||
)
|
||||
|
||||
// ListResponse is the JSON response for the list
|
||||
type ListResponse struct {
|
||||
Total int `json:"total"`
|
||||
Offset int `json:"offset"`
|
||||
Limit int `json:"limit"`
|
||||
Sort []model.Sort `json:"sort"`
|
||||
Filter []model.Filter `json:"filter,omitempty"`
|
||||
Items []Model `json:"items,omitempty"`
|
||||
}
|
@ -1,11 +1,7 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"npm/internal/database"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
// GetByID finds a auth by ID
|
||||
@ -16,12 +12,17 @@ func GetByID(id int) (Model, error) {
|
||||
}
|
||||
|
||||
// GetByUserIDType finds a user by email
|
||||
func GetByUserIDType(userID int, authType string) (Model, error) {
|
||||
var m Model
|
||||
err := m.LoadByUserIDType(userID, authType)
|
||||
return m, err
|
||||
func GetByUserIDType(userID uint, authType string) (Model, error) {
|
||||
var auth Model
|
||||
db := database.GetDB()
|
||||
result := db.
|
||||
Where("user_id = ?", userID).
|
||||
Where("type = ?", authType).
|
||||
First(&auth)
|
||||
return auth, result.Error
|
||||
}
|
||||
|
||||
/*
|
||||
// Create will create a Auth from this model
|
||||
func Create(auth *Model) (int, error) {
|
||||
if auth.ID != 0 {
|
||||
@ -59,7 +60,9 @@ func Create(auth *Model) (int, error) {
|
||||
|
||||
return int(last), nil
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// Update will Update a Auth from this model
|
||||
func Update(auth *Model) error {
|
||||
if auth.ID == 0 {
|
||||
@ -81,3 +84,4 @@ func Update(auth *Model) error {
|
||||
|
||||
return err
|
||||
}
|
||||
*/
|
||||
|
@ -1,52 +1,49 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/types"
|
||||
"npm/internal/entity"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
const (
|
||||
tableName = "auth"
|
||||
|
||||
// TypePassword is the Password Type
|
||||
TypePassword = "password"
|
||||
)
|
||||
|
||||
// Model is the user model
|
||||
// Model is the model
|
||||
type Model struct {
|
||||
ID int `json:"id" db:"id"`
|
||||
UserID int `json:"user_id" db:"user_id"`
|
||||
Type string `json:"type" db:"type"`
|
||||
Secret string `json:"secret,omitempty" db:"secret"`
|
||||
CreatedOn types.DBDate `json:"created_on" db:"created_on"`
|
||||
ModifiedOn types.DBDate `json:"modified_on" db:"modified_on"`
|
||||
IsDeleted bool `json:"is_deleted,omitempty" db:"is_deleted"`
|
||||
entity.ModelBase
|
||||
UserID uint `json:"user_id" gorm:"column:user_id"`
|
||||
Type string `json:"type" gorm:"column:type;default:password"`
|
||||
Secret string `json:"secret,omitempty" gorm:"column:secret"`
|
||||
}
|
||||
|
||||
func (m *Model) getByQuery(query string, params []interface{}) error {
|
||||
return database.GetByQuery(m, query, params)
|
||||
// TableName overrides the table name used by gorm
|
||||
func (Model) TableName() string {
|
||||
return "auth"
|
||||
}
|
||||
|
||||
// LoadByID will load from an ID
|
||||
func (m *Model) LoadByID(id int) error {
|
||||
query := fmt.Sprintf("SELECT * FROM `%s` WHERE id = ? LIMIT 1", tableName)
|
||||
params := []interface{}{id}
|
||||
return m.getByQuery(query, params)
|
||||
db := database.GetDB()
|
||||
result := db.First(&m, id)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// LoadByUserIDType will load from an ID
|
||||
func (m *Model) LoadByUserIDType(userID int, authType string) error {
|
||||
query := fmt.Sprintf("SELECT * FROM `%s` WHERE user_id = ? AND type = ? LIMIT 1", tableName)
|
||||
params := []interface{}{userID, authType}
|
||||
return m.getByQuery(query, params)
|
||||
db := database.GetDB()
|
||||
result := db.
|
||||
Where("user_id = ?", userID).
|
||||
Where("type = ?", authType).
|
||||
First(&m)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
/*
|
||||
// Touch will update model's timestamp(s)
|
||||
func (m *Model) Touch(created bool) {
|
||||
var d types.DBDate
|
||||
@ -56,18 +53,14 @@ func (m *Model) Touch(created bool) {
|
||||
}
|
||||
m.ModifiedOn = d
|
||||
}
|
||||
*/
|
||||
|
||||
// Save will save this model to the DB
|
||||
func (m *Model) Save() error {
|
||||
var err error
|
||||
|
||||
if m.ID == 0 {
|
||||
m.ID, err = Create(m)
|
||||
} else {
|
||||
err = Update(m)
|
||||
}
|
||||
|
||||
return err
|
||||
db := database.GetDB()
|
||||
// todo: touch? not sure that save does this or not?
|
||||
result := db.Save(m)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// SetPassword will generate a hashed password based on given string
|
||||
|
11
backend/internal/entity/capability.go
Normal file
11
backend/internal/entity/capability.go
Normal file
@ -0,0 +1,11 @@
|
||||
package entity
|
||||
|
||||
// Capability is the db model
|
||||
type Capability struct {
|
||||
Name string `json:"name" gorm:"column:name;primaryKey" filter:"name,string"`
|
||||
}
|
||||
|
||||
// TableName overrides the table name used by gorm
|
||||
func (Capability) TableName() string {
|
||||
return "capability"
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package certificate
|
||||
|
||||
import (
|
||||
"npm/internal/entity"
|
||||
)
|
||||
|
||||
var filterMapFunctions = make(map[string]entity.FilterMapFunction)
|
||||
|
||||
// getFilterMapFunctions is a map of functions that should be executed
|
||||
// during the filtering process, if a field is defined here then the value in
|
||||
// the filter will be given to the defined function and it will return a new
|
||||
// value for use in the sql query.
|
||||
func getFilterMapFunctions() map[string]entity.FilterMapFunction {
|
||||
// if len(filterMapFunctions) == 0 {
|
||||
// TODO: See internal/model/file_item.go:620 for an example
|
||||
// }
|
||||
|
||||
return filterMapFunctions
|
||||
}
|
||||
|
||||
// GetFilterSchema returns filter schema
|
||||
func GetFilterSchema() string {
|
||||
var m Model
|
||||
return entity.GetFilterSchema(m)
|
||||
}
|
@ -1,142 +1,54 @@
|
||||
package certificate
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/errors"
|
||||
"npm/internal/jobqueue"
|
||||
"npm/internal/logger"
|
||||
"npm/internal/model"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
// GetByID finds a row by ID
|
||||
func GetByID(id int) (Model, error) {
|
||||
func GetByID(id uint) (Model, error) {
|
||||
var m Model
|
||||
err := m.LoadByID(id)
|
||||
return m, err
|
||||
}
|
||||
|
||||
// Create will create a row from this model
|
||||
func Create(certificate *Model) (int, error) {
|
||||
if certificate.ID != 0 {
|
||||
return 0, eris.New("Cannot create certificate when model already has an ID")
|
||||
}
|
||||
|
||||
certificate.Touch(true)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
result, err := db.NamedExec(`INSERT INTO `+fmt.Sprintf("`%s`", tableName)+` (
|
||||
created_on,
|
||||
modified_on,
|
||||
user_id,
|
||||
type,
|
||||
certificate_authority_id,
|
||||
dns_provider_id,
|
||||
name,
|
||||
domain_names,
|
||||
expires_on,
|
||||
status,
|
||||
error_message,
|
||||
meta,
|
||||
is_ecc,
|
||||
is_deleted
|
||||
) VALUES (
|
||||
:created_on,
|
||||
:modified_on,
|
||||
:user_id,
|
||||
:type,
|
||||
:certificate_authority_id,
|
||||
:dns_provider_id,
|
||||
:name,
|
||||
:domain_names,
|
||||
:expires_on,
|
||||
:status,
|
||||
:error_message,
|
||||
:meta,
|
||||
:is_ecc,
|
||||
:is_deleted
|
||||
)`, certificate)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
last, lastErr := result.LastInsertId()
|
||||
if lastErr != nil {
|
||||
return 0, lastErr
|
||||
}
|
||||
|
||||
return int(last), nil
|
||||
}
|
||||
|
||||
// Update will Update a Auth from this model
|
||||
func Update(certificate *Model) error {
|
||||
if certificate.ID == 0 {
|
||||
return eris.New("Cannot update certificate when model doesn't have an ID")
|
||||
}
|
||||
|
||||
certificate.Touch(false)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
_, err := db.NamedExec(`UPDATE `+fmt.Sprintf("`%s`", tableName)+` SET
|
||||
created_on = :created_on,
|
||||
modified_on = :modified_on,
|
||||
type = :type,
|
||||
user_id = :user_id,
|
||||
certificate_authority_id = :certificate_authority_id,
|
||||
dns_provider_id = :dns_provider_id,
|
||||
name = :name,
|
||||
domain_names = :domain_names,
|
||||
expires_on = :expires_on,
|
||||
status = :status,
|
||||
error_message = :error_message,
|
||||
meta = :meta,
|
||||
is_ecc = :is_ecc,
|
||||
is_deleted = :is_deleted
|
||||
WHERE id = :id`, certificate)
|
||||
|
||||
return err
|
||||
// GetByStatus will select rows that are ready for requesting
|
||||
func GetByStatus(status string) ([]Model, error) {
|
||||
items := make([]Model, 0)
|
||||
db := database.GetDB()
|
||||
result := db.
|
||||
Joins("INNER JOIN certificate_authority ON certificate_authority.id = certificate.certificate_authority_id AND certificate_authority.is_deleted = ?", 0).
|
||||
Where("type IN ?", []string{"http", "dns"}).
|
||||
Where("status = ?", status).
|
||||
Where("certificate_authority_id > ?", 0).
|
||||
Find(&items)
|
||||
return items, result.Error
|
||||
}
|
||||
|
||||
// List will return a list of certificates
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (ListResponse, error) {
|
||||
var result ListResponse
|
||||
var exampleModel Model
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (entity.ListResponse, error) {
|
||||
var result entity.ListResponse
|
||||
|
||||
defaultSort := model.Sort{
|
||||
Field: "name",
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
db := database.GetInstance()
|
||||
if db == nil {
|
||||
return result, errors.ErrDatabaseUnavailable
|
||||
}
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
|
||||
// Get count of items in this search
|
||||
query, params := entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), true)
|
||||
countRow := db.QueryRowx(query, params...)
|
||||
var totalRows int
|
||||
queryErr := countRow.Scan(&totalRows)
|
||||
if queryErr != nil && queryErr != sql.ErrNoRows {
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, queryErr
|
||||
var totalRows int64
|
||||
if res := dbo.Model(&Model{}).Count(&totalRows); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
// Get rows
|
||||
items := make([]Model, 0)
|
||||
query, params = entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), false)
|
||||
err := db.Select(&items, query, params...)
|
||||
if err != nil {
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, err
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
if expand != nil {
|
||||
@ -148,7 +60,7 @@ func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (Lis
|
||||
}
|
||||
}
|
||||
|
||||
result = ListResponse{
|
||||
result = entity.ListResponse{
|
||||
Items: items,
|
||||
Total: totalRows,
|
||||
Limit: pageInfo.Limit,
|
||||
@ -160,33 +72,6 @@ func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (Lis
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetByStatus will select rows that are ready for requesting
|
||||
func GetByStatus(status string) ([]Model, error) {
|
||||
models := make([]Model, 0)
|
||||
db := database.GetInstance()
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
SELECT
|
||||
t.*
|
||||
FROM "%s" t
|
||||
INNER JOIN "certificate_authority" c ON c."id" = t."certificate_authority_id"
|
||||
WHERE
|
||||
t."type" IN ("http", "dns") AND
|
||||
t."status" = ? AND
|
||||
t."certificate_authority_id" > 0 AND
|
||||
t."is_deleted" = 0
|
||||
`, tableName)
|
||||
|
||||
params := []interface{}{StatusReady}
|
||||
err := db.Select(&models, query, params...)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
logger.Error("GetByStatusError", err)
|
||||
logger.Debug("Query: %s -- %+v", query, params)
|
||||
}
|
||||
|
||||
return models, err
|
||||
}
|
||||
|
||||
// AddPendingJobs is intended to be used at startup to add
|
||||
// anything pending to the JobQueue just once, based on
|
||||
// the database row status
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"npm/internal/acme"
|
||||
"npm/internal/config"
|
||||
"npm/internal/database"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/entity/certificateauthority"
|
||||
"npm/internal/entity/dnsprovider"
|
||||
"npm/internal/entity/user"
|
||||
@ -22,8 +23,6 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
tableName = "certificate"
|
||||
|
||||
// TypeCustom custom cert type
|
||||
TypeCustom = "custom"
|
||||
// TypeHTTP http cert type
|
||||
@ -43,54 +42,40 @@ const (
|
||||
StatusProvided = "provided"
|
||||
)
|
||||
|
||||
// Model is the user model
|
||||
// Model is the model
|
||||
type Model struct {
|
||||
ID int `json:"id" db:"id" filter:"id,integer"`
|
||||
CreatedOn types.DBDate `json:"created_on" db:"created_on" filter:"created_on,integer"`
|
||||
ModifiedOn types.DBDate `json:"modified_on" db:"modified_on" filter:"modified_on,integer"`
|
||||
ExpiresOn types.NullableDBDate `json:"expires_on" db:"expires_on" filter:"expires_on,integer"`
|
||||
Type string `json:"type" db:"type" filter:"type,string"`
|
||||
UserID int `json:"user_id" db:"user_id" filter:"user_id,integer"`
|
||||
CertificateAuthorityID int `json:"certificate_authority_id" db:"certificate_authority_id" filter:"certificate_authority_id,integer"`
|
||||
DNSProviderID int `json:"dns_provider_id" db:"dns_provider_id" filter:"dns_provider_id,integer"`
|
||||
Name string `json:"name" db:"name" filter:"name,string"`
|
||||
DomainNames types.JSONB `json:"domain_names" db:"domain_names" filter:"domain_names,string"`
|
||||
Status string `json:"status" db:"status" filter:"status,string"`
|
||||
ErrorMessage string `json:"error_message" db:"error_message" filter:"error_message,string"`
|
||||
Meta types.JSONB `json:"-" db:"meta"`
|
||||
IsECC bool `json:"is_ecc" db:"is_ecc" filter:"is_ecc,bool"`
|
||||
IsDeleted bool `json:"is_deleted,omitempty" db:"is_deleted"`
|
||||
entity.ModelBase
|
||||
ExpiresOn types.NullableDBDate `json:"expires_on" gorm:"column:expires_on" filter:"expires_on,integer"`
|
||||
Type string `json:"type" gorm:"column:type" filter:"type,string"`
|
||||
UserID uint `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"`
|
||||
CertificateAuthorityID uint `json:"certificate_authority_id" gorm:"column:certificate_authority_id" filter:"certificate_authority_id,integer"`
|
||||
DNSProviderID uint `json:"dns_provider_id" gorm:"column:dns_provider_id" filter:"dns_provider_id,integer"`
|
||||
Name string `json:"name" gorm:"column:name" filter:"name,string"`
|
||||
DomainNames types.JSONB `json:"domain_names" gorm:"column:domain_names" filter:"domain_names,string"`
|
||||
Status string `json:"status" gorm:"column:status" filter:"status,string"`
|
||||
ErrorMessage string `json:"error_message" gorm:"column:error_message" filter:"error_message,string"`
|
||||
Meta types.JSONB `json:"-" gorm:"column:meta"`
|
||||
IsECC bool `json:"is_ecc" gorm:"column:is_ecc" filter:"is_ecc,bool"`
|
||||
// Expansions:
|
||||
CertificateAuthority *certificateauthority.Model `json:"certificate_authority,omitempty"`
|
||||
DNSProvider *dnsprovider.Model `json:"dns_provider,omitempty"`
|
||||
User *user.Model `json:"user,omitempty"`
|
||||
CertificateAuthority *certificateauthority.Model `json:"certificate_authority,omitempty" gorm:"-"`
|
||||
DNSProvider *dnsprovider.Model `json:"dns_provider,omitempty" gorm:"-"`
|
||||
User *user.Model `json:"user,omitempty" gorm:"-"`
|
||||
}
|
||||
|
||||
func (m *Model) getByQuery(query string, params []interface{}) error {
|
||||
return database.GetByQuery(m, query, params)
|
||||
// TableName overrides the table name used by gorm
|
||||
func (Model) TableName() string {
|
||||
return "certificate"
|
||||
}
|
||||
|
||||
// LoadByID will load from an ID
|
||||
func (m *Model) LoadByID(id int) error {
|
||||
query := fmt.Sprintf("SELECT * FROM `%s` WHERE id = ? AND is_deleted = ? LIMIT 1", tableName)
|
||||
params := []interface{}{id, 0}
|
||||
return m.getByQuery(query, params)
|
||||
}
|
||||
|
||||
// Touch will update model's timestamp(s)
|
||||
func (m *Model) Touch(created bool) {
|
||||
var d types.DBDate
|
||||
d.Time = time.Now()
|
||||
if created {
|
||||
m.CreatedOn = d
|
||||
}
|
||||
m.ModifiedOn = d
|
||||
func (m *Model) LoadByID(id uint) error {
|
||||
db := database.GetDB()
|
||||
result := db.First(&m, id)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Save will save this model to the DB
|
||||
func (m *Model) Save() error {
|
||||
var err error
|
||||
|
||||
if m.UserID == 0 {
|
||||
return eris.Errorf("User ID must be specified")
|
||||
}
|
||||
@ -108,26 +93,22 @@ func (m *Model) Save() error {
|
||||
// ensure name is trimmed of whitespace
|
||||
m.Name = strings.TrimSpace(m.Name)
|
||||
|
||||
if m.ID == 0 {
|
||||
m.ID, err = Create(m)
|
||||
} else {
|
||||
err = Update(m)
|
||||
}
|
||||
|
||||
return err
|
||||
db := database.GetDB()
|
||||
result := db.Save(m)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Delete will mark a certificate as deleted
|
||||
// Delete will mark row as deleted
|
||||
func (m *Model) Delete() bool {
|
||||
m.Touch(false)
|
||||
m.IsDeleted = true
|
||||
if err := m.Save(); err != nil {
|
||||
if m.ID == 0 {
|
||||
// Can't delete a new object
|
||||
return false
|
||||
}
|
||||
db := database.GetDB()
|
||||
result := db.Delete(m)
|
||||
return result.Error == nil
|
||||
|
||||
// todo: delete from acme.sh as well
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Validate will make sure the data given is expected. This object is a bit complicated,
|
||||
@ -304,8 +285,8 @@ func (m *Model) GetTemplate() Template {
|
||||
|
||||
return Template{
|
||||
ID: m.ID,
|
||||
CreatedOn: m.CreatedOn.Time.String(),
|
||||
ModifiedOn: m.ModifiedOn.Time.String(),
|
||||
CreatedAt: fmt.Sprintf("%d", m.CreatedAt), // todo: nice date string
|
||||
UpdatedAt: fmt.Sprintf("%d", m.UpdatedAt), // todo: nice date string
|
||||
ExpiresOn: m.ExpiresOn.AsString(),
|
||||
Type: m.Type,
|
||||
UserID: m.UserID,
|
||||
|
@ -1,15 +0,0 @@
|
||||
package certificate
|
||||
|
||||
import (
|
||||
"npm/internal/model"
|
||||
)
|
||||
|
||||
// ListResponse is the JSON response for users list
|
||||
type ListResponse struct {
|
||||
Total int `json:"total"`
|
||||
Offset int `json:"offset"`
|
||||
Limit int `json:"limit"`
|
||||
Sort []model.Sort `json:"sort"`
|
||||
Filter []model.Filter `json:"filter,omitempty"`
|
||||
Items []Model `json:"items,omitempty"`
|
||||
}
|
@ -2,14 +2,14 @@ package certificate
|
||||
|
||||
// Template is the model given to the template parser, converted from the Model
|
||||
type Template struct {
|
||||
ID int
|
||||
CreatedOn string
|
||||
ModifiedOn string
|
||||
ID uint
|
||||
CreatedAt string
|
||||
UpdatedAt string
|
||||
ExpiresOn string
|
||||
Type string
|
||||
UserID int
|
||||
CertificateAuthorityID int
|
||||
DNSProviderID int
|
||||
UserID uint
|
||||
CertificateAuthorityID uint
|
||||
DNSProviderID uint
|
||||
Name string
|
||||
DomainNames []string
|
||||
Status string
|
||||
|
@ -1,25 +0,0 @@
|
||||
package certificateauthority
|
||||
|
||||
import (
|
||||
"npm/internal/entity"
|
||||
)
|
||||
|
||||
var filterMapFunctions = make(map[string]entity.FilterMapFunction)
|
||||
|
||||
// getFilterMapFunctions is a map of functions that should be executed
|
||||
// during the filtering process, if a field is defined here then the value in
|
||||
// the filter will be given to the defined function and it will return a new
|
||||
// value for use in the sql query.
|
||||
func getFilterMapFunctions() map[string]entity.FilterMapFunction {
|
||||
// if len(filterMapFunctions) == 0 {
|
||||
// TODO: See internal/model/file_item.go:620 for an example
|
||||
// }
|
||||
|
||||
return filterMapFunctions
|
||||
}
|
||||
|
||||
// GetFilterSchema returns filter schema
|
||||
func GetFilterSchema() string {
|
||||
var m Model
|
||||
return entity.GetFilterSchema(m)
|
||||
}
|
@ -1,128 +1,41 @@
|
||||
package certificateauthority
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/errors"
|
||||
"npm/internal/logger"
|
||||
"npm/internal/model"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
// GetByID finds a row by ID
|
||||
func GetByID(id int) (Model, error) {
|
||||
func GetByID(id uint) (Model, error) {
|
||||
var m Model
|
||||
err := m.LoadByID(id)
|
||||
return m, err
|
||||
}
|
||||
|
||||
// Create will create a row from this model
|
||||
func Create(ca *Model) (int, error) {
|
||||
if ca.ID != 0 {
|
||||
return 0, eris.New("Cannot create certificate authority when model already has an ID")
|
||||
}
|
||||
|
||||
ca.Touch(true)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
result, err := db.NamedExec(`INSERT INTO `+fmt.Sprintf("`%s`", tableName)+` (
|
||||
created_on,
|
||||
modified_on,
|
||||
name,
|
||||
acmesh_server,
|
||||
ca_bundle,
|
||||
max_domains,
|
||||
is_wildcard_supported,
|
||||
is_deleted
|
||||
) VALUES (
|
||||
:created_on,
|
||||
:modified_on,
|
||||
:name,
|
||||
:acmesh_server,
|
||||
:ca_bundle,
|
||||
:max_domains,
|
||||
:is_wildcard_supported,
|
||||
:is_deleted
|
||||
)`, ca)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
last, lastErr := result.LastInsertId()
|
||||
if lastErr != nil {
|
||||
return 0, lastErr
|
||||
}
|
||||
|
||||
return int(last), nil
|
||||
}
|
||||
|
||||
// Update will Update a row from this model
|
||||
func Update(ca *Model) error {
|
||||
if ca.ID == 0 {
|
||||
return eris.New("Cannot update certificate authority when model doesn't have an ID")
|
||||
}
|
||||
|
||||
ca.Touch(false)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
_, err := db.NamedExec(`UPDATE `+fmt.Sprintf("`%s`", tableName)+` SET
|
||||
created_on = :created_on,
|
||||
modified_on = :modified_on,
|
||||
name = :name,
|
||||
acmesh_server = :acmesh_server,
|
||||
ca_bundle = :ca_bundle,
|
||||
max_domains = :max_domains,
|
||||
is_wildcard_supported = :is_wildcard_supported,
|
||||
is_deleted = :is_deleted
|
||||
WHERE id = :id`, ca)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// List will return a list of certificates
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter) (ListResponse, error) {
|
||||
var result ListResponse
|
||||
var exampleModel Model
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse, error) {
|
||||
var result entity.ListResponse
|
||||
|
||||
defaultSort := model.Sort{
|
||||
Field: "name",
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
db := database.GetInstance()
|
||||
if db == nil {
|
||||
return result, errors.ErrDatabaseUnavailable
|
||||
}
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
|
||||
// Get count of items in this search
|
||||
query, params := entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), true)
|
||||
countRow := db.QueryRowx(query, params...)
|
||||
var totalRows int
|
||||
queryErr := countRow.Scan(&totalRows)
|
||||
if queryErr != nil && queryErr != sql.ErrNoRows {
|
||||
logger.Error("ListCertificateAuthoritiesError", queryErr)
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, queryErr
|
||||
var totalRows int64
|
||||
if res := dbo.Model(&Model{}).Count(&totalRows); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
// Get rows
|
||||
items := make([]Model, 0)
|
||||
query, params = entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), false)
|
||||
err := db.Select(&items, query, params...)
|
||||
if err != nil {
|
||||
logger.Error("ListCertificateAuthoritiesError", err)
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, err
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
result = ListResponse{
|
||||
result = entity.ListResponse{
|
||||
Items: items,
|
||||
Total: totalRows,
|
||||
Limit: pageInfo.Limit,
|
||||
|
@ -1,78 +1,55 @@
|
||||
package certificateauthority
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/errors"
|
||||
"npm/internal/types"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
const (
|
||||
tableName = "certificate_authority"
|
||||
)
|
||||
|
||||
// Model is the user model
|
||||
// Model is the model
|
||||
type Model struct {
|
||||
ID int `json:"id" db:"id" filter:"id,integer"`
|
||||
CreatedOn types.DBDate `json:"created_on" db:"created_on" filter:"created_on,integer"`
|
||||
ModifiedOn types.DBDate `json:"modified_on" db:"modified_on" filter:"modified_on,integer"`
|
||||
Name string `json:"name" db:"name" filter:"name,string"`
|
||||
AcmeshServer string `json:"acmesh_server" db:"acmesh_server" filter:"acmesh_server,string"`
|
||||
CABundle string `json:"ca_bundle" db:"ca_bundle" filter:"ca_bundle,string"`
|
||||
MaxDomains int `json:"max_domains" db:"max_domains" filter:"max_domains,integer"`
|
||||
IsWildcardSupported bool `json:"is_wildcard_supported" db:"is_wildcard_supported" filter:"is_wildcard_supported,boolean"`
|
||||
IsReadonly bool `json:"is_readonly" db:"is_readonly" filter:"is_readonly,boolean"`
|
||||
IsDeleted bool `json:"is_deleted,omitempty" db:"is_deleted"`
|
||||
entity.ModelBase
|
||||
Name string `json:"name" gorm:"column:name" filter:"name,string"`
|
||||
AcmeshServer string `json:"acmesh_server" gorm:"column:acmesh_server" filter:"acmesh_server,string"`
|
||||
CABundle string `json:"ca_bundle" gorm:"column:ca_bundle" filter:"ca_bundle,string"`
|
||||
MaxDomains int `json:"max_domains" gorm:"column:max_domains" filter:"max_domains,integer"`
|
||||
IsWildcardSupported bool `json:"is_wildcard_supported" gorm:"column:is_wildcard_supported" filter:"is_wildcard_supported,boolean"`
|
||||
IsReadonly bool `json:"is_readonly" gorm:"column:is_readonly" filter:"is_readonly,boolean"`
|
||||
}
|
||||
|
||||
func (m *Model) getByQuery(query string, params []interface{}) error {
|
||||
return database.GetByQuery(m, query, params)
|
||||
// TableName overrides the table name used by gorm
|
||||
func (Model) TableName() string {
|
||||
return "certificate_authority"
|
||||
}
|
||||
|
||||
// LoadByID will load from an ID
|
||||
func (m *Model) LoadByID(id int) error {
|
||||
query := fmt.Sprintf("SELECT * FROM `%s` WHERE id = ? AND is_deleted = ? LIMIT 1", tableName)
|
||||
params := []interface{}{id, 0}
|
||||
return m.getByQuery(query, params)
|
||||
}
|
||||
|
||||
// Touch will update model's timestamp(s)
|
||||
func (m *Model) Touch(created bool) {
|
||||
var d types.DBDate
|
||||
d.Time = time.Now()
|
||||
if created {
|
||||
m.CreatedOn = d
|
||||
}
|
||||
m.ModifiedOn = d
|
||||
func (m *Model) LoadByID(id uint) error {
|
||||
db := database.GetDB()
|
||||
result := db.First(&m, id)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Save will save this model to the DB
|
||||
func (m *Model) Save() error {
|
||||
var err error
|
||||
|
||||
if m.ID == 0 {
|
||||
m.ID, err = Create(m)
|
||||
} else {
|
||||
err = Update(m)
|
||||
}
|
||||
|
||||
return err
|
||||
db := database.GetDB()
|
||||
result := db.Save(m)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Delete will mark a certificate as deleted
|
||||
// Delete will mark row as deleted
|
||||
func (m *Model) Delete() bool {
|
||||
m.Touch(false)
|
||||
m.IsDeleted = true
|
||||
if err := m.Save(); err != nil {
|
||||
if m.ID == 0 {
|
||||
// Can't delete a new object
|
||||
return false
|
||||
}
|
||||
return true
|
||||
db := database.GetDB()
|
||||
result := db.Delete(m)
|
||||
return result.Error == nil
|
||||
}
|
||||
|
||||
// Check will ensure the ca bundle path exists if it's set
|
||||
|
@ -1,15 +0,0 @@
|
||||
package certificateauthority
|
||||
|
||||
import (
|
||||
"npm/internal/model"
|
||||
)
|
||||
|
||||
// ListResponse is the JSON response for users list
|
||||
type ListResponse struct {
|
||||
Total int `json:"total"`
|
||||
Offset int `json:"offset"`
|
||||
Limit int `json:"limit"`
|
||||
Sort []model.Sort `json:"sort"`
|
||||
Filter []model.Filter `json:"filter,omitempty"`
|
||||
Items []Model `json:"items,omitempty"`
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package dnsprovider
|
||||
|
||||
import (
|
||||
"npm/internal/entity"
|
||||
)
|
||||
|
||||
var filterMapFunctions = make(map[string]entity.FilterMapFunction)
|
||||
|
||||
// getFilterMapFunctions is a map of functions that should be executed
|
||||
// during the filtering process, if a field is defined here then the value in
|
||||
// the filter will be given to the defined function and it will return a new
|
||||
// value for use in the sql query.
|
||||
func getFilterMapFunctions() map[string]entity.FilterMapFunction {
|
||||
// if len(filterMapFunctions) == 0 {
|
||||
// TODO: See internal/model/file_item.go:620 for an example
|
||||
// }
|
||||
|
||||
return filterMapFunctions
|
||||
}
|
||||
|
||||
// GetFilterSchema returns filter schema
|
||||
func GetFilterSchema() string {
|
||||
var m Model
|
||||
return entity.GetFilterSchema(m)
|
||||
}
|
@ -1,128 +1,41 @@
|
||||
package dnsprovider
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/errors"
|
||||
"npm/internal/logger"
|
||||
"npm/internal/model"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
// GetByID finds a row by ID
|
||||
func GetByID(id int) (Model, error) {
|
||||
func GetByID(id uint) (Model, error) {
|
||||
var m Model
|
||||
err := m.LoadByID(id)
|
||||
return m, err
|
||||
}
|
||||
|
||||
// Create will create a row from this model
|
||||
func Create(provider *Model) (int, error) {
|
||||
if provider.ID != 0 {
|
||||
return 0, eris.New("Cannot create dns provider when model already has an ID")
|
||||
}
|
||||
|
||||
provider.Touch(true)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
result, err := db.NamedExec(`INSERT INTO `+fmt.Sprintf("`%s`", tableName)+` (
|
||||
created_on,
|
||||
modified_on,
|
||||
user_id,
|
||||
name,
|
||||
acmesh_name,
|
||||
dns_sleep,
|
||||
meta,
|
||||
is_deleted
|
||||
) VALUES (
|
||||
:created_on,
|
||||
:modified_on,
|
||||
:user_id,
|
||||
:name,
|
||||
:acmesh_name,
|
||||
:dns_sleep,
|
||||
:meta,
|
||||
:is_deleted
|
||||
)`, provider)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
last, lastErr := result.LastInsertId()
|
||||
if lastErr != nil {
|
||||
return 0, lastErr
|
||||
}
|
||||
|
||||
return int(last), nil
|
||||
}
|
||||
|
||||
// Update will Update a row from this model
|
||||
func Update(provider *Model) error {
|
||||
if provider.ID == 0 {
|
||||
return eris.New("Cannot update dns provider when model doesn't have an ID")
|
||||
}
|
||||
|
||||
provider.Touch(false)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
_, err := db.NamedExec(`UPDATE `+fmt.Sprintf("`%s`", tableName)+` SET
|
||||
created_on = :created_on,
|
||||
modified_on = :modified_on,
|
||||
user_id = :user_id,
|
||||
name = :name,
|
||||
acmesh_name = :acmesh_name,
|
||||
dns_sleep = :dns_sleep,
|
||||
meta = :meta,
|
||||
is_deleted = :is_deleted
|
||||
WHERE id = :id`, provider)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// List will return a list of certificates
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter) (ListResponse, error) {
|
||||
var result ListResponse
|
||||
var exampleModel Model
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse, error) {
|
||||
var result entity.ListResponse
|
||||
|
||||
defaultSort := model.Sort{
|
||||
Field: "name",
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
db := database.GetInstance()
|
||||
if db == nil {
|
||||
return result, errors.ErrDatabaseUnavailable
|
||||
}
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
|
||||
// Get count of items in this search
|
||||
query, params := entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), true)
|
||||
countRow := db.QueryRowx(query, params...)
|
||||
var totalRows int
|
||||
queryErr := countRow.Scan(&totalRows)
|
||||
if queryErr != nil && queryErr != sql.ErrNoRows {
|
||||
logger.Error("ListDnsProvidersError", queryErr)
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, queryErr
|
||||
var totalRows int64
|
||||
if res := dbo.Model(&Model{}).Count(&totalRows); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
// Get rows
|
||||
items := make([]Model, 0)
|
||||
query, params = entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), false)
|
||||
err := db.Select(&items, query, params...)
|
||||
if err != nil {
|
||||
logger.Error("ListDnsProvidersError", err)
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, err
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
result = ListResponse{
|
||||
result = entity.ListResponse{
|
||||
Items: items,
|
||||
Total: totalRows,
|
||||
Limit: pageInfo.Limit,
|
||||
|
@ -2,80 +2,58 @@ package dnsprovider
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/dnsproviders"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/logger"
|
||||
"npm/internal/types"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
const (
|
||||
tableName = "dns_provider"
|
||||
)
|
||||
|
||||
// Model is the user model
|
||||
// Also see: https://github.com/acmesh-official/acme.sh/wiki/dnscheck
|
||||
// Model is the model
|
||||
type Model struct {
|
||||
ID int `json:"id" db:"id" filter:"id,integer"`
|
||||
CreatedOn types.DBDate `json:"created_on" db:"created_on" filter:"created_on,integer"`
|
||||
ModifiedOn types.DBDate `json:"modified_on" db:"modified_on" filter:"modified_on,integer"`
|
||||
UserID int `json:"user_id" db:"user_id" filter:"user_id,integer"`
|
||||
Name string `json:"name" db:"name" filter:"name,string"`
|
||||
AcmeshName string `json:"acmesh_name" db:"acmesh_name" filter:"acmesh_name,string"`
|
||||
DNSSleep int `json:"dns_sleep" db:"dns_sleep" filter:"dns_sleep,integer"`
|
||||
Meta types.JSONB `json:"meta" db:"meta"`
|
||||
IsDeleted bool `json:"is_deleted,omitempty" db:"is_deleted"`
|
||||
entity.ModelBase
|
||||
UserID int `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"`
|
||||
Name string `json:"name" gorm:"column:name" filter:"name,string"`
|
||||
AcmeshName string `json:"acmesh_name" gorm:"column:acmesh_name" filter:"acmesh_name,string"`
|
||||
DNSSleep int `json:"dns_sleep" gorm:"column:dns_sleep" filter:"dns_sleep,integer"`
|
||||
Meta types.JSONB `json:"meta" gorm:"column:meta"`
|
||||
}
|
||||
|
||||
func (m *Model) getByQuery(query string, params []interface{}) error {
|
||||
return database.GetByQuery(m, query, params)
|
||||
// TableName overrides the table name used by gorm
|
||||
func (Model) TableName() string {
|
||||
return "dns_provider"
|
||||
}
|
||||
|
||||
// LoadByID will load from an ID
|
||||
func (m *Model) LoadByID(id int) error {
|
||||
query := fmt.Sprintf("SELECT * FROM `%s` WHERE id = ? AND is_deleted = ? LIMIT 1", tableName)
|
||||
params := []interface{}{id, 0}
|
||||
return m.getByQuery(query, params)
|
||||
}
|
||||
|
||||
// Touch will update model's timestamp(s)
|
||||
func (m *Model) Touch(created bool) {
|
||||
var d types.DBDate
|
||||
d.Time = time.Now()
|
||||
if created {
|
||||
m.CreatedOn = d
|
||||
}
|
||||
m.ModifiedOn = d
|
||||
func (m *Model) LoadByID(id uint) error {
|
||||
db := database.GetDB()
|
||||
result := db.First(&m, id)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Save will save this model to the DB
|
||||
func (m *Model) Save() error {
|
||||
var err error
|
||||
|
||||
if m.UserID == 0 {
|
||||
return eris.Errorf("User ID must be specified")
|
||||
}
|
||||
|
||||
if m.ID == 0 {
|
||||
m.ID, err = Create(m)
|
||||
} else {
|
||||
err = Update(m)
|
||||
}
|
||||
|
||||
return err
|
||||
db := database.GetDB()
|
||||
result := db.Save(m)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Delete will mark a certificate as deleted
|
||||
// Delete will mark row as deleted
|
||||
func (m *Model) Delete() bool {
|
||||
m.Touch(false)
|
||||
m.IsDeleted = true
|
||||
if err := m.Save(); err != nil {
|
||||
if m.ID == 0 {
|
||||
// Can't delete a new object
|
||||
return false
|
||||
}
|
||||
return true
|
||||
db := database.GetDB()
|
||||
result := db.Delete(m)
|
||||
return result.Error == nil
|
||||
}
|
||||
|
||||
// GetAcmeShEnvVars returns the env vars required for acme.sh dns cert requests
|
||||
|
@ -1,15 +0,0 @@
|
||||
package dnsprovider
|
||||
|
||||
import (
|
||||
"npm/internal/model"
|
||||
)
|
||||
|
||||
// ListResponse is the JSON response for the list
|
||||
type ListResponse struct {
|
||||
Total int `json:"total"`
|
||||
Offset int `json:"offset"`
|
||||
Limit int `json:"limit"`
|
||||
Sort []model.Sort `json:"sort"`
|
||||
Filter []model.Filter `json:"filter,omitempty"`
|
||||
Items []Model `json:"items,omitempty"`
|
||||
}
|
@ -11,12 +11,6 @@ import (
|
||||
// FilterMapFunction is a filter map function
|
||||
type FilterMapFunction func(value []string) []string
|
||||
|
||||
// FilterTagName tag name user for filter pickups
|
||||
const FilterTagName = "filter"
|
||||
|
||||
// DBTagName tag name user for field name pickups
|
||||
const DBTagName = "db"
|
||||
|
||||
// GenerateSQLFromFilters will return a Query and params for use as WHERE clause in SQL queries
|
||||
// This will use a AND where clause approach.
|
||||
func GenerateSQLFromFilters(filters []model.Filter, fieldMap map[string]string, fieldMapFunctions map[string]FilterMapFunction) (string, []interface{}) {
|
||||
@ -96,6 +90,7 @@ func getSQLAssignmentFromModifier(filter model.Filter, params *[]interface{}) st
|
||||
return clause
|
||||
}
|
||||
|
||||
/*
|
||||
// GetFilterMap returns the filter map
|
||||
func GetFilterMap(m interface{}) map[string]string {
|
||||
var filterMap = make(map[string]string)
|
||||
@ -110,8 +105,8 @@ func GetFilterMap(m interface{}) map[string]string {
|
||||
field := t.Field(i)
|
||||
|
||||
// Get the field tag value
|
||||
filterTag := field.Tag.Get(FilterTagName)
|
||||
dbTag := field.Tag.Get(DBTagName)
|
||||
filterTag := field.Tag.Get("filter")
|
||||
dbTag := field.Tag.Get("db")
|
||||
if filterTag != "" && dbTag != "" && dbTag != "-" && filterTag != "-" {
|
||||
// Filter tag can be a 2 part thing: name,type
|
||||
// ie: account_id,integer
|
||||
@ -124,6 +119,7 @@ func GetFilterMap(m interface{}) map[string]string {
|
||||
|
||||
return filterMap
|
||||
}
|
||||
*/
|
||||
|
||||
// GetDBColumns returns the db columns
|
||||
func GetDBColumns(m interface{}) []string {
|
||||
@ -132,7 +128,7 @@ func GetDBColumns(m interface{}) []string {
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
dbTag := field.Tag.Get(DBTagName)
|
||||
dbTag := field.Tag.Get("db")
|
||||
if dbTag != "" && dbTag != "-" {
|
||||
columns = append(columns, dbTag)
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ func GetFilterSchema(m interface{}) string {
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
filterTag := field.Tag.Get(FilterTagName)
|
||||
filterTag := field.Tag.Get("filter")
|
||||
|
||||
if filterTag != "" && filterTag != "-" {
|
||||
// split out tag value "field,filtreType"
|
||||
|
@ -1,25 +0,0 @@
|
||||
package host
|
||||
|
||||
import (
|
||||
"npm/internal/entity"
|
||||
)
|
||||
|
||||
var filterMapFunctions = make(map[string]entity.FilterMapFunction)
|
||||
|
||||
// getFilterMapFunctions is a map of functions that should be executed
|
||||
// during the filtering process, if a field is defined here then the value in
|
||||
// the filter will be given to the defined function and it will return a new
|
||||
// value for use in the sql query.
|
||||
func getFilterMapFunctions() map[string]entity.FilterMapFunction {
|
||||
// if len(filterMapFunctions) == 0 {
|
||||
// TODO: See internal/model/file_item.go:620 for an example
|
||||
// }
|
||||
|
||||
return filterMapFunctions
|
||||
}
|
||||
|
||||
// GetFilterSchema returns filter schema
|
||||
func GetFilterSchema() string {
|
||||
var m Model
|
||||
return entity.GetFilterSchema(m)
|
||||
}
|
@ -1,181 +1,40 @@
|
||||
package host
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/errors"
|
||||
"npm/internal/logger"
|
||||
"npm/internal/model"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
// GetByID finds a Host by ID
|
||||
func GetByID(id int) (Model, error) {
|
||||
func GetByID(id uint) (Model, error) {
|
||||
var m Model
|
||||
err := m.LoadByID(id)
|
||||
return m, err
|
||||
}
|
||||
|
||||
// create will create a Host from this model
|
||||
func create(host *Model) (int, error) {
|
||||
if host.ID != 0 {
|
||||
return 0, eris.New("Cannot create host when model already has an ID")
|
||||
}
|
||||
|
||||
host.Touch(true)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
result, err := db.NamedExec(`INSERT INTO `+tableName+` (
|
||||
created_on,
|
||||
modified_on,
|
||||
user_id,
|
||||
type,
|
||||
nginx_template_id,
|
||||
listen_interface,
|
||||
domain_names,
|
||||
upstream_id,
|
||||
proxy_scheme,
|
||||
proxy_host,
|
||||
proxy_port,
|
||||
certificate_id,
|
||||
access_list_id,
|
||||
ssl_forced,
|
||||
caching_enabled,
|
||||
block_exploits,
|
||||
allow_websocket_upgrade,
|
||||
http2_support,
|
||||
hsts_enabled,
|
||||
hsts_subdomains,
|
||||
paths,
|
||||
advanced_config,
|
||||
status,
|
||||
error_message,
|
||||
is_disabled,
|
||||
is_deleted
|
||||
) VALUES (
|
||||
:created_on,
|
||||
:modified_on,
|
||||
:user_id,
|
||||
:type,
|
||||
:nginx_template_id,
|
||||
:listen_interface,
|
||||
:domain_names,
|
||||
:upstream_id,
|
||||
:proxy_scheme,
|
||||
:proxy_host,
|
||||
:proxy_port,
|
||||
:certificate_id,
|
||||
:access_list_id,
|
||||
:ssl_forced,
|
||||
:caching_enabled,
|
||||
:block_exploits,
|
||||
:allow_websocket_upgrade,
|
||||
:http2_support,
|
||||
:hsts_enabled,
|
||||
:hsts_subdomains,
|
||||
:paths,
|
||||
:advanced_config,
|
||||
:status,
|
||||
:error_message,
|
||||
:is_disabled,
|
||||
:is_deleted
|
||||
)`, host)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
last, lastErr := result.LastInsertId()
|
||||
if lastErr != nil {
|
||||
return 0, lastErr
|
||||
}
|
||||
|
||||
logger.Debug("Created Host: %+v", host)
|
||||
|
||||
return int(last), nil
|
||||
}
|
||||
|
||||
// update will Update a Host from this model
|
||||
func update(host *Model) error {
|
||||
if host.ID == 0 {
|
||||
return eris.New("Cannot update host when model doesn't have an ID")
|
||||
}
|
||||
|
||||
host.Touch(false)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
_, err := db.NamedExec(`UPDATE `+fmt.Sprintf("`%s`", tableName)+` SET
|
||||
created_on = :created_on,
|
||||
modified_on = :modified_on,
|
||||
user_id = :user_id,
|
||||
type = :type,
|
||||
nginx_template_id = :nginx_template_id,
|
||||
listen_interface = :listen_interface,
|
||||
domain_names = :domain_names,
|
||||
upstream_id = :upstream_id,
|
||||
proxy_scheme = :proxy_scheme,
|
||||
proxy_host = :proxy_host,
|
||||
proxy_port = :proxy_port,
|
||||
certificate_id = :certificate_id,
|
||||
access_list_id = :access_list_id,
|
||||
ssl_forced = :ssl_forced,
|
||||
caching_enabled = :caching_enabled,
|
||||
block_exploits = :block_exploits,
|
||||
allow_websocket_upgrade = :allow_websocket_upgrade,
|
||||
http2_support = :http2_support,
|
||||
hsts_enabled = :hsts_enabled,
|
||||
hsts_subdomains = :hsts_subdomains,
|
||||
paths = :paths,
|
||||
advanced_config = :advanced_config,
|
||||
status = :status,
|
||||
error_message = :error_message,
|
||||
is_disabled = :is_disabled,
|
||||
is_deleted = :is_deleted
|
||||
WHERE id = :id`, host)
|
||||
|
||||
logger.Debug("Updated Host: %+v", host)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// List will return a list of hosts
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (ListResponse, error) {
|
||||
var result ListResponse
|
||||
var exampleModel Model
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (entity.ListResponse, error) {
|
||||
var result entity.ListResponse
|
||||
|
||||
defaultSort := model.Sort{
|
||||
Field: "domain_names",
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
db := database.GetInstance()
|
||||
if db == nil {
|
||||
return result, errors.ErrDatabaseUnavailable
|
||||
}
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
|
||||
// Get count of items in this search
|
||||
query, params := entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), true)
|
||||
countRow := db.QueryRowx(query, params...)
|
||||
var totalRows int
|
||||
queryErr := countRow.Scan(&totalRows)
|
||||
if queryErr != nil && queryErr != sql.ErrNoRows {
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, queryErr
|
||||
var totalRows int64
|
||||
if res := dbo.Model(&Model{}).Count(&totalRows); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
// Get rows
|
||||
items := make([]Model, 0)
|
||||
query, params = entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), false)
|
||||
err := db.Select(&items, query, params...)
|
||||
if err != nil {
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, err
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
if expand != nil {
|
||||
@ -187,7 +46,7 @@ func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (Lis
|
||||
}
|
||||
}
|
||||
|
||||
result = ListResponse{
|
||||
result = entity.ListResponse{
|
||||
Items: items,
|
||||
Total: totalRows,
|
||||
Limit: pageInfo.Limit,
|
||||
@ -201,32 +60,28 @@ func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (Lis
|
||||
|
||||
// GetUpstreamUseCount returns the number of hosts that are using
|
||||
// an upstream, and have not been deleted.
|
||||
func GetUpstreamUseCount(upstreamID int) int {
|
||||
db := database.GetInstance()
|
||||
query := fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE upstream_id = ? AND is_deleted = ?", tableName)
|
||||
countRow := db.QueryRowx(query, upstreamID, 0)
|
||||
var totalRows int
|
||||
queryErr := countRow.Scan(&totalRows)
|
||||
if queryErr != nil && queryErr != sql.ErrNoRows {
|
||||
logger.Debug("%s", query)
|
||||
func GetUpstreamUseCount(upstreamID uint) int64 {
|
||||
db := database.GetDB()
|
||||
|
||||
var count int64
|
||||
if result := db.Model(&Model{}).Where("upstream_id = ?", upstreamID).Count(&count); result.Error != nil {
|
||||
logger.Debug("GetUpstreamUseCount Error: %v", result.Error)
|
||||
return 0
|
||||
}
|
||||
return totalRows
|
||||
return count
|
||||
}
|
||||
|
||||
// GetCertificateUseCount returns the number of hosts that are using
|
||||
// a certificate, and have not been deleted.
|
||||
func GetCertificateUseCount(certificateID int) int {
|
||||
db := database.GetInstance()
|
||||
query := fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE certificate_id = ? AND is_deleted = ?", tableName)
|
||||
countRow := db.QueryRowx(query, certificateID, 0)
|
||||
var totalRows int
|
||||
queryErr := countRow.Scan(&totalRows)
|
||||
if queryErr != nil && queryErr != sql.ErrNoRows {
|
||||
logger.Debug("%s", query)
|
||||
func GetCertificateUseCount(certificateID uint) int64 {
|
||||
db := database.GetDB()
|
||||
|
||||
var count int64
|
||||
if result := db.Model(&Model{}).Where("certificate_id = ?", certificateID).Count(&count); result.Error != nil {
|
||||
logger.Debug("GetUpstreamUseCount Error: %v", result.Error)
|
||||
return 0
|
||||
}
|
||||
return totalRows
|
||||
return count
|
||||
}
|
||||
|
||||
// AddPendingJobs is intended to be used at startup to add
|
||||
|
@ -2,9 +2,8 @@ package host
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/entity/certificate"
|
||||
"npm/internal/entity/nginxtemplate"
|
||||
"npm/internal/entity/upstream"
|
||||
@ -17,8 +16,6 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
tableName = "host"
|
||||
|
||||
// ProxyHostType is self explanatory
|
||||
ProxyHostType = "proxy"
|
||||
// RedirectionHostType is self explanatory
|
||||
@ -27,67 +24,53 @@ const (
|
||||
DeadHostType = "dead"
|
||||
)
|
||||
|
||||
// Model is the user model
|
||||
// Model is the model
|
||||
type Model struct {
|
||||
ID int `json:"id" db:"id" filter:"id,integer"`
|
||||
CreatedOn types.DBDate `json:"created_on" db:"created_on" filter:"created_on,integer"`
|
||||
ModifiedOn types.DBDate `json:"modified_on" db:"modified_on" filter:"modified_on,integer"`
|
||||
UserID int `json:"user_id" db:"user_id" filter:"user_id,integer"`
|
||||
Type string `json:"type" db:"type" filter:"type,string"`
|
||||
NginxTemplateID int `json:"nginx_template_id" db:"nginx_template_id" filter:"nginx_template_id,integer"`
|
||||
ListenInterface string `json:"listen_interface" db:"listen_interface" filter:"listen_interface,string"`
|
||||
DomainNames types.JSONB `json:"domain_names" db:"domain_names" filter:"domain_names,string"`
|
||||
UpstreamID int `json:"upstream_id" db:"upstream_id" filter:"upstream_id,integer"`
|
||||
ProxyScheme string `json:"proxy_scheme" db:"proxy_scheme" filter:"proxy_scheme,string"`
|
||||
ProxyHost string `json:"proxy_host" db:"proxy_host" filter:"proxy_host,string"`
|
||||
ProxyPort int `json:"proxy_port" db:"proxy_port" filter:"proxy_port,integer"`
|
||||
CertificateID int `json:"certificate_id" db:"certificate_id" filter:"certificate_id,integer"`
|
||||
AccessListID int `json:"access_list_id" db:"access_list_id" filter:"access_list_id,integer"`
|
||||
SSLForced bool `json:"ssl_forced" db:"ssl_forced" filter:"ssl_forced,boolean"`
|
||||
CachingEnabled bool `json:"caching_enabled" db:"caching_enabled" filter:"caching_enabled,boolean"`
|
||||
BlockExploits bool `json:"block_exploits" db:"block_exploits" filter:"block_exploits,boolean"`
|
||||
AllowWebsocketUpgrade bool `json:"allow_websocket_upgrade" db:"allow_websocket_upgrade" filter:"allow_websocket_upgrade,boolean"`
|
||||
HTTP2Support bool `json:"http2_support" db:"http2_support" filter:"http2_support,boolean"`
|
||||
HSTSEnabled bool `json:"hsts_enabled" db:"hsts_enabled" filter:"hsts_enabled,boolean"`
|
||||
HSTSSubdomains bool `json:"hsts_subdomains" db:"hsts_subdomains" filter:"hsts_subdomains,boolean"`
|
||||
Paths string `json:"paths" db:"paths" filter:"paths,string"`
|
||||
AdvancedConfig string `json:"advanced_config" db:"advanced_config" filter:"advanced_config,string"`
|
||||
Status string `json:"status" db:"status" filter:"status,string"`
|
||||
ErrorMessage string `json:"error_message" db:"error_message" filter:"error_message,string"`
|
||||
IsDisabled bool `json:"is_disabled" db:"is_disabled" filter:"is_disabled,boolean"`
|
||||
IsDeleted bool `json:"is_deleted,omitempty" db:"is_deleted"`
|
||||
entity.ModelBase
|
||||
UserID uint `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"`
|
||||
Type string `json:"type" gorm:"column:type" filter:"type,string"`
|
||||
NginxTemplateID uint `json:"nginx_template_id" gorm:"column:nginx_template_id" filter:"nginx_template_id,integer"`
|
||||
ListenInterface string `json:"listen_interface" gorm:"column:listen_interface" filter:"listen_interface,string"`
|
||||
DomainNames types.JSONB `json:"domain_names" gorm:"column:domain_names" filter:"domain_names,string"`
|
||||
UpstreamID uint `json:"upstream_id" gorm:"column:upstream_id" filter:"upstream_id,integer"`
|
||||
ProxyScheme string `json:"proxy_scheme" gorm:"column:proxy_scheme" filter:"proxy_scheme,string"`
|
||||
ProxyHost string `json:"proxy_host" gorm:"column:proxy_host" filter:"proxy_host,string"`
|
||||
ProxyPort int `json:"proxy_port" gorm:"column:proxy_port" filter:"proxy_port,integer"`
|
||||
CertificateID uint `json:"certificate_id" gorm:"column:certificate_id" filter:"certificate_id,integer"`
|
||||
AccessListID uint `json:"access_list_id" gorm:"column:access_list_id" filter:"access_list_id,integer"`
|
||||
SSLForced bool `json:"ssl_forced" gorm:"column:ssl_forced" filter:"ssl_forced,boolean"`
|
||||
CachingEnabled bool `json:"caching_enabled" gorm:"column:caching_enabled" filter:"caching_enabled,boolean"`
|
||||
BlockExploits bool `json:"block_exploits" gorm:"column:block_exploits" filter:"block_exploits,boolean"`
|
||||
AllowWebsocketUpgrade bool `json:"allow_websocket_upgrade" gorm:"column:allow_websocket_upgrade" filter:"allow_websocket_upgrade,boolean"`
|
||||
HTTP2Support bool `json:"http2_support" gorm:"column:http2_support" filter:"http2_support,boolean"`
|
||||
HSTSEnabled bool `json:"hsts_enabled" gorm:"column:hsts_enabled" filter:"hsts_enabled,boolean"`
|
||||
HSTSSubdomains bool `json:"hsts_subdomains" gorm:"column:hsts_subdomains" filter:"hsts_subdomains,boolean"`
|
||||
Paths string `json:"paths" gorm:"column:paths" filter:"paths,string"`
|
||||
AdvancedConfig string `json:"advanced_config" gorm:"column:advanced_config" filter:"advanced_config,string"`
|
||||
Status string `json:"status" gorm:"column:status" filter:"status,string"`
|
||||
ErrorMessage string `json:"error_message" gorm:"column:error_message" filter:"error_message,string"`
|
||||
IsDisabled bool `json:"is_disabled" gorm:"column:is_disabled" filter:"is_disabled,boolean"`
|
||||
// Expansions
|
||||
Certificate *certificate.Model `json:"certificate,omitempty"`
|
||||
NginxTemplate *nginxtemplate.Model `json:"nginx_template,omitempty"`
|
||||
User *user.Model `json:"user,omitempty"`
|
||||
Upstream *upstream.Model `json:"upstream,omitempty"`
|
||||
Certificate *certificate.Model `json:"certificate,omitempty" gorm:"-"`
|
||||
NginxTemplate *nginxtemplate.Model `json:"nginx_template,omitempty" gorm:"-"`
|
||||
User *user.Model `json:"user,omitempty" gorm:"-"`
|
||||
Upstream *upstream.Model `json:"upstream,omitempty" gorm:"-"`
|
||||
}
|
||||
|
||||
func (m *Model) getByQuery(query string, params []interface{}) error {
|
||||
return database.GetByQuery(m, query, params)
|
||||
// TableName overrides the table name used by gorm
|
||||
func (Model) TableName() string {
|
||||
return "host"
|
||||
}
|
||||
|
||||
// LoadByID will load from an ID
|
||||
func (m *Model) LoadByID(id int) error {
|
||||
query := fmt.Sprintf("SELECT * FROM `%s` WHERE id = ? AND is_deleted = ? LIMIT 1", tableName)
|
||||
params := []interface{}{id, 0}
|
||||
return m.getByQuery(query, params)
|
||||
}
|
||||
|
||||
// Touch will update model's timestamp(s)
|
||||
func (m *Model) Touch(created bool) {
|
||||
var d types.DBDate
|
||||
d.Time = time.Now()
|
||||
if created {
|
||||
m.CreatedOn = d
|
||||
}
|
||||
m.ModifiedOn = d
|
||||
func (m *Model) LoadByID(id uint) error {
|
||||
db := database.GetDB()
|
||||
result := db.First(&m, id)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Save will save this model to the DB
|
||||
func (m *Model) Save(skipConfiguration bool) error {
|
||||
var err error
|
||||
|
||||
if m.UserID == 0 {
|
||||
return eris.Errorf("User ID must be specified")
|
||||
}
|
||||
@ -97,23 +80,20 @@ func (m *Model) Save(skipConfiguration bool) error {
|
||||
m.Status = status.StatusReady
|
||||
}
|
||||
|
||||
if m.ID == 0 {
|
||||
m.ID, err = create(m)
|
||||
} else {
|
||||
err = update(m)
|
||||
}
|
||||
|
||||
return err
|
||||
db := database.GetDB()
|
||||
result := db.Save(m)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Delete will mark a host as deleted
|
||||
// Delete will mark row as deleted
|
||||
func (m *Model) Delete() bool {
|
||||
m.Touch(false)
|
||||
m.IsDeleted = true
|
||||
if err := m.Save(false); err != nil {
|
||||
if m.ID == 0 {
|
||||
// Can't delete a new object
|
||||
return false
|
||||
}
|
||||
return true
|
||||
db := database.GetDB()
|
||||
result := db.Delete(m)
|
||||
return result.Error == nil
|
||||
}
|
||||
|
||||
// Expand will fill in more properties
|
||||
@ -160,8 +140,8 @@ func (m *Model) GetTemplate() Template {
|
||||
|
||||
t := Template{
|
||||
ID: m.ID,
|
||||
CreatedOn: m.CreatedOn.Time.String(),
|
||||
ModifiedOn: m.ModifiedOn.Time.String(),
|
||||
CreatedAt: fmt.Sprintf("%d", m.CreatedAt), // todo: format as nice string
|
||||
UpdatedAt: fmt.Sprintf("%d", m.UpdatedAt), // todo: format as nice string
|
||||
UserID: m.UserID,
|
||||
Type: m.Type,
|
||||
NginxTemplateID: m.NginxTemplateID,
|
||||
|
@ -1,15 +0,0 @@
|
||||
package host
|
||||
|
||||
import (
|
||||
"npm/internal/model"
|
||||
)
|
||||
|
||||
// ListResponse is the JSON response for this list
|
||||
type ListResponse struct {
|
||||
Total int `json:"total"`
|
||||
Offset int `json:"offset"`
|
||||
Limit int `json:"limit"`
|
||||
Sort []model.Sort `json:"sort"`
|
||||
Filter []model.Filter `json:"filter,omitempty"`
|
||||
Items []Model `json:"items,omitempty"`
|
||||
}
|
@ -4,20 +4,20 @@ import "npm/internal/entity/upstream"
|
||||
|
||||
// Template is the model given to the template parser, converted from the Model
|
||||
type Template struct {
|
||||
ID int
|
||||
CreatedOn string
|
||||
ModifiedOn string
|
||||
UserID int
|
||||
ID uint
|
||||
CreatedAt string
|
||||
UpdatedAt string
|
||||
UserID uint
|
||||
Type string
|
||||
NginxTemplateID int
|
||||
NginxTemplateID uint
|
||||
ProxyScheme string
|
||||
ProxyHost string
|
||||
ProxyPort int
|
||||
ListenInterface string
|
||||
DomainNames []string
|
||||
UpstreamID int
|
||||
CertificateID int
|
||||
AccessListID int
|
||||
UpstreamID uint
|
||||
CertificateID uint
|
||||
AccessListID uint
|
||||
SSLForced bool
|
||||
CachingEnabled bool
|
||||
BlockExploits bool
|
||||
|
36
backend/internal/entity/lists.go
Normal file
36
backend/internal/entity/lists.go
Normal file
@ -0,0 +1,36 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"npm/internal/database"
|
||||
"npm/internal/model"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// ListableModel is a interface for common use
|
||||
type ListableModel interface {
|
||||
TableName() string
|
||||
}
|
||||
|
||||
// ListResponse is the JSON response for users list
|
||||
type ListResponse struct {
|
||||
Total int64 `json:"total"`
|
||||
Offset int `json:"offset"`
|
||||
Limit int `json:"limit"`
|
||||
Sort []model.Sort `json:"sort"`
|
||||
Filter []model.Filter `json:"filter,omitempty"`
|
||||
Items interface{} `json:"items,omitempty"`
|
||||
}
|
||||
|
||||
// ListQueryBuilder is used to setup queries for lists
|
||||
func ListQueryBuilder(
|
||||
pageInfo *model.PageInfo,
|
||||
defaultSort model.Sort,
|
||||
filters []model.Filter,
|
||||
) *gorm.DB {
|
||||
scopes := make([]func(*gorm.DB) *gorm.DB, 0)
|
||||
scopes = append(scopes, ScopeOrderBy(pageInfo, defaultSort))
|
||||
scopes = append(scopes, ScopeOffsetLimit(pageInfo))
|
||||
// scopes = append(scopes, ScopeFilters(GetFilterMap(m)))
|
||||
return database.GetDB().Scopes(scopes...)
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/model"
|
||||
)
|
||||
|
||||
// ListQueryBuilder should be able to return the query and params to get items agnostically based
|
||||
// on given params.
|
||||
func ListQueryBuilder(modelExample interface{}, tableName string, pageInfo *model.PageInfo, defaultSort model.Sort, filters []model.Filter, filterMapFunctions map[string]FilterMapFunction, returnCount bool) (string, []interface{}) {
|
||||
var queryStrings []string
|
||||
var whereStrings []string
|
||||
var params []interface{}
|
||||
|
||||
if returnCount {
|
||||
queryStrings = append(queryStrings, "SELECT COUNT(*)")
|
||||
} else {
|
||||
queryStrings = append(queryStrings, "SELECT *")
|
||||
}
|
||||
|
||||
// nolint: gosec
|
||||
queryStrings = append(queryStrings, fmt.Sprintf("FROM `%s`", tableName))
|
||||
|
||||
// Append filters to where clause:
|
||||
if filters != nil {
|
||||
filterMap := GetFilterMap(modelExample)
|
||||
filterQuery, filterParams := GenerateSQLFromFilters(filters, filterMap, filterMapFunctions)
|
||||
whereStrings = []string{filterQuery}
|
||||
params = append(params, filterParams...)
|
||||
}
|
||||
|
||||
// Add is deletee check if model has the field
|
||||
if hasDeletedField(modelExample) {
|
||||
params = append(params, 0)
|
||||
whereStrings = append(whereStrings, "`is_deleted` = ?")
|
||||
}
|
||||
|
||||
// Append where clauses to query
|
||||
if len(whereStrings) > 0 {
|
||||
// nolint: gosec
|
||||
queryStrings = append(queryStrings, fmt.Sprintf("WHERE %s", strings.Join(whereStrings, " AND ")))
|
||||
}
|
||||
|
||||
if !returnCount {
|
||||
var orderBy string
|
||||
columns := GetDBColumns(modelExample)
|
||||
orderBy, pageInfo.Sort = database.BuildOrderBySQL(columns, &pageInfo.Sort)
|
||||
|
||||
if orderBy != "" {
|
||||
queryStrings = append(queryStrings, orderBy)
|
||||
} else {
|
||||
pageInfo.Sort = append(pageInfo.Sort, defaultSort)
|
||||
queryStrings = append(queryStrings, fmt.Sprintf("ORDER BY `%v` COLLATE NOCASE %v", defaultSort.Field, defaultSort.Direction))
|
||||
}
|
||||
|
||||
params = append(params, pageInfo.Offset)
|
||||
params = append(params, pageInfo.Limit)
|
||||
queryStrings = append(queryStrings, "LIMIT ?, ?")
|
||||
}
|
||||
|
||||
return strings.Join(queryStrings, " "), params
|
||||
}
|
||||
|
||||
func hasDeletedField(modelExample interface{}) bool {
|
||||
t := reflect.TypeOf(modelExample)
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
dbTag := field.Tag.Get(DBTagName)
|
||||
if dbTag == "is_deleted" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
13
backend/internal/entity/model_base.go
Normal file
13
backend/internal/entity/model_base.go
Normal file
@ -0,0 +1,13 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"gorm.io/plugin/soft_delete"
|
||||
)
|
||||
|
||||
// ModelBase include common fields for db control
|
||||
type ModelBase struct {
|
||||
ID uint `json:"id" gorm:"column:id;primaryKey"`
|
||||
CreatedAt int64 `json:"created_at" gorm:"<-:create;autoCreateTime:milli;column:created_at"`
|
||||
UpdatedAt int64 `json:"updated_at" gorm:"<-;autoUpdateTime:milli;column:updated_at"`
|
||||
DeletedAt soft_delete.DeletedAt `json:"-" gorm:"column:is_deleted;softDelete:flag"`
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package nginxtemplate
|
||||
|
||||
import (
|
||||
"npm/internal/entity"
|
||||
)
|
||||
|
||||
var filterMapFunctions = make(map[string]entity.FilterMapFunction)
|
||||
|
||||
// getFilterMapFunctions is a map of functions that should be executed
|
||||
// during the filtering process, if a field is defined here then the value in
|
||||
// the filter will be given to the defined function and it will return a new
|
||||
// value for use in the sql query.
|
||||
func getFilterMapFunctions() map[string]entity.FilterMapFunction {
|
||||
// if len(filterMapFunctions) == 0 {
|
||||
// TODO: See internal/model/file_item.go:620 for an example
|
||||
// }
|
||||
|
||||
return filterMapFunctions
|
||||
}
|
||||
|
||||
// GetFilterSchema returns filter schema
|
||||
func GetFilterSchema() string {
|
||||
var m Model
|
||||
return entity.GetFilterSchema(m)
|
||||
}
|
@ -1,123 +1,41 @@
|
||||
package nginxtemplate
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/errors"
|
||||
"npm/internal/logger"
|
||||
"npm/internal/model"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
// GetByID finds a Host by ID
|
||||
func GetByID(id int) (Model, error) {
|
||||
func GetByID(id uint) (Model, error) {
|
||||
var m Model
|
||||
err := m.LoadByID(id)
|
||||
return m, err
|
||||
}
|
||||
|
||||
// Create will create a Host from this model
|
||||
func Create(host *Model) (int, error) {
|
||||
if host.ID != 0 {
|
||||
return 0, eris.New("Cannot create host template when model already has an ID")
|
||||
}
|
||||
|
||||
host.Touch(true)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
result, err := db.NamedExec(`INSERT INTO `+fmt.Sprintf("`%s`", tableName)+` (
|
||||
created_on,
|
||||
modified_on,
|
||||
user_id,
|
||||
name,
|
||||
host_type,
|
||||
template,
|
||||
is_deleted
|
||||
) VALUES (
|
||||
:created_on,
|
||||
:modified_on,
|
||||
:user_id,
|
||||
:name,
|
||||
:host_type,
|
||||
:template,
|
||||
:is_deleted
|
||||
)`, host)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
last, lastErr := result.LastInsertId()
|
||||
if lastErr != nil {
|
||||
return 0, lastErr
|
||||
}
|
||||
|
||||
return int(last), nil
|
||||
}
|
||||
|
||||
// Update will Update a Host from this model
|
||||
func Update(host *Model) error {
|
||||
if host.ID == 0 {
|
||||
return eris.New("Cannot update host template when model doesn't have an ID")
|
||||
}
|
||||
|
||||
host.Touch(false)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
_, err := db.NamedExec(`UPDATE `+fmt.Sprintf("`%s`", tableName)+` SET
|
||||
created_on = :created_on,
|
||||
modified_on = :modified_on,
|
||||
user_id = :user_id,
|
||||
name = :name,
|
||||
host_type = :host_type,
|
||||
template = :template,
|
||||
is_deleted = :is_deleted
|
||||
WHERE id = :id`, host)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// List will return a list of hosts
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter) (ListResponse, error) {
|
||||
var result ListResponse
|
||||
var exampleModel Model
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse, error) {
|
||||
var result entity.ListResponse
|
||||
|
||||
defaultSort := model.Sort{
|
||||
Field: "created_on",
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
db := database.GetInstance()
|
||||
if db == nil {
|
||||
return result, errors.ErrDatabaseUnavailable
|
||||
}
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
|
||||
// Get count of items in this search
|
||||
query, params := entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), true)
|
||||
countRow := db.QueryRowx(query, params...)
|
||||
var totalRows int
|
||||
queryErr := countRow.Scan(&totalRows)
|
||||
if queryErr != nil && queryErr != sql.ErrNoRows {
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, queryErr
|
||||
var totalRows int64
|
||||
if res := dbo.Model(&Model{}).Count(&totalRows); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
// Get rows
|
||||
items := make([]Model, 0)
|
||||
query, params = entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), false)
|
||||
err := db.Select(&items, query, params...)
|
||||
if err != nil {
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, err
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
result = ListResponse{
|
||||
result = entity.ListResponse{
|
||||
Items: items,
|
||||
Total: totalRows,
|
||||
Limit: pageInfo.Limit,
|
||||
|
@ -1,75 +1,51 @@
|
||||
package nginxtemplate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/types"
|
||||
"npm/internal/entity"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
const (
|
||||
tableName = "nginx_template"
|
||||
)
|
||||
|
||||
// Model is the user model
|
||||
// Model is the model
|
||||
type Model struct {
|
||||
ID int `json:"id" db:"id" filter:"id,integer"`
|
||||
CreatedOn types.DBDate `json:"created_on" db:"created_on" filter:"created_on,integer"`
|
||||
ModifiedOn types.DBDate `json:"modified_on" db:"modified_on" filter:"modified_on,integer"`
|
||||
UserID int `json:"user_id" db:"user_id" filter:"user_id,integer"`
|
||||
Name string `json:"name" db:"name" filter:"name,string"`
|
||||
Type string `json:"type" db:"type" filter:"type,string"`
|
||||
Template string `json:"template" db:"template" filter:"template,string"`
|
||||
IsDeleted bool `json:"is_deleted,omitempty" db:"is_deleted"`
|
||||
entity.ModelBase
|
||||
UserID int `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"`
|
||||
Name string `json:"name" gorm:"column:name" filter:"name,string"`
|
||||
Type string `json:"type" gorm:"column:type" filter:"type,string"`
|
||||
Template string `json:"template" gorm:"column:template" filter:"template,string"`
|
||||
}
|
||||
|
||||
func (m *Model) getByQuery(query string, params []interface{}) error {
|
||||
return database.GetByQuery(m, query, params)
|
||||
// TableName overrides the table name used by gorm
|
||||
func (Model) TableName() string {
|
||||
return "nginx_template"
|
||||
}
|
||||
|
||||
// LoadByID will load from an ID
|
||||
func (m *Model) LoadByID(id int) error {
|
||||
query := fmt.Sprintf("SELECT * FROM `%s` WHERE id = ? AND is_deleted = ? LIMIT 1", tableName)
|
||||
params := []interface{}{id, 0}
|
||||
return m.getByQuery(query, params)
|
||||
}
|
||||
|
||||
// Touch will update model's timestamp(s)
|
||||
func (m *Model) Touch(created bool) {
|
||||
var d types.DBDate
|
||||
d.Time = time.Now()
|
||||
if created {
|
||||
m.CreatedOn = d
|
||||
}
|
||||
m.ModifiedOn = d
|
||||
func (m *Model) LoadByID(id uint) error {
|
||||
db := database.GetDB()
|
||||
result := db.First(&m, id)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Save will save this model to the DB
|
||||
func (m *Model) Save() error {
|
||||
var err error
|
||||
|
||||
if m.UserID == 0 {
|
||||
return eris.Errorf("User ID must be specified")
|
||||
}
|
||||
|
||||
if m.ID == 0 {
|
||||
m.ID, err = Create(m)
|
||||
} else {
|
||||
err = Update(m)
|
||||
}
|
||||
|
||||
return err
|
||||
db := database.GetDB()
|
||||
result := db.Save(m)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Delete will mark a template as deleted
|
||||
// Delete will mark row as deleted
|
||||
func (m *Model) Delete() bool {
|
||||
m.Touch(false)
|
||||
m.IsDeleted = true
|
||||
if err := m.Save(); err != nil {
|
||||
if m.ID == 0 {
|
||||
// Can't delete a new object
|
||||
return false
|
||||
}
|
||||
return true
|
||||
db := database.GetDB()
|
||||
result := db.Delete(m)
|
||||
return result.Error == nil
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
package nginxtemplate
|
||||
|
||||
import (
|
||||
"npm/internal/model"
|
||||
)
|
||||
|
||||
// ListResponse is the JSON response for this list
|
||||
type ListResponse struct {
|
||||
Total int `json:"total"`
|
||||
Offset int `json:"offset"`
|
||||
Limit int `json:"limit"`
|
||||
Sort []model.Sort `json:"sort"`
|
||||
Filter []model.Filter `json:"filter,omitempty"`
|
||||
Items []Model `json:"items,omitempty"`
|
||||
}
|
62
backend/internal/entity/scopes.go
Normal file
62
backend/internal/entity/scopes.go
Normal file
@ -0,0 +1,62 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"npm/internal/model"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func ScopeOffsetLimit(pageInfo *model.PageInfo) func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
if pageInfo.Offset > 0 || pageInfo.Limit > 0 {
|
||||
return db.Limit(pageInfo.Limit).Offset(pageInfo.Offset)
|
||||
}
|
||||
return db
|
||||
}
|
||||
}
|
||||
|
||||
func ScopeOrderBy(pageInfo *model.PageInfo, defaultSort model.Sort) func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
if pageInfo.Sort != nil {
|
||||
// Sort by items in slice
|
||||
return db.Order(sortToOrderString(pageInfo.Sort))
|
||||
} else if defaultSort.Field != "" {
|
||||
// Default to this sort
|
||||
str := defaultSort.Field
|
||||
if defaultSort.Direction != "" {
|
||||
str = str + " " + defaultSort.Direction
|
||||
}
|
||||
return db.Order(str)
|
||||
}
|
||||
return db
|
||||
}
|
||||
}
|
||||
|
||||
func ScopeFilters(filters map[string]string) func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
// todo
|
||||
/*
|
||||
if filters != nil {
|
||||
filterMap := GetFilterMap(m)
|
||||
filterQuery, filterParams := GenerateSQLFromFilters(filters, filterMap, filterMapFunctions)
|
||||
whereStrings = []string{filterQuery}
|
||||
params = append(params, filterParams...)
|
||||
}
|
||||
*/
|
||||
return db
|
||||
}
|
||||
}
|
||||
|
||||
func sortToOrderString(sorts []model.Sort) string {
|
||||
strs := make([]string, 0)
|
||||
for _, i := range sorts {
|
||||
str := i.Field
|
||||
if i.Direction != "" {
|
||||
str = str + " " + i.Direction
|
||||
}
|
||||
strs = append(strs, str)
|
||||
}
|
||||
return strings.Join(strs, ", ")
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package setting
|
||||
|
||||
import (
|
||||
"npm/internal/config"
|
||||
"npm/internal/logger"
|
||||
)
|
||||
|
||||
// ApplySettings will load settings from the DB and apply them where required
|
||||
func ApplySettings() {
|
||||
logger.Debug("Applying Settings")
|
||||
|
||||
// Error-reporting
|
||||
m, err := GetByName("error-reporting")
|
||||
if err != nil {
|
||||
logger.Error("ApplySettingsError", err)
|
||||
} else {
|
||||
config.ErrorReporting = m.Value.Decoded.(bool)
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package setting
|
||||
|
||||
import (
|
||||
"npm/internal/entity"
|
||||
)
|
||||
|
||||
var filterMapFunctions = make(map[string]entity.FilterMapFunction)
|
||||
|
||||
// getFilterMapFunctions is a map of functions that should be executed
|
||||
// during the filtering process, if a field is defined here then the value in
|
||||
// the filter will be given to the defined function and it will return a new
|
||||
// value for use in the sql query.
|
||||
func getFilterMapFunctions() map[string]entity.FilterMapFunction {
|
||||
// if len(filterMapFunctions) == 0 {
|
||||
// TODO: See internal/model/file_item.go:620 for an example
|
||||
// }
|
||||
|
||||
return filterMapFunctions
|
||||
}
|
||||
|
||||
// GetFilterSchema returns filter schema
|
||||
func GetFilterSchema() string {
|
||||
var m Model
|
||||
return entity.GetFilterSchema(m)
|
||||
}
|
@ -1,16 +1,10 @@
|
||||
package setting
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/config"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/errors"
|
||||
"npm/internal/logger"
|
||||
"npm/internal/model"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
// GetByID finds a setting by ID
|
||||
@ -27,95 +21,30 @@ func GetByName(name string) (Model, error) {
|
||||
return m, err
|
||||
}
|
||||
|
||||
// Create will Create a Setting from this model
|
||||
func Create(setting *Model) (int, error) {
|
||||
if setting.ID != 0 {
|
||||
return 0, eris.New("Cannot create setting when model already has an ID")
|
||||
}
|
||||
|
||||
setting.Touch(true)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
result, err := db.NamedExec(`INSERT INTO `+fmt.Sprintf("`%s`", tableName)+` (
|
||||
created_on,
|
||||
modified_on,
|
||||
name,
|
||||
value
|
||||
) VALUES (
|
||||
:created_on,
|
||||
:modified_on,
|
||||
:name,
|
||||
:value
|
||||
)`, setting)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
last, lastErr := result.LastInsertId()
|
||||
if lastErr != nil {
|
||||
return 0, lastErr
|
||||
}
|
||||
|
||||
return int(last), nil
|
||||
}
|
||||
|
||||
// Update will Update a Setting from this model
|
||||
func Update(setting *Model) error {
|
||||
if setting.ID == 0 {
|
||||
return eris.New("Cannot update setting when model doesn't have an ID")
|
||||
}
|
||||
|
||||
setting.Touch(false)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
_, err := db.NamedExec(`UPDATE `+fmt.Sprintf("`%s`", tableName)+` SET
|
||||
created_on = :created_on,
|
||||
modified_on = :modified_on,
|
||||
name = :name,
|
||||
value = :value
|
||||
WHERE id = :id`, setting)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// List will return a list of settings
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter) (ListResponse, error) {
|
||||
var result ListResponse
|
||||
var exampleModel Model
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse, error) {
|
||||
var result entity.ListResponse
|
||||
|
||||
defaultSort := model.Sort{
|
||||
Field: "name",
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
db := database.GetInstance()
|
||||
if db == nil {
|
||||
return result, errors.ErrDatabaseUnavailable
|
||||
}
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
|
||||
// Get count of items in this search
|
||||
query, params := entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), true)
|
||||
countRow := db.QueryRowx(query, params...)
|
||||
var totalRows int
|
||||
queryErr := countRow.Scan(&totalRows)
|
||||
if queryErr != nil && queryErr != sql.ErrNoRows {
|
||||
logger.Debug("%+v", queryErr)
|
||||
return result, queryErr
|
||||
var totalRows int64
|
||||
if res := dbo.Model(&Model{}).Count(&totalRows); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
// Get rows
|
||||
items := make([]Model, 0)
|
||||
query, params = entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), false)
|
||||
err := db.Select(&items, query, params...)
|
||||
if err != nil {
|
||||
logger.Debug("%+v", err)
|
||||
return result, err
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
result = ListResponse{
|
||||
result = entity.ListResponse{
|
||||
Items: items,
|
||||
Total: totalRows,
|
||||
Limit: pageInfo.Limit,
|
||||
@ -126,3 +55,16 @@ func List(pageInfo model.PageInfo, filters []model.Filter) (ListResponse, error)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ApplySettings will load settings from the DB and apply them where required
|
||||
func ApplySettings() {
|
||||
logger.Debug("Applying Settings")
|
||||
|
||||
// Error-reporting
|
||||
m, err := GetByName("error-reporting")
|
||||
if err != nil {
|
||||
logger.Error("ApplySettingsError", err)
|
||||
} else {
|
||||
config.ErrorReporting = m.Value.String() == "true"
|
||||
}
|
||||
}
|
||||
|
@ -1,73 +1,50 @@
|
||||
package setting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/types"
|
||||
"npm/internal/entity"
|
||||
|
||||
"gorm.io/datatypes"
|
||||
)
|
||||
|
||||
const (
|
||||
tableName = "setting"
|
||||
)
|
||||
|
||||
// Model is the user model
|
||||
// Model is the model
|
||||
type Model struct {
|
||||
ID int `json:"id" db:"id" filter:"id,integer"`
|
||||
CreatedOn types.DBDate `json:"created_on" db:"created_on" filter:"created_on,integer"`
|
||||
ModifiedOn types.DBDate `json:"modified_on" db:"modified_on" filter:"modified_on,integer"`
|
||||
Name string `json:"name" db:"name" filter:"name,string"`
|
||||
Description string `json:"description" db:"description" filter:"description,string"`
|
||||
Value types.JSONB `json:"value" db:"value"`
|
||||
entity.ModelBase
|
||||
Name string `json:"name" gorm:"column:name" filter:"name,string"`
|
||||
Description string `json:"description" gorm:"column:description" filter:"description,string"`
|
||||
Value datatypes.JSON `json:"value" gorm:"column:value"`
|
||||
}
|
||||
|
||||
func (m *Model) getByQuery(query string, params []interface{}) error {
|
||||
return database.GetByQuery(m, query, params)
|
||||
// TableName overrides the table name used by gorm
|
||||
func (Model) TableName() string {
|
||||
return "setting"
|
||||
}
|
||||
|
||||
// LoadByID will load from an ID
|
||||
func (m *Model) LoadByID(id int) error {
|
||||
query := fmt.Sprintf("SELECT * FROM `%s` WHERE `id` = ? LIMIT 1", tableName)
|
||||
params := []interface{}{id}
|
||||
return m.getByQuery(query, params)
|
||||
db := database.GetDB()
|
||||
result := db.First(&m, id)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// LoadByName will load from a Name
|
||||
func (m *Model) LoadByName(name string) error {
|
||||
query := fmt.Sprintf("SELECT * FROM `%s` WHERE LOWER(`name`) = ? LIMIT 1", tableName)
|
||||
params := []interface{}{strings.TrimSpace(strings.ToLower(name))}
|
||||
return m.getByQuery(query, params)
|
||||
}
|
||||
|
||||
// Touch will update model's timestamp(s)
|
||||
func (m *Model) Touch(created bool) {
|
||||
var d types.DBDate
|
||||
d.Time = time.Now()
|
||||
if created {
|
||||
m.CreatedOn = d
|
||||
}
|
||||
m.ModifiedOn = d
|
||||
db := database.GetDB()
|
||||
result := db.Where("name = ?", strings.ToLower(name)).First(&m)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Save will save this model to the DB
|
||||
func (m *Model) Save() error {
|
||||
var err error
|
||||
|
||||
// ensure name is trimmed of whitespace
|
||||
m.Name = strings.TrimSpace(m.Name)
|
||||
|
||||
if m.ID == 0 {
|
||||
m.ID, err = Create(m)
|
||||
} else {
|
||||
err = Update(m)
|
||||
db := database.GetDB()
|
||||
if result := db.Save(m); result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Reapply settings
|
||||
if err == nil {
|
||||
ApplySettings()
|
||||
}
|
||||
|
||||
return err
|
||||
ApplySettings()
|
||||
return nil
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
package setting
|
||||
|
||||
import (
|
||||
"npm/internal/model"
|
||||
)
|
||||
|
||||
// ListResponse is the JSON response for settings list
|
||||
type ListResponse struct {
|
||||
Total int `json:"total"`
|
||||
Offset int `json:"offset"`
|
||||
Limit int `json:"limit"`
|
||||
Sort []model.Sort `json:"sort"`
|
||||
Filter []model.Filter `json:"filter,omitempty"`
|
||||
Items []Model `json:"items,omitempty"`
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package stream
|
||||
|
||||
import (
|
||||
"npm/internal/entity"
|
||||
)
|
||||
|
||||
var filterMapFunctions = make(map[string]entity.FilterMapFunction)
|
||||
|
||||
// getFilterMapFunctions is a map of functions that should be executed
|
||||
// during the filtering process, if a field is defined here then the value in
|
||||
// the filter will be given to the defined function and it will return a new
|
||||
// value for use in the sql query.
|
||||
func getFilterMapFunctions() map[string]entity.FilterMapFunction {
|
||||
// if len(filterMapFunctions) == 0 {
|
||||
// TODO: See internal/model/file_item.go:620 for an example
|
||||
// }
|
||||
|
||||
return filterMapFunctions
|
||||
}
|
||||
|
||||
// GetFilterSchema returns filter schema
|
||||
func GetFilterSchema() string {
|
||||
var m Model
|
||||
return entity.GetFilterSchema(m)
|
||||
}
|
@ -1,129 +1,41 @@
|
||||
package stream
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/errors"
|
||||
"npm/internal/logger"
|
||||
"npm/internal/model"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
// GetByID finds a auth by ID
|
||||
func GetByID(id int) (Model, error) {
|
||||
func GetByID(id uint) (Model, error) {
|
||||
var m Model
|
||||
err := m.LoadByID(id)
|
||||
return m, err
|
||||
}
|
||||
|
||||
// Create will create a Auth from this model
|
||||
func Create(host *Model) (int, error) {
|
||||
if host.ID != 0 {
|
||||
return 0, eris.New("Cannot create stream when model already has an ID")
|
||||
}
|
||||
|
||||
host.Touch(true)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
result, err := db.NamedExec(`INSERT INTO `+fmt.Sprintf("`%s`", tableName)+` (
|
||||
created_on,
|
||||
modified_on,
|
||||
user_id,
|
||||
provider,
|
||||
name,
|
||||
domain_names,
|
||||
expires_on,
|
||||
meta,
|
||||
is_deleted
|
||||
) VALUES (
|
||||
:created_on,
|
||||
:modified_on,
|
||||
:user_id,
|
||||
:provider,
|
||||
:name,
|
||||
:domain_names,
|
||||
:expires_on,
|
||||
:meta,
|
||||
:is_deleted
|
||||
)`, host)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
last, lastErr := result.LastInsertId()
|
||||
if lastErr != nil {
|
||||
return 0, lastErr
|
||||
}
|
||||
|
||||
return int(last), nil
|
||||
}
|
||||
|
||||
// Update will Update a Host from this model
|
||||
func Update(host *Model) error {
|
||||
if host.ID == 0 {
|
||||
return eris.New("Cannot update stream when model doesn't have an ID")
|
||||
}
|
||||
|
||||
host.Touch(false)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
_, err := db.NamedExec(`UPDATE `+fmt.Sprintf("`%s`", tableName)+` SET
|
||||
created_on = :created_on,
|
||||
modified_on = :modified_on,
|
||||
user_id = :user_id,
|
||||
provider = :provider,
|
||||
name = :name,
|
||||
domain_names = :domain_names,
|
||||
expires_on = :expires_on,
|
||||
meta = :meta,
|
||||
is_deleted = :is_deleted
|
||||
WHERE id = :id`, host)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// List will return a list of hosts
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter) (ListResponse, error) {
|
||||
var result ListResponse
|
||||
var exampleModel Model
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse, error) {
|
||||
var result entity.ListResponse
|
||||
|
||||
defaultSort := model.Sort{
|
||||
Field: "name",
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
db := database.GetInstance()
|
||||
if db == nil {
|
||||
return result, errors.ErrDatabaseUnavailable
|
||||
}
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
|
||||
// Get count of items in this search
|
||||
query, params := entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), true)
|
||||
countRow := db.QueryRowx(query, params...)
|
||||
var totalRows int
|
||||
queryErr := countRow.Scan(&totalRows)
|
||||
if queryErr != nil && queryErr != sql.ErrNoRows {
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, queryErr
|
||||
var totalRows int64
|
||||
if res := dbo.Model(&Model{}).Count(&totalRows); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
// Get rows
|
||||
items := make([]Model, 0)
|
||||
query, params = entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), false)
|
||||
err := db.Select(&items, query, params...)
|
||||
if err != nil {
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, err
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
result = ListResponse{
|
||||
result = entity.ListResponse{
|
||||
Items: items,
|
||||
Total: totalRows,
|
||||
Limit: pageInfo.Limit,
|
||||
|
@ -1,77 +1,54 @@
|
||||
package stream
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/types"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
const (
|
||||
tableName = "stream"
|
||||
)
|
||||
|
||||
// Model is the user model
|
||||
// Model is the model
|
||||
type Model struct {
|
||||
ID int `json:"id" db:"id" filter:"id,integer"`
|
||||
CreatedOn types.DBDate `json:"created_on" db:"created_on" filter:"created_on,integer"`
|
||||
ModifiedOn types.DBDate `json:"modified_on" db:"modified_on" filter:"modified_on,integer"`
|
||||
ExpiresOn types.DBDate `json:"expires_on" db:"expires_on" filter:"expires_on,integer"`
|
||||
UserID int `json:"user_id" db:"user_id" filter:"user_id,integer"`
|
||||
Provider string `json:"provider" db:"provider" filter:"provider,string"`
|
||||
Name string `json:"name" db:"name" filter:"name,string"`
|
||||
DomainNames types.JSONB `json:"domain_names" db:"domain_names" filter:"domain_names,string"`
|
||||
Meta types.JSONB `json:"-" db:"meta"`
|
||||
IsDeleted bool `json:"is_deleted,omitempty" db:"is_deleted"`
|
||||
entity.ModelBase
|
||||
ExpiresOn types.DBDate `json:"expires_on" gorm:"column:expires_on" filter:"expires_on,integer"`
|
||||
UserID int `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"`
|
||||
Provider string `json:"provider" gorm:"column:provider" filter:"provider,string"`
|
||||
Name string `json:"name" gorm:"column:name" filter:"name,string"`
|
||||
DomainNames types.JSONB `json:"domain_names" gorm:"column:domain_names" filter:"domain_names,string"`
|
||||
Meta types.JSONB `json:"-" gorm:"column:meta"`
|
||||
}
|
||||
|
||||
func (m *Model) getByQuery(query string, params []interface{}) error {
|
||||
return database.GetByQuery(m, query, params)
|
||||
// TableName overrides the table name used by gorm
|
||||
func (Model) TableName() string {
|
||||
return "stream"
|
||||
}
|
||||
|
||||
// LoadByID will load from an ID
|
||||
func (m *Model) LoadByID(id int) error {
|
||||
query := fmt.Sprintf("SELECT * FROM `%s` WHERE id = ? AND is_deleted = ? LIMIT 1", tableName)
|
||||
params := []interface{}{id, 0}
|
||||
return m.getByQuery(query, params)
|
||||
}
|
||||
|
||||
// Touch will update model's timestamp(s)
|
||||
func (m *Model) Touch(created bool) {
|
||||
var d types.DBDate
|
||||
d.Time = time.Now()
|
||||
if created {
|
||||
m.CreatedOn = d
|
||||
}
|
||||
m.ModifiedOn = d
|
||||
func (m *Model) LoadByID(id uint) error {
|
||||
db := database.GetDB()
|
||||
result := db.First(&m, id)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Save will save this model to the DB
|
||||
func (m *Model) Save() error {
|
||||
var err error
|
||||
|
||||
if m.UserID == 0 {
|
||||
return eris.Errorf("User ID must be specified")
|
||||
}
|
||||
|
||||
if m.ID == 0 {
|
||||
m.ID, err = Create(m)
|
||||
} else {
|
||||
err = Update(m)
|
||||
}
|
||||
|
||||
return err
|
||||
db := database.GetDB()
|
||||
result := db.Save(m)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Delete will mark a host as deleted
|
||||
// Delete will mark row as deleted
|
||||
func (m *Model) Delete() bool {
|
||||
m.Touch(false)
|
||||
m.IsDeleted = true
|
||||
if err := m.Save(); err != nil {
|
||||
if m.ID == 0 {
|
||||
// Can't delete a new object
|
||||
return false
|
||||
}
|
||||
return true
|
||||
db := database.GetDB()
|
||||
result := db.Delete(m)
|
||||
return result.Error == nil
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
package stream
|
||||
|
||||
import (
|
||||
"npm/internal/model"
|
||||
)
|
||||
|
||||
// ListResponse is the JSON response for this list
|
||||
type ListResponse struct {
|
||||
Total int `json:"total"`
|
||||
Offset int `json:"offset"`
|
||||
Limit int `json:"limit"`
|
||||
Sort []model.Sort `json:"sort"`
|
||||
Filter []model.Filter `json:"filter,omitempty"`
|
||||
Items []Model `json:"items,omitempty"`
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package upstream
|
||||
|
||||
import (
|
||||
"npm/internal/entity"
|
||||
)
|
||||
|
||||
var filterMapFunctions = make(map[string]entity.FilterMapFunction)
|
||||
|
||||
// getFilterMapFunctions is a map of functions that should be executed
|
||||
// during the filtering process, if a field is defined here then the value in
|
||||
// the filter will be given to the defined function and it will return a new
|
||||
// value for use in the sql query.
|
||||
func getFilterMapFunctions() map[string]entity.FilterMapFunction {
|
||||
// if len(filterMapFunctions) == 0 {
|
||||
// TODO: See internal/model/file_item.go:620 for an example
|
||||
// }
|
||||
|
||||
return filterMapFunctions
|
||||
}
|
||||
|
||||
// GetFilterSchema returns filter schema
|
||||
func GetFilterSchema() string {
|
||||
var m Model
|
||||
return entity.GetFilterSchema(m)
|
||||
}
|
@ -1,147 +1,38 @@
|
||||
package upstream
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/errors"
|
||||
"npm/internal/logger"
|
||||
"npm/internal/model"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
// GetByID finds a Upstream by ID
|
||||
func GetByID(id int) (Model, error) {
|
||||
func GetByID(id uint) (Model, error) {
|
||||
var m Model
|
||||
err := m.LoadByID(id)
|
||||
return m, err
|
||||
}
|
||||
|
||||
// create will create a Upstream from this model
|
||||
func create(u *Model) (int, error) {
|
||||
if u.ID != 0 {
|
||||
return 0, eris.New("Cannot create upstream when model already has an ID")
|
||||
}
|
||||
|
||||
u.Touch(true)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
result, err := db.NamedExec(`INSERT INTO `+fmt.Sprintf("`%s`", tableName)+` (
|
||||
created_on,
|
||||
modified_on,
|
||||
user_id,
|
||||
name,
|
||||
nginx_template_id,
|
||||
ip_hash,
|
||||
ntlm,
|
||||
keepalive,
|
||||
keepalive_requests,
|
||||
keepalive_time,
|
||||
keepalive_timeout,
|
||||
advanced_config,
|
||||
status,
|
||||
error_message,
|
||||
is_deleted
|
||||
) VALUES (
|
||||
:created_on,
|
||||
:modified_on,
|
||||
:user_id,
|
||||
:name,
|
||||
:nginx_template_id,
|
||||
:ip_hash,
|
||||
:ntlm,
|
||||
:keepalive,
|
||||
:keepalive_requests,
|
||||
:keepalive_time,
|
||||
:keepalive_timeout,
|
||||
:advanced_config,
|
||||
:status,
|
||||
:error_message,
|
||||
:is_deleted
|
||||
)`, u)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
last, lastErr := result.LastInsertId()
|
||||
if lastErr != nil {
|
||||
return 0, lastErr
|
||||
}
|
||||
|
||||
logger.Debug("Created Upstream: %+v", u)
|
||||
|
||||
return int(last), nil
|
||||
}
|
||||
|
||||
// update will Update a Upstream from this model
|
||||
func update(u *Model) error {
|
||||
if u.ID == 0 {
|
||||
return eris.New("Cannot update upstream when model doesn't have an ID")
|
||||
}
|
||||
|
||||
u.Touch(false)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
_, err := db.NamedExec(`UPDATE `+fmt.Sprintf("`%s`", tableName)+` SET
|
||||
created_on = :created_on,
|
||||
modified_on = :modified_on,
|
||||
user_id = :user_id,
|
||||
name = :name,
|
||||
nginx_template_id = :nginx_template_id,
|
||||
ip_hash = :ip_hash,
|
||||
ntlm = :ntlm,
|
||||
keepalive = :keepalive,
|
||||
keepalive_requests = :keepalive_requests,
|
||||
keepalive_time = :keepalive_time,
|
||||
advanced_config = :advanced_config,
|
||||
status = :status,
|
||||
error_message = :error_message,
|
||||
is_deleted = :is_deleted
|
||||
WHERE id = :id`, u)
|
||||
|
||||
logger.Debug("Updated Upstream: %+v", u)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// List will return a list of Upstreams
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (ListResponse, error) {
|
||||
var result ListResponse
|
||||
var exampleModel Model
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (entity.ListResponse, error) {
|
||||
var result entity.ListResponse
|
||||
|
||||
defaultSort := model.Sort{
|
||||
Field: "name",
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
db := database.GetInstance()
|
||||
if db == nil {
|
||||
return result, errors.ErrDatabaseUnavailable
|
||||
}
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
|
||||
// Get count of items in this search
|
||||
query, params := entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), true)
|
||||
countRow := db.QueryRowx(query, params...)
|
||||
var totalRows int
|
||||
queryErr := countRow.Scan(&totalRows)
|
||||
if queryErr != nil && queryErr != sql.ErrNoRows {
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, queryErr
|
||||
var totalRows int64
|
||||
if res := dbo.Model(&Model{}).Count(&totalRows); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
// Get rows
|
||||
items := make([]Model, 0)
|
||||
query, params = entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), false)
|
||||
err := db.Select(&items, query, params...)
|
||||
if err != nil {
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, err
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
// Expand to get servers, at a minimum
|
||||
@ -150,7 +41,7 @@ func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (Lis
|
||||
items[idx].Expand(expand)
|
||||
}
|
||||
|
||||
result = ListResponse{
|
||||
result = entity.ListResponse{
|
||||
Items: items,
|
||||
Total: totalRows,
|
||||
Limit: pageInfo.Limit,
|
||||
|
@ -1,79 +1,55 @@
|
||||
package upstream
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/entity/nginxtemplate"
|
||||
"npm/internal/entity/upstreamserver"
|
||||
"npm/internal/entity/user"
|
||||
"npm/internal/status"
|
||||
"npm/internal/types"
|
||||
"npm/internal/util"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
const (
|
||||
tableName = "upstream"
|
||||
)
|
||||
|
||||
// Model is the Upstream model
|
||||
// Model is the model
|
||||
// See: http://nginx.org/en/docs/http/ngx_http_upstream_module.html#upstream
|
||||
type Model struct {
|
||||
ID int `json:"id" db:"id" filter:"id,integer"`
|
||||
CreatedOn types.DBDate `json:"created_on" db:"created_on" filter:"created_on,integer"`
|
||||
ModifiedOn types.DBDate `json:"modified_on" db:"modified_on" filter:"modified_on,integer"`
|
||||
UserID int `json:"user_id" db:"user_id" filter:"user_id,integer"`
|
||||
Name string `json:"name" db:"name" filter:"name,string"`
|
||||
NginxTemplateID int `json:"nginx_template_id" db:"nginx_template_id" filter:"nginx_template_id,integer"`
|
||||
IPHash bool `json:"ip_hash" db:"ip_hash" filter:"ip_hash,boolean"`
|
||||
NTLM bool `json:"ntlm" db:"ntlm" filter:"ntlm,boolean"`
|
||||
Keepalive int `json:"keepalive" db:"keepalive" filter:"keepalive,integer"`
|
||||
KeepaliveRequests int `json:"keepalive_requests" db:"keepalive_requests" filter:"keepalive_requests,integer"`
|
||||
KeepaliveTime string `json:"keepalive_time" db:"keepalive_time" filter:"keepalive_time,string"`
|
||||
KeepaliveTimeout string `json:"keepalive_timeout" db:"keepalive_timeout" filter:"keepalive_timeout,string"`
|
||||
AdvancedConfig string `json:"advanced_config" db:"advanced_config" filter:"advanced_config,string"`
|
||||
Status string `json:"status" db:"status" filter:"status,string"`
|
||||
ErrorMessage string `json:"error_message" db:"error_message" filter:"error_message,string"`
|
||||
IsDeleted bool `json:"is_deleted,omitempty" db:"is_deleted"`
|
||||
entity.ModelBase
|
||||
UserID uint `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"`
|
||||
Name string `json:"name" gorm:"column:name" filter:"name,string"`
|
||||
NginxTemplateID uint `json:"nginx_template_id" gorm:"column:nginx_template_id" filter:"nginx_template_id,integer"`
|
||||
IPHash bool `json:"ip_hash" gorm:"column:ip_hash" filter:"ip_hash,boolean"`
|
||||
NTLM bool `json:"ntlm" gorm:"column:ntlm" filter:"ntlm,boolean"`
|
||||
Keepalive int `json:"keepalive" gorm:"column:keepalive" filter:"keepalive,integer"`
|
||||
KeepaliveRequests int `json:"keepalive_requests" gorm:"column:keepalive_requests" filter:"keepalive_requests,integer"`
|
||||
KeepaliveTime string `json:"keepalive_time" gorm:"column:keepalive_time" filter:"keepalive_time,string"`
|
||||
KeepaliveTimeout string `json:"keepalive_timeout" gorm:"column:keepalive_timeout" filter:"keepalive_timeout,string"`
|
||||
AdvancedConfig string `json:"advanced_config" gorm:"column:advanced_config" filter:"advanced_config,string"`
|
||||
Status string `json:"status" gorm:"column:status" filter:"status,string"`
|
||||
ErrorMessage string `json:"error_message" gorm:"column:error_message" filter:"error_message,string"`
|
||||
// Expansions
|
||||
Servers []upstreamserver.Model `json:"servers"`
|
||||
NginxTemplate *nginxtemplate.Model `json:"nginx_template,omitempty"`
|
||||
User *user.Model `json:"user,omitempty"`
|
||||
Servers []upstreamserver.Model `json:"servers" gorm:"-"`
|
||||
NginxTemplate *nginxtemplate.Model `json:"nginx_template,omitempty" gorm:"-"`
|
||||
User *user.Model `json:"user,omitempty" gorm:"-"`
|
||||
}
|
||||
|
||||
func (m *Model) getByQuery(query string, params []interface{}) error {
|
||||
return database.GetByQuery(m, query, params)
|
||||
// TableName overrides the table name used by gorm
|
||||
func (Model) TableName() string {
|
||||
return "upstream"
|
||||
}
|
||||
|
||||
// LoadByID will load from an ID
|
||||
func (m *Model) LoadByID(id int) error {
|
||||
query := fmt.Sprintf("SELECT * FROM `%s` WHERE id = ? AND is_deleted = ? LIMIT 1", tableName)
|
||||
params := []interface{}{id, 0}
|
||||
err := m.getByQuery(query, params)
|
||||
if err == nil {
|
||||
err = m.Expand(nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Touch will update model's timestamp(s)
|
||||
func (m *Model) Touch(created bool) {
|
||||
var d types.DBDate
|
||||
d.Time = time.Now()
|
||||
if created {
|
||||
m.CreatedOn = d
|
||||
}
|
||||
m.ModifiedOn = d
|
||||
func (m *Model) LoadByID(id uint) error {
|
||||
db := database.GetDB()
|
||||
result := db.First(&m, id)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Save will save this model to the DB
|
||||
func (m *Model) Save(skipConfiguration bool) error {
|
||||
var err error
|
||||
|
||||
if m.UserID == 0 {
|
||||
return eris.Errorf("User ID must be specified")
|
||||
}
|
||||
@ -86,34 +62,33 @@ func (m *Model) Save(skipConfiguration bool) error {
|
||||
m.Status = status.StatusReady
|
||||
}
|
||||
|
||||
if m.ID == 0 {
|
||||
m.ID, err = create(m)
|
||||
} else {
|
||||
err = update(m)
|
||||
db := database.GetDB()
|
||||
if result := db.Save(m); result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Save Servers
|
||||
if err == nil {
|
||||
for idx := range m.Servers {
|
||||
// Continue if previous iteration didn't cause an error
|
||||
if err == nil {
|
||||
m.Servers[idx].UpstreamID = m.ID
|
||||
err = m.Servers[idx].Save()
|
||||
}
|
||||
var err error
|
||||
for idx := range m.Servers {
|
||||
// Continue if previous iteration didn't cause an error
|
||||
if err == nil {
|
||||
m.Servers[idx].UpstreamID = m.ID
|
||||
err = m.Servers[idx].Save()
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete will mark a upstream as deleted
|
||||
// Delete will mark row as deleted
|
||||
func (m *Model) Delete() bool {
|
||||
m.Touch(false)
|
||||
m.IsDeleted = true
|
||||
if err := m.Save(false); err != nil {
|
||||
if m.ID == 0 {
|
||||
// Can't delete a new object
|
||||
return false
|
||||
}
|
||||
return true
|
||||
db := database.GetDB()
|
||||
result := db.Delete(m)
|
||||
return result.Error == nil
|
||||
}
|
||||
|
||||
// Expand will fill in more properties
|
||||
|
@ -1,15 +0,0 @@
|
||||
package upstream
|
||||
|
||||
import (
|
||||
"npm/internal/model"
|
||||
)
|
||||
|
||||
// ListResponse is the JSON response for this list
|
||||
type ListResponse struct {
|
||||
Total int `json:"total"`
|
||||
Offset int `json:"offset"`
|
||||
Limit int `json:"limit"`
|
||||
Sort []model.Sort `json:"sort"`
|
||||
Filter []model.Filter `json:"filter,omitempty"`
|
||||
Items []Model `json:"items,omitempty"`
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package upstreamserver
|
||||
|
||||
import (
|
||||
"npm/internal/entity"
|
||||
)
|
||||
|
||||
var filterMapFunctions = make(map[string]entity.FilterMapFunction)
|
||||
|
||||
// getFilterMapFunctions is a map of functions that should be executed
|
||||
// during the filtering process, if a field is defined here then the value in
|
||||
// the filter will be given to the defined function and it will return a new
|
||||
// value for use in the sql query.
|
||||
func getFilterMapFunctions() map[string]entity.FilterMapFunction {
|
||||
// if len(filterMapFunctions) == 0 {
|
||||
// TODO: See internal/model/file_item.go:620 for an example
|
||||
// }
|
||||
|
||||
return filterMapFunctions
|
||||
}
|
||||
|
||||
// GetFilterSchema returns filter schema
|
||||
func GetFilterSchema() string {
|
||||
var m Model
|
||||
return entity.GetFilterSchema(m)
|
||||
}
|
@ -1,16 +1,9 @@
|
||||
package upstreamserver
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/errors"
|
||||
"npm/internal/logger"
|
||||
"npm/internal/model"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
// GetByID finds a Upstream Server by ID
|
||||
@ -21,128 +14,37 @@ func GetByID(id int) (Model, error) {
|
||||
}
|
||||
|
||||
// GetByUpstreamID finds all servers in the upstream
|
||||
func GetByUpstreamID(upstreamID int) ([]Model, error) {
|
||||
func GetByUpstreamID(upstreamID uint) ([]Model, error) {
|
||||
items := make([]Model, 0)
|
||||
query := `SELECT * FROM ` + fmt.Sprintf("`%s`", tableName) + ` WHERE upstream_id = ? ORDER BY server`
|
||||
db := database.GetInstance()
|
||||
err := db.Select(&items, query, upstreamID)
|
||||
if err != nil {
|
||||
logger.Debug("%s -- %d", query, upstreamID)
|
||||
}
|
||||
return items, err
|
||||
}
|
||||
|
||||
// create will create a Upstream Server from this model
|
||||
func create(u *Model) (int, error) {
|
||||
if u.ID != 0 {
|
||||
return 0, eris.New("Cannot create upstream server when model already has an ID")
|
||||
}
|
||||
|
||||
u.Touch(true)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
result, err := db.NamedExec(`INSERT INTO `+fmt.Sprintf("`%s`", tableName)+` (
|
||||
created_on,
|
||||
modified_on,
|
||||
upstream_id,
|
||||
server,
|
||||
weight,
|
||||
max_conns,
|
||||
max_fails,
|
||||
fail_timeout,
|
||||
backup,
|
||||
is_deleted
|
||||
) VALUES (
|
||||
:created_on,
|
||||
:modified_on,
|
||||
:upstream_id,
|
||||
:server,
|
||||
:weight,
|
||||
:max_conns,
|
||||
:max_fails,
|
||||
:fail_timeout,
|
||||
:backup,
|
||||
:is_deleted
|
||||
)`, u)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
last, lastErr := result.LastInsertId()
|
||||
if lastErr != nil {
|
||||
return 0, lastErr
|
||||
}
|
||||
|
||||
logger.Debug("Created Upstream Server: %+v", u)
|
||||
|
||||
return int(last), nil
|
||||
}
|
||||
|
||||
// update will Update a Upstream from this model
|
||||
func update(u *Model) error {
|
||||
if u.ID == 0 {
|
||||
return eris.New("Cannot update upstream server when model doesn't have an ID")
|
||||
}
|
||||
|
||||
u.Touch(false)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
_, err := db.NamedExec(`UPDATE `+fmt.Sprintf("`%s`", tableName)+` SET
|
||||
created_on = :created_on,
|
||||
modified_on = :modified_on,
|
||||
upstream_id = :upstream_id,
|
||||
server = :server,
|
||||
weight = :weight,
|
||||
max_conns = :max_conns,
|
||||
max_fails = :max_fails,
|
||||
fail_timeout = :fail_timeout,
|
||||
backup = :backup,
|
||||
is_deleted = :is_deleted
|
||||
WHERE id = :id`, u)
|
||||
|
||||
logger.Debug("Updated Upstream Server: %+v", u)
|
||||
|
||||
return err
|
||||
db := database.GetDB()
|
||||
result := db.Where("upstream_id = ?", upstreamID).Order("server ASC").Find(&items)
|
||||
return items, result.Error
|
||||
}
|
||||
|
||||
// List will return a list of Upstreams
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter) (ListResponse, error) {
|
||||
var result ListResponse
|
||||
var exampleModel Model
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse, error) {
|
||||
var result entity.ListResponse
|
||||
|
||||
defaultSort := model.Sort{
|
||||
Field: "server",
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
db := database.GetInstance()
|
||||
if db == nil {
|
||||
return result, errors.ErrDatabaseUnavailable
|
||||
}
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
|
||||
// Get count of items in this search
|
||||
query, params := entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), true)
|
||||
countRow := db.QueryRowx(query, params...)
|
||||
var totalRows int
|
||||
queryErr := countRow.Scan(&totalRows)
|
||||
if queryErr != nil && queryErr != sql.ErrNoRows {
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, queryErr
|
||||
var totalRows int64
|
||||
if res := dbo.Model(&Model{}).Count(&totalRows); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
// Get rows
|
||||
items := make([]Model, 0)
|
||||
query, params = entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), false)
|
||||
err := db.Select(&items, query, params...)
|
||||
if err != nil {
|
||||
logger.Debug("%s -- %+v", query, params)
|
||||
return result, err
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
result = ListResponse{
|
||||
result = entity.ListResponse{
|
||||
Items: items,
|
||||
Total: totalRows,
|
||||
Limit: pageInfo.Limit,
|
||||
|
@ -1,78 +1,48 @@
|
||||
package upstreamserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/types"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
"npm/internal/entity"
|
||||
)
|
||||
|
||||
const (
|
||||
tableName = "upstream_server"
|
||||
)
|
||||
|
||||
// Model is the upstream model
|
||||
// Model is the model
|
||||
type Model struct {
|
||||
ID int `json:"id" db:"id" filter:"id,integer"`
|
||||
CreatedOn types.DBDate `json:"created_on" db:"created_on" filter:"created_on,integer"`
|
||||
ModifiedOn types.DBDate `json:"modified_on" db:"modified_on" filter:"modified_on,integer"`
|
||||
UpstreamID int `json:"upstream_id" db:"upstream_id" filter:"upstream_id,integer"`
|
||||
Server string `json:"server" db:"server" filter:"server,string"`
|
||||
Weight int `json:"weight" db:"weight" filter:"weight,integer"`
|
||||
MaxConns int `json:"max_conns" db:"max_conns" filter:"max_conns,integer"`
|
||||
MaxFails int `json:"max_fails" db:"max_fails" filter:"max_fails,integer"`
|
||||
FailTimeout int `json:"fail_timeout" db:"fail_timeout" filter:"fail_timeout,integer"`
|
||||
Backup bool `json:"backup" db:"backup" filter:"backup,boolean"`
|
||||
IsDeleted bool `json:"is_deleted,omitempty" db:"is_deleted"`
|
||||
entity.ModelBase
|
||||
UpstreamID uint `json:"upstream_id" gorm:"column:upstream_id" filter:"upstream_id,integer"`
|
||||
Server string `json:"server" gorm:"column:server" filter:"server,string"`
|
||||
Weight int `json:"weight" gorm:"column:weight" filter:"weight,integer"`
|
||||
MaxConns int `json:"max_conns" gorm:"column:max_conns" filter:"max_conns,integer"`
|
||||
MaxFails int `json:"max_fails" gorm:"column:max_fails" filter:"max_fails,integer"`
|
||||
FailTimeout int `json:"fail_timeout" gorm:"column:fail_timeout" filter:"fail_timeout,integer"`
|
||||
Backup bool `json:"backup" gorm:"column:is_backup" filter:"backup,boolean"`
|
||||
}
|
||||
|
||||
func (m *Model) getByQuery(query string, params []interface{}) error {
|
||||
return database.GetByQuery(m, query, params)
|
||||
// TableName overrides the table name used by gorm
|
||||
func (Model) TableName() string {
|
||||
return "upstream_server"
|
||||
}
|
||||
|
||||
// LoadByID will load from an ID
|
||||
func (m *Model) LoadByID(id int) error {
|
||||
query := fmt.Sprintf("SELECT * FROM `%s` WHERE id = ? AND is_deleted = ? LIMIT 1", tableName)
|
||||
params := []interface{}{id, 0}
|
||||
return m.getByQuery(query, params)
|
||||
}
|
||||
|
||||
// Touch will update model's timestamp(s)
|
||||
func (m *Model) Touch(created bool) {
|
||||
var d types.DBDate
|
||||
d.Time = time.Now()
|
||||
if created {
|
||||
m.CreatedOn = d
|
||||
}
|
||||
m.ModifiedOn = d
|
||||
db := database.GetDB()
|
||||
result := db.First(&m, id)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Save will save this model to the DB
|
||||
func (m *Model) Save() error {
|
||||
var err error
|
||||
|
||||
if m.UpstreamID == 0 {
|
||||
return eris.Errorf("Upstream ID must be specified")
|
||||
}
|
||||
|
||||
if m.ID == 0 {
|
||||
m.ID, err = create(m)
|
||||
} else {
|
||||
err = update(m)
|
||||
}
|
||||
|
||||
return err
|
||||
db := database.GetDB()
|
||||
result := db.Save(m)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Delete will mark a upstream as deleted
|
||||
// Delete will mark row as deleted
|
||||
func (m *Model) Delete() bool {
|
||||
m.Touch(false)
|
||||
m.IsDeleted = true
|
||||
if err := m.Save(); err != nil {
|
||||
if m.ID == 0 {
|
||||
// Can't delete a new object
|
||||
return false
|
||||
}
|
||||
return true
|
||||
db := database.GetDB()
|
||||
result := db.Delete(m)
|
||||
return result.Error == nil
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
package upstreamserver
|
||||
|
||||
import (
|
||||
"npm/internal/model"
|
||||
)
|
||||
|
||||
// ListResponse is the JSON response for this list
|
||||
type ListResponse struct {
|
||||
Total int `json:"total"`
|
||||
Offset int `json:"offset"`
|
||||
Limit int `json:"limit"`
|
||||
Sort []model.Sort `json:"sort"`
|
||||
Filter []model.Filter `json:"filter,omitempty"`
|
||||
Items []Model `json:"items,omitempty"`
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"npm/internal/entity"
|
||||
)
|
||||
|
||||
var filterMapFunctions = make(map[string]entity.FilterMapFunction)
|
||||
|
||||
// getFilterMapFunctions is a map of functions that should be executed
|
||||
// during the filtering process, if a field is defined here then the value in
|
||||
// the filter will be given to the defined function and it will return a new
|
||||
// value for use in the sql query.
|
||||
func getFilterMapFunctions() map[string]entity.FilterMapFunction {
|
||||
// if len(filterMapFunctions) == 0 {
|
||||
// TODO: See internal/model/file_item.go:620 for an example
|
||||
// }
|
||||
|
||||
return filterMapFunctions
|
||||
}
|
||||
|
||||
// GetFilterSchema returns filter schema
|
||||
func GetFilterSchema() string {
|
||||
var m Model
|
||||
return entity.GetFilterSchema(m)
|
||||
}
|
@ -1,20 +1,14 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/errors"
|
||||
"npm/internal/logger"
|
||||
"npm/internal/model"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
// GetByID finds a user by ID
|
||||
func GetByID(id int) (Model, error) {
|
||||
func GetByID(id uint) (Model, error) {
|
||||
var m Model
|
||||
err := m.LoadByID(id)
|
||||
return m, err
|
||||
@ -27,140 +21,38 @@ func GetByEmail(email string) (Model, error) {
|
||||
return m, err
|
||||
}
|
||||
|
||||
// Create will create a User from given model
|
||||
func Create(user *Model) (int, error) {
|
||||
// We need to ensure that a user can't be created with the same email
|
||||
// as an existing non-deleted user. Usually you would do this with the
|
||||
// database schema, but it's a bit more complex because of the is_deleted field.
|
||||
|
||||
if user.ID != 0 {
|
||||
return 0, eris.New("Cannot create user when model already has an ID")
|
||||
}
|
||||
|
||||
// Check if an existing user with this email exists
|
||||
_, err := GetByEmail(user.Email)
|
||||
if err == nil {
|
||||
return 0, errors.ErrDuplicateEmailUser
|
||||
}
|
||||
|
||||
user.Touch(true)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
result, err := db.NamedExec(`INSERT INTO `+fmt.Sprintf("`%s`", tableName)+` (
|
||||
created_on,
|
||||
modified_on,
|
||||
name,
|
||||
nickname,
|
||||
email,
|
||||
is_disabled
|
||||
) VALUES (
|
||||
:created_on,
|
||||
:modified_on,
|
||||
:name,
|
||||
:nickname,
|
||||
:email,
|
||||
:is_disabled
|
||||
)`, user)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
last, lastErr := result.LastInsertId()
|
||||
if lastErr != nil {
|
||||
return 0, lastErr
|
||||
}
|
||||
|
||||
return int(last), nil
|
||||
}
|
||||
|
||||
// Update will Update a User from this model
|
||||
func Update(user *Model) error {
|
||||
if user.ID == 0 {
|
||||
return eris.New("Cannot update user when model doesn't have an ID")
|
||||
}
|
||||
|
||||
// Check that the email address isn't associated with another user
|
||||
if existingUser, _ := GetByEmail(user.Email); existingUser.ID != 0 && existingUser.ID != user.ID {
|
||||
return errors.ErrDuplicateEmailUser
|
||||
}
|
||||
|
||||
user.Touch(false)
|
||||
|
||||
db := database.GetInstance()
|
||||
// nolint: gosec
|
||||
_, err := db.NamedExec(`UPDATE `+fmt.Sprintf("`%s`", tableName)+` SET
|
||||
created_on = :created_on,
|
||||
modified_on = :modified_on,
|
||||
name = :name,
|
||||
nickname = :nickname,
|
||||
email = :email,
|
||||
is_disabled = :is_disabled,
|
||||
is_deleted = :is_deleted
|
||||
WHERE id = :id`, user)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// IsEnabled is used by middleware to ensure the user is still enabled
|
||||
// returns (userExist, isEnabled)
|
||||
func IsEnabled(userID int) (bool, bool) {
|
||||
// nolint: gosec
|
||||
query := `SELECT is_disabled FROM ` + fmt.Sprintf("`%s`", tableName) + ` WHERE id = ? AND is_deleted = ?`
|
||||
disabled := true
|
||||
db := database.GetInstance()
|
||||
err := db.QueryRowx(query, userID, 0).Scan(&disabled)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
func IsEnabled(userID uint) (bool, bool) {
|
||||
var user Model
|
||||
db := database.GetDB()
|
||||
if result := db.First(&user, userID); result.Error != nil {
|
||||
return false, false
|
||||
} else if err != nil {
|
||||
logger.Error("QueryError", err)
|
||||
}
|
||||
|
||||
return true, !disabled
|
||||
return true, !user.IsDisabled
|
||||
}
|
||||
|
||||
// List will return a list of users
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (ListResponse, error) {
|
||||
var result ListResponse
|
||||
var exampleModel Model
|
||||
func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (entity.ListResponse, error) {
|
||||
var result entity.ListResponse
|
||||
|
||||
defaultSort := model.Sort{
|
||||
Field: "name",
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
db := database.GetInstance()
|
||||
if db == nil {
|
||||
return result, errors.ErrDatabaseUnavailable
|
||||
}
|
||||
|
||||
/*
|
||||
filters = append(filters, model.Filter{
|
||||
Field: "is_system",
|
||||
Modifier: "equals",
|
||||
Value: []string{"0"},
|
||||
})
|
||||
*/
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
|
||||
// Get count of items in this search
|
||||
query, params := entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), true)
|
||||
countRow := db.QueryRowx(query, params...)
|
||||
var totalRows int
|
||||
queryErr := countRow.Scan(&totalRows)
|
||||
if queryErr != nil && queryErr != sql.ErrNoRows {
|
||||
logger.Debug("Query: %s -- %+v", query, params)
|
||||
return result, queryErr
|
||||
var totalRows int64
|
||||
if res := dbo.Model(&Model{}).Count(&totalRows); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
// Get rows
|
||||
items := make([]Model, 0)
|
||||
query, params = entity.ListQueryBuilder(exampleModel, tableName, &pageInfo, defaultSort, filters, getFilterMapFunctions(), false)
|
||||
err := db.Select(&items, query, params...)
|
||||
if err != nil {
|
||||
logger.Debug("Query: %s -- %+v", query, params)
|
||||
return result, err
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
for idx := range items {
|
||||
@ -176,7 +68,7 @@ func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (Lis
|
||||
}
|
||||
}
|
||||
|
||||
result = ListResponse{
|
||||
result = entity.ListResponse{
|
||||
Items: items,
|
||||
Total: totalRows,
|
||||
Limit: pageInfo.Limit,
|
||||
@ -190,41 +82,21 @@ func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (Lis
|
||||
|
||||
// DeleteAll will do just that, and should only be used for testing purposes.
|
||||
func DeleteAll() error {
|
||||
db := database.GetInstance()
|
||||
_, err := db.Exec(fmt.Sprintf("DELETE FROM `%s`", tableName))
|
||||
return err
|
||||
db := database.GetDB()
|
||||
result := db.Exec("DELETE FROM users")
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// GetCapabilities gets capabilities for a user
|
||||
func GetCapabilities(userID int) ([]string, error) {
|
||||
var capabilities []string
|
||||
db := database.GetInstance()
|
||||
if db == nil {
|
||||
return []string{}, errors.ErrDatabaseUnavailable
|
||||
func GetCapabilities(userID uint) ([]string, error) {
|
||||
capabilities := make([]string, 0)
|
||||
var hasCapabilities []UserHasCapabilityModel
|
||||
db := database.GetDB()
|
||||
if result := db.Where("user_id = ?", userID).Find(&hasCapabilities); result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
query := `SELECT c.name FROM "user_has_capability" h
|
||||
INNER JOIN "capability" c ON c.id = h.capability_id
|
||||
WHERE h.user_id = ?`
|
||||
|
||||
rows, err := db.Query(query, userID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
logger.Debug("QUERY: %v -- %v", query, userID)
|
||||
return []string{}, err
|
||||
for _, obj := range hasCapabilities {
|
||||
capabilities = append(capabilities, obj.CapabilityName)
|
||||
}
|
||||
|
||||
// nolint: errcheck
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var name string
|
||||
err := rows.Scan(&name)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
|
||||
capabilities = append(capabilities, name)
|
||||
}
|
||||
|
||||
return capabilities, nil
|
||||
}
|
||||
|
@ -1,62 +1,67 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"npm/internal/database"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/entity/auth"
|
||||
"npm/internal/errors"
|
||||
"npm/internal/logger"
|
||||
"npm/internal/types"
|
||||
"npm/internal/util"
|
||||
|
||||
"github.com/drexedam/gravatar"
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
const (
|
||||
tableName = "user"
|
||||
)
|
||||
|
||||
// Model is the user model
|
||||
// Model is the model
|
||||
type Model struct {
|
||||
ID int `json:"id" db:"id" filter:"id,integer"`
|
||||
Name string `json:"name" db:"name" filter:"name,string"`
|
||||
Nickname string `json:"nickname" db:"nickname" filter:"nickname,string"`
|
||||
Email string `json:"email" db:"email" filter:"email,email"`
|
||||
CreatedOn types.DBDate `json:"created_on" db:"created_on" filter:"created_on,integer"`
|
||||
ModifiedOn types.DBDate `json:"modified_on" db:"modified_on" filter:"modified_on,integer"`
|
||||
GravatarURL string `json:"gravatar_url"`
|
||||
IsDisabled bool `json:"is_disabled" db:"is_disabled" filter:"is_disabled,boolean"`
|
||||
IsSystem bool `json:"is_system,omitempty" db:"is_system"`
|
||||
IsDeleted bool `json:"is_deleted,omitempty" db:"is_deleted"`
|
||||
entity.ModelBase
|
||||
Name string `json:"name" gorm:"column:name" filter:"name,string"`
|
||||
Nickname string `json:"nickname" gorm:"column:nickname" filter:"nickname,string"`
|
||||
Email string `json:"email" gorm:"column:email" filter:"email,email"`
|
||||
IsDisabled bool `json:"is_disabled" gorm:"column:is_disabled" filter:"is_disabled,boolean"`
|
||||
IsSystem bool `json:"is_system,omitempty" gorm:"column:is_system"`
|
||||
// Other
|
||||
GravatarURL string `json:"gravatar_url" gorm:"-"`
|
||||
// Expansions
|
||||
Auth *auth.Model `json:"auth,omitempty" db:"-"`
|
||||
Capabilities []string `json:"capabilities,omitempty"`
|
||||
Auth *auth.Model `json:"auth,omitempty" gorm:"-"`
|
||||
Capabilities []string `json:"capabilities,omitempty" gorm:"-"`
|
||||
}
|
||||
|
||||
func (m *Model) getByQuery(query string, params []interface{}) error {
|
||||
err := database.GetByQuery(m, query, params)
|
||||
m.generateGravatar()
|
||||
return err
|
||||
// TableName overrides the table name used by gorm
|
||||
func (Model) TableName() string {
|
||||
return "user"
|
||||
}
|
||||
|
||||
// UserHasCapabilityModel is the model
|
||||
type UserHasCapabilityModel struct {
|
||||
UserID uint `json:"user_id" gorm:"column:user_id"`
|
||||
CapabilityName string `json:"name" gorm:"column:capability_name"`
|
||||
}
|
||||
|
||||
// TableName overrides the table name used by gorm
|
||||
func (UserHasCapabilityModel) TableName() string {
|
||||
return "user_has_capability"
|
||||
}
|
||||
|
||||
// LoadByID will load from an ID
|
||||
func (m *Model) LoadByID(id int) error {
|
||||
query := fmt.Sprintf("SELECT * FROM `%s` WHERE id = ? AND is_deleted = ? LIMIT 1", tableName)
|
||||
params := []interface{}{id, false}
|
||||
return m.getByQuery(query, params)
|
||||
func (m *Model) LoadByID(id uint) error {
|
||||
db := database.GetDB()
|
||||
result := db.First(&m, id)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// LoadByEmail will load from an Email
|
||||
func (m *Model) LoadByEmail(email string) error {
|
||||
query := fmt.Sprintf("SELECT * FROM `%s` WHERE email = ? AND is_deleted = ? AND is_system = ? LIMIT 1", tableName)
|
||||
params := []interface{}{strings.TrimSpace(strings.ToLower(email)), false, false}
|
||||
return m.getByQuery(query, params)
|
||||
db := database.GetDB()
|
||||
result := db.
|
||||
Where("email = ?", strings.TrimSpace(strings.ToLower(email))).
|
||||
Where("is_system = ?", false).
|
||||
First(&m)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
/*
|
||||
// Touch will update model's timestamp(s)
|
||||
func (m *Model) Touch(created bool) {
|
||||
var d types.DBDate
|
||||
@ -67,34 +72,31 @@ func (m *Model) Touch(created bool) {
|
||||
m.ModifiedOn = d
|
||||
m.generateGravatar()
|
||||
}
|
||||
*/
|
||||
|
||||
// Save will save this model to the DB
|
||||
func (m *Model) Save() error {
|
||||
var err error
|
||||
// Ensure email is nice
|
||||
m.Email = strings.TrimSpace(strings.ToLower(m.Email))
|
||||
|
||||
if m.IsSystem {
|
||||
return errors.ErrSystemUserReadonly
|
||||
}
|
||||
|
||||
if m.ID == 0 {
|
||||
m.ID, err = Create(m)
|
||||
} else {
|
||||
err = Update(m)
|
||||
}
|
||||
|
||||
return err
|
||||
db := database.GetDB()
|
||||
// todo: touch? not sure that save does this or not?
|
||||
result := db.Save(m)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Delete will mark a user as deleted
|
||||
func (m *Model) Delete() bool {
|
||||
m.Touch(false)
|
||||
m.IsDeleted = true
|
||||
if err := m.Save(); err != nil {
|
||||
if m.ID == 0 {
|
||||
// Can't delete a new object
|
||||
return false
|
||||
}
|
||||
return true
|
||||
db := database.GetDB()
|
||||
result := db.Delete(m)
|
||||
return result.Error == nil
|
||||
}
|
||||
|
||||
// SetPermissions will wipe out any existing permissions and add new ones for this user
|
||||
@ -103,30 +105,20 @@ func (m *Model) SetPermissions(permissions []string) error {
|
||||
return eris.Errorf("Cannot set permissions without first saving the User")
|
||||
}
|
||||
|
||||
db := database.GetInstance()
|
||||
|
||||
db := database.GetDB()
|
||||
// Wipe out previous permissions
|
||||
query := `DELETE FROM "user_has_capability" WHERE "user_id" = ?`
|
||||
if _, err := db.Exec(query, m.ID); err != nil {
|
||||
logger.Debug("QUERY: %v -- %v", query, m.ID)
|
||||
return err
|
||||
if result := db.Where("user_id = ?", m.ID).Delete(&UserHasCapabilityModel{}); result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
|
||||
if len(permissions) > 0 {
|
||||
// Add new permissions
|
||||
objs := []*UserHasCapabilityModel{}
|
||||
for _, permission := range permissions {
|
||||
query = `INSERT INTO "user_has_capability" (
|
||||
"user_id", "capability_id"
|
||||
) VALUES (
|
||||
?,
|
||||
(SELECT id FROM capability WHERE name = ?)
|
||||
)`
|
||||
|
||||
_, err := db.Exec(query, m.ID, permission)
|
||||
if err != nil {
|
||||
logger.Debug("QUERY: %v -- %v -- %v", query, m.ID, permission)
|
||||
return err
|
||||
}
|
||||
objs = append(objs, &UserHasCapabilityModel{UserID: m.ID, CapabilityName: permission})
|
||||
}
|
||||
if result := db.Create(objs); result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,21 +156,18 @@ func (m *Model) SaveCapabilities() error {
|
||||
return eris.New("At least 1 capability required for a user")
|
||||
}
|
||||
|
||||
db := database.GetInstance()
|
||||
|
||||
db := database.GetDB()
|
||||
// Get a full list of capabilities
|
||||
var capabilities []string
|
||||
query := `SELECT "name" from "capability"`
|
||||
err := db.Select(&capabilities, query)
|
||||
if err != nil {
|
||||
return err
|
||||
var capabilities []entity.Capability
|
||||
if result := db.Find(&capabilities); result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Check that the capabilities defined exist in the db
|
||||
for _, cap := range m.Capabilities {
|
||||
found := false
|
||||
for _, a := range capabilities {
|
||||
if a == cap {
|
||||
if a.Name == cap {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"npm/internal/model"
|
||||
)
|
||||
|
||||
// ListResponse is the JSON response for users list
|
||||
type ListResponse struct {
|
||||
Total int `json:"total"`
|
||||
Offset int `json:"offset"`
|
||||
Limit int `json:"limit"`
|
||||
Sort []model.Sort `json:"sort"`
|
||||
Filter []model.Filter `json:"filter,omitempty"`
|
||||
Items []Model `json:"items,omitempty"`
|
||||
}
|
Reference in New Issue
Block a user