def test_get_user_chart_user_chart_does_not_exist(self):
        astrology_chart = AstrologyChart()
        AstrologyChartFactory()

        result = asyncio.run(astrology_chart.get_user_chart(98))

        self.assertIsNone(result)
    def test_calc_chart_invalid_time(self):
        astrology_chart = AstrologyChart()
        user_id = 14
        date = '1997/08/10'
        time = 'invalid'
        city_name = "São Paulo"

        with self.assertRaises(AstrologyInvalidInput) as e:
            asyncio.run(astrology_chart.calc_chart(user_id, date, time, city_name))
        
        self.assertIn('Invalid datetime', e.exception.message)
    def test_calc_chart_invalid_city(self):
        astrology_chart = AstrologyChart()
        user_id = 14
        date = '1997/08/10'
        time = '07:17'
        city_name = "InvalidCityForSure"

        with self.assertRaises(AstrologyInvalidInput) as e:
            asyncio.run(astrology_chart.calc_chart(user_id, date, time, city_name))
        
        self.assertEqual(e.exception.message, 'City does not exist')
    def test_get_user_chart_user_chart_exists(self):
        astrology_chart = AstrologyChart()
        user_id = 14
        datetime = ('1997/08/10', '07:17', '-03:00')
        geopos = (-23.5506507, -46.6333824)
        chart = astrology_chart.calc_chart_raw(datetime, geopos)
        asyncio.run(astrology_chart.save_chart(user_id, chart))

        result = asyncio.run(astrology_chart.get_user_chart(user_id))

        self.assertEqual(str(chart.date), str(result.date))
        self.assertEqual(str(chart.pos), str(result.pos))
    def test_save_chart(self):
        user_id = 14
        astrology_chart = AstrologyChart()
        datetime = ('1997/08/10', '07:17', '-03:00')
        geopos = (-23.5506507, -46.6333824)
        chart = astrology_chart.calc_chart_raw(datetime, geopos)
        
        result_id = asyncio.run(astrology_chart.save_chart(user_id, chart))

        result = Session().query(AstrologyChartModel).get(result_id)
        self.assertIsNotNone(result)
        self.assertEqual(result.user_id, user_id)
        self.assertEqual(result.datetime.strftime(
            '%Y/%m/%d %H:%M'), f'{datetime[0]} {datetime[1]}') 
        self.assertEqual(result.timezone, '-03:00:00')
        self.assertEqual(result.latitude, geopos[0])
        self.assertEqual(result.longitude, geopos[1])
    def test_get_user_profile_all_available_fields(self):
        user_1 = UserFactory(name='My very long name')
        user_2 = UserFactory()
        chess_game_1 = ChessGameFactory(player1=user_1, result=1)
        xp_point_1 = XpPointFactory(user=user_1, points=140)
        self.test_session.commit()
        astrology_bot = AstrologyChart()
        datetime = ('1997/08/10', '07:17', '-03:00')
        geopos = (-23.5506507, -46.6333824)
        chart = astrology_bot.calc_chart_raw(datetime, geopos)
        asyncio.run(astrology_bot.save_chart(user_1.id, chart))
        with open(os.path.join('tests', 'support', 'user_avatar.png'),
                  'rb') as f:
            user_avatar_bytes = f.read()

        result = asyncio.run(Profile().get_user_profile(user_1.id,
                                                        user_avatar_bytes,
                                                        lang='pt'))

        with open(
                os.path.join('tests', 'support',
                             'get_user_profile_all_fields.png'), 'rb') as f:
            self.assertEqual(result.getvalue(), f.read())
    def test_calc_chart_valid_params(self):
        astrology_chart = AstrologyChart()
        user_id = 14
        date = '1997/08/10'
        time = '07:17'
        city_name = "São Paulo"

        chart = asyncio.run(astrology_chart.calc_chart(user_id, date, time, city_name))
        sun = astrology_chart.get_sun_sign(chart)
        asc = astrology_chart.get_asc_sign(chart)
        moon = astrology_chart.get_moon_sign(chart)

        self.assertEqual(sun, 'Leo')
        self.assertEqual(asc, 'Leo')
        self.assertEqual(moon, 'Scorpio')
예제 #8
0
 def __init__(self, client):
     self.client = client
     self.astrology_bot = AstrologyChart()
예제 #9
0
class AstrologyCog(commands.Cog):
    """
    Astrologia
    """
    def __init__(self, client):
        self.client = client
        self.astrology_bot = AstrologyChart()

    @commands.command()
    async def mapa_astral(self, ctx, date=None, time=None, *, city_name=None):
        """
        Visualize ou crie via DM seu mapa astral

        Para criar seu mapa astral, envie esse comando em DM para o bot informando \
            a data, hora e local de seu nascimento da seguinte forma: \
            `YYYY/mm/dd HH:MM Nome da cidade`.

        Se já tiver criado seu mapa astral, envie esse comando sem argumentos para \
            visualizá-lo em qualquer canal.

        Exemplo de uso para criação de mapa astral: `mapa_astral 2000/15/01 12:00 Brasília`
        Exemplo de uso para visualização de mapa criado: `mapa_astral`
        """
        if not isinstance(ctx.channel, discord.channel.DMChannel):
            user_chart = await self.astrology_bot.get_user_chart(ctx.author.id)
            if not user_chart:
                return await ctx.send(
                    i(
                        ctx,
                        'You have not yet created your astrology chart. In order to do so, send this command to my DM 😁'
                    ))
            return await self.send_astrology_triad(ctx, user_chart)
        try:
            await ctx.trigger_typing()
            chart = await self.astrology_bot.calc_chart(
                ctx.author.id, date, time, city_name)
            await self.astrology_bot.save_chart(ctx.author.id, chart)
        except AstrologyInvalidInput as e:
            return await ctx.send(i(ctx, e.message))
        except Exception as e:
            logging.warning(e, exc_info=True)
            return await ctx.send(
                i(
                    ctx,
                    'There has been a momentary failure. Please try again in a few moments. If this error persists, then this might be a bug 😬'
                ))
        await self.send_astrology_triad(ctx, chart)

    async def send_astrology_triad(self, ctx, chart):
        sign = self.astrology_bot.get_sun_sign(chart)
        asc = self.astrology_bot.get_asc_sign(chart)
        moon = self.astrology_bot.get_moon_sign(chart)

        embed = discord.Embed(title=i(ctx, 'Your astrology chart'),
                              description=i(ctx, 'Your astrology triad'),
                              colour=discord.Color.blurple(),
                              timestamp=ctx.message.created_at)
        embed.add_field(name=i(ctx, 'Solar sign'), value=sign)
        embed.add_field(name=i(ctx, 'Ascending sign'), value=asc)
        embed.add_field(name=i(ctx, 'Moon sign'), value=moon)
        await ctx.send(embed=embed)
예제 #10
0
 def __init__(self):
     self.astrology_bot = AstrologyChart()
예제 #11
0
class Profile():
    def __init__(self):
        self.astrology_bot = AstrologyChart()

    async def set_user_profile_frame_color(self, user_id: int, color: str):
        """
        Updates given user's profile frame color

        :param user_id: User id
        :type user_id: int
        :param color: Color in hex code
        :type color: str
        :return: Updated user
        :rtype: User
        :raises ValueError: Given color is invalid
        """
        user = await User.get(user_id) or User(id=user_id)
        try:
            ImageColor.getcolor(color, 'RGB')
        except ValueError:
            raise
        user.profile_frame_color = color
        await User.save(user)
        return user

    async def get_user_profile(self,
                               user_id: int,
                               user_avatar: bytes,
                               lang='en'):
        """
        Generates an user profile image banner

        :param user_id: User id
        :type user_id: int
        :param user_avatar: User's avatar
        :type user_avatar: bytes
        :param lang: Language to which present the profile
        :type lang: str
        :return: User's profile banner
        :rtype: BytesIO
        """
        text_max_width = 10
        default_color = '#ca2222'

        user = await User.get(user_id, preload_profile_items=True)
        if not user:
            return
        user_name = user.name if user.name else ''
        user_profile_badges = [
            item.profile_item for item in user.profile_items if item.equipped
            and item.profile_item.type == ProfileItemType.badge
        ]
        user_profile_wallpaper = next(
            (item.profile_item for item in user.profile_items if item.equipped
             and item.profile_item.type == ProfileItemType.wallpaper), None)
        user_chart = await self.astrology_bot.get_user_chart(user_id)
        user_sign = None
        if user_chart:
            user_sign = self.astrology_bot.get_sun_sign(user_chart)
        user_chess_victories = await ChessGame.get_number_of_victories(user_id)
        user_total_points = await XpPoint.get_user_aggregated_points(user_id)
        if not user_total_points:
            user_total_points = 0

        with open(os.path.join('bot', 'images', 'profile_frame.png'),
                  'rb') as f:
            image_frame = Image.open(f).convert('RGBA')
            image_frame_draw = ImageDraw.Draw(image_frame)
            frame_color = ImageColor.getcolor(
                user.profile_frame_color or default_color, 'RGB')
            image_frame_draw.bitmap((0, 0),
                                    image_frame,
                                    fill=frame_color + (175, ))

        image_final = self._draw_wallpaper(image_frame, user_profile_wallpaper)

        image_font_title = ImageFont.truetype(
            os.environ.get("TRUETYPE_FONT_FOR_PROFILE"), size=48)
        image_font_subtitle = ImageFont.truetype(
            os.environ.get("TRUETYPE_FONT_FOR_PROFILE"), size=32)
        image_font_description = ImageFont.truetype(
            os.environ.get("TRUETYPE_FONT_FOR_PROFILE"), size=24)
        image_user_avatar = Image.open(BytesIO(user_avatar))

        image_draw = ImageDraw.Draw(image_final)
        user_name_width = 390
        image_frame_draw.rectangle([(0, 0), (user_name_width + 120, 107)],
                                   fill=frame_color + (255, ))
        image_final.alpha_composite(image_frame)

        image_draw.text((120, 25),
                        user_name[:15],
                        fill="#FFF",
                        font=image_font_title)
        image_draw.text((30, 635),
                        f'{i18n("Points", lang)}: {user_total_points}',
                        fill="#FFF",
                        font=image_font_description)
        image_draw.text((400, 620),
                        f'{i18n("Chess wins", lang)}: {user_chess_victories}',
                        fill="#FFF",
                        font=image_font_subtitle)
        image_draw.text((400, 580),
                        f'{i18n("Sign", lang)}: {user_sign}',
                        fill="#FFF",
                        font=image_font_subtitle)
        if image_user_avatar.mode == 'RGBA':
            user_avatar_mask = image_user_avatar.resize((108, 108))
        else:
            user_avatar_mask = None
        image_final.paste(image_user_avatar.resize((108, 108)), (0, 0),
                          mask=user_avatar_mask)
        image_final = self._draw_user_badges(image_final, user_profile_badges)

        bytesio = BytesIO()
        image_final.save(bytesio, format="png")
        bytesio.seek(0)
        return bytesio

    def _draw_wallpaper(self, image_frame, profile_item):
        image_bytes_io = profile_item and profile_item.get_file_contents()
        if not image_bytes_io:
            with open(
                    os.path.join('bot', 'images',
                                 'profile_default_background.jpg'), 'rb') as f:
                image_final = Image.open(f).crop(
                    (100, 0, image_frame.size[0] + 100,
                     image_frame.size[1])).convert('RGBA')
        else:
            image_final = Image.open(image_bytes_io).crop(
                (0, 0, image_frame.size[0],
                 image_frame.size[1])).convert('RGBA').convert('RGBA')
        return image_final

    def _draw_user_badges(self, image, profile_items):
        for index, profile_item in enumerate(profile_items):
            image_bytes_io = profile_item.get_file_contents()
            if not image_bytes_io:
                continue
            image_badge = Image.open(image_bytes_io)
            image_badge_resized = image_badge.resize((60, 60))
            x_position = 520 + index * 70
            if image_badge_resized.mode == 'RGBA':
                image.paste(image_badge_resized, (x_position, 10),
                            mask=image_badge_resized)
            else:
                image.paste(image_badge_resized, (x_position, 10))
        return image