Пример #1
0
        /// <summary>
        /// Tries to find a server user in the DB context. If it can't find it, it will 
        /// first create the server and user if they don't exit and then create and
        /// return the new server user.
        /// </summary>
        /// <param name="ctx">Database context</param>
        /// <param name="serverId">ID of server</param>
        /// <param name="userId">ID of user</param>
        /// <returns></returns>
        public static ServerUser FindOrCreateUser(MoetronDBContext ctx, long serverId, long userId)
        {
            ServerUser su = ctx.ServerUsers.Find(serverId, userId);
            if (su != null)
                return su;

            Server s = ctx.Servers.Find(serverId);
            if (s == null)
            {
                s = ctx.Servers.Add(new Server()
                {
                    Id = serverId
                });
            }

            User u = ctx.Users.Find(userId);
            if (u == null)
            {
                u = ctx.Users.Add(new User()
                {
                    Id = userId
                });
            }

            su = ctx.ServerUsers.Add(new ServerUser()
            {
                ServerId = serverId,
                UserId = userId,
                LastAllowance = DateTime.UtcNow
            });

            ctx.SaveChanges();
            return su;
        }
Пример #2
0
        /// <summary>
        /// Removes users which exist in database but not on server.
        /// </summary>
        /// <param name="server">Discord server to check</param>
        /// <param name="msg">Return message</param>
        private void DeleteDeadUsers(Discord.Server server, out string msg)
        {
            msg = "";
            _ctx = new MoetronDBContext();

            Model.Server modelServer = _ctx.Servers.Find((long)server.Id);
            if (modelServer == null)
            {
                msg = "Server does not exist in database.";
                return;
            }

            int count = 0;
            Discord.User user;
            foreach (Model.ServerUser su in modelServer.ServerUsers.ToList())
            {
                user = server.Users.FirstOrDefault(x => (long)x.Id == su.UserId);
                if (user == null)
                {
                    _ctx.ServerUsers.Remove(su);
                    count++;
                }
            }
            msg = $"Removed {count} users!";
            _ctx.SaveChanges();
        }
Пример #3
0
 /// <summary>
 /// Deletes a ServerUser
 /// </summary>
 /// <param name="server">Server</param>
 /// <param name="user">User</param>
 public static void DeleteUser(Discord.Server server, Discord.User user)
 {
     _ctx = new MoetronDBContext();
     ServerUser su = _ctx.ServerUsers.Find((long)server.Id, (long)user.Id);
     if (su != null)
         _ctx.ServerUsers.Remove(su);
     _ctx.SaveChanges();
 }
Пример #4
0
 /// <summary>
 /// Check if allowance can be reset, and do so if it's been a day.
 /// </summary>
 /// <param name="ctx">Database context</param>
 /// <param name="su">Server user to check</param>
 /// <returns>Current allowance after check</returns>
 private static int ResetAllowance(MoetronDBContext ctx, ServerUser su)
 {
     //If a day has passed since last allowance, reset it
     if ((DateTime.UtcNow - su.LastAllowance).TotalDays > 1)
     {
         su.Allowance = DEFAULT_ALLOWANCE;
         su.LastAllowance = DateTime.UtcNow;
         ctx.SaveChanges();
     }
     return su.Allowance;
 }
Пример #5
0
        /// <summary>
        /// Checks if a user has enough allowance left to give or remove a number of points.
        /// </summary>
        /// <param name="ctx">Database context</param>
        /// <param name="su">Server user to check against</param>
        /// <param name="num">Number of points</param>
        /// <param name="isGiving">True if giving, false if removing</param>
        /// <returns>True if enough allowance left, false otherwise</returns>
        private bool CheckAllowanceAmount(MoetronDBContext ctx, ServerUser su, long num, bool isGiving)
        {
            if (su == null)
                return false;
            if (num < 1)
                return false;

            ResetAllowance(ctx, su);

            if (isGiving)
            {
                if (num > su.Allowance)
                    return false;
            }
            else
            {
                if (num * REMOVE_ALLOWANCE_COST > su.Allowance)
                    return false;
            }
            return true;
        }
Пример #6
0
        void IModule.Install(ModuleManager manager)
        {
            _manager = manager;
            _client = manager.Client;

            manager.CreateCommands("", cmd =>
            {
                cmd.CreateGroup("points", (b) =>
                {
                    b.AddCheck((c, u, ch) => !ch.IsPrivate);
                    b.MinPermissions((int)AccessLevel.User);
                    b.CreateCommand("allowance")
                        .Alias("left")
                        .Description("Display how much points you have left to use until next allowance.")
                        .Do(async (e) =>
                        {
                            _ctx = new MoetronDBContext();
                            ServerUser su = ModelUtil.FindOrCreateUser(_ctx, (long)e.Server.Id, (long)e.User.Id);
                            //Get time difference between now and next allowance
                            ResetAllowance(_ctx, su);
                            TimeSpan nextAllowance = TimeSpan.FromDays(1) - (DateTime.UtcNow - su.LastAllowance);
                            await e.Message.Delete();
                            await e.Channel.SendMessage($"{e.User.Mention} You have {su.Allowance} allowance points left. Next allowance available in {nextAllowance.Hours} hours and {nextAllowance.Minutes} minutes.");
                        });
                    b.CreateCommand("bal")
                        .Alias("balance")
                        .Description("Display your points balance. Specify a user to return their balance instead.\r\ne.g. `!points bal Moetron`")
                        .Parameter("user", ParameterType.Unparsed)
                        .Do(async (e) =>
                        {
                            Discord.User user;
                            ServerUser su;
                            string err = "";

                            //If user not specified use caller
                            if (e.GetArg("user").Length == 0)
                                user = e.User;
                            else
                                user = e.Server.Users.FindUser(e.GetArg("user"), out err);

                            //If user specified but not found
                            if (user == null)
                            {
                                await e.Channel.SendMessage($"{e.User.Mention} {err}");
                                return;
                            }
                            _ctx = new MoetronDBContext();
                            su = ModelUtil.FindOrCreateUser(_ctx, (long)e.Server.Id, (long)user.Id);
                            await e.Message.Delete();
                            await e.Channel.SendMessage($"{e.User.Mention} {user.NickOrName()} has {su.Points} points!");
                        });
                    b.CreateCommand("clean")
                        .Description("Clean up dead users from the current server.")
                        .MinPermissions((int)AccessLevel.BotOwner)
                        .Do(async (e) =>
                        {
                            string msg;
                            DeleteDeadUsers(e.Server, out msg);
                            await e.Message.Delete();
                            await e.Channel.SendMessage(msg);
                        });
                    b.CreateCommand("give")
                        .Alias(new string[] { "gift", "add" })
                        .Description("Give a user points for being dank. This will take the same "
                            + "amount from your daily allowance.\r\ne.g. `!points give 100 Moetron`")
                        .Parameter("num", ParameterType.Required)
                        .Parameter("user", ParameterType.Unparsed)
                        .Do(async (e) =>
                        {
                            await ModifyPoints(e, true);
                        });
                    b.CreateCommand("ranking")
                        .Alias("rank")
                        .Description("Get your ranking on this server.")
                        .Do(async (e) =>
                        {
                            _ctx = new MoetronDBContext();
                            ServerUser su = ModelUtil.FindOrCreateUser(_ctx, (long)e.Server.Id, (long)e.User.Id);
                            List<ServerUser> userList = _ctx.Servers.Find((long)e.Server.Id).ServerUsers.OrderByDescending(x => x.Points).ToList();

                            await e.Message.Delete();
                            await e.Channel.SendMessage($"{e.User.Mention} You're {userList.IndexOf(su) + 1} out of {userList.Count}.");
                        });
                    b.CreateCommand("remove")
                        .Alias("rem")
                        .Description("Remove a user's points for being lame. This will cost " +
                            $"{REMOVE_ALLOWANCE_COST} points from your daily allowance for each " +
                            $"point removed, as well as remove {REMOVE_COUNTER_FACTOR} times the amount " +
                            "from your own points, so you better think twice!\r\ne.g. `!points rem 100 Moetron`")
                        .Parameter("num", ParameterType.Required)
                        .Parameter("user", ParameterType.Unparsed)
                        .Do(async (e) =>
                        {
                            await ModifyPoints(e, false);
                        });
                    b.CreateCommand("reset")
                        .Description("Reset a user to defaults. This will reset their points, current allowance and last allowance time.\r\ne.g. `!points reset Moetron`")
                        .Parameter("user", ParameterType.Unparsed)
                        .MinPermissions((int)AccessLevel.ServerAdmin)
                        .Do(async (e) =>
                        {
                            string err;
                            Discord.User user = e.Server.Users.FindUser(e.GetArg("user"), out err);
                            ServerUser su;

                            if (user == null)
                            {
                                await e.Channel.SendMessage($"{e.User.Mention} {err}");
                                return;
                            }

                            _ctx = new MoetronDBContext();
                            su = ModelUtil.FindOrCreateUser(_ctx, (long)e.Server.Id, (long)user.Id);
                            su.LastAllowance = DateTime.UtcNow;
                            su.Allowance = DEFAULT_ALLOWANCE;
                            su.Points = DEFAULT_POINTS;

                            _ctx.SaveChanges();

                            await e.Message.Delete();
                            await e.Channel.SendMessage($"{e.User.Mention} {user.Mention}'s points has been reset to defaults.");
                        });
                    b.CreateCommand("resetServer")
                        .Description("Reset the whole server's point system. This will reset points, current allowances and last allowance times. Be careful with that.")
                        .MinPermissions((int)AccessLevel.ServerAdmin)
                        .Do(async (e) =>
                        {
                            _ctx = new MoetronDBContext();
                            foreach (var su in _ctx.Servers.Find((long)e.Server.Id).ServerUsers)
                            {
                                su.LastAllowance = DateTime.UtcNow;
                                su.Allowance = DEFAULT_ALLOWANCE;
                                su.Points = DEFAULT_POINTS;
                            }

                            _ctx.SaveChanges();

                            await e.Message.Delete();
                            await e.Channel.SendMessage($"{e.User.Mention} All users have been reset to defaults.");
                        });
                    b.CreateCommand("top")
                        .Alias("best")
                        .Description("Get the 5 top users of the server.")
                        .Do(async (e) =>
                        {
                            await DisplayRanking(e, true, 5);
                        });
                    b.CreateCommand("what")
                        .Alias("help")
                        .Description("Get an explanation of what points how and how they work.")
                        .Do(async (e) =>
                        {
                            string msg = "Points (aka memepoints) are a server-wide system. Each user " +
                                "is given a starting amount of points (referred to as just points, balance " +
                                "or total) when they start participating. Each user also receives an " +
                                "allowance every 24 hours which they can use to either give or remove " +
                                "other users' points. Giving only removes from your allowance, but " +
                                "removing also removes from your own points! This is done to encourage " +
                                "giving rather than removing. Allowances are only refreshed when you " +
                                "try using it or when you request it, and the timer is on an individual " +
                                "basis (i.e. if you use your points for the first time at 8:00, your next " +
                                "refresh will be after 8:00 the next day when you first try using it) " +
                                ".\r\nAll in all the system is for fun and it's what you make of it!\r\n" +
                                "Commands are used in this format: `!points <subcommand>`, and help " +
                                "with `!help points <subcommand>`. See individual command help for more info.";
                            await e.Message.Delete();
                            await e.User.SendMessage(msg);
                        });
                    b.CreateCommand("worst")
                        .Alias("bottom")
                        .Description("Get the 5 worst users of the server.")
                        .Do(async (e) =>
                        {
                            await DisplayRanking(e, false, 5);
                        });
                });
            });
        }
Пример #7
0
        /// <summary>
        /// Give or remove a user's points. Call from command event.
        /// </summary>
        /// <param name="e">Event from command</param>
        /// <param name="isGiving">True if giving points, false if removing</param>
        /// <returns>A task?</returns>
        private async System.Threading.Tasks.Task ModifyPoints(CommandEventArgs e, bool isGiving)
        {
            int num, allowanceCost;
            long pointCost;
            string msg;
            Discord.User receiver;
            ServerUser suSender, suReceiver;

            //Try to parse number
            if (!Int32.TryParse(e.GetArg("num"), out num))
            {
                await e.Channel.SendMessage($"{e.User.Mention} Must be a valid number. Also, number goes before name, you walnut.");
                return;
            }

            //Number must be positive & not 0
            if (num < 1)
            {
                await e.Channel.SendMessage($"{e.User.Mention} Must be a number higher than 0.");
                return;
            }

            //Try to find user on server
            receiver = e.Server.Users.FindUser(e.GetArg("user"), out msg);
            if (receiver == null)
            {
                await e.Channel.SendMessage($"{e.User.Mention} {msg}");
                return;
            }
            else if (receiver.Id == e.User.Id) //Cannot be caller
            {
                await e.Channel.SendMessage($"{e.User.Mention} You can't {(isGiving ? "give yourself" : "remove your own")} points!");
                return;
            }

            _ctx = new MoetronDBContext();
            suSender = ModelUtil.FindOrCreateUser(_ctx, (long)e.Server.Id, (long)e.User.Id);
            if (!CheckAllowanceAmount(_ctx, suSender, num, isGiving))
            {
                TimeSpan nextAllowance = TimeSpan.FromDays(1) - (DateTime.UtcNow - suSender.LastAllowance);
                await e.Channel.SendMessage($"{e.User.Mention} You don't have enough allowance points! ({suSender.Allowance} left, next allowance in {nextAllowance.Hours} hours and {nextAllowance.Minutes} minutes)");
                return;
            }

            suReceiver = ModelUtil.FindOrCreateUser(_ctx, (long)e.Server.Id, (long)receiver.Id);
            if (isGiving)
            {
                //Give points to receiver, remove allowance from caller
                suReceiver.Points += num;
                suSender.Allowance -= num;
                msg = $"{e.User.Mention} gave {num} points to {receiver.Mention}, raising their total to {suReceiver.Points}!";
                msg += $"\r\n{e.User.Mention} Allowance left: {suSender.Allowance}.";
            }
            else
            {
                //Remove points from receiver, remove points and allowance from caller
                suReceiver.Points -= num;
                pointCost = (long)Math.Round(num * REMOVE_COUNTER_FACTOR, MidpointRounding.AwayFromZero);
                allowanceCost = (int)Math.Round(num * REMOVE_ALLOWANCE_COST, MidpointRounding.AwayFromZero);
                suSender.Points -= pointCost;
                suSender.Allowance -= allowanceCost;
                msg = $"{e.User.Mention} removed {num} points from {receiver.Mention}, lowering their total to {suReceiver.Points}!";
                msg += $"\r\n{e.User.Mention} Allowance left: {suSender.Allowance} & lost {pointCost} from your own points, putting your total at {suSender.Points}.";
            }

            _ctx.SaveChanges();

            await e.Message.Delete();
            await e.Channel.SendMessage(msg);
        }
Пример #8
0
        /// <summary>
        /// Display the ranking of users on a server. Call from command event.
        /// </summary>
        /// <param name="e">Command event</param>
        /// <param name="isTop">True for top, false for worst</param>
        /// <param name="num">Number of users to put in display</param>
        /// <returns>A task?</returns>
        private static async Task DisplayRanking(CommandEventArgs e, bool isTop, int num)
        {
            int i = 1;
            string msg;

            _ctx = new MoetronDBContext();
            IEnumerable<ServerUser> query = _ctx.Servers.Find((long)e.Server.Id).ServerUsers;

            if (isTop)
                query = query.OrderByDescending(x => x.Points).Take(num);
            else
                query = query.OrderBy(x => x.Points).Take(num);

            msg = $"{e.User.Mention} ";

            if (query.Count() == 0)
                msg += "No rankings to display!";
            else
                msg += $"Here's the {(isTop ? "top" : "worst")} 5:\r\n";

            foreach (var su in query)
            {
                msg += $"{i++}. {e.Server.GetUser((ulong)su.UserId)?.NickOrName()}";
                msg += $" with {su.Points}\r\n";
            }

            await e.Message.Delete();
            await e.Channel.SendMessage(msg);
        }