Skip to content

Commit b74435a

Browse files
committed
Initial commit
0 parents  commit b74435a

11 files changed

+888
-0
lines changed

.gitattributes

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

.vscode/extensions.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"recommendations": [
3+
"ms-python.python"
4+
]
5+
}

LICENSE

+674
Large diffs are not rendered by default.

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# RateBot
2+
A simple user rating bot for Discord.

config/auth.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"TOKEN": "",
3+
"deploy_mode": "local"
4+
}

config/commands.json

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"help": {
3+
"name": "Help",
4+
"description": "This command.",
5+
"args": "",
6+
"disabled": false
7+
},
8+
"rate": {
9+
"name": "Rate",
10+
"description": "Rate a user of your choice. You can rate them from 1-5 stars.",
11+
"args": "`user` `rating`",
12+
"disabled": false
13+
},
14+
"profile": {
15+
"name": "Profile",
16+
"description": "View the profile of a user.",
17+
"args": "`user`",
18+
"disabled": false
19+
},
20+
"rating": {
21+
"name": "View Rating",
22+
"description": "View a user's rating.",
23+
"args": "`user`",
24+
"disabled": false
25+
}
26+
}

config/profile.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

db/profiles.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

db/user_ratings.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

main.py

+156
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# Imports
2+
import discord
3+
import json
4+
from os import getenv
5+
from time import strftime
6+
from typing import Union
7+
from discord import option, ApplicationContext
8+
from discord.ext import commands
9+
10+
# Variables
11+
client = discord.Bot()
12+
color = discord.Color.random()
13+
14+
print("[client/startup] Populating databases...")
15+
with open("db/user_ratings.json", 'r') as f: user_ratings = json.load(f)
16+
with open("config/commands.json", 'r') as f: commands_db = json.load(f)
17+
with open("db/profiles.json", 'r') as f: profile_metadata = json.load(f)
18+
19+
def save() -> int:
20+
with open("db/user_ratings.json", 'w+') as f: json.dump(user_ratings, f, indent=4)
21+
# with open("db/profiles.json", 'w+') as f: json.dump(profile_metadata, f, indent=4) TODO: Uncomment this line once full profile metadata support is ready
22+
return 0
23+
24+
def parse_rating(user_id: Union[int, str]) -> int:
25+
users_rated = []
26+
for user in user_ratings[str(user_id)].keys():
27+
users_rated.append(user)
28+
total_stars = 0
29+
number_of_ratings = 0
30+
for rating in users_rated:
31+
number_of_ratings += 1
32+
total_stars += rating
33+
aggregated_rating = round(total_stars/number_of_ratings, 1)
34+
return aggregated_rating
35+
36+
# Events
37+
def on_ready():
38+
print(f"[client] Discord bot user logged in as {client.name}")
39+
print("[client] Ready to accept commands.")
40+
print("-------------")
41+
42+
def on_message(ctx):
43+
if ctx.author.id not in user_ratings: user_ratings[str(ctx.author.id)] = {}
44+
save()
45+
46+
# Slash Commands
47+
@client.slash_command(
48+
name="help",
49+
description="Need some command help?"
50+
)
51+
async def _help(ctx: ApplicationContext):
52+
parsed_desc = ""
53+
for command in commands_db:
54+
parsed_desc += f"\n\n**{commands_db[command]['name']}**: {commands_db[command]['description']}\nFormat: /{command}{commands_db[command]['args']}"
55+
localembed = discord.Embed(
56+
title="My Commands",
57+
description=parsed_desc,
58+
color=color
59+
)
60+
await ctx.respond(embed=localembed)
61+
62+
@client.slash_command(
63+
name="rate",
64+
description="Rate a user of your choice."
65+
)
66+
@option(name="user", description="The person you want to rate", type=discord.User)
67+
@option(name="rating", description="The rating you want to give to the user", type=str, choices=["1 star", "2 stars", "3 stars", "4 stars", "5 stars"])
68+
async def rate(ctx: ApplicationContext, user: discord.User, rating: str):
69+
if ctx.author.id not in user_ratings: user_ratings[str(ctx.author.id)] = {}
70+
if rating not in ["1 star", "2 stars", "3 stars", "4 stars", "5 stars"]: return
71+
if rating == "1 star": rating_int = 1
72+
elif rating == "2 stars": rating_int = 2
73+
elif rating == "3 stars": rating_int = 3
74+
elif rating == "4 stars": rating_int = 4
75+
elif rating == "5 stars": rating_int = 5
76+
user_ratings[str(user.id)][str(ctx.author.id)] = rating_int
77+
save()
78+
localembed = discord.Embed(
79+
title=":star: Rating Submitted!",
80+
description=f"You have rated {user.name} {str(rating_int)} {'star' if rating_int == 1 else 'stars'}",
81+
color=discord.Color.green()
82+
)
83+
await ctx.respond(embed=localembed, ephemeral=True)
84+
85+
@client.slash_command(
86+
name="profile",
87+
description="View the profile of a user."
88+
)
89+
@option(name="user", description="The user you want to view", type=discord.User, default=None)
90+
async def profile(ctx: ApplicationContext, user: discord.User = None):
91+
if user == None: user = ctx.author
92+
localembed = discord.Embed(
93+
title=f"{user.display_name}'s profile",
94+
description=f"{user.name}",
95+
color=user.accent_color
96+
)
97+
localembed.set_thumbnail(url=user.display_avatar)
98+
localembed.add_field(name="Profile Picture URL", value=f"[Click to view]({user.display_avatar})")
99+
localembed.add_field(name="Joined Discord at", value=f"{strftime(user.created_at, '%d %B, %Y')}")
100+
localembed.add_field(name="User id", value=user.id)
101+
localembed.add_field(name="Rating", value=f"{str(parse_rating(user.id))} stars")
102+
# localembed.set_image(url=) TODO: Make profile metadata database, then activate this property
103+
await ctx.respond(embed=localembed)
104+
105+
@client.slash_command(
106+
name="rating",
107+
description="View a user's rating."
108+
)
109+
@option(name="user", description="The user you want to view", type=discord.User, default=None)
110+
async def rating(ctx: ApplicationContext, user: discord.User = None):
111+
if user == None: user = ctx.author
112+
localembed = discord.Embed(
113+
description=f":star: {user.name} has been rated {str(parse_rating(user.id))} stars",
114+
color=color
115+
)
116+
await ctx.respond(embed=localembed)
117+
118+
# User Commands
119+
@client.user_command(name="View Profile")
120+
async def _profile(ctx: ApplicationContext, user: discord.User):
121+
localembed = discord.Embed(
122+
title=f"{user.display_name}'s profile",
123+
description=f"{user.name}",
124+
color=user.accent_color
125+
)
126+
localembed.set_thumbnail(url=user.display_avatar)
127+
localembed.add_field(name="Profile Picture URL", value=f"[Click to view]({user.display_avatar})")
128+
localembed.add_field(name="Joined Discord at", value=f"{strftime(user.created_at, '%d %B, %Y')}")
129+
localembed.add_field(name="User id", value=user.id)
130+
localembed.add_field(name="Rating", value=f"{str(parse_rating(user.id))} stars")
131+
# localembed.set_image(url=) TODO: Make profile metadata database, then activate this property
132+
await ctx.respond(embed=localembed)
133+
134+
@client.user_command(name="View Rating")
135+
async def rating(ctx: ApplicationContext, user: discord.User):
136+
localembed = discord.Embed(
137+
description=f":star: {user.name} has been rated {str(parse_rating(user.id))} stars",
138+
color=color
139+
)
140+
await ctx.respond(embed=localembed)
141+
142+
# Bot Initialization
143+
try:
144+
with open("config/auth.json", 'r', encoding="utf-8") as f: auth_config = json.load(f)
145+
if auth_config["TOKEN"] == "":
146+
print("Unable to deploy client: You have not added a bot token yet. Add one first in 'TOKEN' in 'config/auth.json'.")
147+
print("You can get a bot token from https://discord.com/developers by creating a new application.")
148+
raise SystemExit
149+
if auth_config["deploy_mode"] == "local": client.run(auth_config["TOKEN"])
150+
elif auth_config["deploy_mode"] == "replit": client.run(getenv["TOKEN"])
151+
except KeyError:
152+
print("Unable to deploy client: Your configuration file is likely corrupted. Please reinstall the bot.")
153+
raise SystemExit
154+
except Exception as error:
155+
print(f"An error occured when trying to deploy the client.\nError Info:\n {type(error).__name__}\n {error}")
156+
raise SystemExit

pyproject.toml

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[tool.poetry]
2+
name = "ratebot"
3+
version = "0.1.0"
4+
description = "A simple user rating bot for Discord."
5+
authors = ["notsniped"]
6+
license = "GPL-3.0"
7+
readme = "README.md"
8+
9+
[tool.poetry.dependencies]
10+
python = "^3.11"
11+
py-cord = "^2.4.1"
12+
13+
14+
[build-system]
15+
requires = ["poetry-core"]
16+
build-backend = "poetry.core.masonry.api"

0 commit comments

Comments
 (0)