Example #1
0
    def execute(self, bot, update, args):
        username = update.effective_user.username

        if not Bismuth.wallet_exists(username):
            msg = "Accept terms and create a wallet first with:\n/accept"
            update.message.reply_text(msg)
            return

        if len(args) < 2 or len(args) > 4:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        send_to = args[0]
        amount = args[1]

        operation = ""
        if len(args) > 2:
            operation = args[2]

        data = ""
        if len(args) > 3:
            data = args[3]

        if not BismuthUtil.valid_address(send_to):
            update.message.reply_text(
                text=f"{emo.ERROR} Bismuth address is not valid",
                parse_mode=ParseMode.MARKDOWN)
            return

        if not utl.is_numeric(amount) or float(amount) < 0:
            update.message.reply_text(
                text=f"{emo.ERROR} Specified amount is not valid",
                parse_mode=ParseMode.MARKDOWN)
            return

        message = update.message.reply_text(text=f"{emo.WAIT} Sending...",
                                            parse_mode=ParseMode.MARKDOWN)

        bis = Bismuth(username)
        bis.load_wallet()
        trx = bis.send(send_to, amount, operation, data)

        url = f"{self.BLCK_EXPL_URL}{utl.encode_url(trx)}"

        if trx:
            bot.edit_message_text(
                chat_id=message.chat_id,
                message_id=message.message_id,
                text=f"{emo.DONE} Done!\n[View on Block Explorer]({url})\n"
                f"(Available after ~1 minute)",
                parse_mode=ParseMode.MARKDOWN)
        else:
            bot.edit_message_text(
                chat_id=message.chat_id,
                message_id=message.message_id,
                text=f"{emo.ERROR} Not able to send Transaction")
Example #2
0
    def execute(self, bot, update, args):
        username = update.effective_user.username

        if not Bismuth.wallet_exists(username):
            msg = "Accept terms and create a wallet first with:\n/accept"
            update.message.reply_text(msg)
            return

        message = update.message.reply_text(
            text=f"{emo.WAIT} Checking balance...",
            parse_mode=ParseMode.MARKDOWN)

        bis = Bismuth(username)
        bis.load_wallet()

        balance = bis.get_balance()

        if utl.is_numeric(balance):
            balance = f"`{balance}` BIS"

        bot.edit_message_text(chat_id=message.chat_id,
                              message_id=message.message_id,
                              text=f"Balance: {balance}",
                              parse_mode=ParseMode.MARKDOWN)
Example #3
0
    def execute(self, bot, update, args):
        user = update.effective_user.username

        if len(args) < 2 or len(args) > 4:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        address = args[0]
        amount = args[1]

        operation = ""
        if len(args) > 2:
            operation = args[2]

        data = ""
        if len(args) > 3:
            data = args[3]

        # Check if provided amount is valid
        if not utl.is_numeric(amount) or float(amount) < 0:
            update.message.reply_text(
                text=f"{emo.ERROR} Specified amount is not valid",
                parse_mode=ParseMode.MARKDOWN)
            return

        # Check if provided address is valid
        if not BismuthUtil.valid_address(address):
            update.message.reply_text(
                text=f"{emo.ERROR} Provided address is not valid",
                parse_mode=ParseMode.MARKDOWN)
            return

        # Check if user has a wallet
        if not Bismuth.wallet_exists(user):
            msg = "Accept terms and create a wallet first with:\n/accept"
            update.message.reply_text(msg)
            return

        message = update.message.reply_text(text=f"{emo.WAIT} Processing...",
                                            parse_mode=ParseMode.MARKDOWN)

        bis = Bismuth(user)
        bis.load_wallet()

        balance = bis.get_balance()
        total = float(amount) + BismuthUtil.fee_for_tx(data)

        # Check for sufficient funds
        if not utl.is_numeric(balance) or float(balance) < total:
            bot.edit_message_text(chat_id=message.chat_id,
                                  message_id=message.message_id,
                                  text=f"{emo.ERROR} Not enough funds")
            return

        try:
            # Execute withdrawing
            trx = bis.send(address, amount, operation, data)
        except Exception as e:
            error = f"Error withdrawing {amount} BIS " \
                    f"from @{user} " \
                    f"to {address} " \
                    f"with '{operation}' " \
                    f"and '{data}': {e}"
            logging.error(error)
            self.notify(error)
            trx = None

        if trx:
            logging.debug(f"Withdraw {amount} BIS "
                          f"from @{user} "
                          f"to {address} "
                          f"with '{operation}' "
                          f"and '{data}'")

            # Save withdrawing to database
            insert = self.get_resource("insert_withdraw.sql")
            self.execute_sql(insert, user, address, amount)

            url = f"{self.BLCK_EXPL_URL}{utl.encode_url(trx)}"

            # Send success message
            bot.edit_message_text(
                chat_id=message.chat_id,
                message_id=message.message_id,
                text=f"{emo.DONE} DONE!\n[View on Block Explorer]({url})\n"
                f"(Available after ~1 minute)",
                parse_mode=ParseMode.MARKDOWN)
        else:
            # Send error message
            bot.edit_message_text(
                chat_id=message.chat_id,
                message_id=message.message_id,
                text=
                f"{emo.ERROR} Withdrawing not executed. Something went wrong..."
            )
Example #4
0
    def _update_plugin(self, bot, update):
        """
        Update a plugin by uploading a file to the bot.

        If you provide a .ZIP file then the content will be extracted into
        the plugin with the same name as the file. For example the file
        'about.zip' will be extracted into the 'about' plugin folder.

        It's also possible to provide a .PY file. In this case the file will
        replace the plugin implementation with the same name. For example the
        file 'about.py' will replace the same file in the 'about' plugin.

        All of this will only work in a private chat with the bot.
        """

        # Check if in a private chat
        if bot.get_chat(update.message.chat_id).type != Chat.PRIVATE:
            return

        # Check if user that triggered the command is allowed to execute it
        if update.effective_user.id not in self.config.get("admin", "ids"):
            return

        name = update.message.effective_attachment.file_name.lower()
        zipped = False

        try:
            if name.endswith(".py"):
                plugin_name = name.replace(".py", "")
            elif name.endswith(".zip"):
                if len(name) == 18:
                    msg = f"{emo.ERROR} Only backups of plugins are supported"
                    update.message.reply_text(msg)
                    return
                zipped = True
                if utl.is_numeric(name[:13]):
                    plugin_name = name[14:].replace(".zip", "")
                else:
                    plugin_name = name.replace(".zip", "")
            else:
                msg = f"{emo.ERROR} Wrong file format"
                update.message.reply_text(msg)
                return

            file = bot.getFile(update.message.document.file_id)

            if zipped:
                os.makedirs(con.DIR_TMP, exist_ok=True)
                zip_path = os.path.join(con.DIR_TMP, name)
                file.download(zip_path)

                with ZipFile(zip_path, 'r') as zip_file:
                    plugin_path = os.path.join(con.DIR_SRC, con.DIR_PLG,
                                               plugin_name)
                    zip_file.extractall(plugin_path)
            else:
                file.download(
                    os.path.join(con.DIR_SRC, con.DIR_PLG, plugin_name, name))

            self.remove_plugin(plugin_name)
            self.add_plugin(plugin_name)

            shutil.rmtree(con.DIR_TMP, ignore_errors=True)

            update.message.reply_text(f"{emo.DONE} Plugin successfully loaded")
        except Exception as e:
            logging.error(e)
            msg = f"{emo.ERROR} {e}"
            update.message.reply_text(msg)
Example #5
0
    def execute(self, bot, update, args):
        reply = update.message.reply_to_message

        # Tip the user that you reply to
        if reply:
            # Determine amount to tip
            if len(args) == 0:
                # Tip default BIS amount
                amount = self.DEFAULT_TIP
            elif len(args) == 1:
                # Tip specified BIS amount
                try:
                    amount = float(args[0])
                except:
                    msg = f"{emo.ERROR} Specified amount is not valid"
                    update.message.reply_text(msg)
                    return
            else:
                msg = "You are tipping the user you reply to. " \
                      "Only allowed argument is the amount."
                update.message.reply_text(msg)
                return

            to_user = reply.from_user.username

        # Provide username to be tipped
        else:
            if not args:
                msg = f"Usage:\n{self.get_usage()}"
                update.message.reply_text(msg, parse_mode=ParseMode.MARKDOWN)
                return

            # Determine amount to tip
            if len(args) == 1:
                # Tip default BIS amount
                amount = self.DEFAULT_TIP
            elif len(args) == 2:
                # Tip specified BIS amount
                try:
                    amount = float(args[1])
                except:
                    msg = f"{emo.ERROR} Specified amount is not valid"
                    update.message.reply_text(msg)
                    return
            else:
                # Wrong syntax
                msg = f"{emo.ERROR} Wrong number of arguments:\n{self.get_usage()}"
                update.message.reply_text(msg, parse_mode=ParseMode.MARKDOWN)
                return

            to_user = args[0]

            # Check if username starts with @
            if not to_user.startswith("@"):
                msg = f"{emo.ERROR} Username not valid:\n{self.get_usage()}"
                update.message.reply_text(msg, parse_mode=ParseMode.MARKDOWN)
                return

            to_user = to_user[1:]

        from_user = update.effective_user.username

        # Check if sender has a wallet
        if not Bismuth.wallet_exists(from_user):
            msg = "Accept terms and create a wallet first with:\n/accept"
            update.message.reply_text(msg)
            return

        # Check if recipient has a wallet
        if not Bismuth.wallet_exists(to_user):
            msg = f"{emo.ERROR} User @{utl.esc_md(to_user)} doesn't have a wallet yet"
            update.message.reply_text(msg, parse_mode=ParseMode.MARKDOWN)
            return

        msg = f"{emo.WAIT} Processing..."
        message = update.message.reply_text(msg)

        # Init sender wallet
        bis = Bismuth(from_user)
        bis.load_wallet()

        balance = bis.get_balance()
        total = amount + con.TRX_FEE

        # Check for sufficient funds
        if not utl.is_numeric(balance) or float(balance) < total:
            bot.edit_message_text(
                chat_id=message.chat_id,
                message_id=message.message_id,
                text=f"{emo.ERROR} Not enough funds")
            return

        try:
            # Execute tipping
            trx = bis.tip(to_user, amount)
        except Exception as e:
            error = f"Error executing tip from @{from_user} to @{to_user} with {amount}: {e}"
            logging.error(error)
            self.notify(error)
            trx = None

        if trx:
            logging.debug(f"Tip from '{from_user}' to '{to_user}' with {amount} BIS - TRX: {trx}")

            # Save tipping to database
            insert = self.get_resource("insert_tip.sql")
            self.execute_sql(insert, from_user, to_user, amount)

            # Send success message
            bot.edit_message_text(
                chat_id=message.chat_id,
                message_id=message.message_id,
                text=f"{emo.DONE} @{utl.esc_md(to_user)} received `{amount}` BIS",
                parse_mode=ParseMode.MARKDOWN)

            # Get user ID from tipped user
            sql = self.get_resource("get_user_id.sql")
            res = self.execute_sql(sql, to_user, plugin="wallet")
            to_user_id = res["data"][0][0] if res["success"] else None

            if to_user_id:
                try:
                    # Send success message to tipped user
                    msg = f"You've been tipped with `{amount}` BIS by @{utl.esc_md(from_user)}"
                    bot.send_message(to_user_id, msg, parse_mode=ParseMode.MARKDOWN)
                except Exception as e:
                    error = f"Can't notify user '{to_user}' about tip"
                    logging.debug(f"{error}: {e}")
            else:
                error = f"Can't notify user '{to_user}' about tip. User ID not found in DB"
                logging.error(error)
                self.notify(error)
        else:
            # Send error message
            bot.edit_message_text(
                chat_id=message.chat_id,
                message_id=message.message_id,
                text=f"{emo.ERROR} Tipping not executed. Something went wrong...")
Example #6
0
    def execute(self, bot, update, args):
        if not args:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        # command <total amount> <number of users>
        if len(args) == 2:
            amount = args[0]
            users = args[1]

        # command <total amount>/<number of users>
        elif len(args) == 1 and "/" in args[0]:
            lst = args[0].split("/")
            if len(lst) == 2:
                amount = lst[0]
                users = lst[1]
            else:
                update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                          parse_mode=ParseMode.MARKDOWN)
                return
        else:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        # Make sure that 'amount' and 'users' are valid values
        try:
            amount = float(amount)
            users = int(users)
        except:
            msg = f"{emo.ERROR} Arguments not valid"
            update.message.reply_text(msg)
            return

        if users < 1:
            msg = f"{emo.ERROR} You have to rain on at least one user"
            update.message.reply_text(msg)
            return

        multiplier = 10**2
        user_amount = math.floor(amount / users * multiplier) / multiplier

        if user_amount < 0.01:
            msg = f"{emo.ERROR} Amount per user to small. Has to be at least `0.01`"
            update.message.reply_text(msg, parse_mode=ParseMode.MARKDOWN)
            return

        from_user = update.effective_user.username
        from_user_id = update.effective_user.id

        # Check if sender has a wallet
        if not Bismuth.wallet_exists(from_user):
            msg = "Accept terms and create a wallet first with:\n/accept"
            update.message.reply_text(msg)
            return

        # Get all users from database
        sql = self.get_resource("read_users.sql")
        res = self.execute_sql(sql, plugin="wallet")

        if not res["success"]:
            msg = f"{emo.ERROR} Not possible to retrieve users"
            update.message.reply_text(msg)

            error = res["data"]
            logging.error(error)
            self.notify(error)
            return

        # Remove own user from list of users to rain on
        user_list = [x for x in res["data"] if x[1] != from_user]

        # Check if enough users available to be rained on
        if len(user_list) < users:
            msg = f"{emo.ERROR} Not enough users. {len(user_list)} available"
            update.message.reply_text(msg, parse_mode=ParseMode.MARKDOWN)
            return

        # Randomly choose users from all users
        chosen = random.sample(user_list, users)

        msg = f"{emo.WAIT} Processing..."
        message = update.message.reply_text(msg)

        # Init sender wallet
        bis = Bismuth(from_user)
        bis.load_wallet()

        balance = bis.get_balance()
        total = amount + (users * con.TRX_FEE)

        # Check for sufficient funds
        if not utl.is_numeric(balance) or float(balance) < total:
            bot.edit_message_text(chat_id=message.chat_id,
                                  message_id=message.message_id,
                                  text=f"{emo.ERROR} Not enough funds")
            return

        result = f"{emo.DONE} @{utl.esc_md(from_user)} sent `{user_amount}` BIS each to: "

        for to_data in chosen:
            to_user_id = to_data[0]
            to_user = to_data[1]

            try:
                # Execute tipping
                trx = bis.tip(to_user, user_amount)
            except Exception as e:
                error = f"Error executing rain from @{from_user} to @{to_user} with {user_amount} BIS: {e}"
                logging.error(error)
                self.notify(error)
                trx = None

            if trx:
                logging.debug(
                    f"Rain from '{from_user}' to '{to_user}' with {user_amount} BIS - TRX: {trx}"
                )

                # Save tipping to database
                # TODO: Do i have to lock the DB while writing?
                insert = self.get_resource("insert_rain.sql")
                self.execute_sql(insert, from_user, to_user, amount)

                # Add username of tipped user to confirmation message
                result += f"@{utl.esc_md(to_user)} "

                try:
                    # Send success message to tipped user
                    msg = f"You've been tipped with `{user_amount}` BIS by @{utl.esc_md(from_user)}"
                    bot.send_message(to_user_id,
                                     msg,
                                     parse_mode=ParseMode.MARKDOWN)
                except Exception as e:
                    error = f"Not possible to notify user '{to_user}' about rain"
                    logging.debug(f"{error}: {e}")
            else:
                try:
                    # Send error message to tipping user
                    msg = f"{emo.ERROR} Not possible to send `{user_amount}` BIS to @{utl.esc_md(to_user)}"
                    bot.send_message(from_user_id,
                                     msg,
                                     parse_mode=ParseMode.MARKDOWN)
                except Exception as e:
                    error = f"Not possible to notify tipping user '{from_user}' about failed rain"
                    logging.debug(f"{error}: {e}")

        # Check if at least one user got tipped
        if result.count("@") > 1:
            # TODO: Use 'split_msg' from utils here
            # Send success message
            bot.edit_message_text(chat_id=message.chat_id,
                                  message_id=message.message_id,
                                  text=result,
                                  parse_mode=ParseMode.MARKDOWN)
        else:
            # Send error message
            bot.edit_message_text(
                chat_id=message.chat_id,
                message_id=message.message_id,
                text=f"{emo.ERROR} Rain not executed. Something went wrong...")