一个深漂仅10年的成员立志用未来10年时间去维护一个项目,这个项目的功能未定,用到什么就做什么,遇到什么就写什么。其主要目的有二,一为加深自己的技术深度,二为其他学习者提供参考。
感兴趣的可以跟着我一起做这个项目,不收费、不套路、人间自有真情在。
2、项目准备工作
Go实战项目-给项目添加一个邀请码的功能
前面总结里面说过,我要给我们的blog项目添加一个邀请码的功能,因为这个项目做完之后我要部署出去的,虽说不靠这个东西去盈利,但是实战要有实战的样子至少把一个项目从0做到1的过程还是要有的。这里就涉及到一个很严重的问题:怎么控制内容?(在国内不可能不控制内容的)
-
人工去审核(我没那么多时间)
-
接入第三方内容审核(要花钱的)
-
智能审核(没这个技术~后面也许可以考虑在开源十年中去实现它)
所以没有办法了,既然我控制不了内容,那我就从源头控制:直接控制输出内容的人。
所以我想到的办法就是在注册的时候做一个限制,不能让每个人都可以注册成功,只能让那些得到我们这个圈子成员信任的人才可以注册体验。那么实现的逻辑要提前去思考了:
-
邀请码怎么来的?
邀请码是系统生成的,由已注册会员手动生成,没给会员允许生成5个邀请码,每个邀请码只能使用1次。
-
邀请码在哪使用?
邀请码在新会员注册的时候使用(为必填项)
-
邀请码怎么追溯?
因为邀请码的生成是已注册会员手动生成的,所以我会在库里面去拉一张表单独去记录,如果有新会员使用了邀请码那么我也会记录下来,后面若想去追溯就很简单了
根据上面的思路,我们一步一步来实现其功能:
1、先写接口路由:
r.GET("/v1/account/invite", common.AuthMiddleware(),controller.Invite)
因为邀请码只能是已注册会员去生成,所以必须加上common.AuthMiddleware()权限限制。
2、实现邀请码的生成:
func RandomString(n int) string {var letters = []byte("23456789qwertyupkjhgfdsazxcvbnmMNBVCXZASDFGHJKPOUYTREWQ")result := make([]byte,n)rand.Seed(time.Now().Unix())for i := range result {result[i] = letters[rand.Intn(len(letters))]}return string(result)}
这个其实就是一个生成随机值的函数,其中我把'0'、'1'、'i'、'l'、'I'、'L'等不容易辨认的字符都去掉了。
3、实现邀请码接口功能:
//创建用户邀请码func Invite(ctx *gin.Context){udata ,_:= ctx.Get("user")//首先通过token去获取用户信息dto := dto.ToUserDto(udata.(model.User))DB := common.GetDB()var inviteCodes []model.InviteCodeDB.Where("userid = ?",dto.ID).Find(&inviteCodes)//根据用户信息去查询这个用户有多少个邀请码fmt.Println(len(inviteCodes))if len(inviteCodes) < 5{//如果不够5个则允许他继续生成邀请码code := RandomString(5)newCode := model.InviteCode{Userid: dto.ID,Code: code,Status: 0,}//生成成功后把它记录进库表里面if err := DB.Create(&newCode).Error;err != nil{response.Response(ctx,http.StatusInternalServerError,500,nil,err.Error())return}response.Response(ctx,http.StatusOK,6000,gin.H{"inviteCode":code},"邀请码生成成功")}else{response.Response(ctx,http.StatusOK,60001,nil,"每个人只可以拥有5个邀请码")return}}
上述提到了邀请码的创建,我们创建了一个表invitecode专门用来存储(下文有model代码)
4、去修改注册功能
原本我们的注册只需要手机号并设置密码即可,但是我们要控制注册了,那么要加几个验证条件:
1)推荐人是否存在?
2)邀请码是否存在?
3)邀请码是否和推荐人匹配?
4)邀请码是否被人使用过了?
这几个条件判断之后,如果都通过那么给予放行,放行后还要做一个操作:
1)标记该邀请码已被使用
2)把该邀请码跟注册账号进行关联
针对上述逻辑,首先针对库表进行设计和改造
直接在用户表新增了一个字段invitecode,目的就是把邀请码和注册者进行关联。
type User struct {gorm.ModelName string `gorm:"type:varchar(20);not null"`Mobile string `gorm:"varchar(11);not null;unique"`Password string `gorm:"size:255;not null"`InviteCode string `json:"invitecode" gorm:"not null"`}
然后,新建了一个表,专门用来存我们生成的邀请码,以及记录邀请码和生成邀请码的用户进行关联
type InviteCode struct {gorm.ModelUserid uint `json:"user_id" gorm:"not null"`Code string `json:"code" gorm:"not null"`Status uint `json:"status" gorm:"not null"`}
库表建好了,下面就是在注册时,我们针对以上逻辑的代码实现:(全部代码请查看github)
if isTelephoneExist(DB,recommender){//查询这个推荐者存不存在id := getRecommenderId(DB,recommender)//先获取推荐者的ID//判断其邀请码的准确性var inviteCodes []model.InviteCodeDB.Where("userid = ?",id).Find(&inviteCodes)//根据id去查这个推荐者有多少邀请码isValid := falsefor _,inviteCode := range inviteCodes{//轮寻他所有邀请码isValid = strings.EqualFold(code,inviteCode.Code)//一一对比,查看注册者输入的是否和库里的一致if isValid {if inviteCode.Status == 0 {//如果一致,则再验证这个是否已经被用了DB.Model(&inviteCode).Update("status",1)break}else{response.Response(ctx,http.StatusOK,60002,nil,"邀请码已使用")return}}}if !isValid {response.Response(ctx,http.StatusOK,60002,nil,"邀请码不存在")return}}else {//最后这个提示,我是想避免被人拿这个接口测试用户存在与否response.Response(ctx,http.StatusOK,60002,nil,"邀请码不存在")return}
好了,到这里我们基本就完成这个简单的小功能了,直接go run main.go 去亲自体验一下吧。
ok just this.see you next...
开源十年项目的更新首发于公众号:计算机自学平台,有兴趣的小伙伴可以持续关注,并欢迎各位加我的微信跟我一起完成并推动项目的发展。

文章评论