Skip to content

Commit 4efdd5c

Browse files
authored
Merge pull request #61 from LewisProjects/development
2 parents 1463bef + a7fab0e commit 4efdd5c

File tree

15 files changed

+560
-18
lines changed

15 files changed

+560
-18
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Main Contributors/Developers:
1515
<li><a href="https://github.com/JasonLovesDoggo">JasonLovesDoggo</a></li>
1616
<li><a href="https://github.com/LevaniVashadze">Levani Vashadze</a></li>
1717
</ul>
18-
The bot is currently on release: <b>1.8.0</b><br>
18+
The bot is currently on release: <b>2.0</b><br>
1919
License: MIT<br>
2020
Wish to Contribute to this bot? Checkout: <a href="https://github.com/LewisProjects/Ogiroid/blob/development/CONTRIBUTING.md">contribution guidelines</a>
2121
<hr>

cogs/Birthdays.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import datetime
2+
3+
import disnake
4+
import datetime as dt
5+
from disnake.ext import commands, tasks
6+
import random
7+
8+
from utils.DBhandlers import BirthdayHandler
9+
from utils.exceptions import UserAlreadyExists, UserNotFound
10+
from utils.shortcuts import QuickEmb, sucEmb, errorEmb
11+
from utils.CONSTANTS import months, congrats_messages
12+
from utils.bot import OGIROID
13+
14+
15+
class Birthday(commands.Cog):
16+
def __init__(self, bot: OGIROID):
17+
self.bot = bot
18+
self.birthday: BirthdayHandler = None
19+
self.birthday_check.start()
20+
21+
@commands.Cog.listener()
22+
async def on_ready(self):
23+
if not self.bot.ready_:
24+
self.birthday: BirthdayHandler = BirthdayHandler(self.bot, self.bot.db)
25+
26+
def cog_unload(self):
27+
self.birthday_check.cancel()
28+
29+
@commands.slash_command(name="birthday")
30+
async def birthday(self, inter: disnake.ApplicationCommandInteraction):
31+
pass
32+
33+
@birthday.sub_command(name="set", description="Set your birthday. Cant be removed without Staff.")
34+
async def set(
35+
self,
36+
inter,
37+
day: int = commands.Param(name="day", ge=1, le=31, description="The day of your birthday. Select carefully."),
38+
month: str = commands.Param(
39+
name="month",
40+
description="The month of your birthday. Select carefully.",
41+
choices=months,
42+
),
43+
):
44+
if month is None or day is None:
45+
return await errorEmb(inter, "You need to provide a month and a day")
46+
if day < 1 or day > 31:
47+
return await errorEmb(inter, "The day must be between 1 and 31")
48+
49+
birth_date = f"{day}/{month}"
50+
try:
51+
await self.birthday.create_user(inter.author.id, birth_date)
52+
except UserAlreadyExists:
53+
return await errorEmb(inter, "You already have a birthday set")
54+
55+
await sucEmb(inter, f"Your birthday has been set to {birth_date}")
56+
57+
@commands.has_permissions(manage_roles=True)
58+
@birthday.sub_command(name="edit", description="Edit a users birthday. Can only be done by Staff.")
59+
async def edit(
60+
self,
61+
inter,
62+
day: int = commands.Param(name="day", ge=1, le=31, description="The day of the birthday."),
63+
month: str = commands.Param(
64+
name="month",
65+
description="The month of the birthday.",
66+
choices=months,
67+
),
68+
user: disnake.User = commands.Param(name="user", description="User to edit the birthday of."),
69+
):
70+
try:
71+
await self.birthday.update_user(user.id, f"{day}/{month}")
72+
return await sucEmb(inter, f"Birthday has been updated to {day}/{month}")
73+
except UserNotFound:
74+
return await errorEmb(inter, "The User doesn't have a birthday set")
75+
76+
@commands.has_permissions(manage_roles=True)
77+
@birthday.sub_command(name="remove", description="Remove a birthday. Can only be done by Staff.")
78+
async def remove(
79+
self,
80+
inter: disnake.ApplicationCommandInteraction,
81+
user: disnake.User = commands.Param(name="user", description="Removes the birthday of this user"),
82+
):
83+
try:
84+
await self.birthday.delete_user(user.id)
85+
except UserNotFound:
86+
return await errorEmb(inter, "This user doesn't have a birthday set")
87+
88+
await sucEmb(inter, "The birthday has been removed")
89+
90+
@birthday.sub_command(name="get", description="Get the birthday of a user")
91+
async def get(self, inter, user: disnake.User = commands.Param(name="user", default=None)):
92+
if user is None:
93+
user = inter.author
94+
else:
95+
user = await self.bot.fetch_user(user.id)
96+
97+
birthday = await self.birthday.get_user(user.id)
98+
if birthday is None:
99+
return await errorEmb(inter, "This user doesn't have a birthday set")
100+
101+
next_birthday = datetime.datetime.strptime(birthday.birthday + f"/{dt.datetime.now().year}", "%d/%m/%Y")
102+
if next_birthday < datetime.datetime.now():
103+
next_birthday = datetime.datetime.strptime(birthday.birthday + f"/{dt.datetime.now().year + 1}", "%d/%m/%Y")
104+
await QuickEmb(
105+
inter,
106+
f"{user.mention}'s birthday is in {(next_birthday - datetime.datetime.now()).days} Days."
107+
f" <t:{str(next_birthday.timestamp()).split('.')[0]}:D>",
108+
).send()
109+
110+
# @tasks.loop(time=[dt.time(dt.datetime.utcnow().hour, dt.datetime.utcnow().minute, dt.datetime.utcnow().second + 10)])
111+
# ^ use this when testing birthdays
112+
@tasks.loop(time=[dt.time(8, 0, 0)])
113+
# loops every day at 8:00 UTC time
114+
async def birthday_check(self):
115+
channel = self.bot.get_channel(self.bot.config.channels.birthdays)
116+
guild = self.bot.get_guild(self.bot.config.guilds.main_guild)
117+
if channel is None:
118+
return
119+
today = dt.datetime.utcnow().strftime("%d/%m")
120+
# Gets all users from the db
121+
users = await self.birthday.get_users()
122+
for user in users:
123+
member = await guild.fetch_member(user.user_id)
124+
# if the member is None, the user is not in the server anymore
125+
if member is None:
126+
continue
127+
128+
# if the birthday is today, congratulate the user
129+
if user.birthday == today:
130+
await member.add_roles(guild.get_role(self.bot.config.roles.birthday))
131+
congrats_msg = await channel.send(f"{random.choice(congrats_messages)} {member.mention}! 🎂")
132+
await congrats_msg.add_reaction("🥳")
133+
# If the birthday isn't today and the user still has the birthday role, remove it
134+
elif user.birthday != today and member.get_role(self.bot.config.roles.birthday) is not None:
135+
await member.remove_roles(guild.get_role(self.bot.config.roles.birthday))
136+
137+
138+
def setup(bot):
139+
bot.add_cog(Birthday(bot))

cogs/Fun.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -405,14 +405,13 @@ async def info(
405405
@commands.slash_command(name="urlshortner", description="Shortens a URL.")
406406
async def urlshortner(self, inter: ApplicationCommandInteraction, url: str):
407407
# checking if url starts with http:// or https://, if it does not, adding https:// towards the start
408-
if not url.startswith("http://") and not url.startswith("https://"):
408+
if not (url.startswith("http://") or url.startswith("https://")):
409409
url = f"https://{url}"
410-
response = requests.post(f"https://u.jasoncodes.ca/add/{url}")
411-
if response.status_code == 200:
410+
response = requests.post("https://roman.vm.net.ua/s", url)
411+
if response.status_code == 201:
412412
embed = disnake.Embed(
413-
title=f"URL created for: {url.replace('http://', '').replace('https://', '')}",
414413
color=0xFFFFFF,
415-
description=f"Your shortend URL is: {response.json()['short_url']}, or click [here]({response.json()['short_url']}) to visit it.",
414+
description=f"Your shortend URL is: {response.text}, or click [here]({response.text}) to visit it.",
416415
)
417416
embed.set_footer(text=f"Requested by: {inter.author.name}")
418417
return await inter.send(embed=embed)

cogs/Levels.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ async def generate_image_card(self, user: Member | User, rank: str, xp: int, lvl
221221
avatar: disnake.Asset = user.display_avatar.with_size(512)
222222
# this for loop finds the closest level to the xp and defines the values accordingly
223223
next_xp = LEVELS_AND_XP[int(lvl) + 1]
224-
with Image.open("utils/data/images/rankcard.png").convert("RGBA") as base:
224+
# with Image.open("utils/data/images/rankcard.png").convert("RGBA") as base: NORMAL VERSION
225+
with Image.open("utils/data/images/winterrankcard.png").convert("RGBA") as base: # WINTER VERSION
225226
# make a blank image for the text, initialized to transparent text color
226227
txt = Image.new("RGBA", base.size, (255, 255, 255, 0))
227228

@@ -436,7 +437,7 @@ async def leaderboard(self, inter: ApplicationCommandInteraction):
436437
inline=False,
437438
)
438439

439-
embed.set_footer(text=f"{inter.author}", icon_url=inter.author.avatar.url)
440+
embed.set_footer(text=f"{inter.author}", icon_url=inter.author.display_avatar.url)
440441
embed.timestamp = dt.datetime.now()
441442

442443
await inter.send(embed=embed, view=LeaderboardView(inter, self.controller, embed, inter.author.id))

cogs/Timezone.py

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import disnake
2+
import datetime as dt
3+
from disnake.ext import commands, tasks
4+
import pytz
5+
6+
from utils.DBhandlers import TimezoneHandler
7+
from utils.exceptions import UserAlreadyExists, UserNotFound
8+
from utils.shortcuts import QuickEmb, sucEmb, errorEmb
9+
from utils.CONSTANTS import months, congrats_messages, timezones
10+
from utils.bot import OGIROID
11+
12+
13+
async def autocomplete_timezones(inter, user_input: str):
14+
return [tz for tz in timezones if user_input.lower() in tz.lower()][0:25]
15+
16+
17+
class Timezone(commands.Cog):
18+
def __init__(self, bot: OGIROID):
19+
self.bot = bot
20+
self.db_timezone: TimezoneHandler = None
21+
22+
@commands.Cog.listener()
23+
async def on_ready(self):
24+
if not self.bot.ready_:
25+
self.db_timezone: TimezoneHandler = TimezoneHandler(self.bot, self.bot.db)
26+
27+
@commands.slash_command(name="timezone")
28+
async def timezone(self, inter: disnake.ApplicationCommandInteraction):
29+
pass
30+
31+
@timezone.sub_command(name="set", description="Set your timezone.")
32+
async def set(
33+
self,
34+
inter,
35+
timezone=commands.Param(
36+
name="timezone",
37+
description="Your timezone. Start typing a major city around you or a continent.",
38+
autocomplete=autocomplete_timezones,
39+
),
40+
):
41+
42+
if timezone is None:
43+
return await errorEmb(inter, "You need to provide a timezone")
44+
if timezone not in timezones:
45+
return await errorEmb(inter, "The timezone you provided is not valid")
46+
try:
47+
await self.db_timezone.create_user(inter.author.id, timezone)
48+
except UserAlreadyExists:
49+
return await errorEmb(inter, "You already have a timezone set")
50+
51+
await sucEmb(
52+
inter,
53+
f"Your timezone has been set to {timezone}."
54+
f" Its should be {dt.datetime.now(pytz.timezone(timezone)).strftime('%H:%M')} at your location.",
55+
)
56+
57+
@timezone.sub_command(name="edit", description="Edit your timezone.")
58+
async def edit(
59+
self,
60+
inter,
61+
timezone=commands.Param(
62+
name="timezone",
63+
description="Your timezone. Start typing a major city around you or a continent.",
64+
autocomplete=autocomplete_timezones,
65+
),
66+
):
67+
if timezone is None:
68+
return await errorEmb(inter, "You need to provide a timezone")
69+
if timezone not in timezones:
70+
return await errorEmb(inter, "The timezone you provided is not valid")
71+
try:
72+
await self.db_timezone.update_user(inter.author.id, timezone)
73+
await sucEmb(
74+
inter,
75+
f"Your timezone has been set to {timezone}."
76+
f" Its should be {dt.datetime.now(pytz.timezone(timezone)).strftime('%H:%M')} at your location.",
77+
)
78+
except UserNotFound:
79+
return await errorEmb(inter, "The User doesn't have a timezone set")
80+
81+
@timezone.sub_command(name="remove", description="Remove your timezone.")
82+
async def remove(
83+
self,
84+
inter: disnake.ApplicationCommandInteraction,
85+
):
86+
try:
87+
await self.db_timezone.delete_user(inter.author.id)
88+
except UserNotFound:
89+
return await errorEmb(inter, "This user doesn't have a timezone set")
90+
91+
await sucEmb(inter, "The timezone has been removed")
92+
93+
@timezone.sub_command(name="get", description="Get the timezone of a user")
94+
async def get(self, inter, user: disnake.User = commands.Param(name="user", default=None)):
95+
if user is None:
96+
user = inter.author
97+
else:
98+
user = await self.bot.fetch_user(user.id)
99+
100+
timezone = await self.db_timezone.get_user(user.id)
101+
if timezone is None:
102+
return await errorEmb(inter, "This user doesn't have a timezone set")
103+
await QuickEmb(
104+
inter,
105+
f"{user.mention}'s timezone is {timezone.timezone}."
106+
f" Its currently {dt.datetime.now(pytz.timezone(timezone.timezone)).strftime('%H:%M')} for them",
107+
).send()
108+
109+
110+
def setup(bot):
111+
bot.add_cog(Timezone(bot))

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ Pillow~=9.2.0
1111
expr.py~=0.3.0
1212
cachetools~=5.2.0
1313
python-dateutil~=2.8.2
14-
14+
pytz==2022.6
1515
asyncpg~=0.26.0

secrets.env.template

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1+
# Insert a bots token
12
TOKEN=
3+
# needed for one command can be ignored in development
24
SRA_API_TOKEN=
5+
# Used for weather command can be ignored in development
36
OPEN_WEATHER_MAP_API_KEY=
7+
# Used for the upload checker can be ignored in development
48
YT_API_KEY=
59
POSTGRES_USER=
610
POSTGRES_PASSWORD=
711
POSTGRES_HOST=
812
POSTGRES_PORT=
13+
# Needs to be set to true or false
14+
DEVELOPMENT=

setup.sql

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ IF NOT EXISTS levels
7272
xp INTEGER DEFAULT 0
7373
);
7474

75-
ALTER TABLE levels ADD COLUMN IF NOT EXISTS xp_boost INTEGER DEFAULT 1;
76-
ALTER TABLE levels ADD COLUMN IF NOT EXISTS xp_boost_expiry BIGINT;
77-
75+
-- ALTER TABLE levels ADD COLUMN IF NOT EXISTS xp_boost INTEGER DEFAULT 1;
76+
-- ALTER TABLE levels ADD COLUMN IF NOT EXISTS xp_boost_expiry BIGINT;
77+
-- BUG sqlite3.OperationalError: near "EXISTS": syntax error
7878

7979
CREATE TABLE
8080
IF NOT EXISTS role_rewards
@@ -84,10 +84,27 @@ IF NOT EXISTS role_rewards
8484
required_lvl INTEGER DEFAULT 0
8585
);
8686

87+
CREATE TABLE
88+
IF NOT EXISTS birthday
89+
(
90+
user_id BIGINT,
91+
birthday TEXT DEFAULT NULL,
92+
birthday_last_changed BIGINT DEFAULT NULL
93+
);
94+
95+
CREATE TABLE
96+
IF NOT EXISTS timezone
97+
(
98+
user_id BIGINT,
99+
timezone TEXT DEFAULT NULL,
100+
timezone_last_changed BIGINT DEFAULT NULL
101+
);
102+
87103
CREATE TABLE
88104
IF NOT EXISTS xp_boosts_user
89105
(
90106
guild_id BIGINT,
91107
user_id BIGINT,
92108
boost_amount INTEGER DEFAULT 0
93-
);
109+
110+
);

0 commit comments

Comments
 (0)