diff --git a/README-zh.md b/README-zh.md
index 1adf3dc7..fabab977 100644
--- a/README-zh.md
+++ b/README-zh.md
@@ -305,6 +305,9 @@ Crawlab使用起来很方便,也很通用,可以适用于几乎任何主流
+
+
+
## 社区 & 赞助
diff --git a/README.md b/README.md
index 25a16c8e..edd3b6d7 100644
--- a/README.md
+++ b/README.md
@@ -272,6 +272,9 @@ Crawlab is easy to use, general enough to adapt spiders in any language and any
+
+
+
## Community & Sponsorship
diff --git a/backend/main.go b/backend/main.go
index 1b568ace..6550bbbd 100644
--- a/backend/main.go
+++ b/backend/main.go
@@ -265,7 +265,8 @@ func main() {
}
// 挑战
{
- authGroup.GET("/challenges", routes.GetChallengeList) // 挑战列表
+ authGroup.GET("/challenges", routes.GetChallengeList) // 挑战列表
+ authGroup.POST("/challenges-check", routes.CheckChallengeList) // 检查挑战列表
}
// 操作
{
diff --git a/backend/mock/spider.go b/backend/mock/spider.go
index ef3e6104..e6c20a6b 100644
--- a/backend/mock/spider.go
+++ b/backend/mock/spider.go
@@ -1,6 +1,7 @@
package mock
import (
+ "crawlab/constants"
"crawlab/model"
"github.com/apex/log"
"github.com/gin-gonic/gin"
@@ -26,6 +27,7 @@ var SpiderList = []model.Spider{
LastRunTs: time.Now(),
CreateTs: time.Now(),
UpdateTs: time.Now(),
+ UserId: constants.ObjectIdNull,
},
}
diff --git a/backend/mock/spider_test.go b/backend/mock/spider_test.go
index f4dbea63..11e2c9cd 100644
--- a/backend/mock/spider_test.go
+++ b/backend/mock/spider_test.go
@@ -2,6 +2,7 @@ package mock
import (
"bytes"
+ "crawlab/constants"
"crawlab/model"
"encoding/json"
"github.com/globalsign/mgo/bson"
@@ -61,6 +62,7 @@ func TestPostSpider(t *testing.T) {
LastRunTs: time.Now(),
CreateTs: time.Now(),
UpdateTs: time.Now(),
+ UserId: constants.ObjectIdNull,
}
var resp Response
var spiderId = "5d429e6c19f7abede924fee2"
diff --git a/backend/model/action.go b/backend/model/action.go
index 14968cec..15406181 100644
--- a/backend/model/action.go
+++ b/backend/model/action.go
@@ -1,6 +1,7 @@
package model
import (
+ "crawlab/constants"
"crawlab/database"
"github.com/apex/log"
"github.com/globalsign/mgo/bson"
@@ -82,6 +83,52 @@ func GetActionListTotal(filter interface{}) (int, error) {
return result, nil
}
+func GetVisitDays(uid bson.ObjectId) (int, error) {
+ type ResData struct {
+ Days int `json:"days" bson:"days"`
+ }
+ s, c := database.GetCol("actions")
+ defer s.Close()
+
+ pipeline := []bson.M{
+ {
+ "$match": bson.M{
+ "user_id": uid,
+ "type": constants.ActionTypeVisit,
+ },
+ },
+ {
+ "$addFields": bson.M{
+ "date": bson.M{
+ "$dateToString": bson.M{
+ "format": "%Y%m%d",
+ "date": "$create_ts",
+ "timezone": "Asia/Shanghai",
+ },
+ },
+ },
+ },
+ {
+ "$group": bson.M{
+ "_id": "$date",
+ },
+ },
+ {
+ "_id": nil,
+ "days": bson.M{"$sum": 1},
+ },
+ }
+
+ var resData []ResData
+ if err := c.Pipe(pipeline).All(&resData); err != nil {
+ log.Errorf(err.Error())
+ debug.PrintStack()
+ return 0, err
+ }
+
+ return resData[0].Days, nil
+}
+
func UpdateAction(id bson.ObjectId, item Action) error {
s, c := database.GetCol("actions")
defer s.Close()
diff --git a/backend/model/challenge.go b/backend/model/challenge.go
index 9a96660b..083d216b 100644
--- a/backend/model/challenge.go
+++ b/backend/model/challenge.go
@@ -97,8 +97,28 @@ func GetChallengeList(filter interface{}, skip int, limit int, sortKey string) (
return challenges, err
}
- //for _, ch := range challenges {
- //}
+ return challenges, nil
+}
+
+func GetChallengeListWithAchieved(filter interface{}, skip int, limit int, sortKey string, uid bson.ObjectId) ([]Challenge, error) {
+ challenges, err := GetChallengeList(filter, skip, limit, sortKey)
+ if err != nil {
+ return challenges, err
+ }
+
+ for i, ch := range challenges {
+ query := bson.M{
+ "user_id": uid,
+ "challenge_id": ch.Id,
+ }
+
+ list, err := GetChallengeAchievementList(query, 0, 1, "-_id")
+ if err != nil {
+ continue
+ }
+
+ challenges[i].Achieved = len(list) > 0
+ }
return challenges, nil
}
@@ -152,3 +172,16 @@ func (ca *ChallengeAchievement) Add() error {
return nil
}
+
+func GetChallengeAchievementList(filter interface{}, skip int, limit int, sortKey string) ([]ChallengeAchievement, error) {
+ s, c := database.GetCol("challenges_achievements")
+ defer s.Close()
+
+ var challengeAchievements []ChallengeAchievement
+ if err := c.Find(filter).Skip(skip).Limit(limit).Sort(sortKey).All(&challengeAchievements); err != nil {
+ debug.PrintStack()
+ return challengeAchievements, err
+ }
+
+ return challengeAchievements, nil
+}
diff --git a/backend/model/project.go b/backend/model/project.go
index 92c72655..bc7ca35e 100644
--- a/backend/model/project.go
+++ b/backend/model/project.go
@@ -15,11 +15,12 @@ type Project struct {
Description string `json:"description" bson:"description"`
Tags []string `json:"tags" bson:"tags"`
- CreateTs time.Time `json:"create_ts" bson:"create_ts"`
- UpdateTs time.Time `json:"update_ts" bson:"update_ts"`
-
// 前端展示
Spiders []Spider `json:"spiders" bson:"spiders"`
+
+ UserId bson.ObjectId `json:"user_id" bson:"user_id"`
+ CreateTs time.Time `json:"create_ts" bson:"create_ts"`
+ UpdateTs time.Time `json:"update_ts" bson:"update_ts"`
}
func (p *Project) Save() error {
diff --git a/backend/model/spider.go b/backend/model/spider.go
index 49f735a4..5bc2579b 100644
--- a/backend/model/spider.go
+++ b/backend/model/spider.go
@@ -65,8 +65,9 @@ type Spider struct {
LatestTasks []Task `json:"latest_tasks"` // 最近任务列表
// 时间
- CreateTs time.Time `json:"create_ts" bson:"create_ts"`
- UpdateTs time.Time `json:"update_ts" bson:"update_ts"`
+ UserId bson.ObjectId `json:"user_id" bson:"user_id"`
+ CreateTs time.Time `json:"create_ts" bson:"create_ts"`
+ UpdateTs time.Time `json:"update_ts" bson:"update_ts"`
}
// 更新爬虫
diff --git a/backend/model/task.go b/backend/model/task.go
index abb5ffc5..6b2a44c1 100644
--- a/backend/model/task.go
+++ b/backend/model/task.go
@@ -25,14 +25,16 @@ type Task struct {
RuntimeDuration float64 `json:"runtime_duration" bson:"runtime_duration"`
TotalDuration float64 `json:"total_duration" bson:"total_duration"`
Pid int `json:"pid" bson:"pid"`
- UserId bson.ObjectId `json:"user_id" bson:"user_id"`
+ RunType string `json:"run_type" bson:"run_type"`
+ ScheduleId bson.ObjectId `json:"schedule_id" bson:"schedule_id"`
// 前端数据
SpiderName string `json:"spider_name"`
NodeName string `json:"node_name"`
- CreateTs time.Time `json:"create_ts" bson:"create_ts"`
- UpdateTs time.Time `json:"update_ts" bson:"update_ts"`
+ UserId bson.ObjectId `json:"user_id" bson:"user_id"`
+ CreateTs time.Time `json:"create_ts" bson:"create_ts"`
+ UpdateTs time.Time `json:"update_ts" bson:"update_ts"`
}
type TaskDailyItem struct {
diff --git a/backend/routes/action.go b/backend/routes/action.go
index 26ffe66e..f0d262ab 100644
--- a/backend/routes/action.go
+++ b/backend/routes/action.go
@@ -56,7 +56,7 @@ func PutAction(c *gin.Context) {
return
}
- action.UserId = services.GetCurrentUser(c).Id
+ action.UserId = services.GetCurrentUserId(c)
if err := action.Add(); err != nil {
HandleError(http.StatusInternalServerError, c, err)
diff --git a/backend/routes/challenge.go b/backend/routes/challenge.go
index f8d09b6e..1f03654a 100644
--- a/backend/routes/challenge.go
+++ b/backend/routes/challenge.go
@@ -3,13 +3,15 @@ package routes
import (
"crawlab/constants"
"crawlab/model"
+ "crawlab/services"
+ "crawlab/services/challenge"
"github.com/gin-gonic/gin"
"net/http"
)
func GetChallengeList(c *gin.Context) {
// 获取列表
- users, err := model.GetChallengeList(nil, 0, constants.Infinite, "create_ts")
+ users, err := model.GetChallengeListWithAchieved(nil, 0, constants.Infinite, "create_ts", services.GetCurrentUserId(c))
if err != nil {
HandleError(http.StatusInternalServerError, c, err)
return
@@ -29,3 +31,15 @@ func GetChallengeList(c *gin.Context) {
Total: total,
})
}
+
+func CheckChallengeList(c *gin.Context) {
+ uid := services.GetCurrentUserId(c)
+ if err := challenge.CheckChallengeAndUpdateAll(uid); err != nil {
+ HandleError(http.StatusInternalServerError, c, err)
+ return
+ }
+ c.JSON(http.StatusOK, Response{
+ Status: "ok",
+ Message: "success",
+ })
+}
diff --git a/backend/routes/schedule.go b/backend/routes/schedule.go
index 3776019c..601d467f 100644
--- a/backend/routes/schedule.go
+++ b/backend/routes/schedule.go
@@ -77,7 +77,7 @@ func PutSchedule(c *gin.Context) {
}
// 加入用户ID
- item.UserId = services.GetCurrentUser(c).Id
+ item.UserId = services.GetCurrentUserId(c)
// 更新数据库
if err := model.AddSchedule(item); err != nil {
diff --git a/backend/routes/spider.go b/backend/routes/spider.go
index d195a5e7..b136070b 100644
--- a/backend/routes/spider.go
+++ b/backend/routes/spider.go
@@ -189,6 +189,9 @@ func PutSpider(c *gin.Context) {
// 将FileId置空
spider.FileId = bson.ObjectIdHex(constants.ObjectIdNull)
+ // UserId
+ spider.UserId = services.GetCurrentUserId(c)
+
// 爬虫目录
spiderDir := filepath.Join(viper.GetString("spider.path"), spider.Name)
@@ -274,6 +277,9 @@ func CopySpider(c *gin.Context) {
return
}
+ // UserId
+ spider.UserId = services.GetCurrentUserId(c)
+
// 复制爬虫
if err := services.CopySpider(spider, reqBody.Name); err != nil {
HandleError(http.StatusInternalServerError, c, err)
@@ -365,6 +371,8 @@ func UploadSpider(c *gin.Context) {
Type: constants.Customized,
Src: filepath.Join(srcPath, spiderName),
FileId: fid,
+ ProjectId: bson.ObjectIdHex(constants.ObjectIdNull),
+ UserId: services.GetCurrentUserId(c),
}
if name != "" {
spider.Name = name
@@ -617,7 +625,8 @@ func RunSelectedSpider(c *gin.Context) {
SpiderId: taskParam.SpiderId,
NodeId: node.Id,
Param: taskParam.Param,
- UserId: services.GetCurrentUser(c).Id,
+ UserId: services.GetCurrentUserId(c),
+ RunType: constants.RunTypeAllNodes,
}
id, err := services.AddTask(t)
@@ -633,7 +642,8 @@ func RunSelectedSpider(c *gin.Context) {
t := model.Task{
SpiderId: taskParam.SpiderId,
Param: taskParam.Param,
- UserId: services.GetCurrentUser(c).Id,
+ UserId: services.GetCurrentUserId(c),
+ RunType: constants.RunTypeRandom,
}
id, err := services.AddTask(t)
if err != nil {
@@ -648,7 +658,8 @@ func RunSelectedSpider(c *gin.Context) {
SpiderId: taskParam.SpiderId,
NodeId: nodeId,
Param: taskParam.Param,
- UserId: services.GetCurrentUser(c).Id,
+ UserId: services.GetCurrentUserId(c),
+ RunType: constants.RunTypeSelectedNodes,
}
id, err := services.AddTask(t)
diff --git a/backend/routes/task.go b/backend/routes/task.go
index 2880abb9..ecfbc71f 100644
--- a/backend/routes/task.go
+++ b/backend/routes/task.go
@@ -115,7 +115,8 @@ func PutTask(c *gin.Context) {
SpiderId: reqBody.SpiderId,
NodeId: node.Id,
Param: reqBody.Param,
- UserId: services.GetCurrentUser(c).Id,
+ UserId: services.GetCurrentUserId(c),
+ RunType: constants.RunTypeAllNodes,
}
id, err := services.AddTask(t)
@@ -131,7 +132,8 @@ func PutTask(c *gin.Context) {
t := model.Task{
SpiderId: reqBody.SpiderId,
Param: reqBody.Param,
- UserId: services.GetCurrentUser(c).Id,
+ UserId: services.GetCurrentUserId(c),
+ RunType: constants.RunTypeRandom,
}
id, err := services.AddTask(t)
if err != nil {
@@ -146,7 +148,8 @@ func PutTask(c *gin.Context) {
SpiderId: reqBody.SpiderId,
NodeId: nodeId,
Param: reqBody.Param,
- UserId: services.GetCurrentUser(c).Id,
+ UserId: services.GetCurrentUserId(c),
+ RunType: constants.RunTypeSelectedNodes,
}
id, err := services.AddTask(t)
diff --git a/backend/services/challenge/base.go b/backend/services/challenge/base.go
index 6529d887..9515ff9e 100644
--- a/backend/services/challenge/base.go
+++ b/backend/services/challenge/base.go
@@ -15,14 +15,14 @@ type Service interface {
Check() (bool, error)
}
-func GetService(name string) Service {
+func GetService(name string, uid bson.ObjectId) Service {
switch name {
case constants.ChallengeLogin7d:
- return &Login7dService{}
+ return &Login7dService{UserId: uid}
case constants.ChallengeCreateCustomizedSpider:
- return &CreateCustomizedSpiderService{}
+ return &CreateCustomizedSpiderService{UserId: uid}
case constants.ChallengeRunRandom:
- return &RunRandomService{}
+ return &RunRandomService{UserId: uid}
}
return nil
}
@@ -42,14 +42,14 @@ func AddChallengeAchievement(name string, uid bson.ObjectId) error {
return nil
}
-func CheckChallengeAndUpdate(name string, uid bson.ObjectId) error {
- svc := GetService(name)
+func CheckChallengeAndUpdate(ch model.Challenge, uid bson.ObjectId) error {
+ svc := GetService(ch.Name, uid)
achieved, err := svc.Check()
if err != nil {
return err
}
- if achieved {
- if err := AddChallengeAchievement(name, uid); err != nil {
+ if achieved && !ch.Achieved {
+ if err := AddChallengeAchievement(ch.Name, uid); err != nil {
return err
}
}
@@ -57,6 +57,15 @@ func CheckChallengeAndUpdate(name string, uid bson.ObjectId) error {
}
func CheckChallengeAndUpdateAll(uid bson.ObjectId) error {
+ challenges, err := model.GetChallengeListWithAchieved(nil, 0, constants.Infinite, "-_id", uid)
+ if err != nil {
+ return err
+ }
+ for _, ch := range challenges {
+ if err := CheckChallengeAndUpdate(ch, uid); err != nil {
+ continue
+ }
+ }
return nil
}
diff --git a/backend/services/challenge/create_customized_spider.go b/backend/services/challenge/create_customized_spider.go
index cad1aa25..6c61318f 100644
--- a/backend/services/challenge/create_customized_spider.go
+++ b/backend/services/challenge/create_customized_spider.go
@@ -1,8 +1,23 @@
package challenge
+import (
+ "crawlab/constants"
+ "crawlab/model"
+ "github.com/globalsign/mgo/bson"
+)
+
type CreateCustomizedSpiderService struct {
+ UserId bson.ObjectId
}
func (s *CreateCustomizedSpiderService) Check() (bool, error) {
- return true, nil
+ query := bson.M{
+ "user_id": s.UserId,
+ "type": constants.Customized,
+ }
+ _, count, err := model.GetSpiderList(query, 0, 1, "-_id")
+ if err != nil {
+ return false, err
+ }
+ return count > 0, nil
}
diff --git a/backend/services/challenge/login_7d.go b/backend/services/challenge/login_7d.go
index c10e2d38..91540423 100644
--- a/backend/services/challenge/login_7d.go
+++ b/backend/services/challenge/login_7d.go
@@ -1,8 +1,18 @@
package challenge
+import (
+ "crawlab/model"
+ "github.com/globalsign/mgo/bson"
+)
+
type Login7dService struct {
+ UserId bson.ObjectId
}
func (s *Login7dService) Check() (bool, error) {
- return true, nil
+ days, err := model.GetVisitDays(s.UserId)
+ if err != nil {
+ return false, err
+ }
+ return days >= 7, nil
}
diff --git a/backend/services/challenge/run_random.go b/backend/services/challenge/run_random.go
index dd9e4a40..ebdc11fe 100644
--- a/backend/services/challenge/run_random.go
+++ b/backend/services/challenge/run_random.go
@@ -1,8 +1,23 @@
package challenge
+import (
+ "crawlab/constants"
+ "crawlab/model"
+ "github.com/globalsign/mgo/bson"
+)
+
type RunRandomService struct {
+ UserId bson.ObjectId
}
func (s *RunRandomService) Check() (bool, error) {
- return true, nil
+ query := bson.M{
+ "user_id": s.UserId,
+ "run_type": constants.RunTypeRandom,
+ }
+ list, err := model.GetTaskList(query, 0, 1, "-_id")
+ if err != nil {
+ return false, err
+ }
+ return len(list) > 0, nil
}
diff --git a/backend/services/spider.go b/backend/services/spider.go
index 77bb19ab..0fbc5ebb 100644
--- a/backend/services/spider.go
+++ b/backend/services/spider.go
@@ -471,6 +471,7 @@ func InitDemoSpiders () {
ProjectId: bson.ObjectIdHex(constants.ObjectIdNull),
FileId: bson.ObjectIdHex(constants.ObjectIdNull),
Cmd: configData.Cmd,
+ UserId: bson.ObjectIdHex(constants.ObjectIdNull),
}
if err := spider.Add(); err != nil {
log.Errorf("add spider error: " + err.Error())
@@ -497,6 +498,7 @@ func InitDemoSpiders () {
ProjectId: bson.ObjectIdHex(constants.ObjectIdNull),
FileId: bson.ObjectIdHex(constants.ObjectIdNull),
Config: configData,
+ UserId: bson.ObjectIdHex(constants.ObjectIdNull),
}
if err := spider.Add(); err != nil {
log.Errorf("add spider error: " + err.Error())
diff --git a/backend/services/user.go b/backend/services/user.go
index a01e721b..b01b4923 100644
--- a/backend/services/user.go
+++ b/backend/services/user.go
@@ -115,3 +115,8 @@ func GetCurrentUser(c *gin.Context) *model.User {
data, _ := c.Get("currentUser")
return data.(*model.User)
}
+
+func GetCurrentUserId(c *gin.Context) bson.ObjectId {
+ return GetCurrentUser(c).Id
+}
+
diff --git a/frontend/src/views/challenge/ChallengeList.vue b/frontend/src/views/challenge/ChallengeList.vue
index c0bda6f1..3d45bd35 100644
--- a/frontend/src/views/challenge/ChallengeList.vue
+++ b/frontend/src/views/challenge/ChallengeList.vue
@@ -77,6 +77,7 @@ export default {
},
methods: {
async getData () {
+ await this.$request.post('/challenges-check')
const res = await this.$request.get('/challenges')
this.challenges = res.data.data || []
}