feat: user & article: dev complete

This commit is contained in:
fallen-angle
2022-02-27 16:36:33 +08:00
parent 4f3b16ab9d
commit 80ca1cd46e
33 changed files with 2373 additions and 185 deletions

View File

@@ -8,53 +8,108 @@ import (
"strconv"
)
// SaveArticleHandler save an article
// @Tags Article
// @Accept json
// @Produce json
// @Summary save article
// @Success 200 {object} utils.GinResponse{data=models.BackArticle}
// @Router /article [post]
// @Param Article body models.BackArticle true "article"
// @Param Token header string true "token"
func SaveArticleHandler(c *gin.Context) {
var articleSave models.BackArticle
err := c.ShouldBindJSON(&articleSave)
if err != nil {
var requestBody []byte
_, err := c.Request.Body.Read(requestBody)
if err != nil {
return
}
utils.RequestErr(c, requestBody)
jsonMap := bindJson(c)
if jsonMap == nil {
return
}
if ok := article.SaveArticle(&articleSave); !ok {
utils.ServerErr(c, "Save Failed")
colMap := models.MapJ2c[models.BackArticle](jsonMap, true)
if ok := article.SaveArticle(colMap); !ok {
ServerErr(c, "Save Failed")
return
}
utils.Succ(c, articleSave)
utils.Succ(c, jsonMap)
}
// GetAllArticlesHandler get all article
// @Tags Article
// @Accept json
// @Produce json
// @Summary get all articles
// @Description Admin can get not published article
// @Success 200 {object} utils.GinResponse{data=[]models.BackArticle}
// @Router /article/list [get]
// @Param Token header string false "token"
func GetAllArticlesHandler(c *gin.Context) {
articles := article.GetArticleList()
// TODO: admin need to show more articles
articles := article.ListAllArticles()
utils.Succ(c, articles)
}
// DeleteArticleHandler delete article
// @Tags Article
// @Accept json
// @Produce json
// @Summary delete an article
// @Success 200 {object} utils.GinResponse{}
// @Router /article/{id} [delete]
// @Param Token header string true "token"
// @Param id path string true "id"
func DeleteArticleHandler(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
utils.RequestErr(c, map[string]interface{}{"URI": c.Request.RequestURI})
RequestErr(c, map[string]interface{}{"URI": c.Request.RequestURI})
return
}
if ok := article.DeleteArticle(id); !ok {
utils.DataNotFound(c, "The article not found id = "+strconv.Itoa(id))
ServerErr(c, "Can't delete the article")
return
}
utils.Succ(c, nil)
}
// GetArticleHandler get an article
// @Tags Article
// @Accept json
// @Produce json
// @Summary get all articles
// @Description Admin can get not published article
// @Success 200 {object} utils.GinResponse{data=models.BackArticle}
// @Router /article/{id} [get]
// @Param Token header string false "token"
// @Param id path string true "id"
func GetArticleHandler(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
utils.RequestErr(c, map[string]interface{}{"URI": c.Request.RequestURI})
RequestErr(c, map[string]interface{}{"URI": c.Request.RequestURI})
return
}
res := article.GetArticleById(id)
//TODO: if not admin, will not show not published article
if res == nil {
utils.DataNotFound(c, nil)
DataNotFound(c, nil)
return
}
utils.Succ(c, res)
}
// PublishArticleHandler publish an article
// @Tags Article
// @Accept json
// @Produce json
// @Summary get all articles
// @Success 200 {object} utils.GinResponse{}
// @Router /article/{id}/publish [post]
// @Param Token header string true "token"
// @Param id path string true "id"
func PublishArticleHandler(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
RequestErr(c, map[string]interface{}{"URI": c.Request.RequestURI})
return
}
if ok := article.PublishArticle(id); !ok {
ServerErr(c, "Can't publish the article")
return
}
utils.Succ(c, nil)
}

33
handler/errors.go Normal file
View File

@@ -0,0 +1,33 @@
package handler
import (
"github.com/gin-gonic/gin"
"nCovTrack-Backend/utils"
"net/http"
)
// This file is define some business error
const (
BAD_REQUEST = "Bad Request"
DATA_NOT_FOUND = "Data not Found"
STATUS_DATA_NOT_FOUND = 210
)
func RequestError(c *gin.Context, code int, data interface{}) {
utils.Error(c, http.StatusBadRequest, code, BAD_REQUEST, data)
}
func RequestErr(c *gin.Context, data interface{}) {
RequestError(c, http.StatusBadRequest, data)
}
func ServerError(c *gin.Context, code int, msg interface{}) {
utils.Err(c, http.StatusInternalServerError, code, msg)
}
func ServerErr(c *gin.Context, msg interface{}) {
ServerError(c, http.StatusInternalServerError, msg)
}
func DataNotFound(c *gin.Context, data interface{}) {
utils.Success(c, http.StatusOK, STATUS_DATA_NOT_FOUND, DATA_NOT_FOUND, data)
}

View File

@@ -12,7 +12,7 @@ import (
// @Tags Statistics
// @Produce json
// @Summary province statistics
// @Success 200 {object} models.GinResponse{data=[]models.AreaInfo}
// @Success 200 {object} utils.GinResponse{data=[]models.AreaInfo}
// @Router /statistics/province/{sort} [get]
// @Param sort path string false "data sorted by" Enums(today, total, now, default)
func ProvinceDataHandler(c *gin.Context) {
@@ -25,7 +25,7 @@ func ProvinceDataHandler(c *gin.Context) {
// @Tags Statistics
// @Produce json
// @Summary city statistics
// @Success 200 {object} models.GinResponse{data=[]models.AreaInfo}
// @Success 200 {object} utils.GinResponse{data=[]models.AreaInfo}
// @Router /statistics/city/{sort} [get]
// @Param sort path string false "data sorted by" Enums(today, total, now, default)
func CityDataHandler(c *gin.Context) {
@@ -38,7 +38,7 @@ func CityDataHandler(c *gin.Context) {
// @Tags Statistics
// @Produce json
// @Summary country statistics
// @Success 200 {object} models.GinResponse{data=[]models.AreaInfo}
// @Success 200 {object} utils.GinResponse{data=[]models.AreaInfo}
// @Router /statistics/country/child [get]
// @Router /statistics/country [get]
func CountryDataHandler(c *gin.Context) {
@@ -51,7 +51,7 @@ func CountryDataHandler(c *gin.Context) {
// @Tags Statistics
// @Produce json
// @Summary china data
// @Success 200 {object} models.GinResponse{data=models.ChinaData}
// @Success 200 {object} utils.GinResponse{data=models.ChinaData}
// @Router /statistics/china [get]
func ChinaDataHandler(c *gin.Context) {
data := service.GetChinaNCovStatistic()

144
handler/user.go Normal file
View File

@@ -0,0 +1,144 @@
package handler
import (
"github.com/gin-gonic/gin"
"nCovTrack-Backend/models"
"nCovTrack-Backend/service/user"
"nCovTrack-Backend/utils"
"regexp"
)
//UserRegisterHandler user register
// @Tags User
// @Accept json
// @Produce json
// @Summary user register account
// @Success 200 {object} utils.GinResponse{}
// @Router /user/register [post]
// @Param json body models.UserRegister true "json"
func UserRegisterHandler(c *gin.Context) {
jsonMap := bindJsonStruct[models.UserRegister](c)
if jsonMap == nil {
return
}
registered := user.NoDuplicatePhoneOrEmail(jsonMap["phone"].(string), jsonMap["email"].(string))
if registered {
utils.Success(c, 200, 200, "Registered", nil)
}
colMap := models.MapJ2c[models.BackUser](jsonMap, true)
user.Register(colMap)
}
//UserApproveHandler admin approve account
// @Tags User
// @Accept json
// @Produce json
// @Summary admin approve account, user can use account after approved
// @Success 200 {object} utils.GinResponse{}
// @Router /user/approve [post]
// @Param Token header string true "token"
// @Param json body models.UserApprove true "json"
func UserApproveHandler(c *gin.Context) {
//TODO: auth user is admin or not
jsonMap := bindJsonStruct[models.UserApprove](c)
if jsonMap == nil {
return
}
if !user.ApproveRegister(jsonMap["email"].(string), jsonMap["pass"].(bool)) {
RequestErr(c, "approve failed")
return
}
utils.Succ(c, nil)
}
//UserLoginHandler admin approve account
// @Tags User
// @Accept json
// @Produce json
// @Summary user login
// @Success 200 {object} utils.GinResponse{}
// @Router /user/login [post]
// @Param json body models.UserLogin true "json"
func UserLoginHandler(c *gin.Context) {
jsonMap := bindJsonStruct[models.UserLogin](c)
if jsonMap == nil {
return
}
token := user.Login(jsonMap)
if token == "" {
// TODO: change to request error
utils.Succ(c, map[string]interface{}{"msg": "failed"})
return
}
c.Writer.Header().Set("X-Token", token)
utils.Succ(c, nil)
}
//ListRegisterUserHandler list register infos
// @Tags User
// @Produce json
// @Summary list register infos, which is to be approved
// @Success 200 {object} utils.GinResponse{}
// @Router /user/registers [get]
// @Param Token header string true "token"
func ListRegisterUserHandler(c *gin.Context) {
registers := user.ListRegister()
utils.Succ(c, registers)
}
//SendEmailCodeHandler send verify code
// @Tags User
// @Produce json
// @Summary send verify code
// @Success 200 {object} utils.GinResponse{}
// @Router /user/{code} [get]
// @Param email path string true "email"
func SendEmailCodeHandler(c *gin.Context) {
email := c.Param("email")
match, _ := regexp.Match("^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$", []byte(email))
if !match {
RequestErr(c, map[string]interface{}{"email": email})
return
}
if ok := user.SendEmailCode(email); !ok {
ServerErr(c, "Send Email Failed")
return
}
utils.Succ(c, nil)
}
//VerifyEmailCodeHandler verify code
// @Tags User
// @Produce json
// @Summary send verify code
// @Success 200 {object} utils.GinResponse{}
// @Router /user/code/{email}/{code} [get]
// @Param email path string true "email"
// @Param code path string true "code"
func VerifyEmailCodeHandler(c *gin.Context) {
email := c.Param("email")
code := c.Param("code")
emailMatch, _ := regexp.Match("^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$", []byte(email))
codeMatch, _ := regexp.Match("^[\\w]{6}$", []byte(code))
if !codeMatch || !emailMatch {
RequestErr(c, map[string]interface{}{"email": email, "code": code})
return
}
utils.Succ(c, user.VerifyEmailCode(email, code))
}
//ChangePasswordHandler change user's password
// @Tags User
// @Accept json
// @Produce json
// @Summary change user's password
// @Success 200 {object} utils.GinResponse{}
// @Router /user/chpwd [post]
// @Param json body models.UserChangePwd true "json"
func ChangePasswordHandler(c *gin.Context) {
jsonMap := bindJsonStruct[models.UserChangePwd](c)
if jsonMap == nil {
return
}
utils.Succ(c, map[string]interface{}{"success": user.ChangePassword(jsonMap)})
}

48
handler/utils.go Normal file
View File

@@ -0,0 +1,48 @@
package handler
import (
"encoding/json"
"github.com/gin-gonic/gin"
)
// bindJson bind body as a map
func bindJson(c *gin.Context) map[string]interface{} {
var jsonMap map[string]interface{}
err := c.ShouldBindJSON(&jsonMap)
if err != nil {
var requestBody []byte
_, err := c.Request.Body.Read(requestBody)
if err != nil {
panic(err)
}
RequestErr(c, requestBody)
return nil
}
if jsonMap == nil || len(jsonMap) == 0 {
RequestErr(c, map[string]interface{}{"Body": nil})
return nil
}
return jsonMap
}
// bindJsonStruct bind json as a struct, and convert to map
func bindJsonStruct[T any](c *gin.Context) map[string]interface{} {
var bindObj T
err := c.ShouldBind(&bindObj)
if err != nil {
var requestBody []byte
_, err := c.Request.Body.Read(requestBody)
if err != nil {
panic(err)
}
RequestErr(c, requestBody)
return nil
}
jsonStr, _ := json.Marshal(bindObj)
var jsonMap map[string]interface{}
_ = json.Unmarshal(jsonStr, &jsonMap)
if jsonMap == nil || len(jsonMap) == 0 {
return nil
}
return jsonMap
}