func (us *Users) POST(c *kocha.Context) error { updateUsers := c.Request.Form["users[]"] if len(updateUsers) > 0 { var users []model.User dbInst := db.Get("default") err := dbInst.Select(&users, dbInst.Where("id").In(updateUsers)) if err == nil { action := c.Params.Get("action") var ids []string for _, user := range users { ids = append(ids, strconv.FormatInt(user.Id, 10)) } _, err = dbInst.DB().Exec(` UPDATE users SET enable = ?, updated_at = CURRENT_TIMESTAMP WHERE id IN (`+strings.Join(ids, ",")+`) `, action == "enable") } if err != nil { return c.RenderError(500, err, nil) } } return us.GET(c) }
// ユーザの登録を行います。 func RegisterUser(accessToken *oauth.AccessToken) error { dbInst := db.Get("default") twitterId := accessToken.AdditionalData["user_id"] var users []User condition := dbInst.Where("twitter_id", "=", twitterId) err := dbInst.Select(&users, condition) if err == nil { if len(users) > 0 { user := users[0] user.ScreenName = accessToken.AdditionalData["screen_name"] user.AccessToken = accessToken.Token user.AccessTokenSecret = accessToken.Secret _, err = dbInst.Update(user) } else { _, err = dbInst.Insert(&User{ TwitterId: twitterId, ScreenName: accessToken.AdditionalData["screen_name"], AccessToken: accessToken.Token, AccessTokenSecret: accessToken.Secret, }) } } return err }
func (us *Users) GET(c *kocha.Context) error { var n int var users []model.User num, _ := GetPerItem(c) currentPage, _ := GetPageNum(c) page := currentPage if page > 0 { page-- } dbInst := db.Get("default") condition := dbInst.OrderBy("id", genmai.DESC).Limit(num).Offset(page * num) err := dbInst.Select(&users, condition) if err == nil { if page > 0 && len(users) == 0 { c.Redirect("/users", false) } err = dbInst.Select(&n, dbInst.Count(), dbInst.From(&model.User{})) } if err != nil { c.RenderError(500, err, nil) } pagination, _ := simpagin.New(currentPage, n, num, DEFAULT_PER_PAGE) return c.Render(map[string]interface{}{ "ControllerName": "Users", "users": users, "totalPage": int(math.Ceil(float64(n) / float64(num))), "pagination": pagination, }) }
func (qu *Queues) GET(c *kocha.Context) error { var n int var queues []Queue num, _ := GetPerItem(c) currentPage, _ := GetPageNum(c) page := currentPage if page > 0 { page-- } dbInst := db.Get("default") rows, err := dbInst.DB().Query(` SELECT queues.id, status, screen_name, tweet_id, action, execute_time, fail_count, queues.created_at, queues.updated_at FROM queues JOIN users ON user_id = users.id ORDER BY id DESC LIMIT ? OFFSET ? `, num, page*num) if err == nil { defer rows.Close() for rows.Next() { var queue Queue if err := rows.Scan( &queue.Id, &queue.Status, &queue.ScreenName, &queue.TweetId, &queue.Action, &queue.ExecuteTime, &queue.FailCount, &queue.CreatedAt, &queue.UpdatedAt, ); err != nil { panic(err) } queues = append(queues, queue) } if page > 0 && len(queues) == 0 { c.Redirect("/queues", false) } err = dbInst.Select(&n, dbInst.Count(), dbInst.From(&model.Queue{})) } if err != nil { c.RenderError(500, err, nil) } pagination, _ := simpagin.New(currentPage, n, num, DEFAULT_PER_PAGE) return c.Render(map[string]interface{}{ "ControllerName": "Queues", "queues": queues, "totalPage": int(math.Ceil(float64(n) / float64(num))), "pagination": pagination, }) }
func ExistsTweet(id string) bool { var n int64 dbInst := db.Get("default") condition := dbInst.Where("id", "=", id) from := dbInst.From(&Tweet{}) if err := dbInst.Select(&n, dbInst.Count(), from, condition); err != nil { panic(err) } return n > 0 }
// キューを更新します。 func updateQueue(q Queue) { _, err := db.Get("default").DB().Exec(` UPDATE queues SET status = ?, fail_count = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? `, q.Status, q.FailCount, q.Id) if err != nil { logger.Error(err) panic(err) } }
func Exec() { logger.Info("auto retweet start.") dbInst := db.Get("default") defer func() { if err := recover(); err != nil { dbInst.Rollback() } else { dbInst.Commit() } }() if err := dbInst.Begin(); err != nil { logger.Error(err) panic(err) } queues := findQueue() updateQueueStatus(queues, model.QUEUE_STATUS_LOCKED) client := twitter.GetClient() for _, queue := range queues { accessToken := &oauth.AccessToken{ Token: queue.AccessToken, Secret: queue.AccessTokenSecret, } var err error switch queue.Action { case model.QUEUE_ACTION_RETWEET: err = retweet(queue, client, accessToken) case model.QUEUE_ACTION_TWEET: err = tweet(queue, client, accessToken) case model.QUEUE_ACTION_FAVORITE: err = favorite(queue, client, accessToken) } if err != nil { logger.Info(queue.Action + " failed [ID:" + queue.TwitterId + "]") logger.Error(err) queue.FailCount++ queue.Status = model.QUEUE_STATUS_FAILED } else { logger.Info(queue.Action + " completed [ID:" + queue.TwitterId + "]") queue.Status = model.QUEUE_STATUS_COMPLETED } updateQueue(queue) } logger.Info("auto retweet end.") }
func findQueue() []Queue { rows, err := db.Get("default").DB().Query(` SELECT queues.id, twitter_id, tweet_id, text, status, action, fail_count, access_token, access_token_secret FROM queues JOIN tweets ON tweet_id = tweets.id JOIN users ON user_id = users.id WHERE enable = 1 AND (status = ? OR (status = ? AND fail_count < ?)) AND execute_time <= ?`, model.QUEUE_STATUS_READY, model.QUEUE_STATUS_FAILED, model.QUEUE_FAIL_MAX_COUNT, time.Now().Unix(), ) if err != nil { logger.Error(err) panic(err) } defer rows.Close() var queues []Queue for rows.Next() { var queue Queue if err := rows.Scan( &queue.Id, &queue.TwitterId, &queue.TweetId, &queue.Text, &queue.Status, &queue.Action, &queue.FailCount, &queue.AccessToken, &queue.AccessTokenSecret, ); err != nil { logger.Error(err) panic(err) } queues = append(queues, queue) } return queues }
// キューの状態を一括更新します。 func updateQueueStatus(queues []Queue, status string) { if len(queues) == 0 { return } var ids []string for _, queue := range queues { ids = append(ids, strconv.FormatInt(queue.Id, 10)) } _, err := db.Get("default").DB().Exec(` UPDATE queues SET status = ?, updated_at = CURRENT_TIMESTAMP WHERE id IN (`+strings.Join(ids, ",")+`) `, status) if err != nil { logger.Error(err) panic(err) } }
func (qu *Queues) POST(c *kocha.Context) error { status := c.Params.Get("action") if status == "exec" { if _, err := exec.Command(os.Args[0], "exec").Output(); err != nil { return c.RenderError(500, err, nil) } return qu.GET(c) } if status != "ready" && status != "canceled" { return qu.GET(c) } updateQueues := c.Request.Form["queues[]"] if len(updateQueues) > 0 { var queues []model.Queue dbInst := db.Get("default") err := dbInst.Select(&queues, dbInst.Where("id").In(updateQueues)) if err == nil { var ids []string for _, queue := range queues { ids = append(ids, strconv.FormatInt(queue.Id, 10)) } _, err = dbInst.DB().Exec(` UPDATE queues SET status = ?, updated_at = CURRENT_TIMESTAMP WHERE id IN (`+strings.Join(ids, ",")+`) `, status) } if err != nil { return c.RenderError(500, err, nil) } } return qu.GET(c) }
func Check() { tweet := getLastTweet() if tweet == nil || model.ExistsTweet(tweet.Id) { return } dbInst := db.Get("default") defer func() { if err := recover(); err != nil { dbInst.Rollback() } else { dbInst.Commit() } }() if err := dbInst.Begin(); err != nil { panic(err) } if _, err := dbInst.Insert(tweet); err != nil { panic(err) } var users []model.User condition := dbInst.Where("enable", "=", 1) if err := dbInst.Select(&users, condition); err != nil { panic(err) } rand.Seed(time.Now().UnixNano()) timestamp := time.Now().Unix() period := getActionPeriod() var queues []*model.Queue for _, user := range users { queues = append(queues, &model.Queue{ UserId: user.Id, TweetId: tweet.Id, Status: model.QUEUE_STATUS_READY, Action: model.QUEUE_ACTION_RETWEET, ExecuteTime: timestamp + rand.Int63n(period), }) queues = append(queues, &model.Queue{ UserId: user.Id, TweetId: tweet.Id, Status: model.QUEUE_STATUS_READY, Action: model.QUEUE_ACTION_TWEET, ExecuteTime: timestamp + rand.Int63n(period), }) queues = append(queues, &model.Queue{ UserId: user.Id, TweetId: tweet.Id, Status: model.QUEUE_STATUS_READY, Action: model.QUEUE_ACTION_FAVORITE, ExecuteTime: timestamp + rand.Int63n(period), }) } if _, err := dbInst.Insert(queues); err != nil { panic(err) } }