fix: add role limit

This commit is contained in:
fallen-angle
2022-04-27 22:08:02 +08:00
parent fc347a4140
commit 22cb5ec61f
19 changed files with 274 additions and 77 deletions

View File

@@ -1,11 +1,13 @@
package handler package handler
import ( import (
"github.com/gin-gonic/gin" "nCovTrack-Backend/global"
"nCovTrack-Backend/models" "nCovTrack-Backend/models"
"nCovTrack-Backend/service/article" "nCovTrack-Backend/service/article"
"nCovTrack-Backend/utils" "nCovTrack-Backend/utils"
"strconv" "strconv"
"github.com/gin-gonic/gin"
) )
// SaveArticleHandler save an article // SaveArticleHandler save an article
@@ -19,7 +21,13 @@ import (
// @Param Token header string true "token" // @Param Token header string true "token"
func SaveArticleHandler(c *gin.Context) { func SaveArticleHandler(c *gin.Context) {
jsonMap := bindJson(c) jsonMap := bindJson(c)
claims := utils.ClaimsFromHeader(c)
if claims.Role != global.ROLE_ID_MAP["ADMIN"] {
Forbidden(c)
return
}
if jsonMap == nil { if jsonMap == nil {
RequestErr(c, map[string]interface{}{"URI": c.Request.RequestURI})
return return
} }
colMap := models.MapJ2c[models.BackArticle](jsonMap, true) colMap := models.MapJ2c[models.BackArticle](jsonMap, true)
@@ -30,7 +38,7 @@ func SaveArticleHandler(c *gin.Context) {
utils.Succ(c, jsonMap) utils.Succ(c, jsonMap)
} }
// GetAllArticlesHandler get all article // ListPublishedArticlesHandler get all article
// @Tags Article // @Tags Article
// @Accept json // @Accept json
// @Produce json // @Produce json
@@ -39,9 +47,28 @@ func SaveArticleHandler(c *gin.Context) {
// @Success 200 {object} utils.GinResponse{data=[]models.BackArticle} // @Success 200 {object} utils.GinResponse{data=[]models.BackArticle}
// @Router /article/list [get] // @Router /article/list [get]
// @Param Token header string false "token" // @Param Token header string false "token"
func GetAllArticlesHandler(c *gin.Context) { func ListPublishedArticlesHandler(c *gin.Context) {
// TODO: admin need to show more articles // TODO: admin need to show more articles
articles := article.ListAllArticles() articles := article.ListPublishedArticles()
utils.Succ(c, articles)
}
func ListArticlesByUser(c *gin.Context) {
published := c.Param("published")
claims := utils.ClaimsFromHeader(c)
if claims.Role != global.ROLE_ID_MAP["ADMIN"] {
Forbidden(c)
return
}
var articles *[]models.ListArtile
if published == "published" {
articles = article.ListPublishedArticlesByUser(claims.ID)
} else if published == "notpublished" {
articles = article.ListNotPublishedArticlesByUser(claims.ID)
} else {
UrlNotFound(c)
return
}
utils.Succ(c, articles) utils.Succ(c, articles)
} }
@@ -56,6 +83,11 @@ func GetAllArticlesHandler(c *gin.Context) {
// @Param id path string true "id" // @Param id path string true "id"
func DeleteArticleHandler(c *gin.Context) { func DeleteArticleHandler(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id")) id, err := strconv.Atoi(c.Param("id"))
claims := utils.ClaimsFromHeader(c)
if claims.Role == global.ROLE_ID_MAP["ADMIN"] {
Forbidden(c)
return
}
if err != nil { if err != nil {
RequestErr(c, map[string]interface{}{"URI": c.Request.RequestURI}) RequestErr(c, map[string]interface{}{"URI": c.Request.RequestURI})
return return
@@ -84,7 +116,6 @@ func GetArticleHandler(c *gin.Context) {
return return
} }
res := article.GetArticleById(id) res := article.GetArticleById(id)
//TODO: if not admin, will not show not published article
if res == nil { if res == nil {
DataNotFound(c, nil) DataNotFound(c, nil)
return return
@@ -103,6 +134,11 @@ func GetArticleHandler(c *gin.Context) {
// @Param id path string true "id" // @Param id path string true "id"
func PublishArticleHandler(c *gin.Context) { func PublishArticleHandler(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id")) id, err := strconv.Atoi(c.Param("id"))
claims := utils.ClaimsFromHeader(c)
if claims.Role == global.ROLE_ID_MAP["ADMIN"] {
Forbidden(c)
return
}
if err != nil { if err != nil {
RequestErr(c, map[string]interface{}{"URI": c.Request.RequestURI}) RequestErr(c, map[string]interface{}{"URI": c.Request.RequestURI})
return return

View File

@@ -12,6 +12,8 @@ const (
BAD_REQUEST = "Bad Request" BAD_REQUEST = "Bad Request"
DATA_NOT_FOUND = "Data not Found" DATA_NOT_FOUND = "Data not Found"
STATUS_DATA_NOT_FOUND = 210 STATUS_DATA_NOT_FOUND = 210
FORBIDDENT = "FORBIDDENT"
PAGE_NOT_FOUND = "404 page not found"
) )
func RequestError(c *gin.Context, code int, data interface{}) { func RequestError(c *gin.Context, code int, data interface{}) {
@@ -31,3 +33,10 @@ func ServerErr(c *gin.Context, msg interface{}) {
func DataNotFound(c *gin.Context, data interface{}) { func DataNotFound(c *gin.Context, data interface{}) {
utils.Success(c, http.StatusOK, STATUS_DATA_NOT_FOUND, DATA_NOT_FOUND, data) utils.Success(c, http.StatusOK, STATUS_DATA_NOT_FOUND, DATA_NOT_FOUND, data)
} }
func Forbidden(c *gin.Context) {
utils.Err(c, http.StatusForbidden, http.StatusForbidden, FORBIDDENT)
}
func UrlNotFound(c *gin.Context) {
c.String(http.StatusNotFound, PAGE_NOT_FOUND)
}

View File

@@ -1,11 +1,13 @@
package handler package handler
import ( import (
"github.com/gin-gonic/gin" "nCovTrack-Backend/global"
"nCovTrack-Backend/models" "nCovTrack-Backend/models"
"nCovTrack-Backend/service/user" "nCovTrack-Backend/service/user"
"nCovTrack-Backend/utils" "nCovTrack-Backend/utils"
"regexp" "regexp"
"github.com/gin-gonic/gin"
) )
//UserRegisterHandler user register //UserRegisterHandler user register
@@ -39,12 +41,16 @@ func UserRegisterHandler(c *gin.Context) {
// @Param Token header string true "token" // @Param Token header string true "token"
// @Param json body models.UserApprove true "json" // @Param json body models.UserApprove true "json"
func UserApproveHandler(c *gin.Context) { func UserApproveHandler(c *gin.Context) {
//TODO: auth user is admin or not claims := utils.ClaimsFromHeader(c)
if claims.Role != global.ROLE_ID_MAP["ADMIN"] {
Forbidden(c)
return
}
jsonMap := bindJsonStruct[models.UserApprove](c) jsonMap := bindJsonStruct[models.UserApprove](c)
if jsonMap == nil { if jsonMap == nil {
return return
} }
if !user.ApproveRegister(jsonMap["email"].(string), jsonMap["pass"].(bool)) { if !user.ApproveRegister(claims, jsonMap["email"].(string), jsonMap["pass"].(bool)) {
RequestErr(c, "approve failed") RequestErr(c, "approve failed")
return return
} }
@@ -79,10 +85,24 @@ func UserLoginHandler(c *gin.Context) {
// @Produce json // @Produce json
// @Summary list register infos, which is to be approved // @Summary list register infos, which is to be approved
// @Success 200 {object} utils.GinResponse{} // @Success 200 {object} utils.GinResponse{}
// @Router /user/registers [get] // @Router /user/registers/{approved} [get]
// @Param Token header string true "token" // @Param Token header string true "token"
func ListRegisterUserHandler(c *gin.Context) { func ListRegisterUserHandler(c *gin.Context) {
registers := user.ListRegister() approved := c.Param("approved")
claims := utils.ClaimsFromHeader(c)
if claims.Role != global.ROLE_ID_MAP["ADMIN"] {
Forbidden(c)
return
}
var registers *[]map[string]interface{}
if approved == "notapproved" {
registers = user.ListRegister(claims)
} else if approved == "approved" {
registers = user.ListApprovedRegister(claims)
} else {
UrlNotFound(c)
return
}
utils.Succ(c, registers) utils.Succ(c, registers)
} }

View File

@@ -1,14 +1,12 @@
package initialize package initialize
import ( import (
"nCovTrack-Backend/service/statistics"
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
) )
func initCron() { func initCron() {
c := cron.New() c := cron.New()
//c.AddFunc("@every 10s", func() { global.Redis.Set("OK", time.Now().String(), time.Duration(10*time.Hour)) }) //c.AddFunc("@every 10s", func() { global.Redis.Set("OK", time.Now().String(), time.Duration(10*time.Hour)) })
c.AddFunc("@every 10m", statistics.CacheNCov) //c.AddFunc("@every 10m", statistics.CacheNCov)
c.Start() c.Start()
} }

View File

@@ -1,14 +1,16 @@
package middleware package middleware
import ( import (
"fmt" "encoding/json"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v4"
"nCovTrack-Backend/global" "nCovTrack-Backend/global"
"nCovTrack-Backend/models"
"nCovTrack-Backend/utils" "nCovTrack-Backend/utils"
"net/http" "net/http"
"strconv" "strconv"
"time" "time"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v4"
) )
const UNAUTH_MSG = "unauthorized" const UNAUTH_MSG = "unauthorized"
@@ -24,10 +26,15 @@ func Auth() gin.HandlerFunc {
} }
// Write the field of token to request header // Write the field of token to request header
claims := utils.ParseClaims(oldToken[0]) claims := utils.ParseClaims(oldToken[0])
c.Request.Header.Set("role", fmt.Sprint(claims["role"])) tokenClaims := models.TokenClaims{
c.Request.Header.Set("email", claims["email"].(string)) ID: int(claims["id"].(float64)),
c.Request.Header.Set("id", fmt.Sprint(claims["id"])) Username: claims["username"].(string),
c.Request.Header.Set("role", claims["role"].(string)) Email: claims["email"].(string),
Role: int(claims["role"].(float64)),
Region: claims["region"].(string),
}
claimsByte, _ := json.Marshal(tokenClaims)
c.Request.Header.Add("claims", string(claimsByte))
// renew token, and judge the token's iat is expired or not // renew token, and judge the token's iat is expired or not
renewToken := utils.RenewToken(oldToken[0]) renewToken := utils.RenewToken(oldToken[0])

View File

@@ -13,7 +13,7 @@ func Cors() gin.HandlerFunc {
c.Header("Access-Control-Allow-Origin", origin) c.Header("Access-Control-Allow-Origin", origin)
c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id") c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id")
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS,DELETE,PUT") c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS,DELETE,PUT")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type") c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, X-Token, Access-Control-Allow-Headers, Content-Type")
c.Header("Access-Control-Allow-Credentials", "true") c.Header("Access-Control-Allow-Credentials", "true")
if method == "OPTIONS" { if method == "OPTIONS" {

View File

@@ -8,9 +8,9 @@ import (
type BackArticle struct { type BackArticle struct {
ID int `gorm:"primaryKey;column:id" json:"-"` // 文章id ID int `gorm:"primaryKey;column:id" json:"-"` // 文章id
CreateTime time.Time `gorm:"column:create_time" json:"createTime"` // 文章新建时间 CreateTime time.Time `gorm:"column:create_time" json:"createTime"` // 文章新建时间
CreateUser string `gorm:"column:create_user" json:"createUser"` // 文章创建者id CreateUser int `gorm:"column:create_user" json:"createUser"` // 文章创建者id
ModifyTime time.Time `gorm:"column:modify_time" json:"modifyTime"` // 文章最后更新时间 ModifyTime time.Time `gorm:"column:modify_time" json:"modifyTime"` // 文章最后更新时间
ModifyUser string `gorm:"column:modify_user" json:"modifyUser"` // 文章最后更新者id ModifyUser int `gorm:"column:modify_user" json:"modifyUser"` // 文章最后更新者id
Title string `gorm:"column:title" json:"title"` // 文章标题 Title string `gorm:"column:title" json:"title"` // 文章标题
Tags string `gorm:"column:tags" json:"tags"` // 文章Tag Tags string `gorm:"column:tags" json:"tags"` // 文章Tag
Resume string `gorm:"column:resume" json:"resume"` // 文章简述 Resume string `gorm:"column:resume" json:"resume"` // 文章简述
@@ -20,6 +20,17 @@ type BackArticle struct {
IsDelete int8 `gorm:"column:is_delete" json:"isDelete"` // 删除标志 IsDelete int8 `gorm:"column:is_delete" json:"isDelete"` // 删除标志
} }
type ListArtile struct {
ID int `json:"-"`
Username string `json:"username"`
CreateTime time.Time `json:"createTime"`
ModifyTime time.Time `json:"modifyTime"`
Title string `json:"title"`
Tags string `json:"tags"`
Resume string `json:"resume"`
Cover string `json:"cover"`
}
func init() { func init() {
initJcMap[BackArticle]() initJcMap[BackArticle]()
} }

View File

@@ -41,3 +41,23 @@ type HotelContactRequest struct {
InData FakerDate `json:"in_data"` InData FakerDate `json:"in_data"`
OutData FakerDate `json:"out_data"` OutData FakerDate `json:"out_data"`
} }
type RailwayContactRequest struct {
Name string `json:"name"`
Age int `json:"age,string"`
Sex int `json:"sex,string"`
Phone int `json:"phone"`
Address string `json:"address"`
Train string `json:"train"`
Launch FakerDate `json:"launch"`
Identification string `json:"identification"`
}
type PatientRequest struct {
Name string `json:"name"`
Age int `json:"age,string"`
Sex int `json:"sex,string"`
Phone string `json:"phone"`
Address string `json:"address"`
Identification string `json:"identification"`
}

View File

@@ -3,7 +3,7 @@ package models
import "time" import "time"
type BackUser struct { type BackUser struct {
ID int `gorm:"primaryKey;column:id" json:"-"` // 用户ID ID int `gorm:"primaryKey;column:id" json:"id"` // 用户ID
Username string `gorm:"column:username" json:"username"` // 用户真实姓名 Username string `gorm:"column:username" json:"username"` // 用户真实姓名
Password string `gorm:"column:password" json:"password"` // 用户密码 Password string `gorm:"column:password" json:"password"` // 用户密码
Role int `gorm:"column:role" json:"role"` // 用户角色 Role int `gorm:"column:role" json:"role"` // 用户角色
@@ -14,6 +14,7 @@ type BackUser struct {
Approver int `gorm:"column:approver" json:"approver"` // 注册审核人ID Approver int `gorm:"column:approver" json:"approver"` // 注册审核人ID
ModifyTime time.Time `gorm:"column:modify_time" json:"modifyTime"` ModifyTime time.Time `gorm:"column:modify_time" json:"modifyTime"`
IsDelete int8 `gorm:"column:is_delete" json:"isDelete"` // 删除标志 IsDelete int8 `gorm:"column:is_delete" json:"isDelete"` // 删除标志
Region string `gorm:"column:region" json:"region"` // 用户所属地域
} }
type UserLogin struct { type UserLogin struct {
@@ -27,6 +28,8 @@ type UserRegister struct {
Email string `json:"email"` Email string `json:"email"`
Phone string `json:"phone"` Phone string `json:"phone"`
Aptitude string `json:"aptitude"` Aptitude string `json:"aptitude"`
Region string `json:"region"`
Role int `json:"role"`
} }
type UserChangePwd struct { type UserChangePwd struct {
@@ -40,6 +43,14 @@ type UserApprove struct {
Pass bool `json:"pass"` Pass bool `json:"pass"`
} }
type TokenClaims struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Role int `json:"role"`
Region string `json:"region"`
}
func init() { func init() {
initJcMap[BackUser]() initJcMap[BackUser]()
} }

View File

@@ -93,6 +93,24 @@ func Upsert[T any](colMap map[string]interface{}) (ok bool, rowsAffected int64)
return true, tx.RowsAffected return true, tx.RowsAffected
} }
func Update[T any](queryMap []map[string]interface{}, updateMap map[string]interface{}) (ok bool, rowsAffected int64) {
tx := global.Db.Model(new(T))
for _, e := range queryMap {
e[IS_DELETE] = 0
tx = tx.Or(e)
}
return UpdateByOrm(tx, updateMap)
}
func UpdateByOrm(tx *gorm.DB, updateMap map[string]interface{}) (ok bool, rowsAffected int64) {
tx.Updates(updateMap)
if tx.Error != nil {
fmt.Println(tx.Error)
return false, 0
}
return true, tx.RowsAffected
}
// DeleteById will delete by id, not delete the record from database, only set the field "is_delete" as 1 // DeleteById will delete by id, not delete the record from database, only set the field "is_delete" as 1
func DeleteById[T any](id int) (ok bool, rowsAffected int64) { func DeleteById[T any](id int) (ok bool, rowsAffected int64) {
tx := global.Db.Model(new(T)).Where("id = ?", id).Update("is_delete", 1) tx := global.Db.Model(new(T)).Where("id = ?", id).Update("is_delete", 1)

View File

@@ -10,6 +10,7 @@ func articlePrivateRouter(router *gin.RouterGroup) {
{ {
articleRouter.DELETE("/:id", handler.DeleteArticleHandler) articleRouter.DELETE("/:id", handler.DeleteArticleHandler)
articleRouter.POST("/:id/publish", handler.PublishArticleHandler) articleRouter.POST("/:id/publish", handler.PublishArticleHandler)
articleRouter.GET("/list/:published", handler.ListArticlesByUser)
} }
} }
@@ -17,7 +18,7 @@ func articlePublicRouter(router *gin.RouterGroup) {
articleRouter := router.Group("/article") articleRouter := router.Group("/article")
{ {
articleRouter.POST("", handler.SaveArticleHandler) articleRouter.POST("", handler.SaveArticleHandler)
articleRouter.GET("/list", handler.GetAllArticlesHandler) articleRouter.GET("/list", handler.ListPublishedArticlesHandler)
articleRouter.GET("/:id", handler.GetArticleHandler) articleRouter.GET("/:id", handler.GetArticleHandler)
} }
} }

View File

@@ -19,6 +19,6 @@ func userPrivateRouter(router *gin.RouterGroup) {
userRouter := router.Group("/user") userRouter := router.Group("/user")
{ {
userRouter.POST("/approve", handler.UserApproveHandler) userRouter.POST("/approve", handler.UserApproveHandler)
userRouter.GET("/registers", handler.ListRegisterUserHandler) userRouter.GET("/registers/:approved", handler.ListRegisterUserHandler)
} }
} }

View File

@@ -1,26 +1,40 @@
package article package article
import ( import (
"nCovTrack-Backend/global"
"nCovTrack-Backend/models" "nCovTrack-Backend/models"
"strconv"
) )
//ListPublishedArticles list the articles published, use to show the articles to all people //ListPublishedArticles list the articles published, use to show the articles to all people
func ListPublishedArticles() *[]map[string]interface{} { func ListPublishedArticles() *[]models.ListArtile {
article := models.ListField[models.BackArticle]([]map[string]interface{}{{"is_publish": 0}}, true, "content") return listArticles(1, 0)
if *article == nil {
article = &[]map[string]interface{}{}
}
return article
} }
//ListAllArticles list all articles, will show the articles not published of the user func ListPublishedArticlesByUser(id int) *[]models.ListArtile {
// TODO: need only show the user's not published article return listArticles(1, id)
func ListAllArticles() *[]map[string]interface{} {
article := models.ListField[models.BackArticle]([]map[string]interface{}{{}}, true, "content")
if *article == nil {
article = &[]map[string]interface{}{}
} }
return article
//ListAllArticles list all articles(without not published)
// TODO: need only show the user's not published article
func ListNotPublishedArticlesByUser(id int) *[]models.ListArtile {
return listArticles(0, id)
}
func listArticles(isPublish int, createUser int) *[]models.ListArtile {
queryStr := "back_article.is_delete = 0 AND is_publish = " + strconv.Itoa(isPublish)
if createUser != 0 {
queryStr += " AND create_user = " + strconv.Itoa(createUser)
}
var res []models.ListArtile
global.Db.Table("back_article").
Select("back_user.username, back_article.*").
Joins("join back_user on back_article.create_user=back_user.id").
Where(queryStr).Find(&res)
if res == nil {
res = []models.ListArtile{}
}
return &res
} }
//SaveArticle save the articles //SaveArticle save the articles

View File

@@ -2,7 +2,6 @@ package investigate
import ( import (
"encoding/json" "encoding/json"
"fmt"
"nCovTrack-Backend/global" "nCovTrack-Backend/global"
"nCovTrack-Backend/models" "nCovTrack-Backend/models"
"nCovTrack-Backend/utils" "nCovTrack-Backend/utils"
@@ -16,12 +15,32 @@ func fakerGetRequest(uri string) string {
return string(dataStr) return string(dataStr)
} }
func QueryHotelContacts() { func QueryHotelContacts() []models.HotelContactRequest {
dataStr := fakerGetRequest("query/contacts/hotel/320581199103182689") dataStr := fakerGetRequest("query/contacts/hotel/320581199103182689")
var data []models.HotelContactRequest var data []models.HotelContactRequest
err := json.Unmarshal([]byte(dataStr), &data) err := json.Unmarshal([]byte(dataStr), &data)
if err != nil { if err != nil {
panic(err) panic(err)
} }
fmt.Println(data) return data
}
func QueryRailwayContacts() []models.RailwayContactRequest {
dataStr := fakerGetRequest("query/contacts/railway/320581199103182689")
var data []models.RailwayContactRequest
err := json.Unmarshal([]byte(dataStr), &data)
if err != nil {
panic(err)
}
return data
}
func QueryPatients() []models.PatientRequest {
dataStr := fakerGetRequest("query/contacts/railway/320581199103182689")
var data []models.PatientRequest
err := json.Unmarshal([]byte(dataStr), &data)
if err != nil {
panic(err)
}
return data
} }

View File

@@ -48,7 +48,10 @@ func cacheNCovStatistics() {
var nCovRes map[string]string var nCovRes map[string]string
json.Unmarshal([]byte(resp), &nCovRes) json.Unmarshal([]byte(resp), &nCovRes)
var nCovResData map[string]interface{} var nCovResData map[string]interface{}
json.Unmarshal([]byte(nCovRes["data"]), &nCovResData) err := json.Unmarshal([]byte(nCovRes["data"]), &nCovResData)
if err != nil {
panic(err)
}
if !needToRecache(nCovResData) { if !needToRecache(nCovResData) {
return return
} }

View File

@@ -36,6 +36,7 @@ func GetAllCityData(sort string) []interface{} {
} }
func GetCountryData(child bool) []interface{} { func GetCountryData(child bool) []interface{} {
checkCache()
if child { if child {
return getEntireRedisList(rds_COUNTRY_LEVEL_CHILD_KEY) return getEntireRedisList(rds_COUNTRY_LEVEL_CHILD_KEY)
} }
@@ -43,6 +44,7 @@ func GetCountryData(child bool) []interface{} {
} }
func GetChinaNCovStatistic() models.ChinaData { func GetChinaNCovStatistic() models.ChinaData {
checkCache()
data := models.ChinaData{} data := models.ChinaData{}
json.Unmarshal([]byte(global.Redis.Get(rds_CHINA_ADD_KEY).Val()), &data.ChinaAdd) json.Unmarshal([]byte(global.Redis.Get(rds_CHINA_ADD_KEY).Val()), &data.ChinaAdd)
json.Unmarshal([]byte(global.Redis.Get(rds_CHINA_TOTAL_KEY).Val()), &data.ChinaTotal) json.Unmarshal([]byte(global.Redis.Get(rds_CHINA_TOTAL_KEY).Val()), &data.ChinaTotal)

View File

@@ -1,7 +1,6 @@
package user package user
import ( import (
"encoding/json"
"fmt" "fmt"
"github.com/golang-jwt/jwt/v4" "github.com/golang-jwt/jwt/v4"
"github.com/google/uuid" "github.com/google/uuid"
@@ -18,6 +17,7 @@ const (
// Login if login success, will return token // Login if login success, will return token
func Login(user map[string]interface{}) (token string) { func Login(user map[string]interface{}) (token string) {
// TODO: need to detect is passed or not
account := user["account"].(string) account := user["account"].(string)
var queryMap []map[string]interface{} var queryMap []map[string]interface{}
if strings.Contains(account, "@") { if strings.Contains(account, "@") {
@@ -29,64 +29,73 @@ func Login(user map[string]interface{}) (token string) {
if userInfo == nil { if userInfo == nil {
return "" return ""
} }
if userInfo["approver"].(int) <= 0 {
return ""
}
if !utils.PasswordCompare(user["password"].(string), userInfo["password"].(string)) { if !utils.PasswordCompare(user["password"].(string), userInfo["password"].(string)) {
return "" return ""
} }
claims := jwt.MapClaims{ claims := jwt.MapClaims{
"id": userInfo["id"], "id": userInfo["id"],
"username": userInfo["username"], "username": userInfo["username"],
"role": userInfo["role"],
"email": userInfo["email"], "email": userInfo["email"],
"region": userInfo["region"],
"role": userInfo["role"],
} }
return utils.GenerateToken(claims) return utils.GenerateToken(claims)
} }
// Register user register, user can use account after approved // Register user register, user can use account after approved
func Register(user map[string]interface{}) { func Register(user map[string]interface{}) bool {
user["password"] = utils.PasswordEncrypt(user["password"].(string)) user["password"] = utils.PasswordEncrypt(user["password"].(string))
userStr, _ := json.Marshal(user) user["approver"] = 0
// insert into redis, wait for approve colMap := models.MapJ2c[models.BackUser](user, false)
cmd := global.Redis.HMSet(global.REGISTER_REDIS_KEY, map[string]interface{}{user["email"].(string): userStr}) ok, rowsAffected := models.Upsert[models.BackUser](colMap)
if cmd.Err() != nil { if !ok || rowsAffected == 0 {
panic(cmd.Err()) return false
} }
return true
} }
// ListRegister list the registers in the redis to be approved // ListRegister list the registers in the redis to be approved
func ListRegister() *[]map[string]interface{} { func ListRegister(claims models.TokenClaims) *[]map[string]interface{} {
applyStrMap := global.Redis.HGetAll(global.REGISTER_REDIS_KEY).Val() registers := []map[string]interface{}{}
var applies []map[string]interface{} tx := global.Db.Model(new(models.BackUser)).Omit("password")
for _, v := range applyStrMap { if claims.Region == "" {
var apply map[string]interface{} // do nothing
_ = json.Unmarshal([]byte(v), &apply) } else if !strings.Contains(claims.Region, " ") {
applies = append(applies, apply) tx.Where("approver = 0 AND is_delete = 0 AND region LIKE ? AND role = ?", claims.Region+" %", global.ROLE_ID_MAP["ADMIN"])
registers = *models.ListByOrm(tx)
} else {
tx.Where("approver = 0 AND is_delete = 0 AND region = ? AND role in ?", claims.Region, []int{global.ROLE_ID_MAP["WORKER"], global.ROLE_ID_MAP["VOLUNTEER"]})
registers = *models.ListByOrm(tx)
} }
if applies == nil { return &registers
applies = []map[string]interface{}{}
} }
return &applies
// ListApprovedRegister list registers approved by the admin
func ListApprovedRegister(claims models.TokenClaims) *[]map[string]interface{} {
approvedRegisters := []map[string]interface{}{}
tx := global.Db.Model(new(models.BackUser)).Omit("password").Where("approver in ? and is_delete = 0", []int{claims.ID, -claims.ID})
approvedRegisters = *models.ListByOrm(tx)
return &approvedRegisters
} }
// ApproveRegister approve a register // ApproveRegister approve a register
func ApproveRegister(email string, pass bool) bool { func ApproveRegister(claims models.TokenClaims, email string, pass bool) bool {
if !pass { queryMap := []map[string]interface{}{{"email": email}}
rowsAffected := global.Redis.HDel(global.REGISTER_REDIS_KEY, email).Val() var approver int
return rowsAffected != 0 if pass {
approver = claims.ID
} else {
approver = -claims.ID
} }
// if pass, will get the register info from redis, and the insert into mysql, this mean user is register success updateMap := map[string]interface{}{"approver": approver}
applyStr := global.Redis.HGet(global.REGISTER_REDIS_KEY, email).Val() ok, rowsAffected := models.Update[models.BackUser](queryMap, updateMap)
rowsAffected := global.Redis.HDel(global.REGISTER_REDIS_KEY, email).Val() if !ok || rowsAffected == 0 {
if rowsAffected == 0 {
return false return false
} }
var apply map[string]interface{} return true
_ = json.Unmarshal([]byte(applyStr), &apply)
if !NoDuplicatePhoneOrEmail(apply["phone"].(string), apply["email"].(string)) {
return false
}
colMap := models.MapJ2c[models.BackUser](apply, true)
ok, rowsAffected := models.Upsert[models.BackUser](colMap)
return ok && rowsAffected != 0
} }
// ChangePassword user change password, or user forgot password // ChangePassword user change password, or user forgot password

10
utils/json.go Normal file
View File

@@ -0,0 +1,10 @@
package utils
import (
"encoding/json"
)
func Strcut2Map[S any, T *map[string]interface{} | *[]map[string]interface{}](source S, target T) {
jsonByte, _ := json.Marshal(source)
json.Unmarshal(jsonByte, target)
}

View File

@@ -1,10 +1,13 @@
package utils package utils
import ( import (
"encoding/json"
"fmt" "fmt"
"nCovTrack-Backend/global" "nCovTrack-Backend/global"
"nCovTrack-Backend/models"
"time" "time"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v4" "github.com/golang-jwt/jwt/v4"
) )
@@ -81,3 +84,9 @@ func ParseClaims(tokenStr string) jwt.MapClaims {
} }
return token.Claims.(jwt.MapClaims) return token.Claims.(jwt.MapClaims)
} }
func ClaimsFromHeader(c *gin.Context) models.TokenClaims {
var claims models.TokenClaims
json.Unmarshal([]byte(c.Request.Header.Get("claims")), &claims)
return claims
}