parent
3f194d2ec9
commit
9e40e7a290
@ -0,0 +1,2 @@
|
||||
.idea
|
||||
logs
|
@ -0,0 +1,95 @@
|
||||
package home
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/han-joker/moo-layout/api/home/models"
|
||||
"github.com/han-joker/moo-layout/api/moo/dbm"
|
||||
"github.com/han-joker/moo-layout/api/moo/logm"
|
||||
"github.com/han-joker/moo-layout/api/tables"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func CategoryGets(c *gin.Context) {
|
||||
query := models.CategoryQuery{}
|
||||
if err := c.ShouldBind(&query); err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
}
|
||||
db := dbm.Get().Model(&tables.Category{})
|
||||
if len(query.Filters.Status) > 0 {
|
||||
db.Where("status IN ?", query.Filters.Status)
|
||||
}
|
||||
|
||||
rows := []tables.Category{}
|
||||
if err := db.Order("sorter asc").Find(&rows).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
nested := make([]models.CategoryNested, 0)
|
||||
|
||||
for _, row := range rows {
|
||||
if row.ID == query.Filters.ID {
|
||||
nested = append(nested, models.CategoryNested{
|
||||
Category: row,
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(nested) == 0 {
|
||||
nested = categoryChildren(rows, query.Filters.ID)
|
||||
} else if len(nested) == 1 {
|
||||
nested[0].Children = categoryChildren(rows, query.Filters.ID)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"rows": nested,
|
||||
})
|
||||
}
|
||||
|
||||
func categoryChildren(rows []tables.Category, parentID uint) []models.CategoryNested {
|
||||
children := make([]models.CategoryNested, 0)
|
||||
|
||||
for _, row := range rows {
|
||||
if row.ParentID == parentID {
|
||||
item := models.CategoryNested{
|
||||
Category: row,
|
||||
}
|
||||
item.Children = categoryChildren(rows, row.ID)
|
||||
children = append(children, item)
|
||||
}
|
||||
}
|
||||
|
||||
return children
|
||||
}
|
||||
|
||||
func CategoryGet(c *gin.Context) {
|
||||
|
||||
id, err := strconv.Atoi(c.Query("id"))
|
||||
if err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
row := tables.Category{}
|
||||
if err := dbm.Get().Where("id=?", id).First(&row).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(200, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"row": row,
|
||||
})
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
package home
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/han-joker/moo-layout/api/home/models"
|
||||
"github.com/han-joker/moo-layout/api/moo/dbm"
|
||||
"github.com/han-joker/moo-layout/api/moo/logm"
|
||||
"github.com/han-joker/moo-layout/api/tables"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
contentsLimit = 10
|
||||
)
|
||||
|
||||
func ContentGets(c *gin.Context) {
|
||||
query := models.ContentsQuery{}
|
||||
if err := c.ShouldBind(&query); err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
rows := make([]tables.Content, 0)
|
||||
db := dbm.Get().Model(&tables.Content{})
|
||||
db.Where("status=?", tables.ContentStatusPublish)
|
||||
|
||||
if len(query.Filters.IDs) > 0 {
|
||||
db.Where("id IN ?", query.Filters.IDs)
|
||||
}
|
||||
if query.Filters.CategoryID != 0 {
|
||||
db.Where("category_id=?", query.Filters.CategoryID)
|
||||
}
|
||||
if len(query.Filters.Status) > 0 {
|
||||
db.Where("status IN ?", query.Filters.Status)
|
||||
}
|
||||
if len(query.Filters.Promotes) > 0 {
|
||||
pc := make([]string, len(query.Filters.Promotes))
|
||||
pv := make([]interface{}, len(query.Filters.Promotes))
|
||||
for i, p := range query.Filters.Promotes {
|
||||
pc[i] = "promotes & ? > 0"
|
||||
pv[i] = p
|
||||
}
|
||||
db.Where(strings.Join(pc, " OR "), pv...)
|
||||
}
|
||||
|
||||
if query.Sorter.Field != "" && query.Sorter.Order != "" {
|
||||
db.Order(fmt.Sprintf("%s %s", query.Sorter.Field, models.OrderText[query.Sorter.Order])).
|
||||
Order("updated_at desc")
|
||||
} else {
|
||||
db.Order("updated_at desc")
|
||||
}
|
||||
|
||||
db.Count(&query.Pagination.Total)
|
||||
|
||||
if query.Pagination.PageSize > 0 {
|
||||
offset := (query.Pagination.Current - 1) * query.Pagination.PageSize
|
||||
db.Limit(query.Pagination.PageSize).Offset(offset)
|
||||
}
|
||||
|
||||
db.Find(&rows)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"rows": rows,
|
||||
"pagination": query.Pagination,
|
||||
"filters": query.Filters,
|
||||
"sorter": query.Sorter,
|
||||
})
|
||||
}
|
||||
|
||||
func ContentGet(c *gin.Context) {
|
||||
|
||||
query := models.ContentQuery{}
|
||||
if err := c.ShouldBind(&query); err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
row := tables.Content{}
|
||||
if err := dbm.Get().Where("status=?", tables.ContentStatusPublish).Where("id=?", query.ID).First(&row).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if query.WithCategory {
|
||||
dbm.Get().Model(&row).Association("Category").Find(&row.Category)
|
||||
}
|
||||
if query.WithUser {
|
||||
dbm.Get().Model(&row).Association("User").Find(&row.User)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"row": row,
|
||||
})
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package models
|
||||
|
||||
import "github.com/han-joker/moo-layout/api/tables"
|
||||
|
||||
type CategoryQueryFilters struct {
|
||||
ID uint `json:"id" form:"id"`
|
||||
Status []int `json:"status" form:"status"`
|
||||
}
|
||||
|
||||
type CategoryQuery struct {
|
||||
Pagination `json:"pagination" form:"pagination"`
|
||||
Sorter `json:"sorter" form:"sorter"`
|
||||
Filters CategoryQueryFilters `json:"filters" form:"filters"`
|
||||
}
|
||||
|
||||
type CategoryNested struct {
|
||||
tables.Category
|
||||
Children []CategoryNested `json:"children"`
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package models
|
||||
|
||||
var OrderText = map[string]string{
|
||||
"ascend": "ASC",
|
||||
"desend": "DESC",
|
||||
}
|
||||
|
||||
type ContentsQueryFilters struct {
|
||||
IDs []uint `json:"ids" form:"ids"`
|
||||
CategoryID uint `json:"categoryId" form:"categoryId"`
|
||||
Status []uint `json:"status" form:"status"`
|
||||
Promotes []int `json:"promotes" form:"promotes"`
|
||||
}
|
||||
|
||||
type ContentsQuery struct {
|
||||
Pagination Pagination `json:"pagination" form:"pagination"`
|
||||
Sorter Sorter `json:"sorter" form:"sorter"`
|
||||
Filters ContentsQueryFilters `json:"filters" form:"filters"`
|
||||
WithCategory bool `json:"withCategory" form:"withCategory"'`
|
||||
WithUser bool `json:"withUser" form:"withUser"'`
|
||||
}
|
||||
|
||||
type ContentQuery struct {
|
||||
ID uint `json:"id" form:"id"`
|
||||
WithCategory bool `json:"withCategory" form:"withCategory"'`
|
||||
WithUser bool `json:"withUser" form:"withUser"'`
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package models
|
||||
|
||||
type Pagination struct {
|
||||
Current int `json:"current" form:"current"`
|
||||
Total int64 `json:"total" form:"total"`
|
||||
PageSize int `json:"pageSize" form:"pageSize"`
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package models
|
||||
|
||||
type Sorter struct {
|
||||
Field string `json:"field" form:"field"`
|
||||
Order string `json:"order" form:"order"`
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package cachem
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
one := New()
|
||||
two := New()
|
||||
if one == two {
|
||||
t.Error("new() same instance")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
one := Get()
|
||||
two := Get()
|
||||
if one != two {
|
||||
t.Error("get not single instance")
|
||||
}
|
||||
three := Get(Option{
|
||||
Name: "three",
|
||||
})
|
||||
four := Get(Option{
|
||||
Name: "four",
|
||||
})
|
||||
if three == four {
|
||||
t.Error("get() same instance")
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package confm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInstance(t *testing.T) {
|
||||
m1 := Get()
|
||||
m2 := Get()
|
||||
if m1 != m2 {
|
||||
t.Error("no singleton")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkInstance(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
//New()
|
||||
Get()
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package logm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
//
|
||||
func TestNew(t *testing.T) {
|
||||
one := New()
|
||||
two := New()
|
||||
if one == two {
|
||||
t.Error("new error")
|
||||
}
|
||||
ins := New(Option{
|
||||
OutMode: File,
|
||||
Path: "./logs",
|
||||
})
|
||||
ins.Info("some message")
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
one := Get()
|
||||
two := Get()
|
||||
if one != two {
|
||||
t.Error("get error")
|
||||
}
|
||||
}
|
||||
func TestField(t *testing.T) {
|
||||
one := Get()
|
||||
one.WithField("key", []int{1, 2, 3}).Info("Fields")
|
||||
one.WithFields(Fields{"key": "one", "hello": 123, "xxx": []int{1, 2, 3}}).Info("Fields")
|
||||
}
|
||||
|
||||
func BenchmarkNew(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
New()
|
||||
}
|
||||
}
|
||||
func BenchmarkGet(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Get()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLog_Info(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
ins := Get(Option{
|
||||
OutMode: FilePerSize,
|
||||
SizeMax: 0.5 * 1024 * 1024,
|
||||
Path: "./logs",
|
||||
})
|
||||
ins.Info("some message")
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package moo
|
||||
|
||||
type server struct {
|
||||
// server kind
|
||||
Kind string
|
||||
}
|
||||
|
||||
// 服务单例池
|
||||
var serverPool = map[string]*server{}
|
||||
|
||||
// 单例工厂,标识于 Kind
|
||||
func Server(kind string) *server {
|
||||
instance, exists := serverPool[kind]
|
||||
if !exists {
|
||||
instance = &server{
|
||||
Kind: kind,
|
||||
}
|
||||
serverPool[kind] = instance
|
||||
}
|
||||
return instance
|
||||
}
|
||||
|
||||
func (s *server) Start() {
|
||||
switch s.Kind {
|
||||
case "http":
|
||||
s.StartHttp()
|
||||
case "websocket":
|
||||
fallthrough
|
||||
case "ws":
|
||||
s.StartWebSocket()
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package moo
|
||||
|
||||
import (
|
||||
"github.com/han-joker/moo-layout/api/moo/confm"
|
||||
"github.com/han-joker/moo-layout/routers"
|
||||
)
|
||||
|
||||
func (s *server) StartHttp() {
|
||||
r := routers.RouterInit()
|
||||
r.Run(confm.Get().String("http.addr"))
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package moo
|
||||
|
||||
import (
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/han-joker/moo-layout/api/moo/confm"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (s *server) StartWebSocket() {
|
||||
http.HandleFunc("/", echo)
|
||||
log.Fatal(http.ListenAndServe(confm.Get().String("websocket.addr"), nil))
|
||||
}
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
return true
|
||||
},
|
||||
}
|
||||
|
||||
func echo(w http.ResponseWriter, r *http.Request) {
|
||||
c, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
log.Print("upgrade:", err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
for {
|
||||
mt, message, err := c.ReadMessage()
|
||||
if err != nil {
|
||||
log.Println("read:", err)
|
||||
break
|
||||
}
|
||||
log.Printf("recv: %s", message)
|
||||
err = c.WriteMessage(mt, message)
|
||||
if err != nil {
|
||||
log.Println("write:", err)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package toolm
|
||||
|
||||
func StringDefault(value string, defValues ...string) string {
|
||||
if value != "" {
|
||||
return value
|
||||
}
|
||||
for _, v := range defValues {
|
||||
if v != "" {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func Int64Default(value int64, defValues ...int64) int64 {
|
||||
if value != 0 {
|
||||
return value
|
||||
}
|
||||
for _, v := range defValues {
|
||||
if v != 0 {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package toolm
|
||||
|
||||
func IntSliceContains(value int, container []int) bool {
|
||||
for _, v := range container {
|
||||
if v == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package toolm
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
CharsAll = 1 << iota
|
||||
Digit
|
||||
LowerCase
|
||||
UpperCase
|
||||
)
|
||||
|
||||
const (
|
||||
digit = "0123456789"
|
||||
lowercase = "abcdefghijklmnopqrstuvwxyz"
|
||||
uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
//octal = "01234567"
|
||||
//hex = "0123456789abcdefg"
|
||||
)
|
||||
|
||||
func RandString(l, chars int) string {
|
||||
charset := ""
|
||||
if chars&CharsAll > 0 {
|
||||
charset = digit + lowercase + uppercase
|
||||
}
|
||||
|
||||
charsetLen := len(charset)
|
||||
|
||||
seededRand := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
b := make([]byte, l)
|
||||
for i := range b {
|
||||
b[i] = charset[seededRand.Intn(charsetLen)]
|
||||
}
|
||||
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func Sha256HMacString(message, key string) string {
|
||||
mac := hmac.New(sha256.New, []byte(key))
|
||||
mac.Write([]byte(message))
|
||||
expectedMAC := mac.Sum(nil)
|
||||
return fmt.Sprintf("%X", expectedMAC)
|
||||
}
|
@ -0,0 +1,265 @@
|
||||
package panel
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/han-joker/moo-layout/api/moo/dbm"
|
||||
"github.com/han-joker/moo-layout/api/moo/logm"
|
||||
"github.com/han-joker/moo-layout/api/panel/models"
|
||||
"github.com/han-joker/moo-layout/api/tables"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func CategoryPost(c *gin.Context) {
|
||||
req := models.CategoryReq{}
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
c.JSON(200, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
row := &tables.Category{
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
ParentID: req.ParentID,
|
||||
Sorter: req.Sorter,
|
||||
Status: req.Status,
|
||||
}
|
||||
|
||||
if err := dbm.Get().Create(&row).Error; err != nil {
|
||||
c.JSON(200, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, gin.H{
|
||||
"error": nil,
|
||||
"row": row,
|
||||
})
|
||||
}
|
||||
|
||||
func CategoryPut(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Query("id"))
|
||||
if err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
row := tables.Category{}
|
||||
if err := dbm.Get().Where("id=?", id).First(&row).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
req := models.CategoryReq{}
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
row.Name = req.Name
|
||||
row.Description = req.Description
|
||||
row.Status = req.Status
|
||||
row.Sorter = req.Sorter
|
||||
row.ParentID = req.ParentID
|
||||
|
||||
if err := dbm.Get().Save(&row).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"row": row,
|
||||
})
|
||||
}
|
||||
|
||||
func CategoryGets(c *gin.Context) {
|
||||
query := models.CategoryQuery{}
|
||||
if err := c.ShouldBind(&query); err != nil {
|
||||
}
|
||||
|
||||
rows := []tables.Category{}
|
||||
if err := dbm.Get().Order("sorter asc").Find(&rows).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
nested := make([]models.CategoryNested, 0)
|
||||
for _, row := range rows {
|
||||
if row.ID == query.Filters.ID {
|
||||
nested = append(nested, models.CategoryNested{
|
||||
Category: row,
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(nested) == 0 {
|
||||
nested = categoryChildren(rows, query.Filters.ID)
|
||||
} else if len(nested) == 1 {
|
||||
nested[0].Children = categoryChildren(rows, query.Filters.ID)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"rows": nested,
|
||||
})
|
||||
}
|
||||
|
||||
func categoryChildren(rows []tables.Category, parentID uint) []models.CategoryNested {
|
||||
children := make([]models.CategoryNested, 0)
|
||||
|
||||
for _, row := range rows {
|
||||
if row.ParentID == parentID {
|
||||
item := models.CategoryNested{
|
||||
Category: row,
|
||||
}
|
||||
item.Children = categoryChildren(rows, row.ID)
|
||||
children = append(children, item)
|
||||
}
|
||||
}
|
||||
|
||||
return children
|
||||
}
|
||||
|
||||
func CategoryGet(c *gin.Context) {
|
||||
|
||||
id, err := strconv.Atoi(c.Query("id"))
|
||||
if err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error":err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
row := tables.Category{}
|
||||
if err := dbm.Get().Where("id=?", id).First(&row).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"row": row,
|
||||
})
|
||||
}
|
||||
|
||||
func CategoryDelete(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Query("id"))
|
||||
if err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
row := tables.Category{}
|
||||
if err := dbm.Get().Where("id=?", id).First(&row).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
childrenSize := int64(0)
|
||||
if err := dbm.Get().Model(&tables.Category{}).Where("parent_id=?", row.ID).Count(&childrenSize).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
if childrenSize > 0 {
|
||||
err := errors.New("has children")
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := dbm.Get().Delete(&row).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"row": row,
|
||||
})
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
func CategoryCount(c *gin.Context) {
|
||||
|
||||
query := models.CategoryQuery{}
|
||||
if err := c.ShouldBind(&query); err != nil {
|
||||
}
|
||||
|
||||
|
||||
|
||||
rows := []tables.Category{}
|
||||
if err := dbm.Get().Find(&rows).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
count := categoryCount(rows, query)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"count": count,
|
||||
})
|
||||
}
|
||||
|
||||
func categoryCount(rows []tables.Category, query models.CategoryQuery) int64 {
|
||||
count := int64(0)
|
||||
|
||||
for _, row := range rows {
|
||||
statusCond := true
|
||||
if query.Filters.Status > 0 {
|
||||
statusCond = row.Status == query.Filters.Status
|
||||
}
|
||||
|
||||
if row.ParentID == query.Filters.ParentID && statusCond {
|
||||
count += 1
|
||||
count += categoryCount(rows, models.CategoryQuery{
|
||||
Filters: models.CategoryQueryFilters{
|
||||
ParentID: row.ID,
|
||||
Status: query.Filters.Status,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
@ -0,0 +1,260 @@
|
||||
package panel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/han-joker/moo-layout/api/moo/dbm"
|
||||
"github.com/han-joker/moo-layout/api/moo/logm"
|
||||
"github.com/han-joker/moo-layout/api/panel/models"
|
||||
"github.com/han-joker/moo-layout/api/tables"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
contentsLimit = 10
|
||||
)
|
||||
|
||||
func ContentPost(c *gin.Context) {
|
||||
req := models.ContentReq{}
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
row := &tables.Content{
|
||||
Subject: req.Subject,
|
||||
Content: req.Content,
|
||||
Referer: req.Referer,
|
||||
CategoryID: req.CategoryID,
|
||||
Cover: req.Cover,
|
||||
Status: req.Status,
|
||||
Sorter: req.Sorter,
|
||||
UserID: 1,
|
||||
}
|
||||
if row.Status == tables.ContentStatusPublish {
|
||||
row.PublishTime = time.Now()
|
||||
}
|
||||
for _, p := range req.Promotes {
|
||||
row.Promotes |= p
|
||||
}
|
||||
|
||||
if err := dbm.Get().Create(&row).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"row": row,
|
||||
})
|
||||
}
|
||||
|
||||
func ContentPut(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Query("id"))
|
||||
if err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
row := tables.Content{}
|
||||
if err := dbm.Get().Where("id=?", id).First(&row).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
req := models.ContentReq{}
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
row.Subject = req.Subject
|
||||
row.Content = req.Content
|
||||
row.Referer = req.Referer
|
||||
row.CategoryID = req.CategoryID
|
||||
row.Cover = req.Cover
|
||||
row.Status = req.Status
|
||||
row.Sorter = req.Sorter
|
||||
if row.Status == tables.ContentStatusPublish {
|
||||
row.PublishTime = time.Now()
|
||||
}
|
||||
row.Promotes = 0
|
||||
for _, p := range req.Promotes {
|
||||
row.Promotes |= p
|
||||
}
|
||||
|
||||
if err := dbm.Get().Save(&row).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"row": row,
|
||||
})
|
||||
}
|
||||
|
||||
func ContentGets(c *gin.Context) {
|
||||
query := models.ContentsQuery{}
|
||||
if err := c.ShouldBind(&query); err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
rows := make([]tables.Content, 0)
|
||||
db := dbm.Get().Model(&tables.Content{})
|
||||
|
||||
if len(query.Filters.IDs) > 0 {
|
||||
db.Where("id IN ?", query.Filters.IDs)
|
||||
}
|
||||
if query.Filters.CategoryID != 0 {
|
||||
db.Where("category_id=?", query.Filters.CategoryID)
|
||||
}
|
||||
if len(query.Filters.Status) > 0 {
|
||||
db.Where("status IN ?", query.Filters.Status)
|
||||
}
|
||||
if len(query.Filters.Promotes) > 0 {
|
||||
pc := make([]string, len(query.Filters.Promotes))
|
||||
pv := make([]interface{}, len(query.Filters.Promotes))
|
||||
for i, p := range query.Filters.Promotes {
|
||||
pc[i] = "promotes & ? > 0"
|
||||
pv[i] = p
|
||||
}
|
||||
db.Where(strings.Join(pc, " OR "), pv...)
|
||||
}
|
||||
|
||||
if query.Sorter.Field != "" && query.Sorter.Order != "" {
|
||||
db.Order(fmt.Sprintf("%s %s", query.Sorter.Field, models.OrderText[query.Sorter.Order])).
|
||||
Order("updated_at desc")
|
||||
} else {
|
||||
db.Order("updated_at desc")
|
||||
}
|
||||
|
||||
db.Count(&query.Pagination.Total)
|
||||
|
||||
if query.Pagination.PageSize > 0 {
|
||||
offset := (query.Pagination.Current - 1) * query.Pagination.PageSize
|
||||
db.Limit(query.Pagination.PageSize).Offset(offset)
|
||||
}
|
||||
|
||||
db.Find(&rows)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"rows": rows,
|
||||
"pagination": query.Pagination,
|
||||
"filters": query.Filters,
|
||||
"sorter": query.Sorter,
|
||||
})
|
||||
}
|
||||
|
||||
func ContentGet(c *gin.Context) {
|
||||
|
||||
id, err := strconv.Atoi(c.Query("id"))
|
||||
if err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
row := tables.Content{}
|
||||
if err := dbm.Get().Where("id=?", id).First(&row).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"row": row,
|
||||
})
|
||||
}
|
||||
|
||||
func ContentDelete(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Query("id"))
|
||||
if err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
row := tables.Content{}
|
||||
if err := dbm.Get().Where("id=?", id).First(&row).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := dbm.Get().Delete(&row).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"row": row,
|
||||
})
|
||||
}
|
||||
|
||||
func ContentCount(c *gin.Context) {
|
||||
|
||||
query := models.ContentsQuery{}
|
||||
if err := c.ShouldBind(&query); err != nil {
|
||||
}
|
||||
|
||||
db := dbm.Get().Model(&tables.Content{})
|
||||
|
||||
if query.Filters.CategoryID != 0 {
|
||||
db.Where("category_id=?", query.Filters.CategoryID)
|
||||
}
|
||||
if len(query.Filters.Status) != 0 {
|
||||
db.Where("status IN ?", query.Filters.Status)
|
||||
}
|
||||
count := int64(0)
|
||||
if err := db.Debug().Count(&count).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"count": count,
|
||||
})
|
||||
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang-jwt/jwt"
|
||||
"github.com/han-joker/moo-layout/api/moo/confm"
|
||||
"github.com/han-joker/moo-layout/api/moo/dbm"
|
||||
"github.com/han-joker/moo-layout/api/moo/logm"
|
||||
"github.com/han-joker/moo-layout/api/panel/models"
|
||||
"github.com/han-joker/moo-layout/api/tables"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func JwtToken(c *gin.Context) {
|
||||
// before request
|
||||
header := models.UserJwtTokenHeader{}
|
||||
if err := c.ShouldBindHeader(&header); err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
tokenString := strings.Replace(header.Authorization, "Bearer ", "", 1)
|
||||
token, err := jwt.ParseWithClaims(tokenString, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(confm.Get().String("app.signingKey")), nil
|
||||
})
|
||||
if err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
claims, ok := token.Claims.(*jwt.StandardClaims)
|
||||
if !ok {
|
||||
err := errors.New("token claim type error")
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if !token.Valid {
|
||||
err := errors.New("token valid error")
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(claims.Audience, 10, 0)
|
||||
if err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
user := tables.User{}
|
||||
if err := dbm.Get().Where("id=?", id).First(&user).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if user.JWTToken != tokenString {
|
||||
err := errors.New("token error")
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Set("user", user)
|
||||
c.Next()
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package models
|
||||
|
||||
import "github.com/han-joker/moo-layout/api/tables"
|
||||
|
||||
type CategoryQueryFilters struct {
|
||||
ID uint `json:"id" form:"id"`
|
||||
ParentID uint `json:"parent_id" form:"parent_id"`
|
||||
Status int `json:"status" form:"status"`
|
||||
}
|
||||
|
||||
type CategoryQuery struct {
|
||||
Filters CategoryQueryFilters `json:"filters" form:"filters"`
|
||||
}
|
||||
|
||||
type CategoryNested struct {
|
||||
tables.Category
|
||||
Children []CategoryNested `json:"children"`
|
||||
}
|
||||
|
||||
type CategoryReq struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
ParentID uint `json:"parent_id" form:"parent_id"`
|
||||
Sorter int `json:"sorter"`
|
||||
Status int `json:"status"`
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package models
|
||||
|
||||
type ContentReq struct {
|
||||
ID uint `json:"id" form:"id"`
|
||||
Subject string `json:"subject" form:"subject"`
|
||||
Content string `json:"content" form:"content"`
|
||||
Referer string `json:"referer" form:"referer"`
|
||||
CategoryID uint `json:"categoryId" form:"categoryId"`
|
||||
Status int `json:"status" form:"status"`
|
||||
Sorter int `json:"sorter" form:"sorter"`
|
||||
Cover string `json:"cover" form:"cover"`
|
||||
Promotes []int `json:"promotes" form:"promotes"`
|
||||
}
|
||||
|
||||
type ContentsQueryFilters struct {
|
||||
IDs []uint `json:"ids" form:"ids"`
|
||||
CategoryID uint `json:"categoryId" form:"categoryId"`
|
||||
Status []uint `json:"status" form:"status"`
|
||||
Promotes []int `json:"promotes" form:"promotes"`
|
||||
}
|
||||
|
||||
type ContentsQuery struct {
|
||||
Pagination Pagination `json:"pagination" form:"pagination"`
|
||||
Sorter Sorter `json:"sorter" form:"sorter"`
|
||||
Filters ContentsQueryFilters `json:"filters" form:"filters"`
|
||||
WithCategory bool `json:"withCategory" form:"withCategory"'`
|
||||
WithUser bool `json:"withUser" form:"withUser"'`
|
||||
}
|
||||
|
||||
var OrderText = map[string]string{
|
||||
"ascend": "ASC",
|
||||
"desend": "DESC",
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package models
|
||||
|
||||
type Pagination struct {
|
||||
Current int `json:"current" form:"current"`
|
||||
Total int64 `json:"total" form:"total"`
|
||||
PageSize int `json:"pageSize" form:"pageSize"`
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package models
|
||||
|
||||
type Sorter struct {
|
||||
Field string `json:"field" form:"field"`
|
||||
Order string `json:"order" form:"order"`
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package models
|
||||
|
||||
type UserSignIn struct {
|
||||
Username string `json:"username" form:"username"`
|
||||
Password string `json:"password" form:"password"`
|
||||
AutoSignIn bool `json:"autoSignIn" form:"autoSignIn"`
|
||||
}
|
||||
|
||||
type UserJwtTokenHeader struct {
|
||||
Authorization string `header:"Authorization" form:"authorization"`
|
||||
}
|
||||
|
||||
type UserChangePassword struct {
|
||||
ID uint `json:"id" form:"id"`
|
||||
Password string `json:"password" form:"password"`
|
||||
NewPassword string `json:"newPassword" form:"newPassword"`
|
||||
NewPasswordConfirm string `json:"newPasswordConfirm" form:"newPasswordConfirm"`
|
||||
}
|
@ -0,0 +1,175 @@
|
||||
package panel
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang-jwt/jwt"
|
||||
"github.com/han-joker/moo-layout/api/moo/confm"
|
||||
"github.com/han-joker/moo-layout/api/moo/dbm"
|
||||
"github.com/han-joker/moo-layout/api/moo/logm"
|
||||
"github.com/han-joker/moo-layout/api/moo/toolm"
|
||||
"github.com/han-joker/moo-layout/api/panel/models"
|
||||
"github.com/han-joker/moo-layout/api/tables"
|
||||
"gorm.io/gorm"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func UserSignIn(c *gin.Context) {
|
||||
userSignIn := models.UserSignIn{}
|
||||
if err := c.ShouldBind(&userSignIn); err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
user := tables.User{}
|
||||
if err := dbm.Get().Where("username = ?", userSignIn.Username).First(&user).Error;
|
||||
errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if user.Password != toolm.Sha256HMacString(userSignIn.Password, user.PasswordSalt) {
|
||||
err := errors.New("password error")
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
signingKey := []byte(confm.Get().String("app.signingKey"))
|
||||
// Create the Claims
|
||||
claims := &jwt.StandardClaims{
|
||||
Audience: strconv.FormatUint(uint64(user.ID), 10),
|
||||
ExpiresAt: time.Now().Add(30*24*3600 * time.Second).UnixNano(),
|
||||
Issuer: confm.Get().String("app.issuer"),
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
tokenString, err := token.SignedString(signingKey)
|
||||
if err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
user.JWTToken = tokenString
|
||||
if err := dbm.Get().Save(&user).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"user": user,
|
||||
})
|
||||
}
|
||||
|
||||
func UserCheckJwtToken(c *gin.Context) {
|
||||
|
||||
user := tables.User{}
|
||||
if userInterface, exists := c.Get("user"); !exists {
|
||||
err := errors.New("user not found")
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
} else {
|
||||
user = userInterface.(tables.User)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"user": user,
|
||||
})
|
||||
}
|
||||
|
||||
func UserSignOut(c *gin.Context) {
|
||||
|
||||
user := tables.User{}
|
||||
if userInterface, exists := c.Get("user"); !exists {
|
||||
err := errors.New("user not found")
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
} else {
|
||||
user = userInterface.(tables.User)
|
||||
}
|
||||
|
||||
user.JWTToken = ""
|
||||
dbm.Get().Save(&user)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"user": user,
|
||||
})
|
||||
}
|
||||
|
||||
func UserChangePassword(c *gin.Context) {
|
||||
req := models.UserChangePassword{}
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if req.NewPassword != req.NewPasswordConfirm {
|
||||
err := errors.New("password not equal error")
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
user := tables.User{}
|
||||
if userInterface, exists := c.Get("user"); !exists {
|
||||
err := errors.New("user not found")
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
} else {
|
||||
user = userInterface.(tables.User)
|
||||
}
|
||||
|
||||
if user.Password != toolm.Sha256HMacString(req.Password, user.PasswordSalt) {
|
||||
err := errors.New("password error")
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
user.Password = toolm.Sha256HMacString(req.NewPassword, user.PasswordSalt)
|
||||
if err := dbm.Get().Save(&user).Error; err != nil {
|
||||
logm.Get().Info(err.Error())
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"error": nil,
|
||||
"user": user,
|
||||
})
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package tables
|
||||
|
||||
const (
|
||||
CategoryStatusPublish = iota + 1 // 发布
|
||||
CategoryStatusDraft // 草稿
|
||||
)
|
||||
|
||||
type Category struct {
|
||||
Model
|
||||
|
||||
Name string `gorm:"uniqueIndex" json:"name"`
|
||||
Description string `gorm:"" json:"description"`
|
||||
ParentID uint `gorm:"index" json:"parent_id"`
|
||||
Status int `gorm:"" json:"status"`
|
||||
Sorter int `gorm:"index" json:"sorter"`
|
||||
|
||||
Contents []Content `json:"contents"`
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package tables
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Model struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"`
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package tables
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Role struct {
|
||||
gorm.Model
|
||||
|
||||
Name string `gorm:"uniqueIndex;" json:"name"`
|
||||
Key string `gorm:"uniqueIndex;" json:"key"`
|
||||
|
||||
Users []User `gorm:"many2many:role_user"`
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package tables
|
||||
|
||||
type User struct {
|
||||
Model
|
||||
|
||||
Username string `gorm:"uniqueIndex;" json:"username"`
|
||||
Password string `gorm:"" json:"-"`
|
||||
PasswordSalt string `gorm:"" json:"-"`
|
||||
JWTToken string `gorm:"" json:"jwtToken"`
|
||||
Name string `gorm:"uniqueIndex;" json:"name"`
|
||||
Email string `gorm:"uniqueIndex;" json:"email"`
|
||||
Telephone string `gorm:"uniqueIndex;" json:"telephone"`
|
||||
|
||||
Roles []Role `gorm:"many2many:role_user;" json:"roles"`
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
module github.com/han-joker/moo-layout
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/gin-contrib/cors v1.3.1
|
||||
github.com/gin-gonic/gin v1.7.4
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
gorm.io/driver/sqlite v1.1.4
|
||||
gorm.io/gorm v1.21.14
|
||||
)
|
@ -0,0 +1,94 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA=
|
||||
github.com/gin-contrib/cors v1.3.1/go.mod h1:jjEJ4268OPZUcU7k9Pm653S7lXUGcqMADzFA61xsmDk=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
|
||||
github.com/gin-gonic/gin v1.7.4 h1:QmUZXrvJ9qZ3GfWvQ+2wnW/1ePrTEJqPKMYEU3lD/DM=
|
||||
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=
|
||||
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ=
|
||||
github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM=
|
||||
gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw=
|
||||
gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/gorm v1.21.14 h1:NAR9A/3SoyiPVHouW/rlpMUZvuQZ6Z6UYGz+2tosSQo=
|
||||
gorm.io/gorm v1.21.14/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
|
@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/han-joker/moo-layout/api/moo"
|
||||
)
|
||||
|
||||
func main() {
|
||||
//启动 websocket服务
|
||||
moo.Server("http").Start()
|
||||
}
|
Loading…
Reference in new issue