Skip to content

Commit 8d877d2

Browse files
Merge pull request #80 from smokeyScraper/auth_discord
[feat]: add github authentication using !verify_github command
2 parents 4884600 + 7236056 commit 8d877d2

File tree

5 files changed

+81
-29
lines changed

5 files changed

+81
-29
lines changed

backend/app/core/config.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from pydantic_settings import BaseSettings
22
from dotenv import load_dotenv
3+
from pydantic import field_validator
34

45
load_dotenv()
56

@@ -14,10 +15,9 @@ class Settings(BaseSettings):
1415
github_token: str = ""
1516
discord_bot_token: str = ""
1617

17-
# TODO: Add DB configuration
18-
# Database
19-
# Supabase
20-
# Weaviate
18+
# DB configuration
19+
supabase_url: str
20+
supabase_key: str
2121

2222
# LangSmith Tracing
2323
langsmith_tracing: bool = False
@@ -32,6 +32,13 @@ class Settings(BaseSettings):
3232
agent_timeout: int = 30
3333
max_retries: int = 3
3434

35+
@field_validator("supabase_url", "supabase_key", mode="before")
36+
@classmethod
37+
def _not_empty(cls, v, field):
38+
if not v:
39+
raise ValueError(f"{field.name} must be set")
40+
return v
41+
3542
class Config:
3643
env_file = ".env"
3744
extra = "ignore" # to prevent errors from extra env variables

backend/app/db/supabase/auth.py

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
1+
import asyncio
12
from app.db.supabase.supabase_client import supabase_client
2-
import os
3-
def login_with_oauth(provider: str):
3+
4+
5+
async def login_with_oauth(provider: str):
46
try:
5-
result = supabase_client.auth.sign_in_with_oauth({
6-
"provider": provider,
7-
"options": {
8-
"redirect_to": os.getenv("SUPABASE_REDIRECT_URL", "http://localhost:3000/home")
9-
}
10-
})
7+
result = await asyncio.to_thread(
8+
supabase_client.auth.sign_in_with_oauth,
9+
{"provider": provider}
10+
)
1111
return {"url": result.url}
1212
except Exception as e:
13-
raise Exception(f"OAuth login failed for {provider}: {str(e)}")
13+
raise Exception(f"OAuth login failed for {provider}") from e
1414

15+
async def login_with_github():
16+
return await login_with_oauth("github")
1517

16-
def login_with_github():
17-
return login_with_oauth("github")
18+
async def login_with_discord():
19+
return await login_with_oauth("discord")
1820

19-
def login_with_discord():
20-
return login_with_oauth("discord")
21+
async def login_with_slack():
22+
return await login_with_oauth("slack")
2123

22-
def logout(access_token: str):
24+
async def logout(access_token: str):
2325
try:
2426
supabase_client.auth.set_session(access_token, refresh_token="")
2527
supabase_client.auth.sign_out()

backend/app/db/supabase/supabase_client.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
1-
import os
2-
from dotenv import load_dotenv
1+
from app.core.config import settings
32
from supabase import create_client
43

5-
load_dotenv()
6-
7-
SUPABASE_URL = os.getenv("SUPABASE_URL")
8-
SUPABASE_KEY = os.getenv("SUPABASE_KEY")
9-
10-
if SUPABASE_URL is None or SUPABASE_KEY is None:
11-
raise ValueError("SUPABASE_URL and SUPABASE_KEY must be set in environment variables.")
4+
SUPABASE_URL = settings.supabase_url
5+
SUPABASE_KEY = settings.supabase_key
126

137
supabase_client = create_client(SUPABASE_URL, SUPABASE_KEY)
148

backend/bots/discord/discord_cogs.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
from discord.ext import commands
21
import discord
2+
from discord.ext import commands
3+
import logging
34
from app.core.orchestration.queue_manager import AsyncQueueManager, QueuePriority
5+
from app.db.supabase.auth import login_with_github
46
from bots.discord.discord_bot import DiscordBot
7+
from bots.discord.discord_views import OAuthView
8+
9+
logger = logging.getLogger(__name__)
510

611
class DevRelCommands(commands.Cog):
712
def __init__(self, bot: DiscordBot, queue_manager: AsyncQueueManager):
@@ -33,8 +38,36 @@ async def help_devrel(self, ctx: commands.Context):
3338
name="Commands",
3439
value=(
3540
"• `!reset` – Reset your DevRel thread and memory\n"
36-
"• `!help_devrel` – Show this help message"
41+
"• `!help_devrel` – Show this help message\n"
42+
"• `!verify_github` – Link your GitHub account\n"
3743
),
3844
inline=False
3945
)
4046
await ctx.send(embed=embed)
47+
48+
@commands.command(name="verify_github")
49+
async def verify_github(self, ctx: commands.Context):
50+
"""Get GitHub verification link."""
51+
try:
52+
logger.info(f"User {ctx.author.name}({ctx.author.id}) has requested for GitHub verification")
53+
54+
oauth_result = await login_with_github()
55+
logger.info(f"OAuth result: {oauth_result}")
56+
oauth_url = oauth_result["url"]
57+
58+
embed = discord.Embed(
59+
title="🔗 Verify GitHub Account",
60+
description="Click the button below to link your GitHub account \nAfter authorization, you'll be redirected to your GitHub profile.",
61+
)
62+
embed.add_field(
63+
name="ℹ️ Note:",
64+
value="The link expires in 5 minutes for security purposes.",
65+
inline=False
66+
)
67+
68+
view = OAuthView(oauth_url, "GitHub")
69+
await ctx.send(embed=embed, view=view)
70+
71+
except Exception as e:
72+
logger.error(f"Error in verify_github: {str(e)}")
73+
await ctx.send("Error generating GitHub verification link. Please try again.")
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import discord
2+
3+
class OAuthView(discord.ui.View):
4+
"""View with OAuth button."""
5+
6+
def __init__(self, oauth_url: str, provider_name: str):
7+
super().__init__(timeout=300)
8+
self.oauth_url = oauth_url
9+
self.provider_name = provider_name
10+
11+
button = discord.ui.Button(
12+
label=f"Connect {provider_name}",
13+
style=discord.ButtonStyle.link,
14+
url=oauth_url
15+
)
16+
self.add_item(button)

0 commit comments

Comments
 (0)