Browse Source

refactor: change structure

master
Evan 7 months ago
parent
commit
b27f6f238e
  1. 41
      cmd/cmd.go
  2. 13
      internal/config/default.go
  3. 2
      internal/config/save.go
  4. 0
      internal/constants/roles.go
  5. 22
      internal/constants/system.go
  6. 1
      internal/middleware/cors.go
  7. 2
      internal/middleware/embed_spa.go
  8. 8
      internal/session/session.go
  9. 24
      internal/util/logger.go
  10. 1
      internal/util/parse_sys_var.go
  11. 2
      internal/util/response.go
  12. 8
      main.go
  13. 3
      models/models.go
  14. 58
      models/system.go
  15. 0
      modules/.gitkeep
  16. 24
      services/auth/auth.go
  17. 10
      services/auth/user.go
  18. 42
      services/services.go

41
cmd/cmd.go

@ -2,34 +2,25 @@ package cmd
import (
"fmt"
"log"
"os"
"github.com/pkg/browser"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/mutsuki333/blogo/internal/util"
"github.com/mutsuki333/blogo/internal/config"
"github.com/mutsuki333/blogo/internal/constants"
"github.com/mutsuki333/blogo/models"
"github.com/mutsuki333/blogo/services"
"github.com/robfig/cron/v3"
)
var version = "development"
//SetVersionInfo setup version info
func SetVersionInfo(ver string) {
version = ver
RootCmd.Version = ver
}
var RootCmd = &cobra.Command{
Use: "blogo [-flags] [args]",
Short: "A go blogo server",
Long: `
Starts the blogo server`,
Version: version,
Version: constants.Version,
RunE: start,
}
@ -39,8 +30,6 @@ var (
)
func init() {
setupConfig()
RootCmd.Flags().StringP("port", "p", viper.GetString("server.port"), "port to listen on")
viper.BindPFlag("server.port", RootCmd.Flags().Lookup("port"))
RootCmd.Flags().Bool("no-gui", viper.GetBool("ui.disabled"), "Disables browser support")
@ -48,33 +37,27 @@ func init() {
RootCmd.Flags().BoolVarP(&openBrowser, "open", "O", false, "Opens up the browser")
RootCmd.PersistentFlags().Bool("save", false, "Save config for future usage.")
RootCmd.PersistentFlags().StringP("yaml", "y", viper.GetString("data"), "Location of config file to read from.")
RootCmd.PersistentFlags().StringP("config", "f", viper.GetString("data"), "Location of config file to read from.")
file, err := os.OpenFile("info.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
defer file.Close()
log.SetOutput(file)
log.Print("Server started!")
}
func start(cmd *cobra.Command, args []string) error {
configPath, _ := cmd.Flags().GetString("yaml")
util.ReadConfig(configPath)
configPath, _ := cmd.Flags().GetString("config")
config.ReadConfig(configPath)
models.InitSqlite()
if save, _ := cmd.Flags().GetBool("save"); save {
util.WriteConfig(configPath)
config.WriteConfig(configPath)
}
if constants.Status == constants.Init {
browser.OpenURL("http://localhost:" + viper.GetString("server.port") + "/settings")
}
if openBrowser && !viper.GetBool("ui.disabled") {
if openBrowser {
browser.OpenURL("http://localhost:" + viper.GetString("server.port") + "/")
}
c := cron.New()
c.AddFunc("30 * * * *", func() { fmt.Println("Every half hour") })
c.Start()
services.SetVersionInfo(version)
constants.Status = constants.Up
services.Start()
return nil
}

13
cmd/config.go → internal/config/default.go

@ -1,4 +1,4 @@
package cmd
package config
import (
"path/filepath"
@ -6,13 +6,12 @@ import (
"github.com/spf13/viper"
)
func setupConfig() {
func init() {
dataPath := filepath.FromSlash("./data")
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.SetDefault("data", dataPath)
viper.SetDefault("data", filepath.FromSlash("./data"))
setDefaults()
}
@ -22,12 +21,10 @@ func setDefaults() {
viper.SetDefault("app.mode", "debug")
viper.SetDefault("app.domain", "evanchen.company")
viper.SetDefault("app.timezone", "Asia/Taipei")
viper.SetDefault("app.log", filepath.FromSlash("./data/blogo.log"))
viper.SetDefault("server.port", "8080")
viper.SetDefault("server.https_only", false)
viper.SetDefault("auth.enabled", true)
viper.SetDefault("ui.disabled", false)
viper.SetDefault("swagger.enabled", true)
sqlitePath := filepath.FromSlash("./data/blogo.db")
viper.SetDefault("database.sqlite.path", sqlitePath)
viper.SetDefault("database.sqlite.path", filepath.FromSlash("./data/blogo.db"))
}

2
internal/util/write_to_config.go → internal/config/save.go

@ -1,4 +1,4 @@
package util
package config
import (
"log"

0
internal/constants/constant.go → internal/constants/roles.go

22
internal/constants/system.go

@ -0,0 +1,22 @@
package constants
// Version server version
var Version = "development"
//Status system status
var Status = Init
//SysStatus enum of user permission roles
type SysStatus int
//SysStatus enum of user permission roles
const (
Init SysStatus = iota
Starting
Up
Pending
)
func (s SysStatus) String() string {
return [...]string{"Init", "Starting", "Up", "Pending"}[s]
}

1
internal/middleware/cors.go

@ -0,0 +1 @@
package middleware

2
modules/static/spa_middleware.go → internal/middleware/embed_spa.go

@ -1,4 +1,4 @@
package static
package middleware
import (
"net/http"

8
modules/authenticate/middleware.go → internal/session/session.go

@ -1,4 +1,4 @@
package authenticate
package session
import (
"crypto/sha1"
@ -19,6 +19,7 @@ var shouldSecure bool
const cookieName = "GCSID"
// Session the session model
type Session struct {
ID uint `gorm:"primary_key"`
SessionID string
@ -28,7 +29,8 @@ type Session struct {
UpdatedAt time.Time
}
func Sessions() gin.HandlerFunc {
//Middleware session based middleware
func Middleware() gin.HandlerFunc {
SessionDB, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
if err != nil {
panic("failed to connect Session database")
@ -56,6 +58,7 @@ func Sessions() gin.HandlerFunc {
}
}
//LoginUser logins user
func LoginUser(c *gin.Context, userID uint) {
session := Session{
SessionID: newSessionID(userID),
@ -75,6 +78,7 @@ func LoginUser(c *gin.Context, userID uint) {
// c.SetCookie(cookieName, session.SessionID, 60*30, "/", c.Request.Host, true, true)
}
//LogoutUser logouts user
func LogoutUser(c *gin.Context) {
s, ok := c.Get(cookieName)
if !ok {

24
internal/util/logger.go

@ -0,0 +1,24 @@
package util
import (
"log"
"os"
"github.com/spf13/viper"
)
var file *os.File
//InitLogger setup logger
func InitLogger() {
file, err := os.OpenFile(viper.GetString("app.log"), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
log.SetOutput(file)
}
func CloseLogger() {
file.Close()
}

1
internal/util/parse_sys_var.go

@ -0,0 +1 @@
package util

2
internal/response/response.go → internal/util/response.go

@ -1,4 +1,4 @@
package response
package util
import (
"net/http"

8
main.go

@ -2,6 +2,9 @@ package main
import (
"github.com/mutsuki333/blogo/cmd"
_ "github.com/mutsuki333/blogo/internal/config"
"github.com/mutsuki333/blogo/internal/constants"
"github.com/mutsuki333/blogo/internal/util"
)
//go:generate statik -src=ui/dist -dest=assets -f
@ -10,6 +13,9 @@ import (
var Version = "development"
func main() {
cmd.SetVersionInfo(Version)
constants.Version = Version
constants.Status = constants.Starting
util.InitLogger()
defer util.CloseLogger()
cmd.RootCmd.Execute()
}

3
models/models.go

@ -41,7 +41,8 @@ func InitSqlite() {
}
func migrate() {
db.AutoMigrate(&User{}, &Blog{}, &Tag{}, &Comment{}, &Category{})
db.AutoMigrate(&SysVar{}, &JobStore{}, &User{}, &Blog{}, &Tag{}, &Comment{}, &Category{})
initSysVar()
setDefaultValues()
}

58
models/system.go

@ -0,0 +1,58 @@
package models
import (
"strconv"
"strings"
"github.com/robfig/cron/v3"
"github.com/mutsuki333/blogo/internal/constants"
"gorm.io/gorm/clause"
)
//Type enum of var
type SysVarType int
// Type enum of var
const (
String SysVarType = iota
Bool
Int
Float
Time
)
func (t SysVarType) String() string {
return [...]string{"String", "Bool", "Int", "Float", "Time"}[t]
}
//SysVar system variables
type SysVar struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"unique"`
Description string
Type SysVarType
Value string
}
//JobStore job store
type JobStore struct {
EntryID cron.EntryID `gorm:"primaryKey"`
Finished bool
}
func initSysVar() {
db.Clauses(clause.OnConflict{DoNothing: true}).Model(&SysVar{}).Create([]map[string]interface{}{
{"Name": "SettingUp", "Type": Bool, "Value": strconv.FormatBool(true)},
{"Name": "Version", "Type": String, "Value": strings.Split(constants.Version, "-")[0]},
})
var setup SysVar
db.Where("name = ?", "SettingUp").Find(&setup)
if b, _ := strconv.ParseBool(setup.Value); b {
constants.Status = constants.Init
} else {
constants.Status = constants.Starting
}
}

0
modules/.gitkeep

24
services/auth/auth.go

@ -6,9 +6,9 @@ import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/mutsuki333/blogo/internal/response"
"github.com/mutsuki333/blogo/internal/session"
"github.com/mutsuki333/blogo/internal/util"
"github.com/mutsuki333/blogo/models"
"github.com/mutsuki333/blogo/modules/authenticate"
)
//RegisterAuthService registers auth service to api
@ -27,7 +27,7 @@ func RegisterAuthService(api *gin.RouterGroup) {
// @Success 200
// @Router /auth [get]
func getAuthStatus(c *gin.Context) {
user, ok := authenticate.LoadUser(c)
user, ok := session.LoadUser(c)
if !ok {
return
}
@ -54,25 +54,25 @@ func login(c *gin.Context) {
log.Println("login")
var param loginRequest
if err := c.ShouldBindJSON(&param); err != nil {
response.AbortError(c, err)
util.AbortError(c, err)
return
}
user, err := models.GetUser(param.Username)
if err != nil {
response.AbortError(c, err)
util.AbortError(c, err)
return
}
pwd, err := base64.URLEncoding.DecodeString(param.PwdB64)
if err != nil {
response.AbortError(c, err)
util.AbortError(c, err)
return
}
if err := user.ValidatePassword(string(pwd)); err != nil {
response.AbortError(c, err)
util.AbortError(c, err)
return
}
authenticate.LoginUser(c, user.ID)
response.Ok(c)
session.LoginUser(c, user.ID)
util.Ok(c)
}
@ -83,8 +83,8 @@ func login(c *gin.Context) {
// @Success 200
// @Router /auth/logout [post]
func logout(c *gin.Context) {
authenticate.LogoutUser(c)
response.Ok(c)
session.LogoutUser(c)
util.Ok(c)
}
// @Summary Get Token
@ -94,7 +94,7 @@ func logout(c *gin.Context) {
// @Success 200
// @Router /auth/token [post]
func token(c *gin.Context) {
user, ok := authenticate.LoadUser(c)
user, ok := session.LoadUser(c)
if !ok {
return
}

10
services/auth/user.go

@ -7,7 +7,7 @@ import (
"net/http"
"strconv"
"github.com/mutsuki333/blogo/internal/response"
"github.com/mutsuki333/blogo/internal/util"
"github.com/gin-gonic/gin"
"github.com/mutsuki333/blogo/models"
@ -41,7 +41,7 @@ type userInsertResource struct {
func postUser(c *gin.Context) {
var data userInsertResource
if err := c.ShouldBindJSON(&data); err != nil {
response.AbortError(c, err)
util.AbortError(c, err)
return
}
@ -87,12 +87,12 @@ func listUsers(c *gin.Context) {
func getUser(c *gin.Context) {
userID, err := strconv.Atoi(c.Param("id"))
if err != nil {
response.AbortError(c, err)
util.AbortError(c, err)
return
}
user, err := models.LoadUser(uint(userID))
if err != nil {
response.AbortError(c, err)
util.AbortError(c, err)
return
}
c.JSON(200, user)
@ -142,7 +142,7 @@ type changeUserPasswordRequest struct {
func changeUserPassword(c *gin.Context) {
var data changeUserPasswordRequest
if err := c.ShouldBindJSON(&data); err != nil {
response.AbortError(c, err)
util.AbortError(c, err)
return
}
c.JSON(200, gin.H{

42
services/services.go

@ -4,11 +4,14 @@ package services
import (
"fmt"
"log"
"github.com/gin-gonic/gin"
"github.com/mutsuki333/blogo/docs"
"github.com/mutsuki333/blogo/modules/authenticate"
"github.com/mutsuki333/blogo/modules/static"
"github.com/mutsuki333/blogo/internal/constants"
"github.com/mutsuki333/blogo/internal/middleware"
"github.com/mutsuki333/blogo/internal/session"
"github.com/mutsuki333/blogo/services/auth"
"github.com/mutsuki333/blogo/services/system"
"github.com/spf13/viper"
@ -16,13 +19,6 @@ import (
ginSwagger "github.com/swaggo/gin-swagger"
)
var version = "development"
//SetVersionInfo setup version info
func SetVersionInfo(ver string) {
version = ver
}
//Start starts the service server.
// @title Blogo API
// @version 1.0
@ -44,25 +40,25 @@ func Start() {
gin.SetMode(gin.ReleaseMode)
}
server := gin.Default()
api := server.Group("/api", authenticate.Sessions())
api := server.Group("/api", session.Middleware())
auth.RegisterAuthService(api)
auth.RegisterUserService(api)
system.RegisterSystemService(api)
if !viper.GetBool("ui.disabled") {
if viper.GetBool("swagger.enabled") {
docs.SwaggerInfo.Host = ""
docs.SwaggerInfo.BasePath = "/api"
docs.SwaggerInfo.Version = constants.Version
server.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
}
if viper.GetBool("swagger.enabled") {
docs.SwaggerInfo.Host = ""
docs.SwaggerInfo.BasePath = "/api"
docs.SwaggerInfo.Version = version
server.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
}
server.Use(middleware.ServeEmbed("/"))
// Or in dev
// server.Use(static.Serve("/", static.LocalFile("../ui/dist", true)))
// server.NoRoute(func(c *gin.Context) {
// c.File("../ui/dist/index.html")
// })
// server.Use(static.Serve("/", static.LocalFile("../ui/dist", true)))
server.Use(static.ServeEmbed("/"))
// server.NoRoute(func(c *gin.Context) {
// c.File("../ui/dist/index.html")
// })
}
fmt.Printf("Server started...")
log.Print("Server started!")
server.Run(fmt.Sprintf(":%s", viper.GetString("server.port")))
}