github.com/inhzus/go-berater@v0.0.0-20190602170559-fb80cb14726b/routes/v1/api/api.go (about)

     1  package api
     2  
     3  import (
     4  	"github.com/gin-gonic/gin"
     5  	"github.com/go-redis/redis"
     6  	"github.com/inhzus/go-berater/config"
     7  	"github.com/inhzus/go-berater/middlewares"
     8  	"github.com/inhzus/go-berater/models"
     9  	"github.com/inhzus/go-berater/utils"
    10  	"math/rand"
    11  	"net/http"
    12  	"strconv"
    13  	"time"
    14  )
    15  
    16  var (
    17  	client = redis.NewClient(&redis.Options{
    18  		Addr: config.GetConfig().Redis.Addr,
    19  	})
    20  )
    21  
    22  type CodeStorage struct {
    23  	Code   string
    24  	phone  string
    25  	Status bool
    26  }
    27  
    28  func ApplyRoutes(r *gin.RouterGroup) {
    29  	api := r.Group("/api")
    30  	{
    31  		api.GET("/test/token/:openid", testToken)
    32  	}
    33  	auth := api.Group("")
    34  	auth.Use(middlewares.JwtMiddleware())
    35  	{
    36  		auth.GET("/token", checkToken)
    37  		auth.POST("/code", sendCode)
    38  		auth.GET("/code/:code", checkCode)
    39  		auth.POST("/candidate", addCandidate)
    40  		auth.PATCH("/candidate", updateCandidate)
    41  	}
    42  }
    43  
    44  func testToken(c *gin.Context) {
    45  	openid := c.Param("openid")
    46  	auth, err := middlewares.CreateToken(openid)
    47  	if err != nil {
    48  		c.JSON(http.StatusBadRequest, gin.H{"msg": err.Error(),})
    49  		return
    50  	}
    51  	c.JSON(http.StatusOK, gin.H{
    52  		"token": auth,
    53  	})
    54  }
    55  
    56  func checkToken(c *gin.Context) {
    57  	c.Status(http.StatusOK)
    58  }
    59  
    60  func sendCode(c *gin.Context) {
    61  	conf := config.GetConfig()
    62  	claims := c.MustGet(conf.Jwt.Identity).(*middlewares.OpenidClaims)
    63  	var phoneJson struct {
    64  		Phone string
    65  	}
    66  	err := c.ShouldBindJSON(&phoneJson)
    67  	//err := c.BindJSON(&phoneJson)
    68  	if err != nil {
    69  		c.JSON(http.StatusBadRequest, gin.H{
    70  			"msg": "Request JSON format error or \"phone\" missing",
    71  		})
    72  		return
    73  	}
    74  	lowerBound := 1
    75  	upperBound := 10
    76  	for i := 1; i != conf.Code.Length; i++ {
    77  		lowerBound *= 10
    78  		upperBound *= 10
    79  	}
    80  	genCode := strconv.Itoa(lowerBound + rand.Intn(upperBound-lowerBound))
    81  	err = utils.SendSMS(phoneJson.Phone, genCode)
    82  	if err != nil {
    83  		c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error(),})
    84  		return
    85  	}
    86  	err = client.HMSet(claims.Openid+conf.Code.Suffix, map[string]interface{}{
    87  		"code":   genCode,
    88  		"phone":  phoneJson.Phone,
    89  		"status": false,
    90  	}).Err()
    91  	if err != nil {
    92  		c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error(),})
    93  		return
    94  	}
    95  	client.Expire(claims.Openid+conf.Code.Suffix, time.Duration(conf.Code.ExpireTime)*time.Minute)
    96  	c.Status(http.StatusOK)
    97  }
    98  
    99  func checkCode(c *gin.Context) {
   100  	conf := config.GetConfig()
   101  	claims := c.MustGet(conf.Jwt.Identity).(*middlewares.OpenidClaims)
   102  	redisKey := claims.Openid + conf.Code.Suffix
   103  	code := c.Param("code")
   104  	cached, err := client.HGetAll(redisKey).Result()
   105  	if err != nil || cached["code"] != code {
   106  		c.Status(http.StatusNotFound)
   107  		return
   108  	}
   109  	client.HSet(redisKey, "status", true)
   110  	client.Expire(redisKey, time.Duration(conf.Code.ExpireTime)*time.Minute)
   111  	c.Status(http.StatusOK)
   112  }
   113  
   114  func addCandidate(c *gin.Context) {
   115  	conf := config.GetConfig()
   116  	openid := c.MustGet(conf.Jwt.Identity).(*middlewares.OpenidClaims).Openid
   117  	if models.ExistCandidateById(openid) {
   118  		c.JSON(http.StatusConflict, gin.H{"msg": "Candidate has been created with the openid",})
   119  		return
   120  	}
   121  	var candidate models.Candidate
   122  	err := c.ShouldBindJSON(&candidate)
   123  	if err != nil {
   124  		c.JSON(http.StatusBadRequest, gin.H{"msg": err.Error(),})
   125  		return
   126  	}
   127  	redisKey := openid + conf.Code.Suffix
   128  	cached, err := client.HGet(redisKey, "status").Result()
   129  	if status, _ := strconv.ParseBool(cached); err != nil || !status {
   130  		c.JSON(http.StatusUnauthorized, gin.H{"msg": "Phone not verified",})
   131  		return
   132  	}
   133  	phone, _ := client.HGet(redisKey, "phone").Result()
   134  	candidate.Phone = phone
   135  	candidate.Openid = openid
   136  	err = models.AddCandidate(&candidate)
   137  	if err != nil {
   138  		c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error(),})
   139  	} else {
   140  		c.Status(http.StatusOK)
   141  	}
   142  }
   143  
   144  func updateCandidate(c *gin.Context) {
   145  	conf := config.GetConfig()
   146  	openid := c.MustGet(conf.Jwt.Identity).(*middlewares.OpenidClaims).Openid
   147  
   148  	existed := models.GetCandidateById(openid)
   149  
   150  	if existed == nil {
   151  		c.JSON(http.StatusNotFound, gin.H{"msg": "Candidate not created"})
   152  		return
   153  	}
   154  
   155  	var candidate models.Candidate
   156  	err := c.ShouldBindJSON(&candidate)
   157  	if err != nil {
   158  		c.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
   159  		return
   160  	}
   161  
   162  	redisKey := openid + conf.Code.Suffix
   163  	isExisted, _ := client.Exists(redisKey).Result()
   164  	badHit := false
   165  
   166  	if isExisted != 0 {
   167  		cached, _ := client.HGetAll(redisKey).Result()
   168  		status, _ := strconv.ParseBool(cached["status"])
   169  		if !status && cached["phone"] != existed.Phone {
   170  			badHit = true
   171  		}
   172  		if len(candidate.Phone) != 0 && candidate.Phone != cached["phone"] {
   173  			badHit = true
   174  		}
   175  	} else if len(candidate.Phone) != 0 && candidate.Phone != existed.Phone {
   176  		badHit = true
   177  	}
   178  	if badHit {
   179  		c.JSON(http.StatusUnauthorized, gin.H{"msg": "Phone not verified"})
   180  		return
   181  	}
   182  
   183  	err = models.UpdateCandidate(openid, &candidate)
   184  	if err != nil {
   185  		c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
   186  	} else {
   187  		c.Status(http.StatusOK)
   188  	}
   189  }