Skip to content

Commit

Permalink
app register callback
Browse files Browse the repository at this point in the history
  • Loading branch information
RaoHai committed Apr 14, 2024
1 parent bc54b14 commit 422ff5f
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 20 deletions.
7 changes: 7 additions & 0 deletions server/dao/BaseDAO.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

from abc import abstractmethod

class BaseDAO:
@abstractmethod
def get_client():
...
41 changes: 41 additions & 0 deletions server/dao/authorization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

import json
from dao.BaseDAO import BaseDAO
from db.supabase.client import get_client
from models.authorization import Authorization
from supabase.client import Client, create_client

class AuthorizationDAO(BaseDAO):
client: Client

def __init__(self):
super().__init__()
self.client = get_client()

def exists(self, installation_id: str) -> bool:
try:
authorization = self.client.table("github_app_authorization")\
.select('*', count="exact")\
.eq('installation_id', installation_id) \
.execute()

return bool(authorization.count)

except Exception as e:
print("Error: ", e)
return {"message": "User creation failed"}

def create(self, data: Authorization):
print('supabase github_app_authorization creation', data.model_dump())
try:
authorization = self.client.from_("github_app_authorization")\
.insert(data.model_dump())\
.execute()
if authorization:
return True, {"message": "User created successfully"}
else:
return False, {"message": "User creation failed"}
except Exception as e:
print("Error: ", e)
return {"message": "User creation failed"}

9 changes: 9 additions & 0 deletions server/db/supabase/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from supabase.client import Client, create_client
from uilts.env import get_env_variable

supabase_url = get_env_variable("SUPABASE_URL")
supabase_key = get_env_variable("SUPABASE_SERVICE_KEY")

def get_client():
supabase: Client = create_client(supabase_url, supabase_key)
return supabase
6 changes: 5 additions & 1 deletion server/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from routers import health_checker, messages, github

open_api_key = get_env_variable("OPENAI_API_KEY")
is_dev = bool(get_env_variable("IS_DEV"))

app = FastAPI(
title="Bo-meta Server",
Expand Down Expand Up @@ -51,4 +52,7 @@ def search_knowledge(query: str):
return data

if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", "8080")))
if is_dev:
uvicorn.run("main:app", host="0.0.0.0", port=int(os.environ.get("PORT", "8080")), reload=True)
else:
uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", "8080")))
25 changes: 25 additions & 0 deletions server/models/authorization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from datetime import datetime
import json
from pydantic import BaseModel, field_serializer
from typing import Any, Dict

class Authorization(BaseModel):
token: str
installation_id: str
code: str
created_at: datetime
expires_at: datetime

permissions: Dict

@field_serializer('created_at')
def serialize_created_at(self, created_at: datetime):
return created_at.isoformat()

@field_serializer('expires_at')
def serialize_expires_at(self, expires_at: datetime):
return expires_at.isoformat()

@field_serializer('permissions')
def serialize_permissions(self, permissions: Dict):
return json.dumps(permissions)
6 changes: 2 additions & 4 deletions server/rag/retrieval.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import CharacterTextSplitter
from langchain_community.vectorstores import SupabaseVectorStore
from supabase.client import Client, create_client
from db.supabase.client import get_client
from uilts.env import get_env_variable

supabase_url = get_env_variable("SUPABASE_URL")
Expand All @@ -13,8 +13,6 @@
query_name="match_antd_knowledge"
chunk_size=500

supabase: Client = create_client(supabase_url, supabase_key)

def convert_document_to_dict(document):
return {
'page_content': document.page_content,
Expand All @@ -26,7 +24,7 @@ def init_retriever():
embeddings = OpenAIEmbeddings()
db = SupabaseVectorStore(
embedding=embeddings,
client=supabase,
client=get_client(),
table_name=table_name,
query_name=query_name,
chunk_size=chunk_size,
Expand Down
4 changes: 3 additions & 1 deletion server/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ python-multipart
httpx[socks]
load_dotenv
supabase
boto3>=1.26.79
boto3>=1.34.84
jwt
pydantic>=2.7.0
90 changes: 76 additions & 14 deletions server/routers/github.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
from fastapi import APIRouter, Depends, HTTPException
from fastapi import APIRouter, BackgroundTasks, Header, Request
import logging
import requests
from pydantic import BaseModel

import time
from dao.authorization import AuthorizationDAO
import boto3
from botocore.exceptions import ClientError
from jwt import JWT, jwk_from_pem
from models.authorization import Authorization

from uilts.env import get_env_variable

APP_ID = get_env_variable("GITHUB_APP_ID")
CLIENT_ID = get_env_variable("GITHUB_APP_CLIENT_ID")
CLIENT_SECRET = get_env_variable("GITHUB_APP_CLIENT_SECRET")

Expand All @@ -17,22 +22,79 @@
responses={404: {"description": "Not found"}},
)

def get_pem():
secret_name = "prod/githubapp/petercat/pem"
region_name = "ap-northeast-1"
session = boto3.session.Session()
client = session.client(
service_name='secretsmanager',
region_name=region_name
)
try:
get_secret_value_response = client.get_secret_value(
SecretId=secret_name
)
except ClientError as e:
# For a list of exceptions thrown, see
# https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html
raise e

return get_secret_value_response['SecretString']

def get_jwt():
payload = {
# Issued at time
'iat': int(time.time()),
# JWT expiration time (10 minutes maximum)
'exp': int(time.time()) + 600,
# GitHub App's identifier
'iss': APP_ID
}

pem = get_pem()
signing_key = jwk_from_pem(pem.encode("utf-8"))

@router.get("/app/callback")
def github_app_callback(code: str):
print("Github App Callback", code)
logger.info("Github App Callback: %s", code)
resp = requests.post('https://github.com/login/oauth/access_token',
json={
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"code": code,
print(pem)
jwt_instance = JWT()
return jwt_instance.encode(payload, signing_key, alg='RS256')

def get_app_installations_access_token(installation_id: str, jwt: str):
url = f"https://api.github.com/app/installations/{installation_id}/access_tokens"
print("get_app_installations_access_token", url, jwt)
resp = requests.post(url,
headers={
'X-GitHub-Api-Version': '2022-11-28',
'Accept': 'application/vnd.github+json',
'Authorization': f"Bearer {jwt}"
}
)

return resp.json()

# https://github.com/login/oauth/authorize?client_id=Iv1.c2e88b429e541264
@router.get("/app/installation/callback")
def github_app_callback(code: str, installation_id: str, setup_action: str):
authorizationDAO = AuthorizationDAO()

if setup_action != "install":
return { "success": False, "message": f"Invalid setup_action value {setup_action}" }
elif authorizationDAO.exists(installation_id=installation_id):
return { "success": False, "message": f"Installation_id {installation_id} Exists" }
else:
jwt = get_jwt()
access_token = get_app_installations_access_token(installation_id=installation_id, jwt=jwt)
authorization = Authorization(
**access_token,
code=code,
installation_id=installation_id,
created_at=int(time.time())
)

success, message = authorizationDAO.create(authorization)

return { "success": success, "message": message }

@router.post("/app/webhook")
def github_app_webhook(callbackParams):
logger.info("Github App Webhook: %s", callbackParams)
def github_app_webhook(request: Request, background_tasks: BackgroundTasks, x_github_event: str = Header(...)):
logger.info("github_app_webhook: x_github_event=%s, %s", x_github_event, request.json())
return {"hello": "world"}

0 comments on commit 422ff5f

Please sign in to comment.