Example #1
0
 async def _rename(self, ctx, *args):
     """
     Permet de renommer une devise existante.
     Usage : `!rename <symbole> "<nom>"`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(prog=f'{ctx.prefix}{ctx.command.name}',
                     description="Permet de créer une nouvelle devise.")
     parser.add_argument('symbol', type=str, help="Symbole de la devise")
     parser.add_argument('name', type=str, help="Nom de la devise")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Check currency
     currency = self.get_currency(args.symbol)
     if currency.user != user:
         await ctx.author.send(
             f":no_entry:  Cette devise ne vous appartient pas.")
         return
     # Change name if needed
     if currency.name != args.name:
         currency.name = args.name
         currency.save(only=('name', ))
     await ctx.author.send(
         f":white_check_mark:  Vous avez renommé votre devise **{currency.name}** ({currency.symbol}) avec succès !"
     )
Example #2
0
 async def _seed(self, ctx, *args):
     """
     Modifie la graine du générateur de nombres pseudo-aléatoire (admin uniquement).
     Usage : `!seed [<nombre>]`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description=
         "Permet de modifier la graine du générateur de nombres pseudo-aléatoire."
     )
     parser.add_argument('seed', type=int, nargs='?', help="Seed")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     if args.seed:
         self.seeds.append(args.seed)
     else:
         self.seeds.clear()
     seeds = ', '.join(map(str, self.seeds))
     await ctx.author.send(
         f":game_die:  Graine(s) configurée(s) : **{seeds or 'aucune'}**")
Example #3
0
 async def _rate(self, ctx, *args):
     """
     Permet de consulter le taux d'une devise.
     Usage : `!rate <symbole>`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description="Permet de consulter le taux d'une devise.")
     parser.add_argument('symbol', type=str, help="Symbole de la devise")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Check currency
     currency = self.get_currency(args.symbol)
     if not currency:
         await ctx.author.send(
             f":no_entry:  La devise sélectionnée n'existe pas.")
         return
     # Get currency infos
     base = self.get_currency(DISCORD_MONEY_SYMBOL)
     total = Balance.select(pw.fn.SUM(
         Balance.value)).where(Balance.currency == currency).scalar() or 0.0
     rate = round(currency.value * currency.rate / (total or 1), 5)
     # Display infos
     messages = [
         f"**{currency.name}** ({currency.symbol}), créée par **{currency.user.name}**"
         if currency.user else
         f"**{currency.name}** ({currency.symbol}), devise de base générale",
         f"Nombre en circulation : **{round(total,2):n}**"
     ]
     if currency != base:
         messages.extend([
             f"Taux actuel : **{round(currency.rate, 2):.0%}**",
             f"Valeur totale : **{round(currency.value,2):n} {base.symbol}**",
             f"Valeur individuelle : **{round(rate,2):n} {base.symbol}**"
         ])
     messages.append(
         f"Classement des 10 plus grosses fortunes en **{currency.name}** :"
     )
     balances = Balance.select(Balance, User).join(User).where(
         Balance.currency == currency,
         Balance.value > 0.001).order_by(Balance.value.desc()).limit(10)
     for indice, balance in zip(self.RANKS, balances):
         indice = self.get_icon(indice)
         if currency == base:
             messages.append(
                 f"{indice}  {balance.user.name} : **{round(balance.value,2):n} {currency.symbol}**"
             )
         else:
             messages.append(
                 f"{indice}  {balance.user.name} : **{round(balance.value,2):n} {currency.symbol}** "
                 f"soit **~{round(balance.value * rate,2):n} {base.symbol}**"
             )
     await ctx.author.send("\n".join(messages))
Example #4
0
 async def _roles(self, ctx, *args):
     """
     Permet de s'attribuer un ou plusieurs rôles.
     Usage : `!roles <role> [<role> ...]`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Get roles
     list_roles = [r.split("=") for r in DISCORD_ROLES.split(",")
                   ] if DISCORD_ROLES else []
     help_roles = ",\n".join(f"- {rolename} ({shortcut})"
                             for (shortcut, rolename) in list_roles)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description="Permet de s'attribuer un ou plusieurs rôles.",
         epilog=f"Rôles disponibles :\n{help_roles}",
         formatter_class=argparse.RawTextHelpFormatter)
     parser.add_argument('roles',
                         metavar='role',
                         type=str,
                         nargs='*',
                         help="Rôle")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Collect all allowed roles
     roles = {}
     for role in ctx.guild.roles:
         for shortcut, rolename in list_roles:
             if role.name.lower() == rolename.lower():
                 roles[shortcut] = role
     # Collect selected roles
     new_roles = []
     selected_roles = map(str.lower, args.roles)
     for shortcut, role in roles.items():
         if shortcut.lower() in selected_roles:
             new_roles.append(role)
         elif role.name.lower() in selected_roles:
             new_roles.append(role)
     if not new_roles:
         help_roles = ", ".join(f"**{rolename}** ({shortcut})"
                                for (shortcut, rolename) in list_roles)
         await ctx.author.send(
             f":warning:  Vous devez sélectionner un ou plusieurs rôles parmi : {help_roles}"
         )
         return
     # Clear roles
     old_roles = list(roles.values())
     await ctx.author.remove_roles(*old_roles)
     # Add roles
     await ctx.author.add_roles(*new_roles)
     role_names = ', '.join(role.name for role in new_roles)
     await ctx.author.send(
         f":scroll:  Vous avez désormais accès aux rôles suivants : **{role_names}** !"
     )
Example #5
0
 async def _store(self, ctx, *args):
     """
     Permet d'alimenter une devise pour augmenter sa valeur.
     Usage : `!store <symbole> <montant>`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description=
         "Permet d'alimenter une devise pour augmenter sa valeur.")
     parser.add_argument('symbol', type=str, help="Symbole de la devise")
     parser.add_argument('amount', type=float, help="Quantité d'argent")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Check positive
     if not args.amount > 0:
         await ctx.author.send(
             f":no_entry:  La quantité ne peut être négative ou nulle.")
         return
     # Check currency
     currency = self.get_currency(args.symbol)
     if not currency:
         await ctx.author.send(
             f":no_entry:  La devise sélectionnée n'existe pas.")
         return
     # Check ownership
     if not currency.user:
         await ctx.author.send(
             f":no_entry:  Il n'est pas possible d'alimenter cette devise.")
         return
     # Check balance
     base = self.get_currency(DISCORD_MONEY_SYMBOL)
     balance = self.get_balance(user, base)
     if balance.value < args.amount:
         await ctx.author.send(
             f":no_entry:  Vous n'avez pas assez d'argent sur votre compte : vous avez actuellement "
             f"**{round(balance.value,2):n} {currency.symbol}** "
             f"et il vous faut **{round(args.amount,2):n} {currency.symbol}**."
         )
         return
     # Transfert money
     balance.value -= args.amount
     Balance.update(value=Balance.value -
                    args.amount).where(Balance.id == balance.id).execute()
     currency.value += args.amount
     Currency.update(value=Currency.value + args.amount).where(
         Currency.id == currency.id).execute()
     await ctx.author.send(
         f":white_check_mark:  Vous avez transféré **{args.amount:n} {base.symbol}** ({base.name}) sur la devise "
         f"**{currency.name}** ({currency.symbol}) ! Valeur totale : **{round(currency.value,2):n} {base.symbol}**."
     )
Example #6
0
 async def _open(self, ctx, *args):
     """
     Ferme la soumission des candidatures et ouvre l'accès au vote pour un scrutin.
     Usage : `!open [--poll <poll_id>]`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description=
         "Ferme la soumission des candidatures et ouvre l'accès au vote pour un scrutin."
     )
     parser.add_argument('--poll',
                         '-p',
                         type=str,
                         help="Identifiant de scrutin")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Get active and votable polls
     polls = Poll.select().where(Poll.open_apply & ~Poll.open_vote)
     poll = await self.handle_poll(polls, args, ctx.author)
     if not poll:
         return
     channel = poll.channel or ctx.channel
     # Update poll
     poll.open_apply = False
     poll.open_vote = True
     poll.save(only=(
         'open_apply',
         'open_vote',
     ))
     # Assign letter to every candidate
     for i, candidate in enumerate(
             Candidate.select(Candidate,
                              User).join(User).order_by(User.name.asc())):
         candidate.indice = self.INDICES[i]
         candidate.save(only=('indice', ))
     # Message to user/channel
     message = (
         f":ballot_box:  Les candidatures au scrutin **{poll}** (`{poll.id}`) "
         f"sont désormais fermées et les votes sont ouverts, vous pouvez voter en "
         f"utilisant la commande `{ctx.prefix}vote` et voir les candidats avec `{ctx.prefix}info` !"
     )
     if channel and hasattr(channel, 'topic'):
         await channel.send(message)
     else:
         await ctx.author.send(message)
Example #7
0
 async def _info(self, ctx, *args):
     """
     Permet de consulter la liste des candidats au scrutin.
     Usage : `!info [--poll <poll_id>]`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description="Permet de consulter la liste des candidats au scrutin."
     )
     parser.add_argument('--poll',
                         '-p',
                         type=str,
                         help="Identifiant de scrutin")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Get active and appliable polls
     polls = Poll.select()
     poll = await self.handle_poll(polls, args, ctx.author)
     if not poll:
         return
     # Build message
     message = [
         f"Voici la liste des candidats actuels au scrutin **{poll}** (`{poll.id}`) :"
     ]
     for candidate in Candidate.select(Candidate, User).join(User).order_by(
             Candidate.indice.asc(), User.name.asc()):
         if poll.proposals:
             message.append(
                 f"{self.get_icon(candidate.indice)}  **{candidate.proposal}** (par {candidate.user.name})"
             )
         else:
             message.append(
                 f"{self.get_icon(candidate.indice)}  **{candidate.user.name}**"
             )
     message = '\n'.join(message)
     # Send message
     is_admin = any(role.name == DISCORD_ADMIN for role in ctx.author.roles)
     if is_admin and hasattr(ctx.channel, 'name'):
         channel = poll.channel or ctx.channel
         await channel.send(message)
     else:
         await ctx.author.send(message)
Example #8
0
 async def _money(self, ctx, *args):
     """
     Permet de consulter votre compte en banque.
     Usage : `!money [<utilisateur>]`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description="Permet de consulter votre compte en banque.")
     parser.add_argument('user', type=str, nargs='?', help="Utilisateur")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Check user
     target = await self.get_user(args.user)
     if args.user and not target:
         await ctx.author.send(
             f":no_entry:  L'utilisateur ciblé n'existe pas.")
         return
     # Display infos
     if target:
         messages = [f"**{target.name}** a actuellement :"]
     else:
         messages = ["Vous avez actuellement :"]
         target = user
     balances = Balance.select(Balance, Currency).join(Currency).where(
         Balance.user == target,
         Balance.value > 0.001).order_by(pw.fn.Lower(Currency.name))
     for balance in balances:
         messages.append(
             f"> **{round(balance.value,2):n} {balance.currency.symbol}** ({balance.currency.name})"
         )
     chunks, remaining = [], 2000
     for message in messages:
         length = len(message) + 1
         if length > remaining:
             await ctx.author.send("\n".join(chunks))
             chunks, remaining = [], 2000
         chunks.append(message)
         remaining -= length
     if chunks:
         await ctx.author.send("\n".join(chunks))
Example #9
0
 async def _pass(self, ctx, *args):
     """
     Définit un mot de passe pour pouvoir voter anonymement aux scrutins.
     Usage : `!pass <password>`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description=
         "Définit un mot de passe pour pouvoir voter anonymement aux scrutins."
     )
     parser.add_argument('password',
                         type=str,
                         help="Mot de passe (pour l'anonymat)")
     parser.add_argument('--poll',
                         '-p',
                         type=str,
                         help="Identifiant de scrutin")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Get active and appliable polls
     polls = Poll.select().where(Poll.open_apply | Poll.open_vote)
     poll = await self.handle_poll(polls, args, ctx.author)
     if not poll:
         return
     # Encoding and saving password for the user
     password, created = Password.get_or_create(
         poll=poll,
         user=user,
         defaults=dict(password=self.hash(args.password)))
     if not created:
         # If user already has a password
         await ctx.author.send(
             ":no_entry:  Vous avez déjà défini un mot de passe pour ce scruting."
         )
         return
     await ctx.author.send(
         f":white_check_mark:  Votre mot de passe de scrutin a été défini avec succès."
     )
Example #10
0
 async def _delete(self, ctx, *args):
     """
     Permet de supprimer une devise créée.
     Usage : `!delete <symbole>`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description="Permet de supprimer une devise créée.",
         epilog="Attention ! La suppression d'une devise est définitive "
         "et ses investissements ne seront pas remboursés.")
     parser.add_argument('symbol', type=str, help="Symbole de la devise")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Check currency
     currency = self.get_currency(args.symbol)
     if not currency:
         await ctx.author.send(
             f":no_entry:  La devise sélectionnée n'existe pas.")
         return
     if currency.user != user:
         await ctx.author.send(
             f":no_entry:  Cette devise ne vous appartient pas.")
         return
     # Delete balances and currency
     Balance.delete().where(Balance.currency == currency).execute()
     currency.delete_instance()
     # Empty caches
     self.currencies.clear()
     self.balances.clear()
     await ctx.author.send(
         f":white_check_mark:  La devise **{currency.name}** ({currency.symbol}) a été supprimée avec succès !"
     )
Example #11
0
 async def _create(self, ctx, *args):
     """
     Permet de créer une nouvelle devise.
     Usage : `!create <symbole> "<nom>" [<montant>]`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(prog=f'{ctx.prefix}{ctx.command.name}',
                     description="Permet de créer une nouvelle devise.")
     parser.add_argument('symbol', type=str, help="Symbole de la devise")
     parser.add_argument('name', type=str, help="Nom de la devise")
     parser.add_argument('amount',
                         type=int,
                         nargs='?',
                         help="Investissement initial")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Update balance
     if args.amount and args.amount < DISCORD_MONEY_CREATE:
         await ctx.author.send(
             f":no_entry:  Vous devez investir au minimum **{DISCORD_MONEY_CREATE:n} {DISCORD_MONEY_SYMBOL}** "
             f"lors de la création de votre nouvelle devise.")
         return
     value = args.amount or DISCORD_MONEY_CREATE
     # Check balance
     base_currency = self.get_currency(DISCORD_MONEY_SYMBOL)
     balance = self.get_balance(user, base_currency)
     if balance.value < value:
         await ctx.author.send(
             f":no_entry:  Vous n'avez pas assez d'argent sur votre compte : vous avez actuellement "
             f"**{round(balance.value,2):n} {base_currency.symbol}** "
             f"et il vous faut **{round(value,2):n} {base_currency.symbol}**."
         )
         return
     balance.value -= value
     Balance.update(value=Balance.value -
                    value).where(Balance.id == balance.id).execute()
     # Try create currency
     currency = self.get_currency(args.symbol,
                                  create=True,
                                  name=args.name,
                                  user=user,
                                  value=value)
     if currency.user != user:
         await ctx.author.send(
             f":no_entry:  Cette devise ne vous appartient pas.")
         return
     await ctx.author.send(
         f":white_check_mark:  Votre nouvelle devise **{args.name}** ({args.symbol}) a été créée avec succès !\n"
         f"Vous pouvez désormais en distribuer autant que vous le voulez avec `{ctx.prefix}give`, lui donner de la "
         f"valeur en l'approvisionnant avec `{ctx.prefix}store` et consulter son cours avec `{ctx.prefix}rate`."
     )
Example #12
0
 async def _new(self, ctx, *args):
     """
     Permet de créer un nouveau scrutin et l'ouvre aux candidatures.
     Usage : `!new <name> [--winners <count> --proposals]`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description=
         "Permet de créer un nouveau scrutin et l'ouvre aux candidatures.")
     parser.add_argument('name', type=str, help="Nom du scrutin")
     parser.add_argument('--winners',
                         '-w',
                         type=int,
                         help="Nombre de vainqueurs")
     parser.add_argument('--proposals',
                         '-p',
                         action='store_true',
                         help="Propositions ?")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Create new poll
     poll = Poll.create(name=args.name,
                        winners=args.winners or 1,
                        proposals=args.proposals)
     # Message to user/channel
     message = (
         f":ballot_box:  Le scrutin **{poll}** (`{poll.id}`) a été créé et ouvert aux candidatures, "
         f"vous pouvez utiliser la commande `{ctx.prefix}apply` pour vous présenter (ou `{ctx.prefix}leave` pour vous retirer) !"
     )
     if hasattr(ctx.channel, 'name'):
         # Save channel for announcements
         poll.channel_id = ctx.channel.id
         poll.save(only=('channel_id', ))
         await ctx.channel.send(message)
     else:
         await ctx.author.send(message)
Example #13
0
 async def _vote(self, ctx, *args):
     """
     Permet de voter à un scruting donné.
     Usage : `!vote <candidat> [<candidat> ...] --password <password> [--poll <poll_id>]`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(prog=f'{ctx.prefix}{ctx.command.name}', description="")
     parser.add_argument('password',
                         type=str,
                         help="Mot de passe (pour l'anonymat)")
     parser.add_argument(
         'candidates',
         metavar='candidat',
         type=str,
         nargs='+',
         help="Candidats (par ordre de préférence du plus ou moins apprécié)"
     )
     parser.add_argument('--poll',
                         '-p',
                         type=str,
                         help="Identifiant de scrutin")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Get active and votable polls
     polls = Poll.select().where(~Poll.open_apply & Poll.open_vote)
     poll = await self.handle_poll(polls, args, ctx.author)
     if not poll:
         return
     # Check if all candidates where selected and sorted
     candidates = list(map(str.upper, args.candidates))
     possibles = Candidate.select(Candidate.indice).where(
         Candidate.indice.is_null(False)
         & (Candidate.poll == poll)).order_by(Candidate.indice.asc())
     possibles = {c.indice for c in possibles}
     if possibles != set(candidates) or len(possibles) != len(candidates):
         await ctx.author.send(
             f":no_entry:  Vous n'avez pas sélectionné et/ou classé l'ensemble des candidats !"
         )
         return
     # Create new password for user
     password, created = Password.get_or_create(
         poll=poll,
         user=user,
         defaults=dict(password=self.hash(args.password)))
     # ... or verify user password
     if not created and self.hash(args.password) != password.password:
         await ctx.author.send(
             f":no_entry:  Votre mot de passe de scrutin est incorrect ou n'a pas encore configuré, "
             f"utilisez la commande `{ctx.prefix}pass` pour le définir !")
         return
     # Encrypt user with password and save vote choices
     encrypted, choices = self.encrypt(args.password,
                                       user.id), ' '.join(candidates)
     vote, created = Vote.get_or_create(user=encrypted,
                                        poll=poll,
                                        defaults=dict(choices=choices))
     if not created:
         vote.choices = choices
         vote.save(only=('choices', ))
     await ctx.author.send(f":ballot_box:  Merci pour votre vote !")
Example #14
0
 async def _loto(self, ctx, *args):
     """
     Permet d'enregistrer une participation au tirage du loto du jour.
     Usage : `!loto <nombre> <nombre> <nombre> <nombre> <nombre>`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description=
         "Permet d'enregistrer une participation au tirage du loto du jour."
     )
     parser.add_argument('numbers',
                         metavar='number',
                         type=int,
                         nargs=DISCORD_LOTO_COUNT,
                         help=f"Numéros du tirage (entre 1 et 49)")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Check numbers
     numbers = sorted(set(args.numbers))
     if len(numbers) != DISCORD_LOTO_COUNT or not all(1 <= n <= 49
                                                      for n in numbers):
         await ctx.author.send(
             f":no_entry:  Vous devez sélectionner **{DISCORD_LOTO_COUNT} numéros distincts** "
             f"ayant une valeur comprise **entre 1 et 49**.")
         return
     # Check loto
     loto = LotoDraw.get_or_none(LotoDraw.date == date.today())
     if not loto:
         await ctx.author.send(
             f":no_entry:  Il n'y a pas encore de tirage LOTO prévu pour aujourd'hui. "
             f"Veuillez patienter jusqu'à ce que le tirage de la veille soit réalisé."
         )
         return
     # Check balance
     currency = self.get_currency(DISCORD_MONEY_SYMBOL)
     balance = self.get_balance(user, currency)
     price = round(
         DISCORD_LOTO_PRICE + round(loto.value / DISCORD_LOTO_LIMIT, 1), 1)
     if balance.value < price:
         await ctx.author.send(
             f":no_entry:  Vous n'avez pas assez d'argent sur votre compte : une grille coûte "
             f"**{round(price,2):n} {currency.symbol}** et vous n'avez actuellement que "
             f"**{round(balance.value,2):n} {currency.symbol}**).")
         return
     # Pay and create grid
     balance.value -= price
     Balance.update(value=Balance.value -
                    price).where(Balance.id == balance.id).execute()
     grid = LotoGrid.create(user=user, draw=' '.join(map(str, numbers)))
     # Display information
     draw = ' - '.join(f"{d:02}" for d in numbers)
     for i in range(10):
         draw = draw.replace(str(i), self.get_icon(str(i)))
     await ctx.author.send(
         f":white_check_mark:  Vous avez acheté avec succès une grille pour le tirage du "
         f"**{grid.date:%A %d %B %Y}** avec les numéros suivants : **{draw}**"
     )
Example #15
0
 async def _slot(self, ctx, *args):
     """
     Joue une quantité d'argent à la machine à sous.
     Usage : `!slot <montant> [<symbole>]`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description="Joue une quantité d'argent à la machine à sous.")
     parser.add_argument('amount', type=int, help="Quantité d'argent")
     parser.add_argument('symbol',
                         type=str,
                         nargs='?',
                         help="Symbole de la devise")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Check positive
     if not args.amount > 0:
         await ctx.author.send(
             f":no_entry:  La quantité ne peut être négative ou nulle.")
         return
     # Check currency
     currency = self.get_currency(args.symbol or DISCORD_MONEY_SYMBOL)
     if not currency:
         await ctx.author.send(
             f":no_entry:  La devise sélectionnée n'existe pas.")
         return
     if currency.user == user:
         await ctx.author.send(
             f":no_entry:  Cette devise vous appartient, vous ne pouvez pas la jouer."
         )
         return
     # Check balance
     balance = self.get_balance(user, currency)
     if balance.value < args.amount:
         await ctx.author.send(
             f":no_entry:  Vous n'avez pas assez d'argent sur votre compte : vous avez actuellement "
             f"**{round(balance.value,2):n} {currency.symbol}** "
             f"et il vous faut **{round(args.amount,2):n} {currency.symbol}**."
         )
         return
     # Place the bet
     balance.value -= args.amount
     Balance.update(value=Balance.value -
                    args.amount).where(Balance.id == balance.id).execute()
     # Play the slots
     slots = {
         1: ':apple:',
         2: ':tangerine:',
         3: ':lemon:',
         4: ':four_leaf_clover:',
         5: ':bell:',
         6: ':gem:'
     }
     multipliers = {
         (1, 1, 1): 2.0,
         (2, 2, 2): 3.0,
         (3, 3, 3): 4.0,
         (4, 4, 4): 5.0,
         (5, 5, 5): 10.0,
         (6, 6, 6): 15.0
     }
     values = list(slots.keys())
     seed(self.seeds.pop(0) if self.seeds else None)
     results = choice(values), choice(values), choice(values)
     result = args.amount * multipliers.get(
         results, 1.0 if len(set(results)) < len(results) else 0.0)
     if result:
         balance.value += result
         Balance.update(value=Balance.value +
                        result).where(Balance.id == balance.id).execute()
     # Add loss to loto
     if not result:
         value = args.amount
         if currency.symbol != DISCORD_MONEY_SYMBOL:
             total = Balance.select(pw.fn.SUM(Balance.value)).where(
                 Balance.currency == currency).scalar() or 0.0
             value = round(
                 args.amount * (currency.value * currency.rate /
                                (total or 1)), 5)
             # Reduce value of currency
             subvalue = args.amount * (currency.value / (total or 1))
             currency.value -= subvalue
             Currency.update(value=Currency.value - subvalue).where(
                 Currency.id == currency.id).execute()
         LotoDraw.update(value=LotoDraw.value + value).where(
             LotoDraw.date == date.today()).execute()
     # Create display message
     slot1, slot2, slot3 = sorted(results, reverse=True)
     messages = [
         "C'est parti !", f"{slots[slot1]}", f"{slots[slot2]}",
         f"{slots[slot3]}"
     ]
     if ctx.channel and hasattr(ctx.channel, 'name'):
         endpoint = ctx.channel
         if result > args.amount:
             messages.append(
                 f"<@{user.id}> a remporté **{round(result,2):n} {currency.symbol}** ! :smile:"
             )
         elif result:
             messages.append(
                 f"<@{user.id}> a récupéré sa mise de **{round(result,2):n} {currency.symbol}**. :slight_smile:"
             )
         else:
             messages.append(
                 f"<@{user.id}> a perdu **{round(args.amount,2):n} {currency.symbol}** ! :frowning:"
             )
     else:
         endpoint = ctx.author
         if result > args.amount:
             messages.append(
                 f"Vous remportez **{round(result,2):n} {currency.symbol}** ! :smile:"
             )
         elif result:
             messages.append(
                 f"Vous récupérez votre mise de **{round(result,2):n} {currency.symbol}** ! :slight_smile:"
             )
         else:
             messages.append(
                 f"Vous perdez **{round(args.amount,2):n} {currency.symbol}** ! :frowning:"
             )
     # Display slot machine
     message = await endpoint.send(messages[0])
     for i in range(1, len(results) + 1):
         for value in sample(values, len(values)):
             content = '  '.join(messages[:i] + [slots[value]])
             await message.edit(content=content)
             await asyncio.sleep(0.5)
     content = '  '.join(messages)
     await message.edit(content=content)
Example #16
0
 async def _buy(self, ctx, *args):
     """
     Permet d'acheter une quantité d'une devise quelconque au taux actuel
     Usage : `!buy <nombre> <symbol>`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description="Joue une quantité d'argent à la machine à sous.")
     parser.add_argument('amount', type=int, help="Quantité d'argent")
     parser.add_argument('symbol', type=str, help="Symbole de la devise")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Check positive
     if not args.amount > 0:
         await ctx.author.send(
             f":no_entry:  La quantité ne peut être négative ou nulle.")
         return
     # Check currency
     base_currency = self.get_currency(DISCORD_MONEY_SYMBOL)
     currency = self.get_currency(args.symbol)
     if not currency:
         await ctx.author.send(
             f":no_entry:  La devise sélectionnée n'existe pas.")
         return
     if currency.user == user:
         await ctx.author.send(
             f":no_entry:  Cette devise vous appartient, vous ne pouvez pas en acheter."
         )
         return
     if not currency.user:
         await ctx.author.send(
             f":no_entry:  La devise principale (**{base_currency.name}**) ne peut être achetée."
         )
     # Get currency rate
     total = Balance.select(pw.fn.SUM(
         Balance.value)).where(Balance.currency == currency).scalar() or 0.0
     value = round(
         args.amount * (currency.value * currency.rate / (total or 1)), 5)
     rate = round(args.amount /
                  (total + args.amount), 2) if total + args.amount else 0.0
     rate = max(0.0, min(rate, currency.rate))
     # Check balance
     base_balance = self.get_balance(user, base_currency)
     if base_balance.value < value:
         await ctx.author.send(
             f":no_entry:  Vous n'avez pas assez d'argent sur votre compte : vous avez actuellement "
             f"**{round(base_balance.value,2):n} {currency.symbol}** "
             f"et il vous faut **{round(value,2):n} {currency.symbol}**.")
         return
     # Update balance
     base_balance.value -= value
     Balance.update(value=Balance.value -
                    value).where(Balance.id == base_balance.id).execute()
     balance = self.get_balance(user, currency)
     balance.value += args.amount
     Balance.update(value=Balance.value +
                    args.amount).where(Balance.id == balance.id).execute()
     # Update currency
     currency.value += value
     currency.rate -= rate
     Currency.update(
         value=Currency.value + value,
         rate=Currency.rate - rate,
     ).where(Currency.id == currency.id).execute()
     # Message to user
     await ctx.author.send(
         f":moneybag:  Vous avez acheté **{args.amount:n} {currency.symbol}** ({currency.name}) "
         f"pour une valeur de **{round(value,2):n} {base_currency.symbol}** ({base_currency.name}) !"
     )
Example #17
0
 async def _market(self, ctx, *args):
     """
     Permet de consulter l'ensemble des devises existantes.
     Usage : `!market [<utilisateur>]`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description="Permet de consulter l'ensemble des devises existantes."
     )
     parser.add_argument('user', type=str, nargs='?', help="Utilisateur")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Check user
     target = await self.get_user(args.user)
     if args.user and not target:
         await ctx.author.send(
             f":no_entry:  L'utilisateur ciblé n'existe pas.")
         return
     # Display infos
     base = self.get_currency(DISCORD_MONEY_SYMBOL)
     messages = [
         f"Voici les devises créées par **{target.name}** :"
         if target else "Voici toutes les devises existantes :"
     ]
     currencies = (Currency.select(
         Currency, User,
         pw.fn.SUM(Balance.value).alias('total')).join(
             User, pw.JOIN.LEFT_OUTER)).switch(Currency).join(
                 Balance, pw.JOIN.LEFT_OUTER).group_by(Currency).order_by(
                     pw.fn.Lower(Currency.name))
     if target:
         currencies = currencies.where(Currency.user == target)
     for currency in currencies:
         total = currency.total or 0
         value = (currency.value * currency.rate) / (total or 1)
         if currency.user:
             if target:
                 messages.append(
                     f"> **{currency.name}** ({currency.symbol}) avec "
                     f"**{round(total, 2):n}** unités en circulation d'une valeur de "
                     f"**{round(value, 2):n} {base.symbol}** (taux: {round(currency.rate,2):.0%})"
                 )
             else:
                 messages.append(
                     f"> **{currency.name}** ({currency.symbol}) créée par **{currency.user.name}** avec "
                     f"**{round(total,2):n}** unités en circulation d'une valeur de "
                     f"**{round(value,2):n} {base.symbol}** (taux: {round(currency.rate,2):.0%})"
                 )
         else:
             messages.append(
                 f"> **{currency.name}** ({currency.symbol}) devise principale avec "
                 f"**{round(total, 2):n}** unités en circulation")
     chunks, remaining = [], 2000
     for message in messages:
         length = len(message) + 1
         if length > remaining:
             await ctx.author.send("\n".join(chunks))
             chunks, remaining = [], 2000
         chunks.append(message)
         remaining -= length
     if chunks:
         await ctx.author.send("\n".join(chunks))
Example #18
0
 async def _leave(self, ctx, *args):
     """
     Permet de retirer sa candidature au scrutin.
     Usage : `!leave [--poll <poll_id>]`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description="Permet de retirer sa candidature au scrutin.")
     parser.add_argument('--poll',
                         '-p',
                         type=str,
                         help="Identifiant de scrutin")
     parser.add_argument('--proposal',
                         '-P',
                         type=int,
                         help="Identifiant de la proposition")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Get active and appliable polls
     polls = Poll.select().where(Poll.open_apply & ~Poll.open_vote)
     poll = await self.handle_poll(polls, args, ctx.author)
     if not poll:
         return
     channel = poll.channel or ctx.channel
     # Delete candidate
     if poll.proposals:
         if not args.proposal:
             await ctx.author.send(
                 f":no_entry:  Vous devez fournir l'identifiant de la "
                 f"proposition à retirer à l'aide du paramètre `--proposal <id>`."
             )
             return
         candidate = Candidate.get_or_none(user=user,
                                           poll=poll,
                                           id=args.proposal)
         if candidate:
             candidate.delete_instance()
             await ctx.author.send(
                 f":white_check_mark:  Vous avez retiré avec succès votre proposition "
                 f"**{candidate.proposal}** au scrutin de **{poll}** (`{poll.id}`) !"
             )
             if channel and hasattr(channel, 'topic'):
                 await channel.send(
                     f":door:  <@{user.id}> retire sa proposition **{candidate.proposal}** "
                     f"au scrutin de **{poll}** (`{poll.id}`) !")
             return
         await ctx.author.send(
             f":no_entry:  Vous n'avez pas cette proposition à l'élection de **{poll}** (`{poll.id}`) !"
         )
     else:
         candidate = Candidate.get_or_none(user=user, poll=poll)
         if candidate:
             candidate.delete_instance()
             await ctx.author.send(
                 f":white_check_mark:  Vous vous êtes retiré avec succès en tant "
                 f"que candidat à l'élection de **{poll}** !")
             if channel and hasattr(channel, 'topic'):
                 await channel.send(
                     f":door:  <@{user.id}> se retire en tant que candidat l'élection de **{poll}** !"
                 )
             return
         await ctx.author.send(
             f":no_entry:  Vous n'êtes pas candidat à l'élection de **{poll}** (`{poll.id}`) !"
         )
Example #19
0
 async def _apply(self, ctx, *args):
     """
     Permet de postuler en tant que candidat au scrutin avec ou sans proposition.
     Usage : `!apply [--poll <poll_id> --proposal <text>]`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description=
         "Permet de postuler en tant que candidat au scrutin avec ou sans proposition."
     )
     parser.add_argument('--poll',
                         '-p',
                         type=str,
                         help="Identifiant de scrutin")
     parser.add_argument(
         '--proposal',
         '-P',
         type=str,
         help="Texte de la proposition (si autorisé par le scrutin)")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Get active and appliable polls
     polls = Poll.select().where(Poll.open_apply & ~Poll.open_vote)
     poll = await self.handle_poll(polls, args, ctx.author)
     if not poll:
         return
     channel = poll.channel or ctx.channel
     # Create candidate
     if poll.proposals:
         if not args.proposal:
             await ctx.author.send(
                 f":no_entry:  Ce scrutin nécessite que vous ajoutiez une proposition à votre candidature, "
                 f"vous pouvez le faire en utilisant le paramètre `--proposal \"<proposition>\"`."
             )
             return
         candidate, created = Candidate.get_or_create(
             user=user, poll=poll, proposal=args.proposal)
         if created:
             await ctx.author.send(
                 f":white_check_mark:  Votre proposition **{args.proposal}** "
                 f"(`{candidate.id}`) au scrutin de **{poll}** (`{poll.id}`) a été enregistrée !"
             )
             if channel and hasattr(channel, 'topic'):
                 await channel.send(
                     f":raised_hand:  <@{user.id}> a ajouté la proposition **{args.proposal}** "
                     f"(`{candidate.id}`) au scrutin de **{poll.name}** (`{poll.id}`) !"
                 )
             return
         await ctx.author.send(
             f":no_entry:  Vous avez déjà ajouté la proposition **{args.proposal}** "
             f"(`{candidate.id}`) à l'élection de **{poll}** (`{poll.id}`) !"
         )
     else:
         candidate, created = Candidate.get_or_create(user=user, poll=poll)
         if created:
             await ctx.author.send(
                 f":white_check_mark:  Vous avez postulé avec succès en tant "
                 f"que candidat au scrutin de **{poll}** (`{poll.id}`) !")
             if channel and hasattr(channel, 'topic'):
                 await channel.send(
                     f":raised_hand:  <@{user.id}> se porte candidat "
                     f"au scrutin de **{poll.name}** (`{poll.id}`) !")
             return
         await ctx.author.send(
             f":no_entry:  Vous êtes déjà candidat à l'élection de **{poll}** (`{poll.id}`) !"
         )
Example #20
0
 async def _give(self, ctx, *args):
     """
     Permet de donner de l'argent à un autre utilisateur.
     Usage : `!give <montant> <symbole> <utilisateur>`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description="Permet de donner de l'argent à un autre utilisateur.")
     parser.add_argument('amount', type=int, help="Quantité d'argent")
     parser.add_argument('symbol', type=str, help="Symbole de la devise")
     parser.add_argument('user', type=str, help="Utilisateur")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     if not args.amount > 0:
         await ctx.author.send(
             f":no_entry:  La quantité ne peut être négative ou nulle.")
         return
     if args.amount > DISCORD_MONEY_LIMIT:
         await ctx.author.send(
             f":no_entry:  Il n'est pas possible d'échanger plus de "
             f"**{round(DISCORD_MONEY_LIMIT,2):n} unités** d'une même devise en une seule fois."
         )
         return
     # Check currency
     currency = self.get_currency(args.symbol)
     if not currency:
         await ctx.author.send(
             f":no_entry:  La devise sélectionnée n'existe pas.")
         return
     # Check target
     target = await self.get_user(args.user)
     if not target or target.user.bot or target == user or target == currency.user:
         await ctx.author.send(
             f":no_entry:  Le destinataire n'est pas valide.")
         return
     # Check balance
     if currency.user != user:
         source = self.get_balance(user, currency)
         if source.value < args.amount:
             await ctx.author.send(
                 f":no_entry:  Vous n'avez pas assez d'argent sur votre compte : vous avez actuellement "
                 f"**{round(source.value, 2):n} {currency.symbol}** "
                 f"et il vous faut **{round(args.amount, 2):n} {currency.symbol}**."
             )
             return
         source.value -= args.amount
         Balance.update(value=Balance.value - args.amount).where(
             Balance.id == source.id).execute()
     # Decrease currency rate
     if currency.user:
         currency.rate = max(DISCORD_MONEY_MINI,
                             currency.rate * DISCORD_MONEY_RATE)
         Currency.update(rate=currency.rate).where(
             Currency.id == currency.id).execute()
     # Give money
     balance = self.get_balance(target, currency)
     balance.value += args.amount
     Balance.update(value=Balance.value +
                    args.amount).where(Balance.id == balance.id).execute()
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.channel.send(
             f":moneybag:  <@{user.id}> a donné **{args.amount:n} {currency.symbol}** "
             f"({currency.name}) à <@{target.id}> !")
     else:
         await ctx.author.send(
             f":moneybag:  Vous avez donné **{args.amount:n} {currency.symbol}** "
             f"({currency.name}) à **{target.name}** !")
         await target.user.send(
             f":moneybag:  **{user.name}** vous a donné **{args.amount:n} "
             f"{currency.symbol}** ({currency.name}) !")
Example #21
0
 async def _close(self, ctx, *args):
     """
     Ferme le vote à un scrutin et affiche les résultats.
     Usage : `!close [--poll <poll_id>]`
     """
     if ctx.channel and hasattr(ctx.channel, 'name'):
         await ctx.message.delete()
     user = await self.get_user(ctx.author)
     # Argument parser
     parser = Parser(
         prog=f'{ctx.prefix}{ctx.command.name}',
         description="Ferme le vote à un scrutin et affiche les résultats.")
     parser.add_argument('--poll',
                         '-p',
                         type=str,
                         help="Identifiant de scrutin")
     args = parser.parse_args(args)
     if parser.message:
         await ctx.author.send(f"```{parser.message}```")
         return
     # Get active and votable polls
     polls = Poll.select().where(~Poll.open_apply & Poll.open_vote)
     poll = await self.handle_poll(polls, args, ctx.author)
     if not poll:
         return
     channel = poll.channel or ctx.channel
     # Update poll
     poll.open_apply = False
     poll.open_vote = False
     poll.save(only=(
         'open_apply',
         'open_vote',
     ))
     # Compute results
     self.get_results(poll, save=True)
     # Display winners
     votes = Vote.select(
         Vote.id).where(Vote.poll == poll).count()  # Count total votes
     candidates = Candidate.select(Candidate.id).where(
         Candidate.poll == poll).count()  # Count total candidates
     winners = Candidate.select(Candidate, User).join(User).where(
         Candidate.poll == poll,
         Candidate.winner).order_by(Candidate.proposal.asc(),
                                    User.name.asc())
     winners = ', '.join([
         f"{self.get_icon(winner.indice)}  **{winner.proposal}** (par <@{winner.user_id}>)"
         if poll.proposals else
         f"{self.get_icon(winner.indice)}  <@{winner.user_id}>"
         for winner in winners
     ])
     message = (
         f":trophy:  Les élections de **{poll}** sont désormais terminées, "
         f"il y a eu **{votes}** votes pour **{candidates}** candidatures. "
         f"Merci à tous pour votre participation !\n")
     if poll.winners > 1:
         message += f"Les vainqueurs sont : {winners} ! Félicitations !"
     else:
         message += f"Le vainqueur est : {winners} ! Félicitations !"
     if channel and hasattr(channel, 'topic'):
         await channel.send(message)
     else:
         await ctx.author.send(message)