Ejemplo n.º 1
0
def publish_bot(request):
    if request.is_ajax():
        user_prof = UserProfile.objects.get(user=request.user)
        new_bot_code = json.loads(request.body)['msg']

        if len(new_bot_code.strip('')) == 0:
            return HttpResponse("Can not publish an empty bot")

        # Get the last bot, and check delta
        try:
            latest_bot = Bot.objects.filter(owner=user_prof).latest('creation_date')
            if compare_bots(latest_bot.code, new_bot_code):
                error = "Can not publish this bot, looks like the previous one!"
                return HttpResponse(error)

        except ObjectDoesNotExist:
            # This is the first bot for this user
            pass

        bot = Bot()
        bot.owner = user_prof
        bot.code = new_bot_code
        bot.save()
        user_prof.current_bot = bot
        user_prof.my_buffer = new_bot_code
        user_prof.save()
    return HttpResponse(json.dumps({'success' : True}),
        mimetype='application/json')
Ejemplo n.º 2
0
def mybots(request):
    user_prof = UserProfile.objects.get(user=request.user)
    if request.method == 'POST':
        form = BotBufferForm(request.POST)
        if not form.is_valid():
            print "ERROR in form!"
            return
        new_code = form.cleaned_data['code']
        user_prof.code = new_code

        if 'publish_buffer' in request.POST:
            bot = Bot()
            bot.owner = user_prof
            bot.code = new_code
            bot.save()
            validate_bot.delay(bot.id, new_code)
            user_prof.current_bot = bot

        user_prof.save()
        return redirect('/mybots')
    else:
        form = BotBufferForm(instance=user_prof)

    return render(request, "my_bots.html", {
        'form': form,
        'user_prof': user_prof,
        'tab': 'mybots',
        'my_bots': reversed(Bot.objects.filter(owner=user_prof))
    })
Ejemplo n.º 3
0
def ban_bot(bot, update, chat_data, to_ban: Bot, ban_state: bool):
    if to_ban.disabled and ban_state is True:
        update.message.reply_text(
            mdformat.none_action("{} is already banned.".format(to_ban)),
            parse_mode="markdown",
        )
        return
    if not to_ban.disabled and ban_state is False:
        update.message.reply_text(
            mdformat.none_action("{} is not banned.".format(to_ban)),
            parse_mode="markdown",
        )
        return

    if ban_state:
        to_ban.disable(Bot.DisabledReason.banned)
        update.message.reply_text("Bot was banned.")
    else:
        to_ban.enable()
        update.message.reply_text("Bot was unbanned.")

    to_ban.save()

    from components.explore import send_bot_details

    return send_bot_details(bot, update, chat_data, to_ban)
Ejemplo n.º 4
0
def mybots(request):
    user_prof = UserProfile.objects.get(user=request.user)
    if request.method == 'POST':
        form = BotBufferForm(request.POST)
        if not form.is_valid():
            print "ERROR in form!"
            return
        new_code = form.cleaned_data['code']
        user_prof.code = new_code

        if 'publish_buffer' in request.POST:
            bot = Bot()
            bot.owner = user_prof
            bot.code = new_code
            bot.save()
            validate_bot.delay(bot.id, new_code)
            user_prof.current_bot = bot

        user_prof.save()
        return redirect('/mybots')
    else:
        form = BotBufferForm(instance=user_prof)

    return render(request, "my_bots.html", {
        'form': form,
        'user_prof': user_prof,
        'tab': 'mybots',
        'my_bots': reversed(Bot.objects.filter(owner=user_prof))
    })
Ejemplo n.º 5
0
def common_new(request):
    port = 6667
    if request.POST:
        name = request.POST.get("name")
        server = request.POST.get("server")
        type = int(request.POST.get("type"))
        channels = request.POST.get("channels")
        port = request.POST.get("port")
        nick = name

        # Validate
        errors = {}
        if len(name) > 36 or len(name) < 1:
            errors["name"] = "Username must be 36 characters or less"
        # test name for invalid characters
        
        if Bot.objects.filter(name=name, server=server):
            errors["name"] = "Nick already taken on %s" % server
        
        if not isinstance(type, int):
            errors["type"] = "Invalid bot type"
            
        #TODO: Regex!
        if len(server) < 5:
            errors["server"] = "Invalid server name"

        #TODO: Better checking
        if len(channels) < 1:
            errors["channels"] = "Specify at least one channel"
        elif len(channels) > 2000:
            errors["channels"] = "Too many channels specified"
           
        if len(port) > 5:
            errors["port"] = "Invalid port number, 6667 is default"
            
        if not port:
            port = 6667
        port = int(port)

        if not errors:
            bot = Bot(owner=request.user, name=name, nick=nick, server=server, port=port, type=type, channels=channels, status=0)
            bot.save()

#            args = (type, bot.owner_id, name, server, port, channels)
            args = (server, port, nick, channels)

            # Create the bot on the daemon
            bus = dbus.SessionBus()
            service = bus.get_object('com.excid3.bothost', '/com/excid3/bothost')
            new_bot = service.get_dbus_method('new_bot', 'com.excid3.bothost')
            new_bot(type, bot.id, args)

            #TODO: Display a "successfully created" message at the top of the dashboard
            return HttpResponseRedirect("/")

    locals().update(bottypes=BOT_TYPES)            
    t = loader.get_template("common/new.html")
    c = RequestContext(request, locals())
    return HttpResponse(t.render(c))
def delete_bot(bot, update, to_edit: Bot):
    username = to_edit.username
    to_edit.disable(Bot.DisabledReason.banned)
    to_edit.save()
    bot.formatter.send_or_edit(update.effective_user.id,
                               "Bot has been disabled and banned.",
                               to_edit=util.mid_from_update(update))
    Statistic.of(update, 'disable', username, Statistic.IMPORTANT)
Ejemplo n.º 7
0
def new(request):
    if request.method == 'POST':
        form = BotForm(request.POST)
        if form.is_valid():
            bot = Bot(**form.cleaned_data)
            bot.save()
            return HttpResponseRedirect(bot.get_absolute_url())
    else:
        form = BotForm()
    return render_to_response('bots/new.html', {'form': form}, context_instance=RequestContext(request))
Ejemplo n.º 8
0
def accept_bot_submission(bot, update, of_bot: Bot, category):
    uid = util.uid_from_update(update)
    message_id = util.mid_from_update(update)
    user = User.from_update(update)

    try:
        of_bot.category = category
        of_bot.date_added = datetime.date.today()
        of_bot.approved = True
        of_bot.approved_by = user
        of_bot.save()

        buttons = [[
            InlineKeyboardButton(
                "Edit {} details".format(of_bot.username),
                callback_data=util.callback_for_action(
                    CallbackActions.EDIT_BOT, {"id": of_bot.id}),
            )
        ]]
        reply_markup = InlineKeyboardMarkup(buttons)

        bot.formatter.send_or_edit(
            uid,
            "{} has been accepted to the Botlist. ".format(
                of_bot, settings.BOT_ACCEPTED_IDLE_TIME),
            to_edit=message_id,
            reply_markup=reply_markup,
        )

        log_msg = "{} accepted by {}.".format(of_bot.username, uid)

        # notify submittant
        if of_bot.submitted_by != user:
            try:
                bot.sendMessage(
                    of_bot.submitted_by.chat_id,
                    util.success(
                        messages.ACCEPTANCE_PRIVATE_MESSAGE.format(
                            of_bot.username, of_bot.category)),
                )
                log_msg += "\nUser {} was notified.".format(
                    str(of_bot.submitted_by))
            except TelegramError:
                log_msg += "\nUser {} could NOT be contacted/notified in private.".format(
                    str(of_bot.submitted_by))

        log.info(log_msg)
    except:
        bot.formatter.send_failure(uid, "An error has occured. Bot not added.")
Ejemplo n.º 9
0
async def disable_decider(bot: TelegramBot, to_check: BotModel):
    assert to_check.disabled_reason != BotModel.DisabledReason.banned

    if (
            to_check.offline and
            to_check.offline_for > settings.DISABLE_BOT_INACTIVITY_DELTA and
            to_check.disabled_reason != BotModel.DisabledReason.offline
    ):
        # Disable if the bot has been offline for too long
        if to_check.disable(to_check.DisabledReason.offline):
            to_check.save()

            if to_check.last_response:
                reason = "its last response was " + helpers.slang_datetime(to_check.last_response)
            else:
                reason = "it's been offline for.. like... ever"

            msg = "❌ {} disabled as {}.".format(to_check, reason)
            log.info(msg)
            bot.send_message(settings.BOTLIST_NOTIFICATIONS_ID, msg, timeout=30,
                             parse_mode='markdown')
        else:
            log.info("huhwtf")
    elif (
            to_check.online and
            to_check.disabled_reason == BotModel.DisabledReason.offline
    ):
        # Re-enable if the bot is disabled and came back online
        if to_check.enable():
            to_check.save()
            msg = "{} was included in the @BotList again as it came back online.".format(to_check)
            log.info(msg)
            bot.send_message(settings.BOTLIST_NOTIFICATIONS_ID, msg, timeout=30,
                             parse_mode='markdown')
        else:
            log.info("huhwtf")
Ejemplo n.º 10
0
def new_channel_post(bot, update, photo=None):
    post = update.channel_post
    if post.chat.username != settings.SELF_CHANNEL_USERNAME:
        return
    text = post.text

    channel, created = Channel.get_or_create(chat_id=post.chat_id,
                                             username=post.chat.username)
    if created:
        channel.save()

    category_list = '•Share your bots to the @BotListChat using the hashtag #new' in text
    intro = 'Hi! Welcome' in text
    category = text[0] == '•' and not category_list
    new_bots_list = 'NEW→' in text

    # TODO: is this a document?
    if photo:
        pass
    elif category:
        try:
            # get the category meta data
            meta = re.match(r'•(.*?)([A-Z].*):(?:\n(.*):)?', text).groups()
            if len(meta) < 2:
                raise ValueError("Category could not get parsed.")

            emojis = str.strip(meta[0])
            name = str.strip(meta[1])
            extra = str.strip(meta[2]) if meta[2] else None
            try:
                cat = Category.get(name=name)
            except Category.DoesNotExist:
                cat = Category(name=name)
            cat.emojis = emojis
            cat.extra = extra
            cat.save()

            # get the bots in that category
            bots = re.findall(r'^(🆕)?.*(@\w+)( .+)?$', text, re.MULTILINE)
            languages = Country.select().execute()
            for b in bots:
                username = b[1]
                try:
                    new_bot = Bot.by_username(username)
                except Bot.DoesNotExist:
                    new_bot = Bot(username=username)

                new_bot.category = cat

                new_bot.inlinequeries = "🔎" in b[2]
                new_bot.official = "🔹" in b[2]

                extra = re.findall(r'(\[.*\])', b[2])
                if extra:
                    new_bot.extra = extra[0]

                # find language
                for lang in languages:
                    if lang.emoji in b[2]:
                        new_bot.country = lang

                if b[0]:
                    new_bot.date_added = datetime.date.today()
                else:
                    new_bot.date_added = datetime.date.today(
                    ) - datetime.timedelta(days=31)

                new_bot.save()
        except AttributeError:
            log.error("Error parsing the following text:\n" + text)
def submit():
    if not request.is_json:
        res = _error('MimeType must be application/json.')
        res.status_code = 400
        return res

    content = request.get_json()
    try:
        access = APIAccess.get(APIAccess.token == content.get('token'))
    except APIAccess.DoesNotExist:
        res = _error('The access token is invalid.')
        res.status_code = 401
        return res

    username = content.get('username')
    if username is None or not isinstance(username, str):
        res = _error('You must supply a username.')
        res.status_code = 400
        return res

    # insert `@` if omitted
    username = '******' + username if username[0] != '@' else username

    try:
        Bot.get(Bot.username == username)
        res = _error('The bot {} is already in the BotList.'.format(username))
        res.status_code = 409
        return res
    except Bot.DoesNotExist:
        b = Bot(username=username)

    name = content.get('name')
    description = content.get('description')
    inlinequeries = content.get('inlinequeries')

    try:
        if name:
            if isinstance(name, str):
                b.name = name
            else:
                raise AttributeError('The name field must be a string.')
        if description:
            if isinstance(description, str):
                b.description = description
            else:
                raise AttributeError('The description field must be a string.')
        if inlinequeries:
            if isinstance(inlinequeries, bool):
                b.inlinequeries = inlinequeries
            else:
                raise AttributeError(
                    'The inlinequeries field must be a boolean.')
    except Exception as e:
        res = _error(str(e))
        res.status_code = 400
        return res

    b.date_added = datetime.date.today()
    b.submitted_by = access.user
    b.approved = False

    b.save()
    res = jsonify({'success': '{} was submitted for approval.'.format(b)})
    res.status_code = 201
    return res
Ejemplo n.º 12
0
def newbot(request):
    bot = Bot(name=request.GET['n'])
    bot.save()
    return HttpResponse(
        "successfully created bot named '{1}' with id: {0}".format(
            bot.id, bot.name))
Ejemplo n.º 13
0
def check_submission(bot, bot_checker: "BotChecker", to_check: Bot):
    # TODO: make this method async
    if bot_checker is None:
        return

    botlistbot_user = User.botlist_user_instance()

    log.debug("Checking bot {}...".format(to_check.username))

    def reject(reason):
        to_check.delete_instance()
        msg = notify_submittant_rejected(
            bot,
            botlistbot_user,
            notify_submittant=True,
            reason=reason,
            to_reject=to_check,
        )
        bot.formatter.send_message(settings.BOTLIST_NOTIFICATIONS_ID, msg)

    try:
        peer = bot_checker.resolve_bot(to_check)
    except UsernameNotOccupied:
        to_check.delete_instance()
        reject(
            "The entity you submitted either does not exist or is not a Telegram bot."
        )
        return

    bot_checker.update_bot_details(to_check, peer)

    if to_check.userbot:
        reject(
            "You submitted the name of a Telegram user, not one of a bot. If you're trying to "
            "submit a userbot, please contact the BLSF directly ("
            "@BotListChat).")
        return

    # Check online state
    response = loop.run_until_complete(
        bot_checker.get_ping_response(to_check,
                                      timeout=18,
                                      try_inline=to_check.inlinequeries))

    is_offline = not bool(response)

    if is_offline:
        reject(
            "The bot you sent seems to be offline, unfortunately. Feel free to submit it again "
            "when it's back up 😙")
        return

    now = datetime.datetime.now()
    to_check.last_ping = now
    to_check.last_response = now

    loop.run_until_complete(add_keywords(bot, response, to_check))

    # Download profile picture
    if settings.DOWNLOAD_PROFILE_PICTURES:
        # TODO: does this work asynchronously?
        loop.run_until_complete(
            download_profile_picture(bot, bot_checker, to_check))

    to_check.save()
    log.info(f"{to_check} was evaluated and looks good for approval.")
Ejemplo n.º 14
0
def new_bot_submission(bot, update, chat_data, args=None, bot_checker=None):
    tg_user = update.message.from_user
    user = User.from_telegram_object(tg_user)
    if util.stop_banned(update, user):
        return
    reply_to = util.original_reply_id(update)

    if args:
        text = " ".join(args)
    else:
        text = update.message.text
        command_no_args = (len(re.findall(r"^/new\s*$", text)) > 0
                           or text.lower().strip() == "/new@botlistbot")
        if command_no_args:
            update.message.reply_text(
                util.action_hint(
                    "Please use this command with an argument. For example:\n/new @mybot 🔎"
                ),
                reply_to_message_id=reply_to,
            )
            return

    # `#new` is already checked by handler
    try:
        username = re.match(settings.REGEX_BOT_IN_TEXT, text).groups()[0]
        if username.lower() == "@" + settings.SELF_BOT_NAME.lower():
            log.info("Ignoring {}".format(text))
            return
    except AttributeError:
        if args:
            update.message.reply_text(
                util.failure(
                    "Sorry, but you didn't send me a bot `@username`."),
                quote=True,
                parse_mode=ParseMode.MARKDOWN,
                reply_to_message_id=reply_to,
            )
        log.info("Ignoring {}".format(text))
        # no bot username, ignore update
        return

    try:
        new_bot = Bot.by_username(username, include_disabled=True)
        if new_bot.disabled:
            update.message.reply_text(
                util.failure("{} is banned from the @BotList.".format(
                    new_bot.username)),
                reply_to_message_id=reply_to,
            )
        elif new_bot.approved:
            update.message.reply_text(
                util.action_hint(
                    "Sorry fool, but {} is already in the @BotList 😉".
                    format(new_bot.username)),
                reply_to_message_id=reply_to,
            )
        else:
            update.message.reply_text(
                util.action_hint(
                    "{} has already been submitted. Please have patience...".
                    format(new_bot.username)),
                reply_to_message_id=reply_to,
            )
        return
    except Bot.DoesNotExist:
        new_bot = Bot(
            revision=Revision.get_instance().next,
            approved=False,
            username=username,
            submitted_by=user,
        )

    new_bot.inlinequeries = "🔎" in text
    new_bot.official = "🔹" in text

    # find language
    languages = Country.select().execute()
    for lang in languages:
        if lang.emoji in text:
            new_bot.country = lang

    new_bot.date_added = datetime.date.today()

    description_reg = re.match(settings.REGEX_BOT_IN_TEXT + " -\s?(.*)", text)
    description_notify = ""
    if description_reg:
        description = description_reg.group(2)
        new_bot.description = description
        description_notify = " Your description was included."

    new_bot.save()

    if (util.is_private_message(update)
            and util.uid_from_update(update) in settings.MODERATORS):
        from components.explore import send_bot_details

        send_bot_details(bot, update, chat_data, new_bot)
    else:
        update.message.reply_text(
            util.success("You submitted {} for approval.{}".format(
                new_bot, description_notify)),
            parse_mode=ParseMode.MARKDOWN,
            reply_to_message_id=reply_to,
        )

        # Ask the user to fill in the bot details
        util.send_md_message(
            bot,
            update.effective_user.id,
            "Congratulations, you just submitted a bot to the @BotList. Please help us fill in the details below:",
        )
        edit_bot(bot, update, chat_data, to_edit=new_bot)

    try:
        check_submission(bot, bot_checker, new_bot)
    except Exception as e:
        log.exception(e)

    return ConversationHandler.END
Ejemplo n.º 15
0
async def check_bot(
        bot,
        bot_checker: BotChecker,
        to_check: BotModel,
        result_queue: asyncio.Queue
):
    log.debug("Checking bot {}...".format(to_check.username))

    try:
        peer = bot_checker.resolve_bot(to_check)
    except UsernameNotOccupied:
        markup = InlineKeyboardMarkup([[
            InlineKeyboardButton(captions.EDIT_BOT, callback_data=util.callback_for_action(
                CallbackActions.EDIT_BOT,
                dict(id=to_check.id)
            ))
        ]])
        text = "{} does not exist (anymore). Please resolve this " \
               "issue manually!".format(to_check.username)
        try:
            bot.send_message(settings.BLSF_ID, text, reply_markup=markup)
        except BadRequest:
            bot.send_notification(text)
        return await result_queue.put('not found')

    if not peer:
        return await result_queue.put('skipped')

    bot_checker.update_bot_details(to_check, peer=peer)

    # Check online state
    try:
        response = await bot_checker.get_ping_response(
            to_check,
            timeout=30,
            try_inline=to_check.inlinequeries)
    except UnknownError as e:
        await result_queue.put(e.MESSAGE)
        return
    except Exception as e:
        log.exception(e)
        await result_queue.put(str(e))
        return

    for _ in range(2):
        await result_queue.put('messages sent')

    was_offline = to_check.offline
    is_offline = response.empty if isinstance(response, Response) else not bool(response)

    now = datetime.now()
    to_check.last_ping = now
    if not is_offline:
        to_check.last_response = now

    if was_offline != is_offline:
        bot.send_message(settings.BOTLIST_NOTIFICATIONS_ID, '{} went {}.'.format(
            to_check.str_no_md,
            'offline' if to_check.offline else 'online'
        ), timeout=40)

    await add_keywords(bot, response, to_check)

    # Download profile picture
    if settings.DOWNLOAD_PROFILE_PICTURES:
        await download_profile_picture(bot, bot_checker, to_check)

    to_check.save()

    if settings.DELETE_CONVERSATION_AFTER_PING:
        await bot_checker.schedule_conversation_deletion(to_check.chat_id, 10)

    await disable_decider(bot, to_check)

    await result_queue.put('offline' if to_check.offline else 'online')
Ejemplo n.º 16
0
def common_new(request):
    port = 6667
    if request.POST:
        name = request.POST.get("name")
        server = request.POST.get("server")
        type = int(request.POST.get("type"))
        channels = request.POST.get("channels")
        port = request.POST.get("port")
        nick = name

        # Validate
        errors = {}
        if len(name) > 36 or len(name) < 1:
            errors["name"] = "Username must be 36 characters or less"
        # test name for invalid characters

        if Bot.objects.filter(name=name, server=server):
            errors["name"] = "Nick already taken on %s" % server

        if not isinstance(type, int):
            errors["type"] = "Invalid bot type"

        #TODO: Regex!
        if len(server) < 5:
            errors["server"] = "Invalid server name"

        #TODO: Better checking
        if len(channels) < 1:
            errors["channels"] = "Specify at least one channel"
        elif len(channels) > 2000:
            errors["channels"] = "Too many channels specified"

        if len(port) > 5:
            errors["port"] = "Invalid port number, 6667 is default"

        if not port:
            port = 6667
        port = int(port)

        if not errors:
            bot = Bot(owner=request.user,
                      name=name,
                      nick=nick,
                      server=server,
                      port=port,
                      type=type,
                      channels=channels,
                      status=0)
            bot.save()

            #            args = (type, bot.owner_id, name, server, port, channels)
            args = (server, port, nick, channels)

            # Create the bot on the daemon
            bus = dbus.SessionBus()
            service = bus.get_object('com.excid3.bothost',
                                     '/com/excid3/bothost')
            new_bot = service.get_dbus_method('new_bot', 'com.excid3.bothost')
            new_bot(type, bot.id, args)

            #TODO: Display a "successfully created" message at the top of the dashboard
            return HttpResponseRedirect("/")

    locals().update(bottypes=BOT_TYPES)
    t = loader.get_template("common/new.html")
    c = RequestContext(request, locals())
    return HttpResponse(t.render(c))
Ejemplo n.º 17
0
def newbot(request):
    bot = Bot(name=request.GET['n'])
    bot.save()
    return HttpResponse("successfully created bot named '{1}' with id: {0}".format(bot.id, bot.name))