Skip to content

Oauth integration #1011

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions backend/score.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from fastapi import FastAPI, File, UploadFile, Form, Request
from fastapi import FastAPI, File, UploadFile, Form, Request, HTTPException
from fastapi_health import health
from fastapi.middleware.cors import CORSMiddleware
from src.main import *
Expand All @@ -19,7 +19,6 @@
from src.neighbours import get_neighbour_nodes
import json
from typing import List
from starlette.middleware.sessions import SessionMiddleware
from google.oauth2.credentials import Credentials
import os
from src.logger import CustomLogger
Expand All @@ -33,6 +32,10 @@
from starlette.types import ASGIApp, Receive, Scope, Send
from langchain_neo4j import Neo4jGraph
from src.entities.source_node import sourceNode
from starlette.middleware.sessions import SessionMiddleware
from starlette.responses import HTMLResponse, RedirectResponse,JSONResponse
from starlette.requests import Request
import secrets

logger = CustomLogger()
CHUNK_DIR = os.path.join(os.path.dirname(__file__), "chunks")
Expand Down Expand Up @@ -77,6 +80,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send):
)
await gzip_middleware(scope, receive, send)
app = FastAPI()

app.add_middleware(XContentTypeOptions)
app.add_middleware(XFrame, Option={'X-Frame-Options': 'DENY'})
app.add_middleware(CustomGZipMiddleware, minimum_size=1000, compresslevel=5,paths=["/sources_list","/url/scan","/extract","/chat_bot","/chunk_entities","/get_neighbours","/graph_query","/schema","/populate_graph_schema","/get_unconnected_nodes_list","/get_duplicate_nodes","/fetch_chunktext"])
Expand All @@ -86,14 +90,14 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send):
allow_methods=["*"],
allow_headers=["*"],
)
app.add_middleware(SessionMiddleware, secret_key=os.urandom(24))

is_gemini_enabled = os.environ.get("GEMINI_ENABLED", "False").lower() in ("true", "1", "yes")
if is_gemini_enabled:
add_routes(app,ChatVertexAI(), path="/vertexai")

app.add_api_route("/health", health([healthy_condition, healthy]))

app.add_middleware(SessionMiddleware, secret_key=os.urandom(24))


@app.post("/url/scan")
Expand Down
2 changes: 2 additions & 0 deletions frontend/example.env
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ VITE_BATCH_SIZE=2
VITE_LLM_MODELS_PROD="openai_gpt_4o,openai_gpt_4o_mini,diffbot,gemini_1.5_flash"
VITE_FRONTEND_HOSTNAME="localhost:8080"
VITE_SEGMENT_API_URL=""
VITE_AUTH0_CLIENT_ID=""
VITE_AUTH0_DOMAIN=""
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"preview": "vite preview"
},
"dependencies": {
"@auth0/auth0-react": "^2.2.4",
"@emotion/styled": "^11.11.0",
"@mui/material": "^5.15.10",
"@mui/styled-engine": "^5.15.9",
Expand Down
38 changes: 9 additions & 29 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,13 @@
import './App.css';
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
import ThemeWrapper from './context/ThemeWrapper';
import QuickStarter from './components/QuickStarter';
import { GoogleOAuthProvider } from '@react-oauth/google';
import { APP_SOURCES } from './utils/Constants';
import ErrorBoundary from './components/UI/ErrroBoundary';
import { Toaster } from '@neo4j-ndl/react';
const App: React.FC = () => {
import { Route, Routes } from 'react-router-dom';
import ChatOnlyComponent from './components/ChatBot/ChatOnlyComponent';
import { AuthenticationGuard } from './components/Auth/Auth';
import Home from './Home';
const App = () => {
return (
<>
{APP_SOURCES != undefined && APP_SOURCES.includes('gcs') ? (
<ErrorBoundary>
<GoogleOAuthProvider clientId={process.env.VITE_GOOGLE_CLIENT_ID as string}>
<ThemeWrapper>
<QuickStarter />
<Toaster />
</ThemeWrapper>
</GoogleOAuthProvider>
</ErrorBoundary>
) : (
<ErrorBoundary>
<ThemeWrapper>
<QuickStarter />
<Toaster />
</ThemeWrapper>
</ErrorBoundary>
)}
</>
<Routes>
<Route path='/' element={<AuthenticationGuard component={Home} />}></Route>
<Route path='/chat-only' element={<ChatOnlyComponent />}></Route>
</Routes>
);
};

export default App;
4 changes: 2 additions & 2 deletions frontend/src/HOC/WithVisibility.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { VisibilityProps } from '../types';

export function withVisibility<P>(WrappedComponent: React.ComponentType<P>) {
const VisibityControlled = (props: P & VisibilityProps) => {
const VisibilityControlled = (props: P & VisibilityProps) => {
if (props.isVisible === false) {
return null;
}

return <WrappedComponent {...props} />;
};

return VisibityControlled;
return VisibilityControlled;
}
33 changes: 33 additions & 0 deletions frontend/src/Home.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import './App.css';
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
import ThemeWrapper from './context/ThemeWrapper';
import QuickStarter from './components/QuickStarter';
import { GoogleOAuthProvider } from '@react-oauth/google';
import { APP_SOURCES } from './utils/Constants';
import ErrorBoundary from './components/UI/ErrroBoundary';
import { Toaster } from '@neo4j-ndl/react';
const Home: React.FC = () => {
return (
<>
{APP_SOURCES != undefined && APP_SOURCES.includes('gcs') ? (
<ErrorBoundary>
<GoogleOAuthProvider clientId={process.env.VITE_GOOGLE_CLIENT_ID as string}>
<ThemeWrapper>
<QuickStarter />
<Toaster />
</ThemeWrapper>
</GoogleOAuthProvider>
</ErrorBoundary>
) : (
<ErrorBoundary>
<ThemeWrapper>
<QuickStarter />
<Toaster />
</ThemeWrapper>
</ErrorBoundary>
)}
</>
);
};

export default Home;
30 changes: 30 additions & 0 deletions frontend/src/components/Auth/Auth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import { AppState, Auth0Provider, withAuthenticationRequired } from '@auth0/auth0-react';
import { useNavigate } from 'react-router';
const domain = process.env.VITE_AUTH0_DOMAIN;
const clientId = process.env.VITE_AUTH0_CLIENT_ID;
const Auth0ProviderWithHistory: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const navigate = useNavigate();

function onRedirectCallback(appState?: AppState) {
navigate(appState?.returnTo || window.location.pathname, { state: appState });
}

return (
<Auth0Provider
domain={domain as string}
clientId={clientId as string}
authorizationParams={{ redirect_uri: window.location.origin }}
onRedirectCallback={onRedirectCallback}
>
{children}
</Auth0Provider>
);
};

export const AuthenticationGuard: React.FC<{ component: React.ComponentType<object> }> = ({ component }) => {
const Component = withAuthenticationRequired(component);
return <Component />;
};

export default Auth0ProviderWithHistory;
54 changes: 28 additions & 26 deletions frontend/src/components/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ const Content: React.FC<ContentProps> = ({
const [openGraphView, setOpenGraphView] = useState<boolean>(false);
const [inspectedName, setInspectedName] = useState<string>('');
const [documentName, setDocumentName] = useState<string>('');
const [showConfirmationModal, setShowConfirmationModal] = useState<boolean>(false);
const [showExpirationModal, setShowExpirationModal] = useState<boolean>(false);
const [extractLoading, setIsExtractLoading] = useState<boolean>(false);
const {
setUserCredentials,
userCredentials,
Expand All @@ -72,9 +75,7 @@ const Content: React.FC<ContentProps> = ({
isGCSActive,
chunksToBeProces,
} = useCredentials();
const [showConfirmationModal, setshowConfirmationModal] = useState<boolean>(false);
const [showExpirationModal, setshowExpirationModal] = useState<boolean>(false);
const [extractLoading, setextractLoading] = useState<boolean>(false);

const [retryFile, setRetryFile] = useState<string>('');
const [retryLoading, setRetryLoading] = useState<boolean>(false);
const [showRetryPopup, toggleRetryPopup] = useReducer((state) => !state, false);
Expand Down Expand Up @@ -111,8 +112,10 @@ const Content: React.FC<ContentProps> = ({
const [viewPoint, setViewPoint] = useState<'tableView' | 'showGraphView' | 'chatInfoView' | 'neighborView'>(
'tableView'
);
const [showDeletePopUp, setshowDeletePopUp] = useState<boolean>(false);
const [deleteLoading, setdeleteLoading] = useState<boolean>(false);

const [showDeletePopUp, setShowDeletePopUp] = useState<boolean>(false);
const [deleteLoading, setIsDeleteLoading] = useState<boolean>(false);

const hasSelections = useHasSelections(selectedNodes, selectedRels);

const { updateStatusForLargeFiles } = useServerSideEvent(
Expand Down Expand Up @@ -236,13 +239,13 @@ const Content: React.FC<ContentProps> = ({
if (!isselectedRows) {
const fileItem = filesData.find((f) => f.id == uid);
if (fileItem) {
setextractLoading(true);
setIsExtractLoading(true);
await extractHandler(fileItem, uid);
}
} else {
const fileItem = filesTobeProcess.find((f) => f.id == uid);
if (fileItem) {
setextractLoading(true);
setIsExtractLoading(true);
await extractHandler(fileItem, uid);
}
}
Expand Down Expand Up @@ -508,12 +511,12 @@ const Content: React.FC<ContentProps> = ({
data = triggerBatchProcessing(filesTobeSchedule, filesTobeProcessed, true, true);
}
Promise.allSettled(data).then((_) => {
setextractLoading(false);
setIsExtractLoading(false);
});
} else if (queueFiles && !queue.isEmpty() && processingFilesCount < batchSize) {
data = scheduleBatchWiseProcess(queue.items, true);
Promise.allSettled(data).then((_) => {
setextractLoading(false);
setIsExtractLoading(false);
});
} else {
addFilesToQueue(filesTobeProcessed as CustomFile[]);
Expand All @@ -532,7 +535,7 @@ const Content: React.FC<ContentProps> = ({
data = triggerBatchProcessing(queue.items, queue.items as CustomFile[], true, false);
}
Promise.allSettled(data).then((_) => {
setextractLoading(false);
setIsExtractLoading(false);
});
} else {
const selectedNewFiles = childRef.current
Expand Down Expand Up @@ -680,7 +683,7 @@ const Content: React.FC<ContentProps> = ({

const handleDeleteFiles = async (deleteEntities: boolean) => {
try {
setdeleteLoading(true);
setIsDeleteLoading(true);
const response = await deleteAPI(
userCredentials as UserCredentials,
childRef.current?.getSelectedRows() as CustomFile[],
Expand All @@ -689,7 +692,7 @@ const Content: React.FC<ContentProps> = ({
queue.clear();
setProcessedCount(0);
setRowSelection({});
setdeleteLoading(false);
setIsDeleteLoading(false);
if (response.data.status == 'Success') {
showSuccessToast(response.data.message);
const filenames = childRef.current?.getSelectedRows().map((str) => str.name);
Expand All @@ -703,17 +706,17 @@ const Content: React.FC<ContentProps> = ({
let errorobj = { error: response.data.error, message: response.data.message };
throw new Error(JSON.stringify(errorobj));
}
setshowDeletePopUp(false);
setShowDeletePopUp(false);
} catch (err) {
setdeleteLoading(false);
setIsDeleteLoading(false);
if (err instanceof Error) {
const error = JSON.parse(err.message);
const { message } = error;
showErrorToast(message);
console.log(err);
}
}
setshowDeletePopUp(false);
setShowDeletePopUp(false);
};

const onClickHandler = () => {
Expand All @@ -726,11 +729,10 @@ const Content: React.FC<ContentProps> = ({
(c) => isFileReadyToProcess(c, true) && typeof c.size === 'number' && c.size > largeFileSize
);
if (expiredFilesExists) {
setshowExpirationModal(true);
setShowExpirationModal(true);
} else if (largeFileExists && isGCSActive) {
setshowConfirmationModal(true);
setshowExpirationModal(true);
} else {
setShowConfirmationModal(true);
} else {
handleGenerateGraph(selectedRows.filter((f) => isFileReadyToProcess(f, false)));
}
} else if (filesData.length) {
Expand All @@ -747,9 +749,9 @@ const Content: React.FC<ContentProps> = ({
}, {});
setRowSelection(stringified);
if (largeFileExists) {
setshowConfirmationModal(true);
setShowConfirmationModal(true);
} else if (expiredFileExists && isGCSActive) {
setshowExpirationModal(true);
setShowExpirationModal(true);
} else {
handleGenerateGraph(filesData.filter((f) => isFileReadyToProcess(f, false)));
}
Expand Down Expand Up @@ -792,7 +794,7 @@ const Content: React.FC<ContentProps> = ({
open={showConfirmationModal}
largeFiles={filesForProcessing}
extractHandler={handleGenerateGraph}
onClose={() => setshowConfirmationModal(false)}
onClose={() => setShowConfirmationModal(false)}
loading={extractLoading}
selectedRows={childRef.current?.getSelectedRows() as CustomFile[]}
isLargeDocumentAlert={true}
Expand All @@ -805,7 +807,7 @@ const Content: React.FC<ContentProps> = ({
open={showExpirationModal}
largeFiles={filesForProcessing}
extractHandler={handleGenerateGraph}
onClose={() => setshowExpirationModal(false)}
onClose={() => setShowExpirationModal(false)}
loading={extractLoading}
selectedRows={childRef.current?.getSelectedRows() as CustomFile[]}
isLargeDocumentAlert={false}
Expand All @@ -818,7 +820,7 @@ const Content: React.FC<ContentProps> = ({
open={showExpirationModal}
largeFiles={filesForProcessing}
extractHandler={handleGenerateGraph}
onClose={() => setshowExpirationModal(false)}
onClose={() => setShowExpirationModal(false)}
loading={extractLoading}
selectedRows={childRef.current?.getSelectedRows() as CustomFile[]}
isLargeDocumentAlert={false}
Expand All @@ -830,7 +832,7 @@ const Content: React.FC<ContentProps> = ({
open={showDeletePopUp}
no_of_files={selectedfileslength ?? 0}
deleteHandler={(delentities: boolean) => handleDeleteFiles(delentities)}
deleteCloseHandler={() => setshowDeletePopUp(false)}
deleteCloseHandler={() => setShowDeletePopUp(false)}
loading={deleteLoading}
view='contentView'
></DeletePopUp>
Expand Down Expand Up @@ -1007,7 +1009,7 @@ const Content: React.FC<ContentProps> = ({
!selectedfileslength ? tooltips.deleteFile : `${selectedfileslength} ${tooltips.deleteSelectedFiles}`
}
placement='top'
onClick={() => setshowDeletePopUp(true)}
onClick={() => setShowDeletePopUp(true)}
disabled={!selectedfileslength || isReadOnlyUser}
className='ml-0.5'
label='Delete Files'
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/DataSources/AWS/S3Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const S3Modal: React.FC<S3ModalProps> = ({ hideModal, open }) => {
const [secretKey, setSecretKey] = useState<string>('');
const [status, setStatus] = useState<'unknown' | 'success' | 'info' | 'warning' | 'danger'>('unknown');
const [statusMessage, setStatusMessage] = useState<string>('');
const [isFocused, setisFocused] = useState<boolean>(false);
const [isFocused, setIsFocused] = useState<boolean>(false);
const [isValid, setValid] = useState<boolean>(false);
const { userCredentials } = useCredentials();
const { setFilesData, model, filesData } = useFileContext();
Expand All @@ -25,7 +25,7 @@ const S3Modal: React.FC<S3ModalProps> = ({ hideModal, open }) => {
setAccessKey('');
setSecretKey('');
setValid(false);
setisFocused(false);
setIsFocused(false);
};

const submitHandler = async (url: string) => {
Expand Down Expand Up @@ -174,7 +174,7 @@ const S3Modal: React.FC<S3ModalProps> = ({ hideModal, open }) => {
isRequired={true}
errorText={!isValid && isFocused && 'Please Fill The Valid URL'}
onChange={(e) => {
setisFocused(true);
setIsFocused(true);
setBucketUrl(e.target.value);
}}
/>
Expand Down
Loading
Loading