Exemple #1
0
    async def handle(message: SlackMessage, bot: SlackAdapter, db: DB,
                     battler: CardBattler):
        if not bot.addressed_by(message):
            return

        requested_battle = _user_requesting_battle(message=message, bot=bot)

        if not requested_battle:
            return

        attacker_search = requested_battle[1]
        defender_search = requested_battle[2]

        with db.session_scope() as session:

            attacker = Card.search_for_one(session, attacker_search)

            if not attacker:
                bot.reply(message,
                          f'no card named "{attacker_search}"',
                          create_thread=True)
                return

            defender = Card.search_for_one(session, defender_search)

            if not defender:
                bot.reply(message,
                          f'no card named "{defender_search}"',
                          create_thread=True)
                return

            battle_url = battler.get_battle_url(attacker.engine,
                                                defender.engine)
            bot.reply(message,
                      create_thread=True,
                      blocks=battle_blocks(attacker=attacker,
                                           defender=defender,
                                           battle_url=battle_url))
Exemple #2
0
    async def handle(message: SlackMessage, bot: SlackAdapter, db: DB):
        if not bot.addressed_by(message):
            return

        show_card_pattern = '|'.join([
            '(?:get|show|find) card'
        ])
        show_card_pattern = f'(?:{show_card_pattern})'
        pattern = re.compile(f'{show_card_pattern} (.+)', re.I)
        search = bot.understands(message, with_pattern=pattern)

        if not search:
            return

        with db.session_scope() as session:

            card = Card.search_for_one(session, search[1])

            if not card:
                bot.reply(message, 'no card with that name', create_thread=True)
                return

            bot.reply(message, **render_card(card))
Exemple #3
0
    async def handle(message: SlackMessage, bot: SlackAdapter, db: DB):
        if not bot.addressed_by(message):
            return

        show_card_pattern = '|'.join([
            'cards? (?:stats|statistics)'
        ])
        if not bot.understands(message, with_pattern=re.compile(show_card_pattern, re.I)):
            return

        with db.session_scope() as session:

            game_cards = get_game_cards(session)

            if not game_cards:
                bot.reply(message, "No cards", create_thread=True)
                return

        bot.reply(message,
                  blocks=card_stats_blocks(card_total=len(game_cards)),
                  create_thread=True)

        report = generate_report_charts(game_cards)

        bot.client.api_call(
            'files.upload',
            channels=message.channel,
            thread_ts=message.ts,
            filename='rarity.png',
            file=report['rarity'])

        bot.client.api_call(
            'files.upload',
            channels=message.channel,
            thread_ts=message.ts,
            filename='natures.png',
            file=report['natures'])
Exemple #4
0
    async def handle(message: SlackMessage, bot: SlackAdapter, db: DB):
        if not bot.addressed_by(message):
            return

        show_card_pattern = '|'.join([
            '(?:get|gimme|show|find|list) ?(?:my|muh)? cardo?s'
        ])
        if not bot.understands(message, with_pattern=re.compile(show_card_pattern, re.I)):
            return

        with db.session_scope() as session:

            cards = session.query(Card) \
                .join(User) \
                .filter(User.slack_id == message.user) \
                .filter(Card.published == True) \
                .limit(10) \
                .all()

            if not cards:
                bot.reply(message, "You don't have any cards yet.", create_thread=True)
                return

            bot.reply(message, create_thread=True, blocks=card_index_blocks(cards))
Exemple #5
0
def test_card_creation_state_happy(make_fake_user, grant_kkreds):
    config = test_config
    db_engine = create_engine(config.DATABASE_URL)
    make_session = sessionmaker(bind=db_engine, autoflush=False)

    k = Kaori()

    initial_ts = str(time())
    slack = Mock(spec=SlackClient)
    slack.api_call = MagicMock(return_value={
        'ok': True,
        'ts': initial_ts,
    })
    adapter = SlackAdapter(slack_client=slack)
    adapter._cached_bot_id = token_hex(2)
    k.adapters['slack'] = adapter

    db = DB(make_session=make_session)

    k.skills |= {
        db,
        CardBattler(player_url_base='https://battle.kaori.io/')
    }

    k.skills.add(LocalFileUploader())

    k.plugins |= {
        gacha_plugin,
    }

    u: User = make_fake_user()
    slack_id = u.slack_id
    user_id = u.id

    grant_kkreds(u, 1e10)

    def handle(msg):
        k.handle('slack', msg)

    channel = "CXXXXXX"

    def user_message(**kwargs):
        ts = time()
        return {
            "team_id": "TXXXX",
            "event": {
                "type": "message",
                "user": slack_id,
                "ts": ts,
                "channel": channel,
                "event_ts": ts,
                "channel_type": "channel",
                **kwargs,
            },
            "type": "event_callback",
        }

    with db.session_scope() as session:
        handle(user_message(text='@kaori create card', ts=initial_ts, event_ts=initial_ts))

        card = session.query(Card) \
            .join(User) \
            .filter(Card.creation_thread_ts == initial_ts) \
            .first()

        assert card.owner == user_id
        assert card.creation_cursor == 'set_name'

        name = f'Matt Morgan {token_hex(2)}'

        handle(user_message(text=f'@kaori {name}', thread_ts=initial_ts))

        session.refresh(card)
        assert card.name == name
        assert card.creation_cursor == 'set_image'

        # TODO skipping over image uploading lmao
        card.creation_cursor = 'set_description'
        session.commit()

        handle(user_message(text=f'@kaori ubu uwu', thread_ts=initial_ts))

        session.refresh(card)
        assert card.description == 'ubu uwu'

        handle(user_message(text=f'@kaori stupid feral', thread_ts=initial_ts))

        session.refresh(card)
        assert card.primary_nature == 'stupid'
        assert card.secondary_nature == 'feral'

        handle(user_message(text=f'@kaori S', thread_ts=initial_ts))

        session.refresh(card)
        assert card.rarity_string() == 'S'

        assert card.published is False

        handle(user_message(text=f'@kaori yes', thread_ts=initial_ts))

        session.refresh(card)
        assert card.published is True
        assert card.creation_cursor == 'done'
Exemple #6
0
    async def handle(message: SlackMessage, bot: SlackAdapter, db: DB,
                     file_uploader: FileUploader):
        if not bot.addressed_by(message) or not message.is_thread:
            return

        try:
            session: Session
            with db.session_scope() as session:
                card = resume_card(session,
                                   thread_ts=message.thread_ts,
                                   user=message.user)

                # this thread is not related to a card creation, ignore
                if not card:
                    return

                # lol god this is quickly getting away from me
                # just let me finish this and I'll refactor later
                user_input = ''

                catch_all_pattern = re.compile(r'(.*)', re.IGNORECASE)
                matches = bot.understands(message,
                                          with_pattern=catch_all_pattern)

                if not matches:
                    return

                user_input = matches[1].strip()

                if user_input == 'refresh preview':
                    refresh_card_preview(card, bot)
                    return

                if card.creation_cursor == 'set_image':
                    if message.files:
                        img = Image.from_slack_message(message=message,
                                                       session=session,
                                                       slack_adapter=bot,
                                                       uploader=file_uploader)
                        card.image = img
                        card.creation_cursor = 'query_description'
                        bot.react(message, 'thumbsup')
                    else:
                        bot.reply(message, 'upload an image to slack')
                        return

                card, replies = next_card_creation_step(
                    card=card,
                    user_input=user_input,
                    session=session,
                    kaori_user=User.get_by_slack_id(session, bot.id))

                refresh_card_preview(card, bot)

                session.merge(card)
                session.commit()

                for reply in replies:
                    if reply == ':+1:':
                        bot.react(message, 'thumbsup')
                    else:
                        if isinstance(reply, dict):
                            bot.reply(message, create_thread=True, **reply)
                        else:
                            bot.reply(message, reply, create_thread=True)

        except InvalidCardName as e:
            bot.reply(message, str(e))
        except IntegrityError as e:
            bot.reply(
                message,
                f"Something is wrong with that input...try again or ask Austin to fix it. Code {e.code}"
            )
            print(e)
Exemple #7
0
    async def handle(message: SlackMessage, bot: SlackAdapter, db: DB,
                     file_uploader: FileUploader):
        if not bot.addressed_by(message):
            return

        # start a conversation
        if not bot.understands(message,
                               with_pattern=re.compile(
                                   r'create\s+card|card\s+create$', re.I)):
            return

        if message.is_thread_reply:
            return

        try:
            with db.session_scope() as session:
                user = User.get_by_slack_id(session, message.user)

                if not user:
                    raise UserNotFound('cannot find user')

                # allow creation to recover from errors
                card = resume_card(session,
                                   thread_ts=message.thread_ts,
                                   user=message.user)

                if not card:
                    card = initialize_card(message, user)

                    session.add(card)
                    session.commit()

                draft_message = bot.reply(message,
                                          **render_card(card=card,
                                                        preview_header=True),
                                          create_thread=True,
                                          reply_broadcast=True)

                bot.reply(
                    message,
                    blocks=instructions_blocks(bot_name=bot.mention_string),
                    create_thread=True)

                if not draft_message.get('ok'):
                    print(draft_message)
                    return

                card.draft_message_ts = draft_message.get('ts')
                session.merge(card)

        except UserNotFound as e:
            bot.reply(
                message,
                "Something is wrong...cannot find your user. Try 'kaori refresh users'"
            )
            return

        # fake thread
        # todo: this is kinda dumb
        message = copy.deepcopy(message)
        message.is_thread = True
        message.thread_ts = message.ts

        await UpdateCardCommand.handle(message=message,
                                       bot=bot,
                                       db=db,
                                       file_uploader=file_uploader)
Exemple #8
0
dramatiq.set_broker(rabbitmq_broker)

if not config.SLACK_API_TOKEN:
    raise ValueError('You are missing a slack token! Please set the SLACK_API_TOKEN environment variable in your '
                     '.env file or in the system environment')

sc = SlackClient(config.SLACK_API_TOKEN)
db_engine = create_engine(config.DATABASE_URL)
make_session = sessionmaker(bind=db_engine, autoflush=False)

k = Kaori()

k.adapters['slack'] = SlackAdapter(slack_client=sc)

k.skills |= {
    DB(make_session=make_session),
}

if hasattr(config, 'USE_GCLOUD_STORAGE') and config.USE_GCLOUD_STORAGE:
    creds = service_account.Credentials.from_service_account_info(config.GCLOUD_SERVICE_ACCOUNT_INFO)
    bucket = storage.Client(project=creds.project_id, credentials=creds).bucket(config.IMAGES_BUCKET_GCLOUD)

    k.skills.add(GCloudStorageUploader(bucket=bucket,
                                       base_path=config.IMAGES_BUCKET_PATH))

elif config.KIZUNA_ENV == 'development':
    k.skills.add(LocalFileUploader())
else:
    k.logger.warning('no file upload handler specified!')

if hasattr(config, 'GACHA_BATTLE_URL_BASE') and config.GACHA_BATTLE_URL_BASE:
Exemple #9
0
def db() -> DB:
    return DB(make_session=db_sessionmaker())