初始化项目

This commit is contained in:
lianghuanjie
2024-12-05 20:51:35 +08:00
commit e2ba6924b8
30 changed files with 1560 additions and 0 deletions

26
.gitignore vendored Normal file
View File

@@ -0,0 +1,26 @@
# ---> Go
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# local config
*_local.yaml
# Dependency directories (remove the comment below to include it)
vendor/
builder/
logs/
static/
bin/
cert/
.idea/

31
Dockerfile Normal file
View File

@@ -0,0 +1,31 @@
FROM golang:1.23.4-alpine AS builder
LABEL stage=gobuilder
ENV CGO_ENABLED=0
ENV GOPROXY=https://goproxy.cn,direct
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
RUN apk update --no-cache && apk add --no-cache tzdata
WORKDIR /build
ADD go.mod .
ADD go.sum .
RUN go mod download
COPY . .
COPY ./etc /app/etc
RUN go build -ldflags="-s -w" -o /app/novatask novatask.go
FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=builder /usr/share/zoneinfo/UTC /usr/share/zoneinfo/UTC
ENV TZ=UTC
WORKDIR /app
COPY --from=builder /app/novatask /app/novatask
COPY --from=builder /app/etc /app/etc
CMD ["./novatask", "-f", "etc/novatask.yaml"]

65
Makefile Normal file
View File

@@ -0,0 +1,65 @@
host ?= 192.168.2.108:3306
user ?= huangjie
pwd ?= jMDqPQM^a6hsAR
table ?=
cache ?=
database ?= "nova_home"
.PHONY: db
# 链接数据库生成模型代码
db:
goctl model mysql datasource -url="${user}:${pwd}@tcp(${host})/${database}" -table="${table}" --dir internal/model --strict --style go_zero ${cache}
.PHONY: init
# 初始化开发环境,安装依赖工具
init:
go install github.com/zeromicro/go-zero/tools/goctl@latest
goctl env check --install --verbose --force
go install github.com/zeromicro/goctl-swagger@latest
.PHONY: api-format
# 格式化api文件
api-format:
goctl api format --dir doc/api/
goctl api plugin -plugin goctl-swagger="swagger -filename nova-task.json" -api doc/api/nova-task.api -dir doc/swagger
.PHONY: api
# 根据api文件生成代码
api:
make api-format
goctl api go -api doc/api/nova-task.api --dir . --style go_zero
.PHONY: build
# 编译二进制可执行文件
build:
mkdir -p bin/ && go build -ldflags="-s -w" -o ./bin/ ./...
.PHONY: img
# 构建Docker镜像
img:
docker build --platform=amd64 -t nova-task:latest .
docker tag `docker images -aq -f "reference=nova-task:latest"` harbor.phantom-u3d002.com/nova/nova-task:latest
.PHONY: push
push:
docker push harbor.phantom-u3d002.com/nova/nova-task:latest
# 帮助信息
help:
@echo ''
@echo 'Usage:'
@echo ' make [target]'
@echo ''
@echo 'Targets:'
@awk '/^[a-zA-Z\-\0-9]+:/ { \
helpMessage = match(lastLine, /^# (.*)/); \
if (helpMessage) { \
helpCommand = substr($$1, 0, index($$1, ":")-1); \
helpMessage = substr(lastLine, RSTART + 2, RLENGTH); \
printf "\033[36m%-22s\033[0m %s\n", helpCommand,helpMessage; \
} \
} \
{ lastLine = $$0 }' $(MAKEFILE_LIST)
.DEFAULT_GOAL := help

21
README.md Normal file
View File

@@ -0,0 +1,21 @@
# nova task 服务端
## 快速开始
1. 基于go-zero框架开发
2. golang 1.23.0+
3. 安装依赖工具: make init
## 组件依赖
1. MySQL 8.0+
2. Docker 27.1+
## 配置文件 [novatask.yaml](etc/saas.yaml)
1. 修改Mysql中的数据库地址以及账号密码
2. 其他配置项根据注释说明和实际需求自行修改
## 正式服部署
1. 将[docker-compose.yml](docker-compose.yml)文件拷贝到服务器上,并修改需要部署的镜像版本以及根据配置的端口修改端口映射
2. 在同一目录下创建文件夹etc 并将[novatask.yaml](etc/saas.yaml)文件拷贝到etc目录下并根据需求修改配置文件
3. 拉取镜像:``docker compose pull``
4. 起服:``docker compose up -d``
5. 配置http反向代理将``/api/task``前缀的路由代理到映射出来的端口上

46
doc/api/nova-task.api Normal file
View File

@@ -0,0 +1,46 @@
syntax = "v1"
@server (
prefix: /api/task/v1
group: task
jwt: Auth
)
service novatask {
@doc "获取任务列表"
@handler GetTaskList
get /tasks (GetTaskListReq) returns (GetTaskListResp)
@doc "领取任务奖励"
@handler GetTaskReward
get /reward/:id (GetTaskRewardReq) returns (GetTaskRewardResp)
}
type GetTaskListReq {
CommunityId uint `form:"community_id"`
}
type Task {
Id uint `json:"id"`
Title string `json:"title"`
SubTitle string `json:"sub_title"`
Description string `json:"description"`
Points int `json:"points"`
ButtonText string `json:"button_text"`
Type int8 `json:"type"`
StartAt string `json:"start_at"`
EndAt string `json:"end_at"`
Status int8 `json:"status"`
}
type GetTaskListResp {
Tasks []Task `json:"tasks"`
}
type GetTaskRewardReq {
ID uint `path:"id"`
}
type GetTaskRewardResp {
Points int `json:"points"`
}

190
doc/swagger/nova-task.json Normal file
View File

@@ -0,0 +1,190 @@
{
"swagger": "2.0",
"info": {
"title": "",
"version": ""
},
"schemes": [
"http",
"https"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/api/task/v1/reward/{id}": {
"get": {
"summary": "领取任务奖励",
"operationId": "GetTaskReward",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetTaskRewardResp"
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
}
],
"tags": [
"task"
],
"security": [
{
"apiKey": []
}
]
}
},
"/api/task/v1/tasks": {
"get": {
"summary": "获取任务列表",
"operationId": "GetTaskList",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetTaskListResp"
}
}
},
"parameters": [
{
"name": "community_id",
"in": "query",
"required": true,
"type": "integer",
"format": "uint32"
}
],
"tags": [
"task"
],
"consumes": [
"multipart/form-data"
],
"security": [
{
"apiKey": []
}
]
}
}
},
"definitions": {
"GetTaskListReq": {
"type": "object",
"properties": {
"community_id": {
"type": "integer",
"format": "uint32"
}
},
"title": "GetTaskListReq",
"required": [
"community_id"
]
},
"GetTaskListResp": {
"type": "object",
"properties": {
"tasks": {
"type": "array",
"items": {
"$ref": "#/definitions/Task"
}
}
},
"title": "GetTaskListResp",
"required": [
"tasks"
]
},
"GetTaskRewardReq": {
"type": "object",
"title": "GetTaskRewardReq"
},
"GetTaskRewardResp": {
"type": "object",
"properties": {
"points": {
"type": "integer",
"format": "int32"
}
},
"title": "GetTaskRewardResp",
"required": [
"points"
]
},
"Task": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "uint32"
},
"title": {
"type": "string"
},
"sub_title": {
"type": "string"
},
"description": {
"type": "string"
},
"points": {
"type": "integer",
"format": "int32"
},
"button_text": {
"type": "string"
},
"type": {
"type": "integer",
"format": "int8"
},
"start_at": {
"type": "string"
},
"end_at": {
"type": "string"
},
"status": {
"type": "integer",
"format": "int8"
}
},
"title": "Task",
"required": [
"id",
"title",
"sub_title",
"description",
"points",
"button_text",
"type",
"start_at",
"end_at",
"status"
]
}
},
"securityDefinitions": {
"apiKey": {
"type": "apiKey",
"description": "Enter JWT Bearer token **_only_**",
"name": "Authorization",
"in": "header"
}
}
}

13
docker-compose.yml Normal file
View File

@@ -0,0 +1,13 @@
services:
saas-server:
image: harbor.phantom-u3d002.com/nova/nova-task:latest
container_name: nova-task
privileged: true
restart: always
ports:
- "8888:8888"
volumes:
- ./logs:/app/logs
- ./etc:/app/etc
environment:
TZ: UTC

13
etc/novatask.yaml Normal file
View File

@@ -0,0 +1,13 @@
Name: novatask
Host: 0.0.0.0
Port: 8888
Auth: # js-sdk鉴权相关配置
AccessSecret: "ac2d27613e131be6286c0eb1713929dd" # 鉴权token密钥
AccessExpire: 168h # 鉴权token过期时间
MySql: # mysql相关配置
Addr: "127.0.0.1:3306" # mysql地址
User: "root" # mysql用户
Password: "123456" # mysql密码
Database: "nova_home" # 数据库名

53
go.mod Normal file
View File

@@ -0,0 +1,53 @@
module nova_task
go 1.23.4
require (
github.com/golang-jwt/jwt/v4 v4.5.1
github.com/spf13/cast v1.7.0
github.com/zeromicro/go-zero v1.7.4
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.3 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/prometheus/client_golang v1.20.5 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 // indirect
go.opentelemetry.io/otel/exporters/zipkin v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.uber.org/automaxprocs v1.6.0 // indirect
golang.org/x/net v0.31.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/text v0.20.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
google.golang.org/grpc v1.65.0 // indirect
google.golang.org/protobuf v1.35.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

137
go.sum Normal file
View File

@@ -0,0 +1,137 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg=
github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/zeromicro/go-zero v1.7.4 h1:lyIUsqbpVRzM4NmXu5pRM3XrdRdUuWOkQmHiNmJF0VU=
github.com/zeromicro/go-zero v1.7.4/go.mod h1:jmv4hTdUBkDn6kxgI+WrKQw0q6LKxDElGPMfCLOeeEY=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4=
go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 h1:s0PHtIkN+3xrbDOpt2M8OTG92cWqUESvzh2MxiR5xY8=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0/go.mod h1:hZlFbDbRt++MMPCCfSJfmhkGIWnX1h3XjkfxZUjLrIA=
go.opentelemetry.io/otel/exporters/zipkin v1.24.0 h1:3evrL5poBuh1KF51D9gO/S+N/1msnm4DaBqs/rpXUqY=
go.opentelemetry.io/otel/exporters/zipkin v1.24.0/go.mod h1:0EHgD8R0+8yRhUYJOGR8Hfg2dpiJQxDOszd5smVO9wM=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d h1:kHjw/5UfflP/L5EbledDrcG4C2597RtymmGRZvHiCuY=
google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=

159
goctl.yaml Normal file
View File

@@ -0,0 +1,159 @@
model:
types_map:
bigint:
null_type: sql.NullInt64
type: int64
unsigned_type: uint64
dec:
null_type: decimal.NullDecimal
pkg: github.com/shopspring/decimal
type: decimal.Decimal
decimal:
null_type: decimal.NullDecimal
pkg: github.com/shopspring/decimal
type: decimal.Decimal
double:
null_type: sql.NullFloat64
type: float64
float:
null_type: sql.NullFloat64
type: float64
float4:
null_type: sql.NullFloat64
type: float64
float8:
null_type: sql.NullFloat64
type: float64
int:
null_type: sql.NullInt64
type: int
unsigned_type: uint
int1:
null_type: sql.NullInt64
type: int64
unsigned_type: uint64
int2:
null_type: sql.NullInt64
type: int64
unsigned_type: uint64
int3:
null_type: sql.NullInt64
type: int64
unsigned_type: uint64
int4:
null_type: sql.NullInt64
type: int64
unsigned_type: uint64
int8:
null_type: sql.NullInt64
type: int64
unsigned_type: uint64
integer:
null_type: sql.NullInt64
type: int
unsigned_type: uint
mediumint:
null_type: sql.NullInt64
type: int64
unsigned_type: uint64
middleint:
null_type: sql.NullInt64
type: int64
unsigned_type: uint64
smallint:
null_type: sql.NullInt64
type: int64
unsigned_type: uint64
tinyint:
null_type: sql.NullInt16
type: int8
unsigned_type: uint8
date:
null_type: sql.NullTime
type: time.Time
datetime:
null_type: sql.NullTime
type: time.Time
timestamp:
null_type: sql.NullTime
type: time.Time
time:
null_type: sql.NullString
type: string
year:
null_type: sql.NullInt64
type: int64
unsigned_type: uint64
bit:
null_type: sql.NullByte
type: byte
unsigned_type: byte
bool:
null_type: sql.NullBool
type: bool
boolean:
null_type: sql.NullBool
type: bool
char:
null_type: sql.NullString
type: string
varchar:
null_type: sql.NullString
type: string
nvarchar:
null_type: sql.NullString
type: string
nchar:
null_type: sql.NullString
type: string
character:
null_type: sql.NullString
type: string
longvarchar:
null_type: sql.NullString
type: string
linestring:
null_type: sql.NullString
type: string
multilinestring:
null_type: sql.NullString
type: string
binary:
null_type: "[]byte"
type: "[]byte"
varbinary:
null_type: "[]byte"
type: "[]byte"
tinytext:
null_type: sql.NullString
type: string
text:
null_type: sql.NullString
type: string
mediumtext:
null_type: sql.NullString
type: string
longtext:
null_type: sql.NullString
type: string
enum:
null_type: sql.NullString
type: string
set:
null_type: sql.NullString
type: string
json:
null_type: sql.NullString
type: string
blob:
null_type: "[]byte"
type: "[]byte"
longblob:
null_type: "[]byte"
type: "[]byte"
mediumblob:
null_type: "[]byte"
type: "[]byte"
tinyblob:
null_type: "[]byte"
type: "[]byte"

40
internal/config/config.go Normal file
View File

@@ -0,0 +1,40 @@
package config
import (
"fmt"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/rest"
"net/url"
)
type Config struct {
rest.RestConf
MySql MySqlConf
Auth struct {
AccessSecret string
AccessExpire int64
}
}
// MySqlConf mysql配置
type MySqlConf struct {
Addr string
User string
Password string
Database string
Loc string `json:",default=Local"`
Log string `json:",default=disableStmt,options=allow|disable|disableStmt"`
}
func (m MySqlConf) Dsn() string {
return fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=%s", m.User, m.Password, m.Addr, m.Database, url.QueryEscape(m.Loc))
}
func (m MySqlConf) Conn(opts ...sqlx.SqlOption) sqlx.SqlConn {
if m.Log == "disable" {
sqlx.DisableLog()
} else if m.Log == "disableStmt" {
sqlx.DisableStmtLog()
}
return sqlx.NewMysql(m.Dsn(), opts...)
}

View File

@@ -0,0 +1,34 @@
// Code generated by goctl. DO NOT EDIT.
// goctl 1.7.3
package handler
import (
"net/http"
task "nova_task/internal/handler/task"
"nova_task/internal/svc"
"github.com/zeromicro/go-zero/rest"
)
func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes(
[]rest.Route{
{
// 领取任务奖励
Method: http.MethodGet,
Path: "/reward/:id",
Handler: task.GetTaskRewardHandler(serverCtx),
},
{
// 获取任务列表
Method: http.MethodGet,
Path: "/tasks",
Handler: task.GetTaskListHandler(serverCtx),
},
},
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
rest.WithPrefix("/api/task/v1"),
)
}

View File

@@ -0,0 +1,29 @@
package task
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"nova_task/internal/logic/task"
"nova_task/internal/svc"
"nova_task/internal/types"
)
// 获取任务列表
func GetTaskListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.GetTaskListReq
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := task.NewGetTaskListLogic(r.Context(), svcCtx)
resp, err := l.GetTaskList(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}

View File

@@ -0,0 +1,29 @@
package task
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"nova_task/internal/logic/task"
"nova_task/internal/svc"
"nova_task/internal/types"
)
// 领取任务奖励
func GetTaskRewardHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.GetTaskRewardReq
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := task.NewGetTaskRewardLogic(r.Context(), svcCtx)
resp, err := l.GetTaskReward(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}

View File

@@ -0,0 +1,53 @@
package task
import (
"context"
"nova_task/internal/pkg/errs"
"time"
"nova_task/internal/svc"
"nova_task/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetTaskListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// NewGetTaskListLogic 获取任务列表
func NewGetTaskListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetTaskListLogic {
return &GetTaskListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *GetTaskListLogic) GetTaskList(req *types.GetTaskListReq) (*types.GetTaskListResp, error) {
tasks, err := l.svcCtx.TaskModel.FindTasksByCommunity(l.ctx, req.CommunityId)
if err != nil {
l.Errorw("get task list failed", logx.Field("err", err), logx.Field("communityId", req.CommunityId))
return nil, errs.InternalServer(errs.ErrDatabaseOperate, err)
}
resp := &types.GetTaskListResp{}
for _, t := range tasks {
resp.Tasks = append(resp.Tasks, types.Task{
Id: t.Id,
Title: t.Title,
SubTitle: t.SubTitle,
Description: t.Description,
Points: t.Points,
ButtonText: t.ButtonText,
Type: t.Type,
StartAt: t.StartAt.Time.Format(time.DateTime),
EndAt: t.EndAt.Time.Format(time.DateTime),
Status: t.Status,
})
}
return resp, nil
}

View File

@@ -0,0 +1,31 @@
package task
import (
"context"
"nova_task/internal/svc"
"nova_task/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetTaskRewardLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// 领取任务奖励
func NewGetTaskRewardLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetTaskRewardLogic {
return &GetTaskRewardLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *GetTaskRewardLogic) GetTaskReward(req *types.GetTaskRewardReq) (resp *types.GetTaskRewardResp, err error) {
// todo: add your logic here and delete this line
return
}

45
internal/model/nh_task_model.go Executable file
View File

@@ -0,0 +1,45 @@
package model
import (
"context"
"errors"
"fmt"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
var _ NhTaskModel = (*customNhTaskModel)(nil)
type (
// NhTaskModel is an interface to be customized, add more methods here,
// and implement the added methods in customNhTaskModel.
NhTaskModel interface {
nhTaskModel
withSession(session sqlx.Session) NhTaskModel
FindTasksByCommunity(ctx context.Context, communityId uint) ([]*NhTask, error)
}
customNhTaskModel struct {
*defaultNhTaskModel
}
)
func (m *customNhTaskModel) FindTasksByCommunity(ctx context.Context, communityId uint) ([]*NhTask, error) {
query := fmt.Sprintf("select %s from %s where community_id = ?", nhTaskRows, m.table)
var tasks []*NhTask
err := m.conn.QueryRowsCtx(ctx, &tasks, query, communityId)
if err != nil && !errors.Is(err, sqlx.ErrNotFound) {
return nil, err
}
return tasks, nil
}
// NewNhTaskModel returns a model for the database table.
func NewNhTaskModel(conn sqlx.SqlConn) NhTaskModel {
return &customNhTaskModel{
defaultNhTaskModel: newNhTaskModel(conn),
}
}
func (m *customNhTaskModel) withSession(session sqlx.Session) NhTaskModel {
return NewNhTaskModel(sqlx.NewSqlConnFromSession(session))
}

View File

@@ -0,0 +1,97 @@
// Code generated by goctl. DO NOT EDIT.
// versions:
// goctl version: 1.7.3
package model
import (
"context"
"database/sql"
"fmt"
"strings"
"time"
"github.com/zeromicro/go-zero/core/stores/builder"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/core/stringx"
)
var (
nhTaskFieldNames = builder.RawFieldNames(&NhTask{})
nhTaskRows = strings.Join(nhTaskFieldNames, ",")
nhTaskRowsExpectAutoSet = strings.Join(stringx.Remove(nhTaskFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",")
nhTaskRowsWithPlaceHolder = strings.Join(stringx.Remove(nhTaskFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?"
)
type (
nhTaskModel interface {
Insert(ctx context.Context, data *NhTask) (sql.Result, error)
FindOne(ctx context.Context, id uint) (*NhTask, error)
Update(ctx context.Context, data *NhTask) error
Delete(ctx context.Context, id uint) error
}
defaultNhTaskModel struct {
conn sqlx.SqlConn
table string
}
NhTask struct {
Id uint `db:"id"`
CommunityId uint `db:"community_id"` // 合作社区ID0=官方平台
Title string `db:"title"` // 大标题
SubTitle string `db:"sub_title"` // 子标题
Description string `db:"description"` // 描述
Points int `db:"points"` // 积分数量
ButtonText string `db:"button_text"` // 按钮上的文字
Type int8 `db:"type"` // 0=一次性任务1=每天任务
Status int8 `db:"status"` // 0=不启用1=启用
StartAt sql.NullTime `db:"start_at"` // 开始时间
EndAt sql.NullTime `db:"end_at"` // 结束时间
CreatedAt time.Time `db:"created_at"` // 创建时间
UpdatedAt time.Time `db:"updated_at"` // 修改时间
}
)
func newNhTaskModel(conn sqlx.SqlConn) *defaultNhTaskModel {
return &defaultNhTaskModel{
conn: conn,
table: "`nh_task`",
}
}
func (m *defaultNhTaskModel) Delete(ctx context.Context, id uint) error {
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
_, err := m.conn.ExecCtx(ctx, query, id)
return err
}
func (m *defaultNhTaskModel) FindOne(ctx context.Context, id uint) (*NhTask, error) {
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", nhTaskRows, m.table)
var resp NhTask
err := m.conn.QueryRowCtx(ctx, &resp, query, id)
switch err {
case nil:
return &resp, nil
case sqlx.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultNhTaskModel) Insert(ctx context.Context, data *NhTask) (sql.Result, error) {
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, nhTaskRowsExpectAutoSet)
ret, err := m.conn.ExecCtx(ctx, query, data.CommunityId, data.Title, data.SubTitle, data.Description, data.Points, data.ButtonText, data.Type, data.Status, data.StartAt, data.EndAt)
return ret, err
}
func (m *defaultNhTaskModel) Update(ctx context.Context, data *NhTask) error {
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, nhTaskRowsWithPlaceHolder)
_, err := m.conn.ExecCtx(ctx, query, data.CommunityId, data.Title, data.SubTitle, data.Description, data.Points, data.ButtonText, data.Type, data.Status, data.StartAt, data.EndAt, data.Id)
return err
}
func (m *defaultNhTaskModel) tableName() string {
return m.table
}

5
internal/model/vars.go Normal file
View File

@@ -0,0 +1,5 @@
package model
import "github.com/zeromicro/go-zero/core/stores/sqlx"
var ErrNotFound = sqlx.ErrNotFound

View File

@@ -0,0 +1,106 @@
package jwt
import (
"errors"
"fmt"
jwt "github.com/golang-jwt/jwt/v4"
"github.com/spf13/cast"
"github.com/zeromicro/go-zero/rest/token"
"net/http"
"time"
)
type Config struct {
AccessSecret string `json:",default=ac2d27613e131be6286c0eb17139293d"`
AccessExpire time.Duration `json:",default=24h"`
}
type TokenBuilder struct {
config Config
}
func NewTokenBuilder(config Config) *TokenBuilder {
return &TokenBuilder{config: config}
}
// GenerateToken 生成token
func (b *TokenBuilder) GenerateToken(kvs map[string]any) (string, int64, error) {
// 创建一个新的 Token
tok := jwt.New(jwt.SigningMethodHS256)
// 设置 Token 的声明Payload
claims := tok.Claims.(jwt.MapClaims)
for k, v := range kvs {
claims[k] = v
}
expiredAt := time.Now().Add(b.config.AccessExpire).Unix()
claims["exp"] = expiredAt // 设置过期时间
// 使用密钥签名 Token
tkStr, err := tok.SignedString([]byte(b.config.AccessSecret))
return tkStr, expiredAt, err
}
func (b *TokenBuilder) ParseUidFromToken(tokenStr string) (string, string, string, int64, error) {
r := &http.Request{Header: http.Header{}}
r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", tokenStr))
parser := token.NewTokenParser()
tok, err := parser.ParseToken(r, b.config.AccessSecret, "")
if err != nil {
return "", "", "", 0, err
}
if !tok.Valid {
return "", "", "", 0, errors.New("token is invalid")
}
var appid, userId, tgId string
var expiredAt int64
if claims, ok := tok.Claims.(jwt.MapClaims); ok {
if uid, ok := claims["uid"]; ok {
userId = cast.ToString(uid)
}
if aid, ok := claims["app_id"]; ok {
appid = cast.ToString(aid)
}
if tid, ok := claims["tg_id"]; ok {
tgId = cast.ToString(tid)
}
if exp, ok := claims["exp"]; ok {
expiredAt = cast.ToInt64(exp)
}
}
return appid, userId, tgId, expiredAt, nil
}
//// ParseUid 解析出uid
//func (b *TokenBuilder) ParseUid(r *http.Request) (string, error) {
// parser := token.NewTokenParser()
// tok, err := parser.ParseToken(r, b.config.AccessSecret, "")
// if err != nil {
// return "", err
// }
// if !tok.Valid {
// return "", errors.New("token is invalid")
// }
// if claims, ok := tok.Claims.(jwt.MapClaims); ok {
// if uid, ok := claims["uid"]; ok {
// return cast.ToString(uid), nil
// }
// }
// return "", errors.New("token not exist uid")
//}
//func ParseUid(r *http.Request, accessSecret string) (string, error) {
// parser := token.NewTokenParser()
// tok, err := parser.ParseToken(r, accessSecret, "")
// if err != nil {
// return "", err
// }
// if !tok.Valid {
// return "", errors.New("token is invalid")
// }
// if claims, ok := tok.Claims.(jwt.MapClaims); ok {
// if uid, ok := claims["uid"]; ok {
// return cast.ToString(uid), nil
// }
// }
// return "", errors.New("token not exist uid")
//}

View File

@@ -0,0 +1,31 @@
package md5
import (
"crypto/md5"
"encoding/hex"
"fmt"
)
func Md5(src []byte) string {
has := md5.Sum(src)
md5Str := hex.EncodeToString(has[:])
return md5Str
}
func Md5str(src string) string {
return Md5([]byte(src))
}
func Md516(src string) string {
data := []byte(src)
has := md5.Sum(data)
md5Str := hex.EncodeToString(has[:])
return md5Str[8:24]
}
func Md516Upper(src string) string {
data := []byte(src)
has := md5.Sum(data)
md5Str := fmt.Sprintf("%X", has)
return md5Str[8:24]
}

View File

@@ -0,0 +1,30 @@
package sha
import (
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
)
func Sha1(src string) string {
h := sha1.New()
h.Write([]byte(src))
sh := hex.EncodeToString(h.Sum(nil))
return sh
}
func Sha256(src string) string {
m := sha256.New()
m.Write([]byte(src))
res := hex.EncodeToString(m.Sum(nil))
return res
}
func HmacSha256Base64(src, secret string) string {
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(src))
sign := base64.StdEncoding.EncodeToString(h.Sum(nil))
return sign
}

View File

@@ -0,0 +1,40 @@
package errs
import (
"fmt"
"github.com/spf13/cast"
)
type err struct {
code int
reason Reason
msg string
}
func New(code int, reason Reason, message any) error {
return err{
code: code,
reason: reason,
msg: cast.ToString(message),
}
}
// Error error
func (e err) Error() string {
return fmt.Sprintf("code=%d msg=%s", e.code, e.msg)
}
// Code return code
func (e err) Code() int {
return e.code
}
// Reason return reason
func (e err) Reason() Reason {
return e.reason
}
// Message return message
func (e err) Message() string {
return e.msg
}

View File

@@ -0,0 +1,56 @@
package errs
import (
"net/http"
)
func Success() error {
return New(http.StatusOK, ErrSucceed, "success")
}
func NotFound(reason Reason, v any) error {
return New(http.StatusNotFound, reason, v)
}
func BadRequest(reason Reason, v any) error {
return New(http.StatusBadRequest, reason, v)
}
func InternalServer(reason Reason, v any) error {
return New(http.StatusInternalServerError, reason, v)
}
// Unauthorized new Unauthorized error that is mapped to a 401 response.
func Unauthorized(reason Reason, v any) error {
return New(http.StatusUnauthorized, reason, v)
}
// Forbidden new Forbidden error that is mapped to a 403 response.
func Forbidden(reason Reason, v any) error {
return New(http.StatusForbidden, reason, v)
}
// Conflict new Conflict error that is mapped to a 409 response.
func Conflict(reason Reason, v any) error {
return New(http.StatusConflict, reason, v)
}
// ServiceUnavailable new ServiceUnavailable error that is mapped to an HTTP 503 response.
func ServiceUnavailable(reason Reason, v any) error {
return New(http.StatusServiceUnavailable, reason, v)
}
// GatewayTimeout new GatewayTimeout error that is mapped to an HTTP 504 response.
func GatewayTimeout(reason Reason, v any) error {
return New(http.StatusGatewayTimeout, reason, v)
}
// BadGateway new BadGateway error that is mapped to an HTTP 504 response.
func BadGateway(reason Reason, v any) error {
return New(http.StatusBadGateway, reason, v)
}
// ClientClosed new ClientClosed error that is mapped to an HTTP 499 response.
func ClientClosed(reason Reason, v any) error {
return New(499, reason, v)
}

View File

@@ -0,0 +1,64 @@
package errs
import (
"context"
"github.com/zeromicro/go-zero/rest/httpx"
"net/http"
"os"
"strings"
)
var debug bool
func init() {
if strings.ToLower(os.Getenv("VANS_API_DEBUG")) == "on" {
debug = true
}
httpx.SetErrorHandlerCtx(ErrorHandleCtx)
httpx.SetErrorHandler(ErrorHandle)
}
func SetDebug(d bool) {
debug = d
}
func ErrorHandle(err error) (int, any) {
return ErrorHandleCtx(context.Background(), err)
}
func ErrorHandleCtx(ctx context.Context, err error) (int, any) {
code := http.StatusBadRequest
reason := ErrInternalServer
var msg string
if ec, ok := err.(interface{ Code() int }); ok {
code = ec.Code()
}
if ec, ok := err.(interface{ Message() string }); ok {
msg = ec.Message()
} else {
msg = err.Error()
}
if ec, ok := err.(interface{ Reason() Reason }); ok {
reason = ec.Reason()
}
var errMsg string
if reason < ErrUnknownLogicError && reason != ErrSucceed {
errMsg = msg
msg = "system error"
}
body := map[string]any{
"code": reason,
"message": msg,
}
if errMsg != "" && debug {
body["err"] = errMsg
}
if ec, ok := err.(interface{ Metadata() any }); ok {
if md := ec.Metadata(); md != nil {
body["metadata"] = md
}
}
return code, body
}

View File

@@ -0,0 +1,33 @@
package errs
type Reason int
const (
// ======= 系统错误0~999 =======
ErrUnknownReason Reason = 0 // 未知错误
ErrSucceed Reason = 200 // 成功
ErrOverload Reason = 403 // 请求超载
// ======= 服务器内部错误1000~9999 =======
ErrInternalServer Reason = 1000 // 未知的服务器内部错误
ErrDatabaseOperate Reason = 1001 // 数据库错误
ErrRedisOperate Reason = 1002 // redis错误
ErrEncodePassword Reason = 1003 // 密码加密错误
ErrGenerateUUid Reason = 1004 // 生成uuid错误
ErrGenerateToken Reason = 1005 // 生成token错误
ErrGetExchangeRate Reason = 1005 // 获取汇率错误
// ======= 业务层错误10000~99999 =======
ErrUnknownLogicError Reason = 10000 // 未知的业务错误
ErrInvalidParam Reason = 10001 // 无效参数错误
ErrInvalidSignature Reason = 10002 // 无效签名错误
ErrInvalidToken Reason = 10003 // 无效的token
ErrInvoiceHasPaid Reason = 10004 // 订单已支付
ErrInvalidAppId Reason = 10005 // 应用id无效
ErrUserNotHasInviter Reason = 10006 // 用户没有邀请人
// ========= admin 业务相关错误码: 30000~39999 =========
ErrUnknownAdminError Reason = 30000 // 未知的admin错误
ErrInvalidPassword Reason = 30001 // 无效密码
ErrInvalidAccount Reason = 30002 // 无效账号
)

View File

@@ -0,0 +1,18 @@
package svc
import (
"nova_task/internal/config"
"nova_task/internal/model"
)
type ServiceContext struct {
Config config.Config
TaskModel model.NhTaskModel
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
TaskModel: model.NewNhTaskModel(c.MySql.Conn()),
}
}

33
internal/types/types.go Normal file
View File

@@ -0,0 +1,33 @@
// Code generated by goctl. DO NOT EDIT.
// goctl 1.7.3
package types
type GetTaskListReq struct {
CommunityId uint `form:"community_id"`
}
type GetTaskListResp struct {
Tasks []Task `json:"tasks"`
}
type GetTaskRewardReq struct {
ID uint `path:"id"`
}
type GetTaskRewardResp struct {
Points int `json:"points"`
}
type Task struct {
Id uint `json:"id"`
Title string `json:"title"`
SubTitle string `json:"sub_title"`
Description string `json:"description"`
Points int `json:"points"`
ButtonText string `json:"button_text"`
Type int8 `json:"type"`
StartAt string `json:"start_at"`
EndAt string `json:"end_at"`
Status int8 `json:"status"`
}

32
novatask.go Normal file
View File

@@ -0,0 +1,32 @@
package main
import (
"flag"
"fmt"
"nova_task/internal/config"
"nova_task/internal/handler"
"nova_task/internal/svc"
"github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/rest"
)
var configFile = flag.String("f", "etc/novatask.yaml", "the config file")
func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
c.MustSetUp()
server := rest.MustNewServer(c.RestConf)
defer server.Stop()
ctx := svc.NewServiceContext(c)
handler.RegisterHandlers(server, ctx)
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
server.Start()
}