From 5d2a3af4909a05b060f180fd24a456136be6c58f Mon Sep 17 00:00:00 2001 From: CounterFire2023 <136581895+CounterFire2023@users.noreply.github.com> Date: Wed, 20 Dec 2023 19:32:35 +0800 Subject: [PATCH] add twitter connect, accomplish other tasks --- initdatas/activity_info.json | 11 ++++++--- src/controllers/tasks.controller.ts | 38 +++++++++++++++++++++++------ src/models/ActivityUser.ts | 9 ++++++- src/tasks/DiscordJoin.ts | 29 +++++++++++++++++++--- src/tasks/DiscordRole.ts | 20 ++++++++++++--- src/tasks/TwitterConnect.ts | 36 +++++++++++++++++++++++++++ src/tasks/TwitterFollow.ts | 32 ++++++++++-------------- src/tasks/TwitterRetweet.ts | 20 ++++++++++++--- src/tasks/UpdateScore.ts | 18 +++++++++++--- src/tasks/base/ITask.ts | 4 +-- 10 files changed, 167 insertions(+), 50 deletions(-) create mode 100644 src/tasks/TwitterConnect.ts diff --git a/initdatas/activity_info.json b/initdatas/activity_info.json index d8b3b89..51c1050 100644 --- a/initdatas/activity_info.json +++ b/initdatas/activity_info.json @@ -4,20 +4,23 @@ "name": "First Activity1", "description": "This is the first test activity", "tasks": [{ - "task": "TwitterFollow", + "task": "TwitterConnect", "params": {} + }, { + "task": "TwitterFollow", + "params": {"time": 6, "failRate": 60} }, { "task": "TwitterRetweet", - "params": {} + "params": {"time": 6, "failRate": 60} }, { "task": "DiscordJoin", "params": {} }, { "task": "DiscordRole", - "params": {} + "params": {"time": 6, "failRate": 60} }, { "task": "UpdateScore", - "params": {} + "params": {"score": [100, 20]} }], "startTime": 1702628292366, "endTime": 1705220292366 diff --git a/src/controllers/tasks.controller.ts b/src/controllers/tasks.controller.ts index b53a822..be6bb72 100644 --- a/src/controllers/tasks.controller.ts +++ b/src/controllers/tasks.controller.ts @@ -2,7 +2,8 @@ import { ZError } from "common/ZError"; import BaseController, { ROLE_ANON } from "common/base.controller"; import { role, router } from "decorators/router"; import { all } from "deepmerge"; -import { ActivityUser, TaskStatusEnum } from "models/ActivityUser"; +import { ActivityInfo } from "models/ActivityInfo"; +import { ActivityUser, TaskStatus, TaskStatusEnum } from "models/ActivityUser"; import { join } from 'path' const fs = require('fs') @@ -30,14 +31,16 @@ const parseCurrentTask = (user: typeof ActivityUser, task: string) => { } let preEnd = true; let currentTask = null; + let nextTask = null; for (let taskData of user.taskProgress) { if (taskData.id === task) { currentTask = taskData; - break; } - if (taskData.status !== 2) { + if (taskData.status !== 2 && !currentTask) { preEnd = false; - break; + } + if (currentTask && !nextTask) { + nextTask = taskData; } } if (!preEnd) { @@ -46,7 +49,20 @@ const parseCurrentTask = (user: typeof ActivityUser, task: string) => { if (!currentTask) { throw new ZError(13, 'task not found') } - return {preEnd, currentTask} + return {preEnd, currentTask, nextTask} +} + +const parseNextTask = async ( + user: typeof ActivityUser, + activity: typeof ActivityInfo, + task: TaskStatus) => { + let Task = require('../tasks/' + task.id); + if (!Task.default.auto) { + return true + } + let taskInstance = new Task.default({user, activity}); + let result = await taskInstance.execute({}); + return result } export default class TasksController extends BaseController { @@ -69,7 +85,7 @@ export default class TasksController extends BaseController { if (!user.taskProgress || user.taskProgress.length === 0) { for (let task of activity.tasks) { if (allTasks.has(task.task)) { - user.taskProgress.push({id: task.task, status: 0, time: 0}) + user.taskProgress.push({id: task.task, status: 0}) } } await user.save(); @@ -94,11 +110,17 @@ export default class TasksController extends BaseController { let user = req.user; let activity = req.activity; let { task } = req.params; - let { currentTask } = parseCurrentTask(user, task); + let { currentTask, nextTask } = parseCurrentTask(user, task); + if (currentTask.status !== TaskStatusEnum.RUNNING) { + throw new ZError(11, 'task not begin'); + } if (currentTask.status !== TaskStatusEnum.SUCCESS) { let Task = require('../tasks/' + task); let taskInstance = new Task.default({user, activity}); - await taskInstance.check(); + let result = await taskInstance.execute({}); + if (result) { + await parseNextTask(user, activity, nextTask); + } } return currentTask } diff --git a/src/models/ActivityUser.ts b/src/models/ActivityUser.ts index e6d333c..4910488 100644 --- a/src/models/ActivityUser.ts +++ b/src/models/ActivityUser.ts @@ -26,7 +26,7 @@ export class TaskStatus { @prop() timeFinish: number @prop({ type: mongoose.Schema.Types.Mixed }) - params: any + data: any } interface ActivityUserClass extends Base, TimeStamps {} @@ -34,6 +34,8 @@ interface ActivityUserClass extends Base, TimeStamps {} @index({ address: 1, activity: 1 }, { unique: true }) @index({ inviteCode: 1, activity: 1 }, { unique: true }) @index({ inviteUser: 1, activity: 1 }, { unique: false }) +@index({ twitterId: 1 }, { unique: true, partialFilterExpression: { twitterId: { $exists: true } } }) +@index({ discordId: 1 }, { unique: true, partialFilterExpression: { discordId: { $exists: true } } }) @modelOptions({ schemaOptions: { collection: 'activity_user', timestamps: true }, options: { allowMixed: Severity.ALLOW } }) @pre('save', async function () { if (!this.inviteCode) { @@ -68,6 +70,11 @@ class ActivityUserClass extends BaseModule { @prop() public comment?: string + @prop() + public twitterId?: string + @prop() + public discordId: string + @prop() public lastLogin?: Date diff --git a/src/tasks/DiscordJoin.ts b/src/tasks/DiscordJoin.ts index 52775f3..c4b97a1 100644 --- a/src/tasks/DiscordJoin.ts +++ b/src/tasks/DiscordJoin.ts @@ -1,14 +1,35 @@ +import { checkDiscord } from "services/oauth.svr"; import { ITask } from "./base/ITask"; +import { ZError } from "common/ZError"; +import { TaskStatusEnum } from "models/ActivityUser"; export default class DiscordJoin extends ITask { static desc = 'join discord' static show: boolean = true async execute(data: any) { - // do nothing - } - async check(data: any) { - // do nothing + let { address } = this.params.user + let res = await checkDiscord(address) + console.log(res); + if (res.status !== 200) { + throw new ZError(11, 'discord check failed') + } + if (res.data.errcode) { + throw new ZError(res.data.errcode, res.data.errmsg) + } + let task = this.params.user.taskProgress.find(t => t.id === this.constructor.name) + if (res.data.data.userid && task.status !== TaskStatusEnum.SUCCESS) { + task.status = TaskStatusEnum.SUCCESS + task.timeFinish = Date.now() + task.data = res.data.data + task.discordId = res.data.data.userid + try { + await this.params.user.save() + } catch(err) { + throw new ZError(100, 'discord already binded') + } + + } return true } diff --git a/src/tasks/DiscordRole.ts b/src/tasks/DiscordRole.ts index 756cea5..eeb51eb 100644 --- a/src/tasks/DiscordRole.ts +++ b/src/tasks/DiscordRole.ts @@ -1,13 +1,25 @@ +import { ZError } from "common/ZError"; import { ITask } from "./base/ITask"; +import { TaskStatusEnum } from "models/ActivityUser"; export default class DiscordRole extends ITask { static desc = 'acquire discord role' static show: boolean = true async execute(data: any) { - // do nothing - } - async check(data: any) { - // do nothing + let task = this.params.user.taskProgress.find(t => t.id === this.constructor.name) + let cfg = this.params.activity.tasks.find(t => t.task === this.constructor.name) + let time = cfg.params.time; + if (Date.now() - task.timeStart < time * 1000) { + throw new ZError(11, 'check discord role failed') + } + let num = Math.random() * 100 + if (num < cfg.params.failRate) { + throw new ZError(12, 'check discord role failed') + } + task.status = TaskStatusEnum.SUCCESS + task.timeFinish = Date.now() + task.data = {} + await this.params.user.save() return true } diff --git a/src/tasks/TwitterConnect.ts b/src/tasks/TwitterConnect.ts new file mode 100644 index 0000000..c566cf8 --- /dev/null +++ b/src/tasks/TwitterConnect.ts @@ -0,0 +1,36 @@ +import { checkTwitter } from "services/oauth.svr"; +import { ITask } from "./base/ITask"; +import { ActivityUser, TaskStatusEnum } from "models/ActivityUser"; +import { ZError } from "common/ZError"; + +export default class TwitterConnect extends ITask { + static desc = 'twitter connect' + static show: boolean = true + + async execute(data: any) { + let { address } = this.params.user + let res = await checkTwitter(address) + console.log(res); + if (res.status !== 200) { + throw new ZError(11, 'twitter check failed') + } + if (res.data.errcode) { + throw new ZError(res.data.errcode, res.data.errmsg) + } + let task = this.params.user.taskProgress.find(t => t.id === this.constructor.name) + if (res.data.data.userid && task.status !== TaskStatusEnum.SUCCESS) { + task.status = TaskStatusEnum.SUCCESS + task.timeFinish = Date.now() + task.data = res.data.data + task.twitterId = res.data.data.userid + try { + await this.params.user.save() + } catch(err) { + throw new ZError(100, 'twitter already binded') + } + + } + return true + } + +} \ No newline at end of file diff --git a/src/tasks/TwitterFollow.ts b/src/tasks/TwitterFollow.ts index 304ba1b..b57852d 100644 --- a/src/tasks/TwitterFollow.ts +++ b/src/tasks/TwitterFollow.ts @@ -1,31 +1,25 @@ -import { checkTwitter } from "services/oauth.svr"; import { ITask } from "./base/ITask"; -import { ActivityUser, TaskStatusEnum } from "models/ActivityUser"; +import { TaskStatusEnum } from "models/ActivityUser"; import { ZError } from "common/ZError"; export default class TwitterFollow extends ITask { static desc = 'twitter follow' static show: boolean = true async execute(data: any) { - // do nothing - } - async check(data: any) { - let { address } = this.params.user - let res = await checkTwitter(address) - console.log(res); - if (res.status !== 200) { - throw new ZError(11, 'twitter check failed') - } - if (res.data.errcode) { - throw new ZError(res.data.errcode, res.data.errmsg) - } let task = this.params.user.taskProgress.find(t => t.id === this.constructor.name) - if (res.data.data.userid && task.status !== TaskStatusEnum.SUCCESS) { - task.status = TaskStatusEnum.SUCCESS - task.timeFinish = Date.now() - task.params = res.data.data - await this.params.user.save() + let cfg = this.params.activity.tasks.find(t => t.task === this.constructor.name) + let time = cfg.params.time; + if (Date.now() - task.timeStart < time * 1000) { + throw new ZError(11, 'follow failed') } + let num = Math.random() * 100 + if (num < cfg.params.failRate) { + throw new ZError(12, 'follow failed') + } + task.status = TaskStatusEnum.SUCCESS + task.timeFinish = Date.now() + task.data = {} + await this.params.user.save() return true } diff --git a/src/tasks/TwitterRetweet.ts b/src/tasks/TwitterRetweet.ts index 21b1b1a..9b5c63a 100644 --- a/src/tasks/TwitterRetweet.ts +++ b/src/tasks/TwitterRetweet.ts @@ -1,13 +1,25 @@ +import { ZError } from "common/ZError"; import { ITask } from "./base/ITask"; +import { TaskStatusEnum } from "models/ActivityUser"; export default class TwitterRetweet extends ITask { static desc = 'twitter retweet' static show: boolean = true async execute(data: any) { - // do nothing - } - async check(data: any) { - // do nothing + let task = this.params.user.taskProgress.find(t => t.id === this.constructor.name) + let cfg = this.params.activity.tasks.find(t => t.task === this.constructor.name) + let time = cfg.params.time; + if (Date.now() - task.timeStart < time * 1000) { + throw new ZError(11, 'retweet failed') + } + let num = Math.random() * 100 + if (num < cfg.params.failRate) { + throw new ZError(12, 'retweet failed') + } + task.status = TaskStatusEnum.SUCCESS + task.timeFinish = Date.now() + task.data = {} + await this.params.user.save() return true } diff --git a/src/tasks/UpdateScore.ts b/src/tasks/UpdateScore.ts index 61d99ce..736e197 100644 --- a/src/tasks/UpdateScore.ts +++ b/src/tasks/UpdateScore.ts @@ -1,13 +1,23 @@ +import { ActivityUser, TaskStatus } from "models/ActivityUser"; import { ITask } from "./base/ITask"; +import { TaskCfg } from "models/ActivityInfo"; export default class UpdateScore extends ITask { static desc = 'update invite score' static show: boolean = false + static auto: boolean = true async execute(data: any) { - // do nothing - } - async check(data: any) { - // do nothing + let task = this.params.user.taskProgress.find((t: TaskStatus) => t.id === this.constructor.name) + let cfg = this.params.activity.tasks.find((t: TaskCfg) => t.task === this.constructor.name) + let scores = cfg.params.scores; + for (let i = 0, l = scores.length; i < l; i++) { + let score = scores[i] + let user = await ActivityUser.findById(this.params.user.inviteUser) + if (user) { + + } + + } return true } diff --git a/src/tasks/base/ITask.ts b/src/tasks/base/ITask.ts index dfa42ab..13d4b42 100644 --- a/src/tasks/base/ITask.ts +++ b/src/tasks/base/ITask.ts @@ -2,11 +2,11 @@ export abstract class ITask { static desc: string static show: boolean = true + static auto: boolean = false params: any constructor(params: any) { // do nothing this.params = params } - abstract execute(data: any): Promise - abstract check(data: any): Promise + abstract execute(data: any): Promise } \ No newline at end of file