From 0e81fc00ec40b2a80e00abae095910494d60cbf2 Mon Sep 17 00:00:00 2001 From: yingying Date: Wed, 18 Dec 2024 16:51:10 +0800 Subject: [PATCH 1/4] refactor: reorganize the query list api --- server/bot/list.py | 52 ++++++++++++++++++++++++++++++++++++++++++++ server/bot/router.py | 38 +++----------------------------- 2 files changed, 55 insertions(+), 35 deletions(-) create mode 100644 server/bot/list.py diff --git a/server/bot/list.py b/server/bot/list.py new file mode 100644 index 00000000..788e39f4 --- /dev/null +++ b/server/bot/list.py @@ -0,0 +1,52 @@ +from typing import Optional + +from github import Github +from core.dao.repositoryConfigDAO import RepositoryConfigDAO +from petercat_utils import get_client +from github import Github, Auth + + +def query_list( + name: Optional[str] = None, + user_id: Optional[str] = None, + access_token: Optional[str] = None, + personal: Optional[str] = None, +): + try: + supabase = get_client() + query = supabase.table("bots").select( + "id, created_at, updated_at, avatar, description, name, public, starters, uid, repo_name" + ) + + if personal == "true": + if not access_token or not user_id: + return {"data": [], "personal": personal} + + auth = Auth.Token(token=access_token) + github_user = Github(auth=auth).get_user() + orgs_ids = [org.id for org in github_user.get_orgs()] + bot_ids = [] + + repository_config_dao = RepositoryConfigDAO() + bots = repository_config_dao.query_bot_id_by_owners( + orgs_ids + [github_user.id] + ) + + if bots: + bot_ids = [bot["robot_id"] for bot in bots if bot["robot_id"]] + + or_clause = f"uid.eq.{user_id}" + ( + f",id.in.({','.join(map(str, bot_ids))})" if bot_ids else "" + ) + query = query.or_(or_clause) + else: + query = query.eq("public", True) + + if name: + query = query.filter("name", "like", f"%{name}%") + + query = query.order("updated_at", desc=True) + data = query.execute() + return data.data + except Exception as e: + print(f"query list error: {e}") diff --git a/server/bot/router.py b/server/bot/router.py index 4bd489ed..8eb0e6ee 100644 --- a/server/bot/router.py +++ b/server/bot/router.py @@ -3,6 +3,7 @@ from fastapi.responses import JSONResponse from github import Github, Auth from auth.get_user_info import get_user, get_user_id +from bot.list import query_list from core.dao.botApprovalDAO import BotApprovalDAO from core.dao.botDAO import BotDAO from core.dao.repositoryConfigDAO import RepositoryConfigDAO @@ -32,42 +33,9 @@ def get_bot_list( user: Annotated[User | None, Depends(get_user)] = None, ): try: - supabase = get_client() - query = supabase.table("bots").select( - "id, created_at, updated_at, avatar, description, name, public, starters, uid, repo_name" - ) - - if personal == "true": - if not user or not user.access_token: - return {"data": [], "personal": personal} - - auth = Auth.Token(token=user.access_token) - github_user = Github(auth=auth).get_user() - orgs_ids = [org.id for org in github_user.get_orgs()] - bot_ids = [] - - repository_config_dao = RepositoryConfigDAO() - bots = repository_config_dao.query_bot_id_by_owners( - orgs_ids + [github_user.id] - ) - - if bots: - bot_ids = [bot["robot_id"] for bot in bots if bot["robot_id"]] - - or_clause = f"uid.eq.{user.id}" + ( - f",id.in.({','.join(map(str, bot_ids))})" if bot_ids else "" - ) - query = query.or_(or_clause) - else: - query = query.eq("public", True) - - if name: - query = query.filter("name", "like", f"%{name}%") - - query = query.order("updated_at", desc=True) - data = query.execute() + data = query_list(name, user.id, user.access_token, personal) - return {"data": data.data if data and data.data else [], "personal": personal} + return {"data": data if data else [], "personal": personal} except Exception as e: return JSONResponse( From 4c0d36a0dbb1428103b89aa40ece81cd6e760960 Mon Sep 17 00:00:00 2001 From: yingying Date: Wed, 18 Dec 2024 17:17:31 +0800 Subject: [PATCH 2/4] feat: add join selection for the list query --- server/bot/list.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/server/bot/list.py b/server/bot/list.py index 788e39f4..b6e76207 100644 --- a/server/bot/list.py +++ b/server/bot/list.py @@ -14,8 +14,12 @@ def query_list( ): try: supabase = get_client() - query = supabase.table("bots").select( - "id, created_at, updated_at, avatar, description, name, public, starters, uid, repo_name" + query = ( + supabase.rpc("get_bots_with_profiles_and_github") + if personal == "true" + else supabase.table("bots").select( + "id, created_at, updated_at, avatar, description, name, public, starters, uid, repo_name" + ) ) if personal == "true": @@ -47,6 +51,12 @@ def query_list( query = query.order("updated_at", desc=True) data = query.execute() + if data.data: + unique_data = {} + for item in data.data: + unique_data[item["id"]] = item + deduplicated_list = list(unique_data.values()) + return deduplicated_list return data.data except Exception as e: print(f"query list error: {e}") From fd509b761a97fbc3440d598f328e3ee6699b239e Mon Sep 17 00:00:00 2001 From: yingying Date: Wed, 18 Dec 2024 17:28:26 +0800 Subject: [PATCH 3/4] refactory: remove usless request --- client/app/factory/list/components/BotCard.tsx | 17 +++++++++-------- server/bot/list.py | 5 ++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/client/app/factory/list/components/BotCard.tsx b/client/app/factory/list/components/BotCard.tsx index 6533480f..45bf6814 100644 --- a/client/app/factory/list/components/BotCard.tsx +++ b/client/app/factory/list/components/BotCard.tsx @@ -17,11 +17,7 @@ import { Tooltip, } from '@nextui-org/react'; import { useRouter } from 'next/navigation'; -import { - useBotDelete, - useGetBotBoundRepos, - useGetBotRagTask, -} from '@/app/hooks/useBot'; +import { useBotDelete, useGetBotRagTask } from '@/app/hooks/useBot'; import { TaskStatus } from '@/types/task'; import ErrorBadgeIcon from '@/public/icons/ErrorBadgeIcon'; import KnowledgeTaskCompleteIcon from '@/public/icons/CheckBadgeIcon'; @@ -33,12 +29,17 @@ import CardCartIcon from '@/public/icons/CardCartIcon'; declare type Bot = Tables<'bots'>; -const BotInfoIconList = (props: { bot: Bot }) => { +interface BotInfo extends Bot { + github_installed?: boolean; + picture?: string; + nickname?: string; +} + +const BotInfoIconList = (props: { bot: BotInfo }) => { const { bot } = props; - const { data } = useGetBotBoundRepos(bot.id); const showHomeIcon = bot.domain_whitelist && bot.domain_whitelist.length > 0; const showCartIcon = bot.public; - const showGithubIcon = data && Array.isArray(data) && data.length > 0; + const showGithubIcon = bot.github_installed; const texts = [ showGithubIcon ? I18N.components.BotCard.gITHU : '', showHomeIcon ? I18N.components.BotCard.guanWang : undefined, diff --git a/server/bot/list.py b/server/bot/list.py index b6e76207..f0b5638e 100644 --- a/server/bot/list.py +++ b/server/bot/list.py @@ -21,6 +21,8 @@ def query_list( "id, created_at, updated_at, avatar, description, name, public, starters, uid, repo_name" ) ) + if name: + query = query.filter("name", "like", f"%{name}%") if personal == "true": if not access_token or not user_id: @@ -46,9 +48,6 @@ def query_list( else: query = query.eq("public", True) - if name: - query = query.filter("name", "like", f"%{name}%") - query = query.order("updated_at", desc=True) data = query.execute() if data.data: From 320fa715e10a66a388fcef5286a84cdf43ce0074 Mon Sep 17 00:00:00 2001 From: yingying Date: Wed, 18 Dec 2024 17:38:23 +0800 Subject: [PATCH 4/4] chore: sync the db --- .../20241218093541_remote_schema.sql | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 migrations/supabase/migrations/20241218093541_remote_schema.sql diff --git a/migrations/supabase/migrations/20241218093541_remote_schema.sql b/migrations/supabase/migrations/20241218093541_remote_schema.sql new file mode 100644 index 00000000..1de61dc0 --- /dev/null +++ b/migrations/supabase/migrations/20241218093541_remote_schema.sql @@ -0,0 +1,70 @@ +alter table "public"."profiles" drop constraint "profile_pkey"; + +drop index if exists "public"."profile_pkey"; + +alter table "public"."profiles" alter column "sub" set not null; + +CREATE INDEX idx_file_sha ON public.rag_docs USING btree (file_sha); + +CREATE UNIQUE INDEX profiles_pkey ON public.profiles USING btree (id); + +alter table "public"."profiles" add constraint "profiles_pkey" PRIMARY KEY using index "profiles_pkey"; + +set check_function_bodies = off; + +create or replace view "public"."bots_with_profiles_and_github" as SELECT bots.id, + bots.created_at, + bots.updated_at, + bots.avatar, + bots.description, + bots.name, + bots.public, + bots.starters, + bots.uid, + bots.repo_name, + profiles.picture, + profiles.nickname, + CASE + WHEN (github_repo_config.robot_id IS NOT NULL) THEN true + ELSE false + END AS github_installed + FROM ((bots + LEFT JOIN profiles ON (((bots.uid)::text = (profiles.sub)::text))) + LEFT JOIN github_repo_config ON ((bots.id = (github_repo_config.robot_id)::uuid))); + + +CREATE OR REPLACE FUNCTION public.get_bots_with_profiles_and_github() + RETURNS TABLE(id uuid, created_at timestamp without time zone, updated_at timestamp without time zone, avatar text, description text, name text, public boolean, starters text, uid text, domain_whitelist text[], repo_name text, picture text, nickname text, github_installed boolean) + LANGUAGE plpgsql +AS $function$ +BEGIN + RETURN QUERY + SELECT + b.id::uuid, + b.created_at::timestamp, + b.updated_at::timestamp, + b.avatar::text, + b.description::text, + b.name::text, + b.public::boolean, + b.starters::text, + b.uid::text, + b.domain_whitelist::text[], + b.repo_name::text, + p.picture::text, + p.nickname::text, + CASE + WHEN grc.robot_id IS NOT NULL THEN TRUE + ELSE FALSE + END AS github_installed + FROM + bots b + LEFT JOIN + profiles p ON b.uid = p.sub + LEFT JOIN + github_repo_config grc ON b.id::varchar = grc.robot_id; +END; +$function$ +; + +