Commit 2a47dede authored by 贾浩@五瓣科技's avatar 贾浩@五瓣科技

update

parent e99d95e9
FROM golang:1.21-alpine AS base FROM golang:1.21-alpine AS builder
# Set up dependencies WORKDIR /app
ENV PACKAGES git openssh-client build-base
# Install dependencies
RUN apk add --update $PACKAGES
# Add source files
RUN mkdir -p ./sdk-api
COPY ./ ./sdk-api/
FROM base AS build COPY . .
RUN cd sdk-api && go mod tidy && go build -v -o /tmp/api ./cmd/api && go build -v -o /tmp/messenger ./cmd/messenger RUN go mod tidy && go build -v -o /tmp/api ./cmd/api
FROM alpine FROM alpine:latest
WORKDIR /app WORKDIR /app
COPY ./config.toml /config.toml COPY ./config.toml .
COPY --from=build /tmp/api /usr/bin/api
COPY --from=build /tmp/messenger /usr/bin/messenger COPY --from=builder /tmp/api /usr/bin/api
EXPOSE 8080 EXPOSE 8080
\ No newline at end of file
debug = true debug = true
[mysql] [pgsql]
host = "127.0.0.1" host = "aws-0-ap-northeast-1.pooler.supabase.com"
port = 3306 port = 5432
user = "root" user = "postgres.vbxtvjffhsirnyxjcuku"
password = "" password = ""
database = "task" database = "postgres"
max_conn = 10 max_conn = 5
max_idle_conn = 2 max_idle_conn = 2
enable_log = true enable_log = true
cert_file = "ca.crt"
[server] [server]
listen = "0.0.0.0:8080" listen = "0.0.0.0:8080"
[tg_bot] [tg_task]
token = "6507972032:AAFAjaNz70ibA42kSH7k2gblyIQa1gWJiW0" url = "http://16.163.191.255:30001"
[twitter_task]
url = "http://43.198.54.207:8001"
\ No newline at end of file
...@@ -11,7 +11,7 @@ type Config struct { ...@@ -11,7 +11,7 @@ type Config struct {
PGSQL PGSQLConfig `toml:"pgsql"` PGSQL PGSQLConfig `toml:"pgsql"`
Server ServerConfig `toml:"server"` Server ServerConfig `toml:"server"`
TGTask TGTaskConfig `toml:"tg_task"` TGTask TGTaskConfig `toml:"tg_task"`
TweeterTask TweeterTaskConfig `toml:"tweeter_task"` TwitterTask TwitterTaskConfig `toml:"twitter_task"`
} }
type SupabaseConfig struct { type SupabaseConfig struct {
...@@ -30,13 +30,14 @@ type PGSQLConfig struct { ...@@ -30,13 +30,14 @@ type PGSQLConfig struct {
MaxConn int `toml:"max_conn"` MaxConn int `toml:"max_conn"`
MaxIdleConn int `toml:"max_idle_conn"` MaxIdleConn int `toml:"max_idle_conn"`
EnableLog bool `toml:"enable_log"` EnableLog bool `toml:"enable_log"`
CertFile string `toml:"cert_file"`
} }
type TGTaskConfig struct { type TGTaskConfig struct {
URL string `toml:"url"` URL string `toml:"url"`
} }
type TweeterTaskConfig struct { type TwitterTaskConfig struct {
URL string `toml:"url"` URL string `toml:"url"`
} }
......
...@@ -66,7 +66,7 @@ var TaskAction = map[string][]string{ ...@@ -66,7 +66,7 @@ var TaskAction = map[string][]string{
} }
const ( const (
TwitterAPIActionRetweeter = "retweeters" TwitterAPIActionRetwitter = "retweeters"
TwitterAPIActionLike = "like" TwitterAPIActionLike = "like"
TwitterAPIActionFollow = "follow" TwitterAPIActionFollow = "follow"
) )
...@@ -2,6 +2,7 @@ package dao ...@@ -2,6 +2,7 @@ package dao
import ( import (
"fmt" "fmt"
"os"
"sdk_api/config" "sdk_api/config"
dbModel "sdk_api/model/db" dbModel "sdk_api/model/db"
"time" "time"
...@@ -27,8 +28,8 @@ func New(_c *config.Config) (dao *Dao, err error) { ...@@ -27,8 +28,8 @@ func New(_c *config.Config) (dao *Dao, err error) {
// dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True", // dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True",
// _c.PGSQL.User, _c.PGSQL.Password, _c.PGSQL.Host, _c.PGSQL.Port, _c.PGSQL.Database) // _c.PGSQL.User, _c.PGSQL.Password, _c.PGSQL.Host, _c.PGSQL.Port, _c.PGSQL.Database)
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%d sslmode=verify-ca sslrootcert=ca.crt", dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%d sslmode=verify-ca sslrootcert=%s",
_c.PGSQL.Host, _c.PGSQL.User, _c.PGSQL.Password, _c.PGSQL.Database, _c.PGSQL.Port, _c.PGSQL.Host, _c.PGSQL.User, _c.PGSQL.Password, _c.PGSQL.Database, _c.PGSQL.Port, _c.PGSQL.CertFile,
) )
lgr := logger.Default lgr := logger.Default
...@@ -53,6 +54,8 @@ func New(_c *config.Config) (dao *Dao, err error) { ...@@ -53,6 +54,8 @@ func New(_c *config.Config) (dao *Dao, err error) {
sqlDB.SetMaxOpenConns(_c.PGSQL.MaxConn) sqlDB.SetMaxOpenConns(_c.PGSQL.MaxConn)
sqlDB.SetMaxIdleConns(_c.PGSQL.MaxIdleConn) sqlDB.SetMaxIdleConns(_c.PGSQL.MaxIdleConn)
sqlDB.SetConnMaxIdleTime(time.Hour) sqlDB.SetConnMaxIdleTime(time.Hour)
if os.Getenv("MIGRATE") == "true" {
err = dao.db.AutoMigrate(&dbModel.TaskAction{}, &dbModel.Project{}, &dbModel.TaskGroup{}, &dbModel.Task{}, &dbModel.TaskHistory{}) err = dao.db.AutoMigrate(&dbModel.TaskAction{}, &dbModel.Project{}, &dbModel.TaskGroup{}, &dbModel.Task{}, &dbModel.TaskHistory{})
if err != nil { if err != nil {
return return
...@@ -60,5 +63,7 @@ func New(_c *config.Config) (dao *Dao, err error) { ...@@ -60,5 +63,7 @@ func New(_c *config.Config) (dao *Dao, err error) {
if err = dao.InitTaskAction(); err != nil { if err = dao.InitTaskAction(); err != nil {
panic(err) panic(err)
} }
}
return dao, nil return dao, nil
} }
...@@ -31,8 +31,13 @@ func (d *Dao) CreateProject(p *dbModel.Project) (err error) { ...@@ -31,8 +31,13 @@ func (d *Dao) CreateProject(p *dbModel.Project) (err error) {
return d.db.Create(p).Error return d.db.Create(p).Error
} }
func (d *Dao) GetProjectList(page, pageSize int) (list []*dbModel.Project, err error) { func (d *Dao) GetProjectList(page, pageSize int) (list []*dbModel.Project, totalCount int, err error) {
return list, d.db.Limit(pageSize).Offset((page - 1) * pageSize).Find(&list).Error var tmpCount int64
err = d.db.Model(&dbModel.Project{}).Count(&tmpCount).Error
if err != nil {
return
}
return list, int(tmpCount), d.db.Limit(pageSize).Offset((page - 1) * pageSize).Find(&list).Error
} }
func (d *Dao) GetProject(id int) (p *dbModel.Project, err error) { func (d *Dao) GetProject(id int) (p *dbModel.Project, err error) {
...@@ -48,8 +53,14 @@ func (d *Dao) CreateGroup(g *dbModel.TaskGroup) (err error) { ...@@ -48,8 +53,14 @@ func (d *Dao) CreateGroup(g *dbModel.TaskGroup) (err error) {
return d.db.Create(g).Error return d.db.Create(g).Error
} }
func (d *Dao) GetGroupList(page, pageSize int) (list []*dbModel.TaskGroup, err error) { func (d *Dao) GetGroupList(page, pageSize int) (list []*dbModel.TaskGroup, totalCount int, err error) {
return list, d.db.Limit(pageSize).Offset((page - 1) * pageSize).Find(&list).Error var tmpCount int64
err = d.db.Model(&dbModel.TaskGroup{}).Count(&tmpCount).Error
if err != nil {
return
}
totalCount = int(tmpCount)
return list, totalCount, d.db.Limit(pageSize).Offset((page - 1) * pageSize).Find(&list).Error
} }
func (d *Dao) GetGroup(id int) (g *dbModel.TaskGroup, err error) { func (d *Dao) GetGroup(id int) (g *dbModel.TaskGroup, err error) {
......
...@@ -13,6 +13,22 @@ import ( ...@@ -13,6 +13,22 @@ import (
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
) )
func (d *Dao) GetTGGroupInfo(chatId int) (title, username string, err error) {
url := fmt.Sprintf("%s/api/v1/chat?chatId=%d", strings.TrimSuffix(d.c.TGTask.URL, "/"), chatId)
log.WithField("url", url).Debug("get tg group info")
data, err := httpGet(url)
if err != nil {
return
}
retCode := gjson.Get(string(data), "code").Int()
if retCode == 1 {
return "", "", errors.New(string(data))
}
return gjson.Get(string(data), "data.title").String(), gjson.Get(string(data), "data.username").String(), nil
}
func (d *Dao) CheckTGJoin(userId string, chatId int) (ok bool, err error) { func (d *Dao) CheckTGJoin(userId string, chatId int) (ok bool, err error) {
url := fmt.Sprintf("%s/api/v1/user/joined?chatId=%d&userId=%s", strings.TrimSuffix(d.c.TGTask.URL, "/"), chatId, userId) url := fmt.Sprintf("%s/api/v1/user/joined?chatId=%d&userId=%s", strings.TrimSuffix(d.c.TGTask.URL, "/"), chatId, userId)
log.WithField("url", url).Debug("check tg join") log.WithField("url", url).Debug("check tg join")
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"strconv"
"strings" "strings"
"time" "time"
...@@ -12,10 +13,10 @@ import ( ...@@ -12,10 +13,10 @@ import (
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
) )
func (d *Dao) CreateTwitterProject(apiKey, apiSecret, accessToken, accessSecret, token, projectName string) (tweetId, tweetHandle, tweetName string, err error) { func (d *Dao) CreateTwitterProject(apiKey, apiSecret, accessToken, accessSecret, token, projectName string) (twitterUserId int, twitterHandle, twitterName string, err error) {
body := map[string]string{ body := map[string]string{
"api_key": apiKey, "api_key": apiKey,
"api_secret": apiSecret, "api_key_secret": apiSecret,
"access_token": accessToken, "access_token": accessToken,
"access_token_secret": accessSecret, "access_token_secret": accessSecret,
"token": token, "token": token,
...@@ -26,8 +27,7 @@ func (d *Dao) CreateTwitterProject(apiKey, apiSecret, accessToken, accessSecret, ...@@ -26,8 +27,7 @@ func (d *Dao) CreateTwitterProject(apiKey, apiSecret, accessToken, accessSecret,
if err != nil { if err != nil {
return return
} }
resp, err := httpPost(fmt.Sprintf("%s/project", strings.TrimRight(d.c.TwitterTask.URL, "/")), buf)
resp, err := httpPost(fmt.Sprintf("%s/project", strings.TrimRight(d.c.TweeterTask.URL, "/")), buf)
if err != nil { if err != nil {
return return
} }
...@@ -47,18 +47,21 @@ func (d *Dao) CreateTwitterProject(apiKey, apiSecret, accessToken, accessSecret, ...@@ -47,18 +47,21 @@ func (d *Dao) CreateTwitterProject(apiKey, apiSecret, accessToken, accessSecret,
return return
} }
if respTemp.Code != 200 && respTemp.Msg != "task already existed" { // if respTemp.Code != 200 && respTemp.Msg != "task already existed" {
if respTemp.Code != 200 && respTemp.Msg != "already existed" {
err = errors.New(string(resp)) err = errors.New(string(resp))
return return
} }
return respTemp.Data.UserID, respTemp.Data.Username, respTemp.Data.Name, nil userId, _ := strconv.Atoi(respTemp.Data.UserID)
return userId, respTemp.Data.Username, respTemp.Data.Name, nil
} }
func (d *Dao) DoTweetTask(tweetUserId, tweetId, action string, start bool) (err error) { func (d *Dao) DoTweetTask(twitterUserId int, tweetId int, action string, start bool) (err error) {
body := map[string]string{ body := map[string]string{
"user_id": tweetUserId, "user_id": fmt.Sprintf("%d", twitterUserId),
"task_id": tweetId, "task_id": fmt.Sprintf("%d", tweetId),
"task_type": action, "task_type": action,
} }
...@@ -68,9 +71,11 @@ func (d *Dao) DoTweetTask(tweetUserId, tweetId, action string, start bool) (err ...@@ -68,9 +71,11 @@ func (d *Dao) DoTweetTask(tweetUserId, tweetId, action string, start bool) (err
return return
} }
url := fmt.Sprintf("%s/task/add", strings.TrimRight(d.c.TweeterTask.URL, "/")) log.Info(buf.String())
url := fmt.Sprintf("%s/task/add", strings.TrimRight(d.c.TwitterTask.URL, "/"))
if !start { if !start {
url = fmt.Sprintf("%s/task/stop", strings.TrimRight(d.c.TweeterTask.URL, "/")) url = fmt.Sprintf("%s/task/stop", strings.TrimRight(d.c.TwitterTask.URL, "/"))
} }
resp, err := httpPost(url, buf) resp, err := httpPost(url, buf)
...@@ -78,15 +83,15 @@ func (d *Dao) DoTweetTask(tweetUserId, tweetId, action string, start bool) (err ...@@ -78,15 +83,15 @@ func (d *Dao) DoTweetTask(tweetUserId, tweetId, action string, start bool) (err
return return
} }
if gjson.Get(string(resp), "code").Int() != 200 { if gjson.Get(string(resp), "code").Int() != 200 && gjson.Get(string(resp), "msg").String() != "task already existed" {
return errors.New(string(resp)) return errors.New(string(resp))
} }
return return
} }
func (d *Dao) CheckTweeterFollow(userId, followerId string) (ok bool, err error) { func (d *Dao) CheckTwitterFollow(userId int, followerId string) (ok bool, err error) {
url := fmt.Sprintf("%s/verify/follow?user_id=%s&follower_id=%s", strings.TrimSuffix(d.c.TweeterTask.URL, "/"), userId, followerId) url := fmt.Sprintf("%s/verify/follow?user_id=%d&follower_id=%s", strings.TrimSuffix(d.c.TwitterTask.URL, "/"), userId, followerId)
log.WithField("url", url).Debug("check tweet follow") log.WithField("url", url).Debug("check tweet follow")
data, err := httpGet(url) data, err := httpGet(url)
if err != nil { if err != nil {
...@@ -99,8 +104,8 @@ func (d *Dao) CheckTweeterFollow(userId, followerId string) (ok bool, err error) ...@@ -99,8 +104,8 @@ func (d *Dao) CheckTweeterFollow(userId, followerId string) (ok bool, err error)
return gjson.Get(string(data), "data.ok").Bool(), nil return gjson.Get(string(data), "data.ok").Bool(), nil
} }
func (d *Dao) CheckTweeterLike(tweetId, userId string, begin, end int) (ok bool, err error) { func (d *Dao) CheckTwitterLike(tweetId int, userId string, begin, end int) (ok bool, err error) {
url := fmt.Sprintf("%s/verify/like?tweet_id=%s&user_id=%s", strings.TrimSuffix(d.c.TweeterTask.URL, "/"), tweetId, userId) url := fmt.Sprintf("%s/verify/like?tweet_id=%d&user_id=%s", strings.TrimSuffix(d.c.TwitterTask.URL, "/"), tweetId, userId)
if begin != 0 && end != 0 { if begin != 0 && end != 0 {
url += fmt.Sprintf("&begin=%s&end=%s", time.Unix(int64(begin), 0).Format(time.RFC3339), time.Unix(int64(end), 0).Format(time.RFC3339)) url += fmt.Sprintf("&begin=%s&end=%s", time.Unix(int64(begin), 0).Format(time.RFC3339), time.Unix(int64(end), 0).Format(time.RFC3339))
} }
...@@ -117,8 +122,8 @@ func (d *Dao) CheckTweeterLike(tweetId, userId string, begin, end int) (ok bool, ...@@ -117,8 +122,8 @@ func (d *Dao) CheckTweeterLike(tweetId, userId string, begin, end int) (ok bool,
return gjson.Get(string(data), "data.ok").Bool(), nil return gjson.Get(string(data), "data.ok").Bool(), nil
} }
func (d *Dao) CheckTweeterRetweet(tweetId, userId string, begin, end int) (ok bool, err error) { func (d *Dao) CheckTwitterRetweet(tweetId int, userId string, begin, end int) (ok bool, err error) {
url := fmt.Sprintf("%s/verify/retweeter?tweet_id=%s&retweeter_id=%s", strings.TrimSuffix(d.c.TweeterTask.URL, "/"), tweetId, userId) url := fmt.Sprintf("%s/verify/retweeter?tweet_id=%d&retweeter_id=%s", strings.TrimSuffix(d.c.TwitterTask.URL, "/"), tweetId, userId)
if begin != 0 && end != 0 { if begin != 0 && end != 0 {
url += fmt.Sprintf("&begin=%s&end=%s", time.Unix(int64(begin), 0).Format(time.RFC3339), time.Unix(int64(end), 0).Format(time.RFC3339)) url += fmt.Sprintf("&begin=%s&end=%s", time.Unix(int64(begin), 0).Format(time.RFC3339), time.Unix(int64(end), 0).Format(time.RFC3339))
} }
......
...@@ -2,31 +2,43 @@ package api_model ...@@ -2,31 +2,43 @@ package api_model
type CreateProjectRequest struct { type CreateProjectRequest struct {
ProjectName string `json:"projectName" binding:"required"` ProjectName string `json:"projectName" binding:"required"`
Description string `json:"description" binding:"required"` Description string `json:"description"`
TweeterAPIKey string `json:"tweeterAPIKey" binding:"required"` TwitterAPIKey string `json:"twitterAPIKey" binding:"required"`
TweeterAPISecret string `json:"tweeterAPISecret" binding:"required"` TwitterAPISecret string `json:"twitterAPISecret" binding:"required"`
TweeterAccessToken string `json:"tweeterAccessToken" binding:"required"` TwitterAccessToken string `json:"twitterAccessToken" binding:"required"`
TweeterAccessSecret string `json:"tweeterAccessSecret" binding:"required"` TwitterAccessSecret string `json:"twitterAccessSecret" binding:"required"`
TweeterToken string `json:"tweeterToken" binding:"required"` TwitterToken string `json:"twitterToken" binding:"required"`
TelegramChatId int `json:"telegramChatId" binding:"required"` TelegramChatId int `json:"telegramChatId" binding:"required"`
} }
type CreateProjectResponse struct {
ProjectId int `json:"projectId"`
TwitterHandle string `json:"twitterHandle"`
TwitterName string `json:"twitterName"`
TelegramChatTitle string `json:"telegramChatTitle"`
TelegramChatUsername string `json:"telegramChatUsername"`
}
type GetProjectResponse struct { type GetProjectResponse struct {
ProjectId int `json:"projectId,omitempty"`
TelegramChatId int `json:"telegramChatId"` TelegramChatId int `json:"telegramChatId"`
TelegramChatUsername string `json:"telegramChatUsername"`
TelegramChatTitle string `json:"telegramChatTitle"`
TwitterHandle string `json:"twitterHandle"` TwitterHandle string `json:"twitterHandle"`
TweeterName string `json:"tweeterName"` TwitterName string `json:"twitterName"`
TweeterUserId string `json:"tweeterUserId"` TwitterUserId int `json:"twitterUserId"`
ProjectName string `json:"projectName"` ProjectName string `json:"projectName"`
Description string `json:"description"` Description string `json:"description"`
TweeterAPIKey string `json:"tweeterAPIKey,omitempty"` TwitterAPIKey string `json:"twitterAPIKey,omitempty"`
TweeterAPISecret string `json:"tweeterAPISecret,omitempty"` TwitterAPISecret string `json:"twitterAPISecret,omitempty"`
TweeterAccessToken string `json:"tweeterAccessToken,omitempty"` TwitterAccessToken string `json:"twitterAccessToken,omitempty"`
TweeterAccessSecret string `json:"tweeterAccessSecret,omitempty"` TwitterAccessSecret string `json:"twitterAccessSecret,omitempty"`
TweeterToken string `json:"tweeterToken,omitempty"` TwitterToken string `json:"twitterToken,omitempty"`
} }
type CreateGroupRequest struct { type CreateGroupRequest struct {
ProjectId int `json:"projectId" binding:"required"` ProjectId int `json:"projectId" binding:"required"`
GroupId int `json:"groupId,omitempty"`
Description string `json:"description"` Description string `json:"description"`
Tasks []Task `json:"tasks"` Tasks []Task `json:"tasks"`
} }
...@@ -35,10 +47,8 @@ type Task struct { ...@@ -35,10 +47,8 @@ type Task struct {
TaskId int `json:"taskId,omitempty"` TaskId int `json:"taskId,omitempty"`
Platform string `json:"platform" binding:"required"` Platform string `json:"platform" binding:"required"`
Action string `json:"action" binding:"required"` Action string `json:"action" binding:"required"`
Url string `json:"url" binding:"required"` Url string `json:"url"`
TwitterUserId string `json:"twitterUserId"` TweetId int `json:"tweetId"`
TelegramChatId int `json:"telegramChatId"`
TweetId string `json:"tweetId"`
Description string `json:"description" binding:"required"` Description string `json:"description" binding:"required"`
Reward int `json:"reward" binding:"required"` Reward int `json:"reward" binding:"required"`
Start int `json:"start" binding:"required"` Start int `json:"start" binding:"required"`
...@@ -47,3 +57,13 @@ type Task struct { ...@@ -47,3 +57,13 @@ type Task struct {
} }
type GetGroupResponse CreateGroupRequest type GetGroupResponse CreateGroupRequest
type GetGroupListResponse struct {
TotalCount int `json:"totalCount"`
Items []*GetGroupResponse `json:"items"`
}
type GetProjectListResponse struct {
TotalCount int `json:"totalCount"`
Items []*GetProjectResponse `json:"items"`
}
...@@ -4,7 +4,6 @@ import ( ...@@ -4,7 +4,6 @@ import (
"time" "time"
"gorm.io/datatypes" "gorm.io/datatypes"
"gorm.io/gorm"
) )
type Identity struct { type Identity struct {
...@@ -15,7 +14,8 @@ type Identity struct { ...@@ -15,7 +14,8 @@ type Identity struct {
Provider string `gorm:"type:text;not null;comment:第三方用户平台"` Provider string `gorm:"type:text;not null;comment:第三方用户平台"`
LastSignInAt time.Time `gorm:"type:timestamp;not null;comment:最后登录时间"` LastSignInAt time.Time `gorm:"type:timestamp;not null;comment:最后登录时间"`
Email string `gorm:"type:text;not null;comment:用户邮箱"` Email string `gorm:"type:text;not null;comment:用户邮箱"`
gorm.Model CreatedAt time.Time
UpdatedAt time.Time
} }
func (*Identity) TableName() string { func (*Identity) TableName() string {
......
...@@ -19,15 +19,17 @@ type Project struct { ...@@ -19,15 +19,17 @@ type Project struct {
Id int `gorm:"primaryKey;autoIncrement:false"` Id int `gorm:"primaryKey;autoIncrement:false"`
Name string `gorm:"type:text;not null;comment:项目名称"` Name string `gorm:"type:text;not null;comment:项目名称"`
Description string `gorm:"type:text;not null;comment:项目描述"` Description string `gorm:"type:text;not null;comment:项目描述"`
TweeterAPIKey string `gorm:"type:text;not null;comment:tweet api key"` TwitterAPIKey string `gorm:"type:text;not null;comment:tweet api key"`
TweeterAPISecret string `gorm:"type:text;not null;comment:tweet api secret"` TwitterAPISecret string `gorm:"type:text;not null;comment:tweet api secret"`
TweeterAccessToken string `gorm:"type:text;not null;comment:tweet access token"` TwitterAccessToken string `gorm:"type:text;not null;comment:tweet access token"`
TweeterAccessSecret string `gorm:"type:text;not null;comment:tweet access secret"` TwitterAccessSecret string `gorm:"type:text;not null;comment:tweet access secret"`
TweeterToken string `gorm:"type:text;not null;comment:tweet token"` TwitterToken string `gorm:"type:text;not null;comment:tweet token"`
TweeterHandle string `gorm:"type:text;not null;comment:tweet handle"` TwitterHandle string `gorm:"type:text;not null;comment:tweet handle"`
TweeterName string `gorm:"type:text;not null;comment:tweet name"` TwitterName string `gorm:"type:text;not null;comment:tweet name"`
TweeterUserId string `gorm:"type:text;not null;comment:tweet user id"` TwitterUserId int `gorm:"type:int;not null;comment:tweet user id"`
TelegramChatId int `gorm:"type:int;not null;comment:telegram chat id"` TelegramChatId int `gorm:"type:int;not null;comment:telegram chat id"`
TelegramChatUsername string `gorm:"type:text;not null;comment:telegram chat username"`
TelegramChatTitle string `gorm:"type:text;not null;comment:telegram chat title"`
gorm.Model gorm.Model
Groups []*TaskGroup Groups []*TaskGroup
...@@ -54,9 +56,11 @@ type Task struct { ...@@ -54,9 +56,11 @@ type Task struct {
Platform string `gorm:"type:text;not null;comment:任务平台"` Platform string `gorm:"type:text;not null;comment:任务平台"`
Action string `gorm:"type:text;not null;comment:任务动作"` Action string `gorm:"type:text;not null;comment:任务动作"`
Url string `gorm:"type:text;not null;comment:任务链接"` Url string `gorm:"type:text;not null;comment:任务链接"`
TweeterUserId string `gorm:"type:int;not null;comment:tweet用户id,用于关注"` TwitterUserId int `gorm:"type:int;not null;comment:tweet user id,用于关注"`
TweetId string `gorm:"type:int;not null;comment:推文id,用于转发点赞"` TwitterHandle string `gorm:"type:text;not null;comment:tweet handle,用于关注"`
TweetId int `gorm:"type:int;not null;comment:推文id,用于转发点赞"`
TelegramChatId int `gorm:"type:int;not null;comment:telegram群id"` TelegramChatId int `gorm:"type:int;not null;comment:telegram群id"`
TelegramChatUsername string `gorm:"type:text;not null;comment:telegram群用户名"`
Description string `gorm:"type:text;not null;comment:任务描述"` Description string `gorm:"type:text;not null;comment:任务描述"`
Reward int `gorm:"type:int;not null;comment:任务奖励"` Reward int `gorm:"type:int;not null;comment:任务奖励"`
Start int `gorm:"type:int;not null;comment:任务开始时间"` Start int `gorm:"type:int;not null;comment:任务开始时间"`
......
# telegram-任务中心 # 任务中心
和sdk部分共用一个数据库,启动&停止命令 启动&停止命令
``` ```
docker compose up -d tg-messenger-api docker compose up -d
docker compose down tg-messenger-api docker compose down
``` ```
\ No newline at end of file
...@@ -6,11 +6,13 @@ import ( ...@@ -6,11 +6,13 @@ import (
"strconv" "strconv"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
) )
func createGroup(c *gin.Context) { func createGroup(c *gin.Context) {
req := &apiModel.CreateGroupRequest{} req := &apiModel.CreateGroupRequest{}
if err := c.ShouldBindJSON(req); err != nil { if err := c.ShouldBindJSON(req); err != nil {
log.Info("11111", err)
c.JSON(200, withError(constant.InvalidParam)) c.JSON(200, withError(constant.InvalidParam))
return return
} }
...@@ -33,6 +35,7 @@ func createGroup(c *gin.Context) { ...@@ -33,6 +35,7 @@ func createGroup(c *gin.Context) {
for _, task := range req.Tasks { for _, task := range req.Tasks {
if !constant.IsValidAction(task.Action) || !constant.IsValidPlatform(task.Platform) { if !constant.IsValidAction(task.Action) || !constant.IsValidPlatform(task.Platform) {
log.Info("1111", task.Action, task.Platform)
c.JSON(200, withError(constant.InvalidParam)) c.JSON(200, withError(constant.InvalidParam))
return return
} }
...@@ -45,7 +48,7 @@ func createGroup(c *gin.Context) { ...@@ -45,7 +48,7 @@ func createGroup(c *gin.Context) {
// return // return
// } // }
if task.Platform == constant.TaskPlatformTwitter && task.Action == constant.TaskActionFollow && task.TweetId == "" { if task.Platform == constant.TaskPlatformTwitter && task.Action != constant.TaskActionFollow && task.TweetId == 0 {
c.JSON(200, withError(constant.InvalidParam)) c.JSON(200, withError(constant.InvalidParam))
return return
} }
...@@ -75,3 +78,22 @@ func getGroup(c *gin.Context) { ...@@ -75,3 +78,22 @@ func getGroup(c *gin.Context) {
} }
c.JSON(200, withSuccess(resp)) c.JSON(200, withSuccess(resp))
} }
func listGroup(c *gin.Context) {
_page := c.DefaultQuery("page", "1")
_pageSize := c.DefaultQuery("pageSize", "10")
page, _ := strconv.Atoi(_page)
pageSize, _ := strconv.Atoi(_pageSize)
if page < 1 || pageSize < 1 || pageSize > 100 {
c.JSON(200, withError(constant.InvalidParam))
return
}
resp, err := srv.GetGroupList(page, pageSize)
if err != nil {
c.JSON(200, withError(constant.InternalError))
return
}
c.JSON(200, withSuccess(resp))
}
package server package server
import ( import (
"fmt"
"sdk_api/constant" "sdk_api/constant"
apiModel "sdk_api/model/api" apiModel "sdk_api/model/api"
"strconv" "strconv"
...@@ -11,16 +12,17 @@ import ( ...@@ -11,16 +12,17 @@ import (
func createProject(c *gin.Context) { func createProject(c *gin.Context) {
req := &apiModel.CreateProjectRequest{} req := &apiModel.CreateProjectRequest{}
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
fmt.Println(err)
c.JSON(200, withError(constant.InvalidParam)) c.JSON(200, withError(constant.InvalidParam))
return return
} }
pid, err := srv.CreateProject(req) resp, err := srv.CreateProject(req)
if err != nil { if err != nil {
c.JSON(200, withError(constant.InternalError)) c.JSON(200, withError(constant.InternalError))
return return
} }
c.JSON(200, withSuccess(gin.H{"projectId": pid})) c.JSON(200, withSuccess(resp))
} }
func listProject(c *gin.Context) { func listProject(c *gin.Context) {
......
...@@ -21,6 +21,7 @@ func initRouter(e *gin.Engine) { ...@@ -21,6 +21,7 @@ func initRouter(e *gin.Engine) {
{ {
group := v1.Group("/group") group := v1.Group("/group")
group.GET("/:gid", getGroup) // 获取任务组任务详情 group.GET("/:gid", getGroup) // 获取任务组任务详情
group.GET("/list", listGroup) // 获取任务组任务详情
group.POST("/create", createGroup) // 创建任务组 group.POST("/create", createGroup) // 创建任务组
} }
......
...@@ -30,6 +30,7 @@ func checkTask(c *gin.Context) { ...@@ -30,6 +30,7 @@ func checkTask(c *gin.Context) {
if done || expired { if done || expired {
c.JSON(200, withSuccess(gin.H{"done": done})) c.JSON(200, withSuccess(gin.H{"done": done}))
return
} }
done, err = srv.SyncTask(taskId, userId) done, err = srv.SyncTask(taskId, userId)
......
package service package service
import ( import (
"fmt"
"sdk_api/constant" "sdk_api/constant"
apiModel "sdk_api/model/api" apiModel "sdk_api/model/api"
dbModel "sdk_api/model/db" dbModel "sdk_api/model/db"
...@@ -21,7 +22,7 @@ func (s *Service) CreateGroup(req *apiModel.CreateGroupRequest) (gid int, err er ...@@ -21,7 +22,7 @@ func (s *Service) CreateGroup(req *apiModel.CreateGroupRequest) (gid int, err er
return return
} }
project, err := s.GetProject(req.ProjectId) project, err := s.d.GetProject(req.ProjectId)
if err != nil { if err != nil {
log.WithError(err).Error("get project error") log.WithError(err).Error("get project error")
return 0, err return 0, err
...@@ -37,7 +38,8 @@ func (s *Service) CreateGroup(req *apiModel.CreateGroupRequest) (gid int, err er ...@@ -37,7 +38,8 @@ func (s *Service) CreateGroup(req *apiModel.CreateGroupRequest) (gid int, err er
GroupId: g.Id, GroupId: g.Id,
Platform: task.Platform, Platform: task.Platform,
Action: task.Action, Action: task.Action,
Url: task.Url, TwitterHandle: project.TwitterHandle,
TwitterUserId: project.TwitterUserId,
Description: task.Description, Description: task.Description,
Reward: task.Reward, Reward: task.Reward,
Start: task.Start, Start: task.Start,
...@@ -45,27 +47,26 @@ func (s *Service) CreateGroup(req *apiModel.CreateGroupRequest) (gid int, err er ...@@ -45,27 +47,26 @@ func (s *Service) CreateGroup(req *apiModel.CreateGroupRequest) (gid int, err er
Daily: daily, Daily: daily,
} }
if task.Platform == constant.TaskPlatformTwitter { if task.Platform == constant.TaskPlatformTwitter {
if task.Action == constant.TaskActionFollow {
gt.TweeterUserId = project.TweeterUserId
} else {
gt.TweetId = task.TweetId
}
var twitterAPIAction string var twitterAPIAction string
switch task.Action { switch task.Action {
case constant.TaskActionFollow: case constant.TaskActionFollow:
twitterAPIAction = constant.TwitterAPIActionFollow twitterAPIAction = constant.TwitterAPIActionFollow
gt.Url = fmt.Sprintf("https://x.com/intent/follow?screen_name=%s", project.TwitterHandle)
case constant.TaskActionLike: case constant.TaskActionLike:
twitterAPIAction = constant.TwitterAPIActionLike twitterAPIAction = constant.TwitterAPIActionLike
gt.TweetId = task.TweetId
gt.Url = fmt.Sprintf("https://x.com/intent/like?tweet_id=%d", task.TweetId)
case constant.TaskActionRetweet: case constant.TaskActionRetweet:
twitterAPIAction = constant.TwitterAPIActionRetweeter twitterAPIAction = constant.TwitterAPIActionRetwitter
gt.TweetId = task.TweetId
gt.Url = fmt.Sprintf("https://x.com/intent/retweet?tweet_id=%d", task.TweetId)
} }
tweetId := gt.TweetId tweetId := gt.TweetId
if task.Action == constant.TaskActionFollow { if task.Action == constant.TaskActionFollow {
tweetId = gt.TweeterUserId tweetId = gt.TwitterUserId
} }
// 推特任务中心,启动任务 // 推特任务中心,启动任务
err = s.d.DoTweetTask(gt.TweeterUserId, tweetId, twitterAPIAction, true) err = s.d.DoTweetTask(gt.TwitterUserId, tweetId, twitterAPIAction, true)
if err != nil { if err != nil {
log.WithError(err).Error("do tweet task error") log.WithError(err).Error("do tweet task error")
return 0, err return 0, err
...@@ -74,6 +75,8 @@ func (s *Service) CreateGroup(req *apiModel.CreateGroupRequest) (gid int, err er ...@@ -74,6 +75,8 @@ func (s *Service) CreateGroup(req *apiModel.CreateGroupRequest) (gid int, err er
} }
if task.Platform == constant.TaskPlatformTelegram { if task.Platform == constant.TaskPlatformTelegram {
gt.TelegramChatId = project.TelegramChatId gt.TelegramChatId = project.TelegramChatId
gt.TelegramChatUsername = project.TelegramChatUsername
gt.Url = fmt.Sprintf("https://t.me/%s", project.TelegramChatUsername)
} }
err = s.d.CreateGroupTask(gt) err = s.d.CreateGroupTask(gt)
...@@ -97,6 +100,9 @@ func (s *Service) GetGroup(gid int) (resp *apiModel.GetGroupResponse, err error) ...@@ -97,6 +100,9 @@ func (s *Service) GetGroup(gid int) (resp *apiModel.GetGroupResponse, err error)
return nil, nil return nil, nil
} }
resp.ProjectId = g.ProjectId
resp.Description = g.Description
tasks, err := s.d.GetGroupTasks(g.Id) tasks, err := s.d.GetGroupTasks(g.Id)
if err != nil { if err != nil {
log.WithError(err).Error("get group tasks error") log.WithError(err).Error("get group tasks error")
...@@ -114,7 +120,50 @@ func (s *Service) GetGroup(gid int) (resp *apiModel.GetGroupResponse, err error) ...@@ -114,7 +120,50 @@ func (s *Service) GetGroup(gid int) (resp *apiModel.GetGroupResponse, err error)
Start: task.Start, Start: task.Start,
End: task.End, End: task.End,
Daily: task.Daily == 1, Daily: task.Daily == 1,
TweetId: task.TweetId,
})
}
return
}
func (s *Service) GetGroupList(page, pageSize int) (resp *apiModel.GetGroupListResponse, err error) {
resp = &apiModel.GetGroupListResponse{}
list, count, err := s.d.GetGroupList(page, pageSize)
if err != nil {
log.WithError(err).Error("get group list error")
return
}
resp.TotalCount = count
resp.Items = make([]*apiModel.GetGroupResponse, 0)
for _, v := range list {
resp.Items = append(resp.Items, &apiModel.GetGroupResponse{
GroupId: v.Id,
ProjectId: v.ProjectId,
Description: v.Description,
})
tasks, err := s.d.GetGroupTasks(v.Id)
if err != nil {
log.WithError(err).Error("get group tasks error")
return resp, err
}
log.Error("len: ", len(tasks))
for _, task := range tasks {
resp.Items[len(resp.Items)-1].Tasks = append(resp.Items[len(resp.Items)-1].Tasks, apiModel.Task{
TaskId: task.Id,
Platform: task.Platform,
Action: task.Action,
Url: task.Url,
Description: task.Description,
Reward: task.Reward,
Start: task.Start,
End: task.End,
Daily: task.Daily == 1,
TweetId: task.TweetId,
}) })
} }
}
return return
} }
...@@ -8,49 +8,70 @@ import ( ...@@ -8,49 +8,70 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
func (s *Service) CreateProject(req *apiModel.CreateProjectRequest) (pid int, err error) { func (s *Service) CreateProject(req *apiModel.CreateProjectRequest) (resp *apiModel.CreateProjectResponse, err error) {
tweetId, tweetHandle, tweetName, err := s.d.CreateTwitterProject(req.TweeterAPIKey, req.TweeterAPISecret, req.TweeterAccessToken, req.TweeterAccessSecret, req.TweeterToken, req.ProjectName) resp = &apiModel.CreateProjectResponse{}
twitterUserId, twitterHandle, twitterName, err := s.d.CreateTwitterProject(req.TwitterAPIKey, req.TwitterAPISecret, req.TwitterAccessToken, req.TwitterAccessSecret, req.TwitterToken, req.ProjectName)
if err != nil { if err != nil {
log.WithError(err).Error("create twitter project error") log.WithError(err).Error("create twitter project error")
return return
} }
tgTitle, tgUsername, err := s.d.GetTGGroupInfo(req.TelegramChatId)
if err != nil {
log.WithError(err).Error("get telegram group info error")
return
}
p := &dbModel.Project{ p := &dbModel.Project{
Id: util.GenFlakeID(), Id: util.GenFlakeID(),
Name: req.ProjectName, Name: req.ProjectName,
Description: req.Description, Description: req.Description,
TweeterAPIKey: req.TweeterAPIKey, TwitterAPIKey: req.TwitterAPIKey,
TweeterAPISecret: req.TweeterAPISecret, TwitterAPISecret: req.TwitterAPISecret,
TweeterAccessToken: req.TweeterAccessToken, TwitterAccessToken: req.TwitterAccessToken,
TweeterAccessSecret: req.TweeterAccessSecret, TwitterAccessSecret: req.TwitterAccessSecret,
TweeterToken: req.TweeterToken, TwitterToken: req.TwitterToken,
TweeterHandle: tweetHandle, TwitterHandle: twitterHandle,
TweeterName: tweetName, TwitterName: twitterName,
TweeterUserId: tweetId, TwitterUserId: twitterUserId,
TelegramChatId: req.TelegramChatId, TelegramChatId: req.TelegramChatId,
TelegramChatTitle: tgTitle,
TelegramChatUsername: tgUsername,
} }
err = s.d.CreateProject(p) err = s.d.CreateProject(p)
if err != nil { if err != nil {
log.WithError(err).Error("create project error") log.WithError(err).Error("create project error")
return return
} }
return p.Id, nil
resp.TelegramChatUsername = tgUsername
resp.TelegramChatTitle = tgTitle
resp.TwitterName = twitterName
resp.TwitterHandle = twitterHandle
resp.ProjectId = p.Id
return
} }
func (s *Service) GetProjectList(page, pageSize int) (resp []*apiModel.GetProjectResponse, err error) { func (s *Service) GetProjectList(page, pageSize int) (resp *apiModel.GetProjectListResponse, err error) {
list, err := s.d.GetProjectList(page, pageSize) resp = &apiModel.GetProjectListResponse{}
list, count, err := s.d.GetProjectList(page, pageSize)
if err != nil { if err != nil {
log.WithError(err).Error("get project list error") log.WithError(err).Error("get project list error")
return return
} }
resp = make([]*apiModel.GetProjectResponse, 0) resp.TotalCount = count
resp.Items = make([]*apiModel.GetProjectResponse, 0)
for _, v := range list { for _, v := range list {
resp = append(resp, &apiModel.GetProjectResponse{ resp.Items = append(resp.Items, &apiModel.GetProjectResponse{
ProjectId: v.Id,
TelegramChatId: v.TelegramChatId, TelegramChatId: v.TelegramChatId,
TwitterHandle: v.TweeterHandle, TwitterHandle: v.TwitterHandle,
TweeterName: v.TweeterName, TwitterName: v.TwitterName,
TweeterUserId: v.TweeterUserId, TwitterUserId: v.TwitterUserId,
Description: v.Description, Description: v.Description,
TelegramChatTitle: v.TelegramChatTitle,
TelegramChatUsername: v.TelegramChatUsername,
ProjectName: v.Name,
}) })
} }
return return
...@@ -69,15 +90,17 @@ func (s *Service) GetProject(pid int) (resp *apiModel.GetProjectResponse, err er ...@@ -69,15 +90,17 @@ func (s *Service) GetProject(pid int) (resp *apiModel.GetProjectResponse, err er
return &apiModel.GetProjectResponse{ return &apiModel.GetProjectResponse{
TelegramChatId: p.TelegramChatId, TelegramChatId: p.TelegramChatId,
TwitterHandle: p.TweeterHandle, TelegramChatUsername: p.TelegramChatUsername,
TweeterName: p.TweeterName, TelegramChatTitle: p.TelegramChatTitle,
TweeterUserId: p.TweeterUserId, TwitterHandle: p.TwitterHandle,
TwitterName: p.TwitterName,
TwitterUserId: p.TwitterUserId,
ProjectName: p.Name, ProjectName: p.Name,
Description: p.Description, Description: p.Description,
// TweeterAPIKey: p.TweeterAPIKey, // TwitterAPIKey: p.TwitterAPIKey,
// TweeterAPISecret: p.TweeterAPISecret, // TwitterAPISecret: p.TwitterAPISecret,
// TweeterAccessToken: p.TweeterAccessToken, // TwitterAccessToken: p.TwitterAccessToken,
// TweeterAccessSecret: p.TweeterAccessSecret, // TwitterAccessSecret: p.TwitterAccessSecret,
// TweeterToken: p.TweeterToken, // TwitterToken: p.TwitterToken,
}, nil }, nil
} }
...@@ -19,6 +19,7 @@ func (s *Service) CheckTask(taskId int, userId string) (exist, done bool, expire ...@@ -19,6 +19,7 @@ func (s *Service) CheckTask(taskId int, userId string) (exist, done bool, expire
exist = false exist = false
return return
} }
log.Debugf("task: %+v", task)
// 超出时间后只查询不再更新状态 // 超出时间后只查询不再更新状态
if int64(task.Start) > time.Now().Unix() || int64(task.End) < time.Now().Unix() { if int64(task.Start) > time.Now().Unix() || int64(task.End) < time.Now().Unix() {
...@@ -90,9 +91,9 @@ func (s *Service) SyncTask(taskId int, userId string) (done bool, err error) { ...@@ -90,9 +91,9 @@ func (s *Service) SyncTask(taskId int, userId string) (done bool, err error) {
switch task.Action { switch task.Action {
case constant.TaskActionFollow: case constant.TaskActionFollow:
followed, err := s.d.CheckTweeterFollow(task.TweeterUserId, twitterUserId) followed, err := s.d.CheckTwitterFollow(task.TwitterUserId, twitterUserId)
if err != nil { if err != nil {
log.WithError(err).Error("check tweeter follow error") log.WithError(err).Error("check twitter follow error")
return false, err return false, err
} }
if !followed { if !followed {
...@@ -107,12 +108,12 @@ func (s *Service) SyncTask(taskId int, userId string) (done bool, err error) { ...@@ -107,12 +108,12 @@ func (s *Service) SyncTask(taskId int, userId string) (done bool, err error) {
case constant.TaskActionLike, constant.TaskActionRetweet, constant.TaskActionReply: case constant.TaskActionLike, constant.TaskActionRetweet, constant.TaskActionReply:
var taskDone bool var taskDone bool
if task.Action == constant.TaskActionLike { if task.Action == constant.TaskActionLike {
taskDone, err = s.d.CheckTweeterLike(task.TweetId, twitterUserId, 0, 0) taskDone, err = s.d.CheckTwitterLike(task.TweetId, twitterUserId, 0, 0)
} else { } else {
taskDone, err = s.d.CheckTweeterRetweet(task.TweetId, twitterUserId, 0, 0) taskDone, err = s.d.CheckTwitterRetweet(task.TweetId, twitterUserId, 0, 0)
} }
if err != nil { if err != nil {
log.WithError(err).Errorf("check tweeter %s error", task.Action) log.WithError(err).Errorf("check twitter %s error", task.Action)
return false, err return false, err
} }
if !taskDone { if !taskDone {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment