-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* GCS connector * fix token + do not use external files for GCS * clean up + increment version
- Loading branch information
Showing
8 changed files
with
199 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { | ||
ConnectorSettings, | ||
ISourceConnector, | ||
SourceConnectorDefinition, | ||
SyncItem, | ||
SearchResults, | ||
ConnectorParameters, | ||
Field, | ||
FileStatus, | ||
} from '../models'; | ||
import { Observable, of, from, switchMap, map } from 'rxjs'; | ||
import { GoogleBaseImpl } from './google.base'; | ||
|
||
const BUCKET_KEY = 'GCS_BUCKET'; | ||
|
||
const MAX_PAGE_SIZE = 1000; | ||
|
||
export const GCSConnector: SourceConnectorDefinition = { | ||
id: 'gcs', | ||
title: 'Google Cloud', | ||
logo: 'assets/logos/gcs.svg', | ||
description: 'File storage service developed by Google', | ||
factory: (data?: ConnectorSettings) => of(new GCSImpl(data)), | ||
}; | ||
|
||
class GCSImpl extends GoogleBaseImpl implements ISourceConnector { | ||
override DISCOVERY_DOCS = ['https://www.googleapis.com/discovery/v1/apis/storage/v1/rest']; | ||
isExternal = false; | ||
resumable = false; | ||
|
||
constructor(data?: ConnectorSettings) { | ||
super(data); | ||
} | ||
|
||
getParameters(): Observable<Field[]> { | ||
return of([ | ||
{ | ||
id: 'bucket', | ||
label: 'Bucket', | ||
type: 'text', | ||
required: true, | ||
}, | ||
]); | ||
} | ||
|
||
handleParameters(params: ConnectorParameters) { | ||
localStorage.setItem(BUCKET_KEY, params.bucket); | ||
} | ||
|
||
getFiles(query?: string, pageSize?: number): Observable<SearchResults> { | ||
if (query) { | ||
// GCS API doesn't have any command to filter by keywords. | ||
// As a workaround we retrieve all the objects and do the filtering ourselves. | ||
pageSize = MAX_PAGE_SIZE; | ||
} | ||
return this._getFiles(query, pageSize); | ||
} | ||
|
||
private _getFiles(query?: string, pageSize: number = 50, nextPage?: string | number): Observable<SearchResults> { | ||
const regexp = query ? new RegExp(`(${query})`, 'i') : null; | ||
const bucket = localStorage.getItem(BUCKET_KEY); | ||
if (!bucket) { | ||
return of({ items: [] as SyncItem[] }); | ||
} else { | ||
return from( | ||
fetch( | ||
`https://storage.googleapis.com/storage/v1/b/${bucket}/o?maxResults=${pageSize}&pageToken=${nextPage || ''}`, | ||
{ | ||
headers: { Authorization: 'Bearer ' + localStorage.getItem(this.TOKEN) }, | ||
}, | ||
), | ||
).pipe( | ||
switchMap((res) => res.json()), | ||
map((res) => ({ | ||
items: (res.items as any[]).map(this.mapResult).filter((item) => !regexp || regexp.test(item.title)), | ||
nextPage: res.nextPageToken ? this._getFiles(query, pageSize, res.nextPageToken) : undefined, | ||
})), | ||
); | ||
} | ||
} | ||
|
||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
private mapResult(result: any): SyncItem { | ||
return { | ||
originalId: result.id, | ||
title: result.name, | ||
uuid: '', | ||
metadata: { | ||
mediaLink: result.mediaLink, | ||
}, | ||
status: FileStatus.PENDING, | ||
}; | ||
} | ||
|
||
download(resource: SyncItem): Observable<Blob> { | ||
return from( | ||
fetch(resource.metadata.mediaLink, { headers: { Authorization: 'Bearer ' + localStorage.getItem(this.TOKEN) } }), | ||
).pipe(switchMap((res) => res.blob())); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
/// <reference path="../../../../../../node_modules/@types/gapi/index.d.ts" /> | ||
/// <reference path="../../../../../../node_modules/@types/gapi.auth2/index.d.ts" /> | ||
/// <reference path="../../../../../../node_modules/@types/gapi.client.drive/index.d.ts" /> | ||
|
||
import { ConnectorSettings } from '../models'; | ||
import { BehaviorSubject, Observable } from 'rxjs'; | ||
import { injectScript } from '@flaps/core'; | ||
import { environment } from '../../../environments/environment'; | ||
|
||
declare var gapi: any; | ||
|
||
export class GoogleBaseImpl { | ||
TOKEN = 'GOOGLE_TOKEN'; | ||
DISCOVERY_DOCS: string[] = []; | ||
hasServerSideAuth = true; | ||
private isAuthenticated: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); | ||
API_KEY: string; | ||
|
||
constructor(data?: ConnectorSettings) { | ||
this.API_KEY = data?.API_KEY || ''; | ||
} | ||
|
||
goToOAuth(reset?: boolean) { | ||
if (reset) { | ||
localStorage.removeItem(this.TOKEN); | ||
} | ||
const token = localStorage.getItem(this.TOKEN); | ||
if (token) { | ||
injectScript('https://apis.google.com/js/api.js').subscribe(() => | ||
gapi.load('client', () => { | ||
gapi.client.init({ | ||
apiKey: this.API_KEY, | ||
discoveryDocs: this.DISCOVERY_DOCS, | ||
}); | ||
gapi.client.setToken({ access_token: token }); | ||
this.isAuthenticated.next(true); | ||
}), | ||
); | ||
} else { | ||
if ((window as any)['electron']) { | ||
(window as any)['electron'].openExternal( | ||
`${environment.connectors.google.endpoint}?redirect=nuclia-desktop://`, | ||
); | ||
} else { | ||
location.href = `${environment.connectors.google.endpoint}?redirect=http://localhost:4200`; | ||
} | ||
} | ||
} | ||
|
||
authenticate(): Observable<boolean> { | ||
if (!this.isAuthenticated.getValue()) { | ||
injectScript('https://apis.google.com/js/api.js').subscribe(() => { | ||
gapi.load('client', () => { | ||
gapi.client.init({ | ||
apiKey: this.API_KEY, | ||
discoveryDocs: this.DISCOVERY_DOCS, | ||
}); | ||
const interval = setInterval(() => { | ||
const deeplink = (window as any)['deeplink'] || location.search; | ||
if (deeplink && deeplink.includes('?')) { | ||
const params = new URLSearchParams(deeplink.split('?')[1]); | ||
const isGoogle = params.get('google'); | ||
if (isGoogle) { | ||
const token = params.get('token') || ''; | ||
localStorage.setItem(this.TOKEN, token); | ||
gapi.client.setToken({ access_token: token }); | ||
clearInterval(interval); | ||
this.isAuthenticated.next(true); | ||
} | ||
} | ||
}, 500); | ||
}); | ||
}); | ||
} | ||
return this.isAuthenticated.asObservable(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters