(fix:auth) refresh drive token

This commit is contained in:
ManishMadan2882 committed 2025-09-19 22:57:09 +05:30
1 parent 0ee875bee4
commit 896612a5a3
3 files changed
+177 -140

No files matched your search

+21 -1
View File
@@ -441,9 +441,29 @@ class ConnectorValidateSession(Resource):
auth = ConnectorCreator.create_auth(provider) auth = ConnectorCreator.create_auth(provider)
is_expired = auth.is_token_expired(token_info) is_expired = auth.is_token_expired(token_info)
if is_expired and token_info.get('refresh_token'):
try:
new_token_info = auth.refresh_access_token(token_info.get('refresh_token'))
sessions_collection.update_one(
{"session_token": session_token},
{"$set": {"token_info": new_token_info}}
)
token_info = new_token_info
is_expired = False
except Exception as refresh_error:
current_app.logger.error(f"Failed to refresh token: {refresh_error}")
if is_expired:
return make_response(jsonify({
"success": False,
"expired": True,
"error": "Session token has expired. Please reconnect."
}), 401)
return make_response(jsonify({ return make_response(jsonify({
"success": True, "success": True,
"expired": is_expired, "expired": False,
"user_email": session.get('user_email', 'Connected User'), "user_email": session.get('user_email', 'Connected User'),
"access_token": token_info.get('access_token') "access_token": token_info.get('access_token')
}), 200) }), 200)
+63 -28
View File
@@ -7,20 +7,21 @@ interface ConnectorAuthProps {
onSuccess: (data: { session_token: string; user_email: string }) => void; onSuccess: (data: { session_token: string; user_email: string }) => void;
onError: (error: string) => void; onError: (error: string) => void;
label?: string; label?: string;
isConnected?: boolean;
userEmail?: string;
onDisconnect?: () => void;
errorMessage?: string;
} }
const providerLabel = (provider: string) => {
const map: Record<string, string> = {
google_drive: 'Google Drive',
};
return map[provider] || provider.replace(/_/g, ' ');
};
const ConnectorAuth: React.FC<ConnectorAuthProps> = ({ const ConnectorAuth: React.FC<ConnectorAuthProps> = ({
provider, provider,
onSuccess, onSuccess,
onError, onError,
label, label,
isConnected = false,
userEmail = '',
onDisconnect,
errorMessage,
}) => { }) => {
const token = useSelector(selectToken); const token = useSelector(selectToken);
const completedRef = useRef(false); const completedRef = useRef(false);
@@ -36,12 +37,8 @@ const ConnectorAuth: React.FC<ConnectorAuthProps> = ({
const handleAuthMessage = (event: MessageEvent) => { const handleAuthMessage = (event: MessageEvent) => {
const successGeneric = event.data?.type === 'connector_auth_success'; const successGeneric = event.data?.type === 'connector_auth_success';
const successProvider = const successProvider = event.data?.type === `${provider}_auth_success`;
event.data?.type === `${provider}_auth_success` || const errorProvider = event.data?.type === `${provider}_auth_error`;
event.data?.type === 'google_drive_auth_success';
const errorProvider =
event.data?.type === `${provider}_auth_error` ||
event.data?.type === 'google_drive_auth_error';
if (successGeneric || successProvider) { if (successGeneric || successProvider) {
completedRef.current = true; completedRef.current = true;
@@ -109,22 +106,60 @@ const ConnectorAuth: React.FC<ConnectorAuthProps> = ({
} }
}; };
const buttonLabel = label || `Connect ${providerLabel(provider)}`;
return ( return (
<button <>
onClick={handleAuth} {errorMessage && (
className="flex w-full items-center justify-center gap-2 rounded-lg bg-blue-500 px-4 py-3 text-white transition-colors hover:bg-blue-600" <div className="mb-4 flex items-center gap-2 rounded-md border border-[#E60000] bg-[#FFEBEB] p-3">
> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg className="h-5 w-5" viewBox="0 0 24 24"> <path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-11v4h2v-4h-2zm0-6v2h2V5h-2z" fill="#E60000"/>
<path </svg>
fill="currentColor" <span style={{
d="M6.28 3l5.72 10H24l-5.72-10H6.28zm11.44 0L12 13l5.72 10H24L18.28 3h-.56zM0 13l5.72 10h5.72L5.72 13H0z" fontFamily: 'Inter',
/> fontWeight: 400,
</svg> fontSize: '15px',
{buttonLabel} lineHeight: '100%',
</button> color: '#E60000'
}}>
{errorMessage}
</span>
</div>
)}
{isConnected ? (
<div className="mb-4">
<div className="w-full flex items-center justify-between rounded-[10px] bg-[#8FDD51] px-4 py-2 text-[#212121] font-medium text-sm">
<div className="flex items-center gap-2">
<svg className="h-4 w-4" viewBox="0 0 24 24">
<path fill="currentColor" d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
</svg>
<span>Connected as {userEmail}</span>
</div>
{onDisconnect && (
<button
onClick={onDisconnect}
className="text-[#212121] hover:text-gray-700 font-medium text-xs underline"
>
Disconnect
</button>
)}
</div>
</div>
) : (
<button
onClick={handleAuth}
className="flex w-full items-center justify-center gap-2 rounded-lg bg-blue-500 px-4 py-3 text-white transition-colors hover:bg-blue-600"
>
<svg className="h-5 w-5" viewBox="0 0 24 24">
<path
fill="currentColor"
d="M6.28 3l5.72 10H24l-5.72-10H6.28zm11.44 0L12 13l5.72 10H24L18.28 3h-.56zM0 13l5.72 10h5.72L5.72 13H0z"
/>
</svg>
{label}
</button>
)}
</>
); );
}; };
export default ConnectorAuth; export default ConnectorAuth;
+93 -111
View File
@@ -119,9 +119,10 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
clientId: clientId, clientId: clientId,
developerKey: developerKey, developerKey: developerKey,
appId: appId, appId: appId,
setSelectFolderEnabled: true,
viewId: "DOCS", viewId: "DOCS",
showUploadView: false, showUploadView: false,
showUploadFolders: false, showUploadFolders: true,
supportDrives: false, supportDrives: false,
multiselect: true, multiselect: true,
token: accessToken, token: accessToken,
@@ -201,122 +202,103 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
onSelectionChange([], []); onSelectionChange([], []);
}; };
if (!isConnected) {
return (
<div>
{authError && (
<div className="text-red-500 text-sm mb-4 text-center">{authError}</div>
)}
<ConnectorAuth
provider="google_drive"
onSuccess={(data) => {
setUserEmail(data.user_email || 'Connected User');
setIsConnected(true);
setAuthError('');
if (data.session_token) {
setSessionToken('google_drive', data.session_token);
validateSession(data.session_token);
}
}}
onError={(error) => {
setAuthError(error);
setIsConnected(false);
}}
/>
</div>
);
}
return ( return (
<div> <div>
<div className="mb-4"> <ConnectorAuth
<div className="w-full flex items-center justify-between rounded-[10px] bg-[#8FDD51] px-4 py-2 text-[#212121] font-medium text-sm"> provider="google_drive"
<div className="flex items-center gap-2"> label="Connect to Google Drive"
<svg className="h-4 w-4" viewBox="0 0 24 24"> onSuccess={(data) => {
<path fill="currentColor" d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" /> setUserEmail(data.user_email || 'Connected User');
</svg> setIsConnected(true);
<span>Connected as {userEmail}</span> setAuthError('');
</div>
<button
onClick={handleDisconnect}
className="text-[#212121] hover:text-gray-700 font-medium text-xs underline"
>
Disconnect
</button>
</div>
</div>
<div className="border border-[#EEE6FF78] rounded-lg dark:border-[#6A6A6A]"> if (data.session_token) {
<div className="p-4"> setSessionToken('google_drive', data.session_token);
<div className="flex justify-between items-center mb-4"> validateSession(data.session_token);
<h3 className="text-sm font-medium">Selected Files</h3> }
<button }}
onClick={() => handleOpenPicker()} onError={(error) => {
className="bg-[#A076F6] hover:bg-[#8A5FD4] text-white text-sm py-1 px-3 rounded-md" setAuthError(error);
disabled={isLoading} setIsConnected(false);
> }}
{isLoading ? 'Loading...' : 'Select Files'} isConnected={isConnected}
</button> userEmail={userEmail}
</div> onDisconnect={handleDisconnect}
errorMessage={authError}
/>
{selectedFiles.length === 0 && selectedFolders.length === 0 ? ( {isConnected && (
<p className="text-gray-600 dark:text-gray-400 text-sm">No files or folders selected</p> <div className="border border-[#EEE6FF78] rounded-lg dark:border-[#6A6A6A]">
) : ( <div className="p-4">
<div className="max-h-60 overflow-y-auto"> <div className="flex justify-between items-center mb-4">
{selectedFolders.length > 0 && ( <h3 className="text-sm font-medium">Selected Files</h3>
<div className="mb-2"> <button
<h4 className="text-xs font-medium text-gray-500 mb-1">Folders</h4> onClick={() => handleOpenPicker()}
{selectedFolders.map((folder) => ( className="bg-[#A076F6] hover:bg-[#8A5FD4] text-white text-sm py-1 px-3 rounded-md"
<div key={folder.id} className="flex items-center p-2 border-b border-gray-200 dark:border-gray-700"> disabled={isLoading}
<img src={folder.iconUrl} alt="Folder" className="w-5 h-5 mr-2" /> >
<span className="text-sm truncate flex-1">{folder.name}</span> {isLoading ? 'Loading...' : 'Select Files'}
<button </button>
onClick={() => {
const newSelectedFolders = selectedFolders.filter(f => f.id !== folder.id);
setSelectedFolders(newSelectedFolders);
onSelectionChange(
selectedFiles.map(f => f.id),
newSelectedFolders.map(f => f.id)
);
}}
className="text-red-500 hover:text-red-700 text-sm ml-2"
>
Remove
</button>
</div>
))}
</div>
)}
{selectedFiles.length > 0 && (
<div>
<h4 className="text-xs font-medium text-gray-500 mb-1">Files</h4>
{selectedFiles.map((file) => (
<div key={file.id} className="flex items-center p-2 border-b border-gray-200 dark:border-gray-700">
<img src={file.iconUrl} alt="File" className="w-5 h-5 mr-2" />
<span className="text-sm truncate flex-1">{file.name}</span>
<button
onClick={() => {
const newSelectedFiles = selectedFiles.filter(f => f.id !== file.id);
setSelectedFiles(newSelectedFiles);
onSelectionChange(
newSelectedFiles.map(f => f.id),
selectedFolders.map(f => f.id)
);
}}
className="text-red-500 hover:text-red-700 text-sm ml-2"
>
Remove
</button>
</div>
))}
</div>
)}
</div> </div>
)}
{selectedFiles.length === 0 && selectedFolders.length === 0 ? (
<p className="text-gray-600 dark:text-gray-400 text-sm">No files or folders selected</p>
) : (
<div className="max-h-60 overflow-y-auto">
{selectedFolders.length > 0 && (
<div className="mb-2">
<h4 className="text-xs font-medium text-gray-500 mb-1">Folders</h4>
{selectedFolders.map((folder) => (
<div key={folder.id} className="flex items-center p-2 border-b border-gray-200 dark:border-gray-700">
<img src={folder.iconUrl} alt="Folder" className="w-5 h-5 mr-2" />
<span className="text-sm truncate flex-1">{folder.name}</span>
<button
onClick={() => {
const newSelectedFolders = selectedFolders.filter(f => f.id !== folder.id);
setSelectedFolders(newSelectedFolders);
onSelectionChange(
selectedFiles.map(f => f.id),
newSelectedFolders.map(f => f.id)
);
}}
className="text-red-500 hover:text-red-700 text-sm ml-2"
>
Remove
</button>
</div>
))}
</div>
)}
{selectedFiles.length > 0 && (
<div>
<h4 className="text-xs font-medium text-gray-500 mb-1">Files</h4>
{selectedFiles.map((file) => (
<div key={file.id} className="flex items-center p-2 border-b border-gray-200 dark:border-gray-700">
<img src={file.iconUrl} alt="File" className="w-5 h-5 mr-2" />
<span className="text-sm truncate flex-1">{file.name}</span>
<button
onClick={() => {
const newSelectedFiles = selectedFiles.filter(f => f.id !== file.id);
setSelectedFiles(newSelectedFiles);
onSelectionChange(
newSelectedFiles.map(f => f.id),
selectedFolders.map(f => f.id)
);
}}
className="text-red-500 hover:text-red-700 text-sm ml-2"
>
Remove
</button>
</div>
))}
</div>
)}
</div>
)}
</div>
</div> </div>
</div> )}
</div> </div>
); );
}; };