Skip to content

Commit

Permalink
fix: catch user info is null (#214)
Browse files Browse the repository at this point in the history
- Github App 安装的加回来
  • Loading branch information
RaoHai authored Aug 18, 2024
2 parents 40472f4 + 3dfd119 commit d11a50d
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 2 deletions.
19 changes: 19 additions & 0 deletions client/app/github/installed/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use client';

import React from 'react';

export default function GithubAppInstalled() {
return (
<div className="flex h-screen w-full flex-col items-center bg-white pb-16 pt-20 sm:pb-20 md:pt-36 lg:py-32">
<p className='font-display text-4xl font-bold tracking-tight text-slate-900'>
Installation Approved
</p>
<p>
Thank you for installing PeterCat&#x27;s GitHub App!
</p>
<p>
Your Team will now be able to use robots for your GitHub organization!
</p>
</div>
)
}
6 changes: 6 additions & 0 deletions server/dao/BaseDAO.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from abc import abstractmethod

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

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

from petercat_utils.db.client.supabase import get_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"}
26 changes: 26 additions & 0 deletions server/models/authorization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
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)

2 changes: 1 addition & 1 deletion server/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ httpx[socks]
load_dotenv
supabase
boto3>=1.34.84
pyjwt>=2.4.0
jwt
pydantic>=2.7.0
unstructured[md]
python-dotenv
Expand Down
54 changes: 53 additions & 1 deletion server/routers/github.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
from fastapi import APIRouter, BackgroundTasks, Header, Request
import logging
from fastapi.responses import RedirectResponse
import requests
import time
from github import Auth
from dao.authorizationDAO import AuthorizationDAO
from models.authorization import Authorization
from utils.github import get_handler, get_private_key
from petercat_utils import get_env_variable
from jwt import JWT, jwk_from_pem

APP_ID = get_env_variable("X_GITHUB_APP_ID")
WEB_URL = get_env_variable("WEB_URL")

logger = logging.getLogger()
logger.setLevel("INFO")
Expand All @@ -15,12 +22,57 @@
responses={404: {"description": "Not found"}},
)

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_private_key()
signing_key = jwk_from_pem(pem.encode("utf-8"))

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):
return {"success": True}
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)
print(f"github_app_callback: success={success}, message={message}")

return RedirectResponse(url=f'{WEB_URL}/github/installed?message={message}', status_code=302)

@router.post("/app/webhook")
async def github_app_webhook(
Expand Down

0 comments on commit d11a50d

Please sign in to comment.