commands

package
v0.0.0-...-ed41999 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 17, 2025 License: AGPL-3.0 Imports: 22 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var BadgePlayerGiveCmd = &cobra.Command{
	Use:   "badge:player:give",
	Short: "Gives a player a badge",
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) < 2 {
			logrus.Error("You must provide a badge id and a player id")
			return
		}

		badgeId, err := strconv.Atoi(args[0])

		if err != nil {
			logrus.Error(err)
			return
		}

		playerId, err := strconv.Atoi(args[1])

		if err != nil {
			logrus.Error(err)
			return
		}

		_, err = db.GetUserById(playerId)

		if err != nil {
			logrus.Error("Error retrieving player: ", err)
			return
		}

		hasBadge, err := db.UserHasBadge(playerId, badgeId)

		if err != nil {
			logrus.Error("Error checking user has badge: ", err)
			return
		}

		if hasBadge {
			logrus.Info("User already has badge")
			return
		}

		badge := &db.UserBadge{
			UserId:  playerId,
			BadgeId: badgeId,
		}

		if err := badge.Insert(); err != nil {
			logrus.Error("Error inserting badge: ", err)
			return
		}

		logrus.Info("Done!")
	},
}
View Source
var CacheClanLeaderboard = &cobra.Command{
	Use:   "cache:leaderboard:clan",
	Short: "Caches the clan leaderboard",
	Run: func(cmd *cobra.Command, args []string) {
		batchSize := 1000
		offset := 0

		logrus.Info("Caching clan leaderboards...")

		for {
			var clans = make([]*db.Clan, 0)

			result := db.SQL.
				Preload("Stats").
				Limit(batchSize).
				Offset(offset).
				Order("id ASC").
				Find(&clans)

			if result.Error != nil {
				logrus.Error(result.Error)
				return
			}

			if len(clans) == 0 {
				break
			}

			for _, clan := range clans {
				if err := db.UpdateAllClanLeaderboards(clan); err != nil {
					logrus.Error(err)
					return
				}
			}

			offset += batchSize
		}

		logrus.Info("Complete!")
	},
}
View Source
var CacheClearCmd = &cobra.Command{
	Use:   "cache:clear",
	Short: "Clears the cache",
	Long:  `Clears the application cache.`,
	Run: func(cmd *cobra.Command, args []string) {
		keys, err := db.Redis.Keys(db.RedisCtx, "quaver:*").Result()

		if err != nil && err != redis.Nil {
			logrus.Println(err)
			return
		}

		if len(keys) > 0 {
			delCount, err := db.Redis.Del(db.RedisCtx, keys...).Result()

			if err != nil {
				logrus.Errorf("Failed to DELETE keys: %v", err)
				return
			}

			logrus.Printf("Deleted %d keys\n", delCount)
		}

		logrus.Println("Cache has been cleared.")
	},
}
View Source
var CacheLeaderboardCmd = &cobra.Command{
	Use:   "cache:leaderboard",
	Short: "Populates the leaderboards in cache",
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) > 0 && strings.ToLower(args[0]) == "delete-all" {
			if err := deleteOldLeaderboards(); err != nil {
				logrus.Error(err)
				return
			}
		}

		logrus.Println("Populating leaderboards...")

		if err := populateLeaderboard(); err != nil {
			logrus.Error(err)
			return
		}

		logrus.Println("Leaderboards populated.")
	},
}
View Source
var CacheScoreboardClearCmd = &cobra.Command{
	Use:   "cache:scoreboards:clear",
	Short: "Clears the scoreboard cache",
	Long:  `Clears the scoreboard cache.`,
	Run: func(cmd *cobra.Command, args []string) {
		keys, err := db.Redis.Keys(db.RedisCtx, "quaver:scoreboard:*").Result()

		if err != nil && err != redis.Nil {
			logrus.Println(err)
			return
		}

		if len(keys) > 0 {
			delCount, err := db.Redis.Del(db.RedisCtx, keys...).Result()

			if err != nil {
				logrus.Errorf("Failed to DELETE keys: %v", err)
				return
			}

			logrus.Printf("Deleted %d keys\n", delCount)
		}

		logrus.Info("Scoreboard cache has been cleared.")
	},
}
View Source
var ClanRankMapCmd = &cobra.Command{
	Use:   "clan:rank:map",
	Short: "Ranks a map for clans",
	Run: func(cmd *cobra.Command, args []string) {
		const increment = 17

		for i := 1; i <= 2; i++ {
			for j := 0; j < 3; j++ {
				mapQua, err := getRandomMap(i, float64(j*increment), float64((j+1)*increment))

				if err != nil {
					logrus.Error("Error retrieving random map", err)
				}

				if err := db.UpdateMapClanRanked(mapQua.Id, true); err != nil {
					logrus.Error("Error updating clan ranked status: ", err)
					return
				}

				clanUsers, err := db.GetAllUsersInAClan()

				if err != nil {
					logrus.Error("Error retrieving users a part of a clan", err)
					return
				}

				for _, user := range clanUsers {
					if err := db.NewClanMapRankedNotification(mapQua, user.Id).Insert(); err != nil {
						logrus.Error("Error inserting clan map ranked notification", err)
						return
					}
				}

				if err := sendClanMapToRedis(mapQua); err != nil {
					logrus.Error("Error sending clan map to redis: ", err)
				}

				logrus.Info("Ranked Clan Map: ", mapQua.Id, mapQua, mapQua.DifficultyRating)
				_ = webhooks.SendClanRankedWebhook(mapQua)
			}
		}
	},
}
View Source
var ClanRecalculateCommand = &cobra.Command{
	Use:   "clan:recalc",
	Short: "Recalculates all clans",
	Run: func(cmd *cobra.Command, args []string) {
		clans, err := db.GetClans()

		if err != nil {
			logrus.Error(err)
			return
		}

		for _, clan := range clans {
			if err := db.PerformFullClanRecalculation(clan); err != nil {
				logrus.Error(err)
				return
			}
		}

		for _, clan := range clans {
			for i := 1; i <= 2; i++ {
				if err := db.UpdateClanLeaderboard(clan, enums.GameMode(i)); err != nil {
					logrus.Error(err)
					return
				}
			}
		}
	},
}
View Source
var DatabaseBackupCmd = &cobra.Command{
	Use:   "backup:database",
	Short: "Backs up the database and uploads to s3",
	Run: func(cmd *cobra.Command, args []string) {
		sqlPath, _ := filepath.Abs(fmt.Sprintf("%v/backup.sql", files.GetBackupsDirectory()))
		zipPath, _ := filepath.Abs(fmt.Sprintf("%v/backup.sql.zip", files.GetBackupsDirectory()))

		if err := deletePreviousBackups(s3BackupFolderName, 28); err != nil {
			logrus.Error(err)
			_ = webhooks.SendBackupWebhook(false, err)
			return
		}

		files, err := s3util.Instance().ListFiles(s3BackupFolderName)

		if err != nil {
			logrus.Error(err)
			_ = webhooks.SendBackupWebhook(false, err)
			return
		}

		s3FileName := "001.zip"

		if len(files) > 0 {
			name := strings.Replace(files[len(files)-1], ".zip", "", -1)
			name = strings.Replace(name, fmt.Sprintf("%v/", s3BackupFolderName), "", -1)

			fileNumber, err := strconv.Atoi(name)

			if err != nil {
				logrus.Error(err)
				_ = webhooks.SendBackupWebhook(false, err)
				return
			}

			s3FileName = fmt.Sprintf("%03d.zip", fileNumber+1)
		}

		if err := performDatabaseBackupBackup(sqlPath, zipPath, s3BackupFolderName, s3FileName); err != nil {
			_ = webhooks.SendBackupWebhook(false, err)
			return
		}

		_ = webhooks.SendBackupWebhook(true)
	},
}
View Source
var DatabaseBackupHourlyCmd = &cobra.Command{
	Use:   "backup:database:hourly",
	Short: "Backs up the database hourly and uploads to s3",
	Run: func(cmd *cobra.Command, args []string) {
		sqlPath, _ := filepath.Abs(fmt.Sprintf("%v/backup-hourly.sql", files.GetBackupsDirectory()))
		s3FileName := "backup-hourly.sql.zip"
		zipPath, _ := filepath.Abs(fmt.Sprintf("%v/%v", files.GetBackupsDirectory(), s3FileName))

		if err := performDatabaseBackupBackup(sqlPath, zipPath, s3HourlyBackupFolderName, s3FileName); err != nil {
			_ = webhooks.SendBackupWebhook(false, err)
			return
		}

		_ = webhooks.SendBackupWebhook(true)
	},
}
View Source
var DatabaseScoresBatchDeleteFailed = &cobra.Command{
	Use:   "database:scores:batch:delete",
	Short: "Deletes every failed score",
	Run: func(cmd *cobra.Command, args []string) {
		batchSize := 5000
		offset := 0

		for {
			var scoreIDs []int

			result := db.SQL.
				Model(&db.Score{}).
				Where("failed = 1").
				Limit(batchSize).
				Offset(offset).
				Pluck("id", &scoreIDs)

			if result.Error != nil {
				logrus.Info("Something went wrong")
				break
			}

			if len(scoreIDs) == 0 {
				if offset == 0 {
					logrus.Info("No more failed scores found!")
				} else {
					logrus.Info("There are no scores left to delete!")
				}

				break
			}

			deletedBatch := db.SQL.Where("id IN ?", scoreIDs).Delete(&db.Score{})

			if deletedBatch.Error != nil {
				logrus.Info("Something went wrong when deleting scores")
				break
			}

			logrus.Infof("Deleted %d failed scores", deletedBatch.RowsAffected)

			offset += batchSize
		}
	},
}
View Source
var DeleteScoreCmd = &cobra.Command{
	Use:   "score:delete",
	Short: "Soft deletes a score from the db",
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) == 0 {
			logrus.Error("You must provide a score to delete")
		}

		id, err := strconv.Atoi(args[0])

		if err != nil {
			logrus.Error(err)
			return
		}

		score, err := db.GetScoreById(id)

		if err != nil && err != gorm.ErrRecordNotFound {
			logrus.Error(err)
			return
		}

		if score == nil {
			logrus.Error("Score not found")
			return
		}

		if err := score.SoftDelete(); err != nil {
			logrus.Error(err)
			return
		}

		logrus.Info("The provided score has been soft deleted.")
	},
}
View Source
var DenyOnHoldCmd = &cobra.Command{
	Use:   "ranking:queue:hold:deny",
	Short: "Denies mapsets in the ranking queue that are on hold for a month",
	Run: func(cmd *cobra.Command, args []string) {
		onHoldMapsets, err := db.GetOldOnHoldMapsetsInRankingQueue()

		if err != nil {
			logrus.Error(err)
			return
		}

		for _, mapset := range onHoldMapsets {
			if err := mapset.UpdateStatus(db.RankingQueueDenied); err != nil {
				logrus.Error(err)
				return
			}

			logrus.Info("Auto-denied on hold mapset: ", mapset.MapsetId)

			avatar := webhooks.QuaverLogo

			_ = webhooks.SendQueueWebhook(&db.User{
				Id:        2,
				Username:  "QuaverBot",
				AvatarUrl: &avatar,
			}, mapset.Mapset, db.RankingQueueActionDeny)
		}
	},
}
View Source
var ElasticIndexMapsets = &cobra.Command{
	Use:   "elastic:index:mapsets",
	Short: "Indexes all mapsets in Elastic Search",
	Run: func(cmd *cobra.Command, args []string) {
		if err := db.IndexAllElasticSearchMapsets(true); err != nil {
			logrus.Error(err)
			return
		}

		logrus.Info("Complete!")
	},
}
View Source
var FixStatsCmd = &cobra.Command{
	Use:   "stats:fix",
	Short: "Fixes missing stats on a user",
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) == 0 {
			logrus.Error("You must provide a user id to fix")
		}

		id, err := strconv.Atoi(args[0])

		if err != nil {
			logrus.Error(err)
			return
		}

		user, err := db.GetUserById(id)

		if err != nil {
			logrus.Error(err)
			return
		}

		if user.StatsKeys4 == nil {
			if err := db.SQL.Create(&db.UserStatsKeys4{UserId: user.Id}).Error; err != nil {
				logrus.Error(err)
				return
			}

			logrus.Info("Fixed missing 4K stats for user: ", user.Id)
		}

		if user.StatsKeys7 == nil {
			if err := db.SQL.Create(&db.UserStatsKeys7{UserId: user.Id}).Error; err != nil {
				logrus.Error(err)
				return
			}

			logrus.Info("Fixed missing 7K stats for user: ", user.Id)
		}
	},
}
View Source
var PlayerDonatorCheckCmd = &cobra.Command{
	Use:   "player:donator:check",
	Short: "Checks if a player is a donator",
	Run: func(cmd *cobra.Command, args []string) {
		expiredUsers := map[int]*db.UserNotification{}

		removeExpiredDonator(expiredUsers)
		addDiscordPremiumDonator(expiredUsers)

		for _, notification := range expiredUsers {
			if err := notification.Insert(); err != nil {
				logrus.Error("Error inserting donator expired notification: ", err)
			}
		}
	},
}
View Source
var RemoveUnrankedClanScores = &cobra.Command{
	Use:   "clan:remove:unranked",
	Short: "Removes unranked clan scores",
	Run: func(cmd *cobra.Command, args []string) {
		scores := make([]*db.Score, 0)

		result := db.SQL.
			Where("clan_id IS NOT NULL AND mods > 0").
			Find(&scores)

		if result.Error != nil {
			logrus.Error(result.Error)
			return
		}

		for _, score := range scores {
			if enums.IsModComboRanked(enums.Mods(score.Modifiers)) {
				continue
			}

			err := db.SQL.Model(&db.Score{}).
				Where("id = ?", score.Id).
				Update("clan_id", nil).Error

			if err != nil {
				logrus.Error(err)
				return
			}

			logrus.Info("Removed clan score: ", score.Id)
		}
	},
}
View Source
var SupervisorActivityCmd = &cobra.Command{
	Use:   "supervisor:activity",
	Short: "Handles providing donator for supervisor activity",
	Run: func(cmd *cobra.Command, args []string) {
		supervisors, err := db.GetRankingSupervisors(true)

		if err != nil {
			logrus.Error("Error retrieving supervisors from DB: ", err)
			return
		}

		if len(supervisors) == 0 {
			return
		}

		timeStart := time.Now().AddDate(0, 0, -7).UnixMilli()
		timeEnd := time.Now().UnixMilli()

		var userActions = map[*db.User]int{}

		for _, supervisor := range supervisors {
			actions, err := db.GetUserRankingQueueComments(supervisor.Id, timeStart, timeEnd)

			if err != nil {
				logrus.Error("Error retrieving ranking queue comments: ", err)
				return
			}

			userActions[supervisor] = len(actions)

			if len(actions) < config.Instance.RankingQueue.WeeklyRequiredSupervisorActions {
				continue
			}

			var endTime int64

			if supervisor.DonatorEndTime == 0 {
				endTime = time.Now().AddDate(0, 0, 7).UnixMilli()
			} else {
				endTime = time.UnixMilli(supervisor.DonatorEndTime).AddDate(0, 0, 7).UnixMilli()
			}

			if err := supervisor.UpdateDonatorEndTime(endTime); err != nil {
				logrus.Error("Error updating supervisor donator end time: ", err)
				return
			}

			logrus.Infof("[Supervisor Activity] Gave 1 week donator to: %v (#%v)", supervisor.Username, supervisor.Id)

			if enums.HasUserGroup(supervisor.UserGroups, enums.UserGroupDonator) {
				continue
			}

			if err := supervisor.UpdateUserGroups(supervisor.UserGroups | enums.UserGroupDonator); err != nil {
				logrus.Error("Error updating supervisor donator usergroup: ", err)
				return
			}

			logrus.Infof("[Supervisor Activity] Gave dono group to: %v (#%v)", supervisor.Username, supervisor.Id)
		}

		_ = webhooks.SendSupervisorActivityWebhook(userActions, timeStart, timeEnd)
	},
}
View Source
var UpdateStripePriceId = &cobra.Command{
	Use:   "update:stripe:id",
	Short: "Updates the stripe price id for an order item",
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) < 2 {
			logrus.Error("You must provide an order item id and a stripe price id.")
			return
		}

		id, err := strconv.Atoi(args[0])

		if err != nil {
			logrus.Error(err)
			return
		}

		item, err := db.GetOrderItemById(db.OrderItemId(id))

		if err != nil {
			logrus.Error(err)
			return
		}

		if item.Id == db.OrderItemDonator {
			logrus.Error("Cannot update donator price id")
			return
		}

		if err := item.UpdateStripePriceId(args[1]); err != nil {
			logrus.Error(err)
			return
		}

		logrus.Info("Done!")
	},
}
View Source
var UserRankCmd = &cobra.Command{
	Use:   "stats:rank",
	Short: "Inserts the rank stats for all users ",
	Run: func(cmd *cobra.Command, args []string) {
		batchSize := 1000
		offset := 0

		for {
			var users = make([]*db.User, 0)

			result := db.SQL.
				Where("allowed = 1").
				Limit(batchSize).
				Offset(offset).
				Find(&users)

			if result.Error != nil {
				logrus.Println(result.Error)
			}

			if len(users) == 0 {
				break
			}

			for _, user := range users {
				for i := 1; i <= 2; i++ {
					key := fmt.Sprintf("quaver:leaderboard:%v", i)
					userStr := fmt.Sprintf("%v", user.Id)

					data, err := db.Redis.ZRevRankWithScore(db.RedisCtx, key, userStr).Result()

					if err != nil && err != redis.Nil {
						logrus.Error(err)
						return
					}

					if err == redis.Nil {
						logrus.Info("Skipping user: ", user.Id, " (no rank found)")
						continue
					}

					switch enums.GameMode(i) {
					case enums.GameModeKeys4:
						rank := &db.UserRankKeys4{
							UserId:                   user.Id,
							Rank:                     int(data.Rank + 1),
							OverallPerformanceRating: data.Score,
							Timestamp:                time.Now(),
						}

						if err := db.SQL.Create(&rank).Error; err != nil {
							logrus.Error(err)
							return
						}

					case enums.GameModeKeys7:
						rank := &db.UserRankKeys7{
							UserId:                   user.Id,
							Rank:                     int(data.Rank + 1),
							OverallPerformanceRating: data.Score,
							Timestamp:                time.Now(),
						}

						if err := db.SQL.Create(&rank).Error; err != nil {
							logrus.Error(err)
							return
						}
					}

					logrus.Info("Inserted rank for user: ", user.Id)
				}
			}

			offset += batchSize
		}

		for i := 1; i <= 2; i++ {
			table := fmt.Sprintf("user_rank_%v", enums.GetGameModeString(enums.GameMode(i)))
			query := fmt.Sprintf("DELETE FROM %v WHERE timestamp <= (CURDATE() - INTERVAL 90 DAY)", table)

			result := db.SQL.Exec(query)

			if result.Error != nil {
				logrus.Error(result.Error)
				return
			}
		}

		logrus.Info("Complete!")
	},
}
View Source
var WeeklyMostPlayedMapsetsCmd = &cobra.Command{
	Use:   "mapsets:weekly:cache",
	Short: "Caches the most played mapsets of the week in redis",
	Run: func(cmd *cobra.Command, args []string) {
		mapsets, err := db.GetWeeklyMostPlayedMapsets(true)

		if err != nil {
			logrus.Error("Error caching weekly most played mapsets", err)
		}

		logrus.Infof("Successfully cached: %v weekly most played mapsets", len(mapsets))
	},
}

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL