Go实战项目-给项目添加一个邀请码的功能【开源十年项目第9次更新】

kaiyuan10nian · 2022-04-11 19:10:00 · 2067 次点击 · 预计阅读时间 5 分钟 · 大约8小时之前 开始浏览    
这是一个创建于 2022-04-11 19:10:00 的文章,其中的信息可能已经有所发展或是发生改变。

一个深漂近10年的程序员立志用未来10年时间去维护一个项目,这个项目的功能未定,用到什么就做什么,遇到什么就写什么。其主要目的有二,一为加深自己的技术深度,二为其他学习者提供参考。

感兴趣的可以跟着我一起做这个项目,不收费、不套路、人间自有真情在。

备注:前面项目中用到的代码已经分享到GitHub中去了,并且以后所有项目中会出现的代码都会提交上去,欢迎查阅。

地址:https://github.com/kaiyuan10nian/kaiyuan10nian 感兴趣的可以点个star哦~开源十年项目的更新首发于公众号:计算机自学平台,有兴趣的小伙伴可以持续关注,并欢迎各位加我的微信(kaiyuan10nian)跟我一起完成并推动项目的发展。


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.InviteCode
    DB.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.Model
    Name      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.Model
    Userid  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.InviteCode
        DB.Where("userid = ?",id).Find(&inviteCodes)//根据id去查这个推荐者有多少邀请码
        isValid := false
        for _,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...


有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2067 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传