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 }