add setting support

Signed-off-by: yxxhero <aiopsclub@163.com>
This commit is contained in:
yxxhero 2021-08-13 08:17:07 +08:00 committed by Gaius
parent 16e23b50de
commit b0781a2c0e
No known key found for this signature in database
GPG Key ID: 8B4E5D1290FA2FFB
12 changed files with 319 additions and 86 deletions

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
"io/ioutil"
"net/http"
"strings"
"golang.org/x/oauth2"
"golang.org/x/oauth2/github"
@ -21,11 +22,10 @@ func NewGithubOauth2(name string, clientID string, clientSecret string, db *gorm
oa.Config = &oauth2.Config{
ClientID: clientID,
ClientSecret: clientSecret,
Scopes: []string{"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email"},
Scopes: strings.Split(GithubScopes, ","),
Endpoint: github.Endpoint,
}
oa.UserInfoURL = "https://api.github.com/user"
oa.UserInfoURL = GithubUserInfoURL
redirectURL, err := oa.GetRediectURL(db)
if err != nil {

View File

@ -1,6 +1,8 @@
package oauth
import (
"strings"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"gorm.io/gorm"
@ -17,11 +19,10 @@ func NewGoogleOauth2(name string, clientID string, clientSecret string, db *gorm
oa.Config = &oauth2.Config{
ClientID: clientID,
ClientSecret: clientSecret,
Scopes: []string{"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email"},
Scopes: strings.Split(GoogleScopes, ","),
Endpoint: google.Endpoint,
}
oa.UserInfoURL = "https://www.googleapis.com/oauth2/v2/userinfo"
oa.UserInfoURL = GithubUserInfoURL
redirectURL, err := oa.GetRediectURL(db)
if err != nil {

View File

@ -16,6 +16,14 @@ import (
"gorm.io/gorm"
)
const (
GoogleScopes = "https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/userinfo.profile"
GoogleUserInfoURL = "https://www.googleapis.com/oauth2/v2/userinfo"
GithubScopes = "user,public_repo"
GithubUserInfoURL = "https://api.github.com/user"
)
type baseOauth2 struct {
Name string
UserInfoURL string

View File

@ -193,33 +193,17 @@ func (h *Handlers) GetOauth(ctx *gin.Context) {
// @Tags Oauth
// @Accept json
// @Produce json
// @Param page query int true "current page" default(0)
// @Param per_page query int true "return max item count, default 10, max 50" default(10) minimum(2) maximum(50)
// @Success 200 {object} []model.Oauth
// @Failure 400 {object} HTTPError
// @Failure 404 {object} HTTPError
// @Failure 500 {object} HTTPError
// @Router /oauths [get]
func (h *Handlers) GetOauths(ctx *gin.Context) {
var query types.GetOauthsQuery
if err := ctx.ShouldBindQuery(&query); err != nil {
ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()})
return
}
h.setPaginationDefault(&query.Page, &query.PerPage)
oauths, err := h.Service.GetOauths(query)
oauths, err := h.Service.GetOauths()
if err != nil {
ctx.Error(err)
return
}
totalCount, err := h.Service.OauthTotalCount(query)
if err != nil {
ctx.Error(err)
return
}
h.setPaginationLinkHeader(ctx, query.Page, query.PerPage, int(totalCount))
ctx.JSON(http.StatusOK, oauths)
}

View File

@ -0,0 +1,132 @@
package handlers
import (
"net/http"
"d7y.io/dragonfly/v2/manager/types"
"github.com/gin-gonic/gin"
)
// @Summary Create Setting
// @Description create by json config
// @Tags Setting
// @Accept json
// @Produce json
// @Param Setting body types.CreateSettingRequest true "Setting"
// @Success 200 {object} model.Setting
// @Failure 400 {object} HTTPError
// @Failure 404 {object} HTTPError
// @Failure 500 {object} HTTPError
// @Router /settings [post]
func (h *Handlers) CreateSetting(ctx *gin.Context) {
var json types.CreateSettingRequest
if err := ctx.ShouldBindJSON(&json); err != nil {
ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()})
return
}
setting, err := h.Service.CreateSetting(json)
if err != nil {
ctx.Error(err)
return
}
ctx.JSON(http.StatusOK, setting)
}
// @Summary Destroy Setting
// @Description Destroy by key
// @Tags Setting
// @Accept json
// @Produce json
// @Param id path string true "key"
// @Success 200
// @Failure 400 {object} HTTPError
// @Failure 404 {object} HTTPError
// @Failure 500 {object} HTTPError
// @Router /settings/{id} [delete]
func (h *Handlers) DestroySetting(ctx *gin.Context) {
var params types.SettingParams
if err := ctx.ShouldBindUri(&params); err != nil {
ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()})
return
}
err := h.Service.DestroySetting(params.Key)
if err != nil {
ctx.Error(err)
return
}
ctx.Status(http.StatusOK)
}
// @Summary Update Setting
// @Description Update by json config
// @Tags Setting
// @Accept json
// @Produce json
// @Param key path string true "key"
// @Param Setting body types.UpdateSettingRequest true "Setting"
// @Success 200 {object} model.Setting
// @Failure 400 {object} HTTPError
// @Failure 404 {object} HTTPError
// @Failure 500 {object} HTTPError
// @Router /settings/{id} [patch]
func (h *Handlers) UpdateSetting(ctx *gin.Context) {
var params types.SettingParams
if err := ctx.ShouldBindUri(&params); err != nil {
ctx.Error(err)
return
}
var json types.UpdateSettingRequest
if err := ctx.ShouldBindJSON(&json); err != nil {
ctx.Error(err)
return
}
setting, err := h.Service.UpdateSetting(params.Key, json)
if err != nil {
ctx.Error(err)
return
}
ctx.JSON(http.StatusOK, setting)
}
// @Summary Get Settings
// @Description Get Settings
// @Tags Setting
// @Accept json
// @Produce json
// @Param page query int true "current page" default(0)
// @Param per_page query int true "return max item count, default 10, max 50" default(10) minimum(2) maximum(50)
// @Success 200 {object} []model.Setting
// @Failure 400 {object} HTTPError
// @Failure 404 {object} HTTPError
// @Failure 500 {object} HTTPError
// @Router /settings [get]
func (h *Handlers) GetSettings(ctx *gin.Context) {
var query types.GetSettingsQuery
if err := ctx.ShouldBindQuery(&query); err != nil {
ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()})
return
}
h.setPaginationDefault(&query.Page, &query.PerPage)
settings, err := h.Service.GetSettings(query)
if err != nil {
ctx.Error(err)
return
}
totalCount, err := h.Service.SettingTotalCount()
if err != nil {
ctx.Error(err)
return
}
h.setPaginationLinkHeader(ctx, query.Page, query.PerPage, int(totalCount))
ctx.JSON(http.StatusOK, settings)
}

View File

@ -1,7 +1,7 @@
package model
type Settings struct {
Model
Key string `gorm:"column:key;type:varchar(256);index:unique;not null;comment: setting key" json:"key"`
ID uint `gorm:"primarykey;comment:id" json:"id"`
Key string `gorm:"column:key;type:varchar(256);index:uk_settings_key,unique;not null;comment:setting key" json:"key"`
Value string `gorm:"column:value;type:varchar(256);not null;comment:setting value" json:"value"`
}

View File

@ -104,6 +104,13 @@ func Init(console bool, verbose bool, publicPath string, service service.REST, e
s.GET(":id", h.GetScheduler)
s.GET("", h.GetSchedulers)
// Settings
st := apiv1.Group("/settings")
st.POST("", h.CreateSetting)
st.DELETE(":id", h.DestroySetting)
st.PATCH("", h.UpdateSetting)
st.GET("", h.GetSettings)
// CDN Cluster
cc := apiv1.Group("/cdn-clusters")
cc.POST("", h.CreateCDNCluster)

View File

@ -1,25 +1,47 @@
package service
import (
"d7y.io/dragonfly/v2/manager/auth/oauth"
"d7y.io/dragonfly/v2/manager/model"
"d7y.io/dragonfly/v2/manager/oauth"
"d7y.io/dragonfly/v2/manager/types"
"golang.org/x/oauth2/github"
"golang.org/x/oauth2/google"
)
func (s *rest) CreateOauth(json types.CreateOauthRequest) (*model.Oauth, error) {
oauth := model.Oauth{
o := model.Oauth{}
o.ClientID = json.ClientID
o.ClientSecret = json.ClientSecret
o.Name = json.Name
switch json.Name {
case "google":
o.AuthURL = google.Endpoint.AuthURL
o.TokenURL = google.Endpoint.TokenURL
o.Scopes = oauth.GoogleScopes
o.UserInfoURL = oauth.GoogleUserInfoURL
case "github":
o.AuthURL = github.Endpoint.AuthURL
o.TokenURL = github.Endpoint.TokenURL
o.Scopes = oauth.GithubScopes
o.UserInfoURL = oauth.GithubUserInfoURL
default:
o = model.Oauth{
ClientID: json.ClientID,
ClientSecret: json.ClientSecret,
Name: json.Name,
Scopes: json.Scopes,
AuthURL: json.AuthURL,
TokenURL: json.TokenURL,
UserInfoURL: json.UserInfoURL,
}
}
if err := s.db.Create(&oauth).Error; err != nil {
if err := s.db.Create(&o).Error; err != nil {
return nil, err
}
return &oauth, nil
return &o, nil
}
func (s *rest) DestroyOauth(id uint) error {
@ -53,52 +75,40 @@ func (s *rest) GetOauth(id uint) (*model.Oauth, error) {
return &oauth, nil
}
func (s *rest) GetOauths(q types.GetOauthsQuery) (*[]model.Oauth, error) {
func (s *rest) GetOauths() (*[]model.Oauth, error) {
oauths := []model.Oauth{}
if q.Name != "" {
if err := s.db.Scopes(model.Paginate(q.Page, q.PerPage)).Where(&model.Oauth{
Name: q.Name,
}).Find(&oauths).Error; err != nil {
if err := s.db.Find(&oauths).Error; err != nil {
return nil, err
}
} else {
if err := s.db.Scopes(model.Paginate(q.Page, q.PerPage)).Find(&oauths).Error; err != nil {
return nil, err
}
}
return &oauths, nil
}
func (s *rest) OauthTotalCount(q types.GetOauthsQuery) (int64, error) {
var count int64
if q.Name != "" {
if err := s.db.Model(&model.Oauth{}).Where(&model.Oauth{
Name: q.Name,
}).Count(&count).Error; err != nil {
return 0, err
}
} else {
if err := s.db.Model(&model.Oauth{}).Where(&model.Oauth{}).Count(&count).Error; err != nil {
return 0, err
}
}
return count, nil
}
func (s *rest) OauthSignin(name string) (string, error) {
oauthModel := model.Oauth{}
if err := s.db.First(&oauthModel, name).Error; err != nil {
return "", err
}
o, err := oauth.NewBaseOauth2(name, oauthModel.ClientID, oauthModel.ClientSecret, oauthModel.Scopes, oauthModel.AuthURL, oauthModel.TokenURL, s.db)
var o oauth.Oauther
var err error
switch name {
case "google":
o, err = oauth.NewGoogleOauth2(name, oauthModel.ClientID, oauthModel.ClientSecret, s.db)
if err != nil {
return "", err
}
case "github":
o, err = oauth.NewGithubOauth2(name, oauthModel.ClientID, oauthModel.ClientSecret, s.db)
if err != nil {
return "", err
}
default:
o, err = oauth.NewBaseOauth2(name, oauthModel.ClientID, oauthModel.ClientSecret, oauthModel.Scopes, oauthModel.AuthURL, oauthModel.TokenURL, s.db)
if err != nil {
return "", err
}
}
return o.AuthCodeURL(), nil
}
@ -107,11 +117,26 @@ func (s *rest) OauthCallback(name, code string) (*model.User, error) {
if err := s.db.First(&oauthModel, name).Error; err != nil {
return nil, err
}
o, err := oauth.NewBaseOauth2(name, oauthModel.ClientID, oauthModel.ClientSecret, oauthModel.Scopes, oauthModel.AuthURL, oauthModel.TokenURL, s.db)
var o oauth.Oauther
var err error
switch name {
case "google":
o, err = oauth.NewGoogleOauth2(name, oauthModel.ClientID, oauthModel.ClientSecret, s.db)
if err != nil {
return nil, err
}
case "github":
o, err = oauth.NewGithubOauth2(name, oauthModel.ClientID, oauthModel.ClientSecret, s.db)
if err != nil {
return nil, err
}
default:
o, err = oauth.NewBaseOauth2(name, oauthModel.ClientID, oauthModel.ClientSecret, oauthModel.Scopes, oauthModel.AuthURL, oauthModel.TokenURL, s.db)
if err != nil {
return nil, err
}
}
user, err := o.ExchangeUserByCode(code, s.db)
if err != nil {
return nil, err

View File

@ -81,6 +81,12 @@ type REST interface {
GetSchedulers(types.GetSchedulersQuery) (*[]model.Scheduler, error)
SchedulerTotalCount(types.GetSchedulersQuery) (int64, error)
CreateSetting(types.CreateSettingRequest) (*model.Settings, error)
DestroySetting(string) error
UpdateSetting(string, types.UpdateSettingRequest) (*model.Settings, error)
GetSettings(types.GetSettingsQuery) (*[]model.Settings, error)
SettingTotalCount() (int64, error)
CreateSecurityGroup(types.CreateSecurityGroupRequest) (*model.SecurityGroup, error)
DestroySecurityGroup(uint) error
UpdateSecurityGroup(uint, types.UpdateSecurityGroupRequest) (*model.SecurityGroup, error)
@ -97,8 +103,7 @@ type REST interface {
DestroyOauth(uint) error
UpdateOauth(uint, types.UpdateOauthRequest) (*model.Oauth, error)
GetOauth(uint) (*model.Oauth, error)
GetOauths(types.GetOauthsQuery) (*[]model.Oauth, error)
OauthTotalCount(types.GetOauthsQuery) (int64, error)
GetOauths() (*[]model.Oauth, error)
OauthSignin(name string) (string, error)
OauthCallback(name, code string) (*model.User, error)
}

View File

@ -0,0 +1,57 @@
package service
import (
"d7y.io/dragonfly/v2/manager/model"
"d7y.io/dragonfly/v2/manager/types"
)
func (s *rest) CreateSetting(json types.CreateSettingRequest) (*model.Settings, error) {
setting := model.Settings{
Key: json.Key,
Value: json.Value,
}
if err := s.db.Create(&setting).Error; err != nil {
return nil, err
}
return &setting, nil
}
func (s *rest) DestroySetting(key string) error {
if err := s.db.Unscoped().Delete(&model.Settings{}, model.Settings{Key: key}).Error; err != nil {
return err
}
return nil
}
func (s *rest) UpdateSetting(key string, json types.UpdateSettingRequest) (*model.Settings, error) {
setting := model.Settings{}
if err := s.db.First(&setting, model.Settings{Key: key}).Updates(model.Settings{
Key: json.Key,
Value: json.Value,
}).Error; err != nil {
return nil, err
}
return &setting, nil
}
func (s *rest) GetSettings(q types.GetSettingsQuery) (*[]model.Settings, error) {
settings := []model.Settings{}
if err := s.db.Scopes(model.Paginate(q.Page, q.PerPage)).Find(&settings).Error; err != nil {
return nil, err
}
return &settings, nil
}
func (s *rest) SettingTotalCount() (int64, error) {
var count int64
if err := s.db.Model(&model.Settings{}).Count(&count).Error; err != nil {
return 0, err
}
return count, nil
}

View File

@ -16,6 +16,7 @@ type OauthBaseRquest struct {
Scopes string `json:"scopes" binding:"omitempty"`
AuthURL string `json:"auth_url" binding:"omitempty"`
TokenURL string `json:"token_url" binding:"omitempty"`
UserInfoURL string `json:"user_info_url" binding:"omitempty"`
}
type CreateOauthRequest struct {
@ -25,9 +26,3 @@ type CreateOauthRequest struct {
type UpdateOauthRequest struct {
OauthBaseRquest
}
type GetOauthsQuery struct {
Name string `json:"name" binding:"required"`
Page int `form:"page" binding:"omitempty,gte=1"`
PerPage int `form:"per_page" binding:"omitempty,gte=1,lte=50"`
}

19
manager/types/settings.go Normal file
View File

@ -0,0 +1,19 @@
package types
type SettingParams struct {
Key string `uri:"key" binding:"required"`
}
type CreateSettingRequest struct {
Key string `json:"key" binding:"required"`
Value string `json:"value" binding:"required"`
}
type UpdateSettingRequest struct {
Key string `json:"key" binding:"required"`
Value string `json:"value" binding:"required"`
}
type GetSettingsQuery struct {
Page int `form:"page" binding:"omitempty,gte=1"`
PerPage int `form:"per_page" binding:"omitempty,gte=1,lte=50"`
}