Skip to content
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

[Import GeoJSON] Write imported LOIs using new schema #1821

Merged
merged 144 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
144 commits
Select commit Hold shift + click to select a range
2696322
Refactor scripts, include npm install
gino-m Jan 16, 2024
5feb0aa
Merge branch 'master' of https://github.com/google/ground-platform in…
gino-m Jan 16, 2024
392747f
Add missing dir to clean command
gino-m Jun 4, 2024
70f8643
Fix build issue
gino-m Jun 4, 2024
a6114c2
Fix generated dist target
gino-m Jun 4, 2024
4fcca2c
Refactor prebuild step
gino-m Jun 4, 2024
f74c263
Reorder scripts
gino-m Jun 4, 2024
eb6dbb9
Merge branch 'master' into gino-m/1758/add-lib-to-functions
gino-m Jun 4, 2024
5f58542
Add properties field to LOI proto
gino-m Jun 4, 2024
5478ec2
Update import function
gino-m Jun 4, 2024
5dde538
Configure buf for formatting and lint
gino-m Jun 4, 2024
4902f7e
Format in-place
gino-m Jun 4, 2024
7692a03
Auto-format
gino-m Jun 4, 2024
99956ca
Run linter in CI
gino-m Jun 4, 2024
8d7293f
Fix typo
gino-m Jun 4, 2024
e88ec47
Add valid package names
gino-m Jun 4, 2024
f9082c4
Fix lint errors
gino-m Jun 4, 2024
0931178
Install deps first
gino-m Jun 4, 2024
4bd2981
Fix relative proto imports
gino-m Jun 4, 2024
d9c165f
Fix tests
gino-m Jun 4, 2024
575ae05
Fix namespacing
gino-m Jun 4, 2024
ec04eb6
Add TODO
gino-m Jun 4, 2024
fdf0dde
Merge branch 'master' into gino-m/1758/refactor-pbts-codegen
gino-m Jun 4, 2024
d026b36
Merge branch 'master' of https://github.com/google/ground-platform in…
gino-m Jun 5, 2024
6fc82f5
Configure custom spec reporter
gino-m Jun 5, 2024
0b5bcc8
Fix proto namespace resolution
gino-m Jun 5, 2024
9408359
Add CR
gino-m Jun 5, 2024
a525ba3
Remove debug //
gino-m Jun 5, 2024
cd69a9d
Revert and update package lock
gino-m Jun 5, 2024
c9e8115
Add CR
gino-m Jun 5, 2024
0c77a56
Fix "dev null" on npm i
gino-m Jun 5, 2024
b74566a
Remove TODO comment
gino-m Jun 5, 2024
2921644
Add CR
gino-m Jun 5, 2024
45ed01f
Merge branch 'gino-m/1758/refactor-pbts-codegen' into gino-m/1758/upd…
gino-m Jun 5, 2024
dcdb041
Add back changes lost in merge
gino-m Jun 5, 2024
049cca6
Merge branch 'master' of https://github.com/google/ground-platform in…
gino-m Jun 6, 2024
8599f5d
Fix build
gino-m Jun 6, 2024
0ae6000
Refactor deepMerge function
gino-m Jun 6, 2024
7b03fe6
Refactor geometry conversion
gino-m Jun 6, 2024
32b4144
[WIP] Implement GeoJSON -> Pb -> Firestore
gino-m Jun 6, 2024
4fb164a
Fix compile error
gino-m Jun 6, 2024
3ccb546
Convert multipolygons
gino-m Jun 6, 2024
78d84e0
Working import LOIs prototype
gino-m Jun 7, 2024
95c78c0
Fix conversion of GeoPoints
gino-m Jun 7, 2024
ffc6057
Fix typo
gino-m Jun 7, 2024
695f3e0
Add CR
gino-m Jun 7, 2024
32ce8d6
bool -> enum
gino-m Jun 7, 2024
fa2a7f5
Add support for 'double' and 'repeated'
gino-m Jun 7, 2024
0990b8b
Simplify number conversion
gino-m Jun 7, 2024
b6e5e5b
Fix proto lint error
gino-m Jun 7, 2024
e37eb54
Rename enum values
gino-m Jun 7, 2024
e2f823d
Delete spec template
gino-m Jun 7, 2024
53bf1c7
Remove redundant fn
gino-m Jun 10, 2024
cad56b6
Remove redundant checks
gino-m Jun 10, 2024
164398a
Merge branch 'master' of https://github.com/google/ground-platform in…
gino-m Jun 10, 2024
86c1f6c
Update enum values
gino-m Jun 10, 2024
2e7a69a
Remove deleted export
gino-m Jun 10, 2024
01d4939
Scaffold test
gino-m Jun 10, 2024
11e6667
Merge branch 'master' of https://github.com/google/ground-platform in…
gino-m Jun 12, 2024
a35c301
Scaffold import GeoJSON tests
gino-m Jun 13, 2024
208f411
Restore order for diff
gino-m Jun 13, 2024
ea16564
Move exception handling into handler
gino-m Jun 13, 2024
5e0f8b0
Remove duplicate survey request
gino-m Jun 13, 2024
63d85c0
Lazy init datastore to allow mocking
gino-m Jun 13, 2024
5b04522
Cleanup error handling
gino-m Jun 13, 2024
753abff
Working tests!
gino-m Jun 14, 2024
a795bad
Refactor error handling
gino-m Jun 14, 2024
0d85569
Merge branch 'master' of https://github.com/google/ground-platform in…
gino-m Jun 14, 2024
946d5ee
Delete import CSV code
gino-m Jun 14, 2024
9f8f905
Merge branch 'master' of https://github.com/google/ground-platform in…
gino-m Jun 14, 2024
3980888
Merge branch 'gino-m/1177/rm-import-csv' into gino-m/1758/update-impo…
gino-m Jun 14, 2024
805bf07
Merge branch 'master' of https://github.com/google/ground-platform in…
gino-m Jun 14, 2024
21f25a9
Fix lint errors
gino-m Jun 14, 2024
4684397
Stop deleting node_modules on clean
gino-m Jun 18, 2024
1f919b2
Remove auto npm install
gino-m Jun 18, 2024
a7aed69
Use workspace syntax instead of prefix
gino-m Jun 18, 2024
5d5ae73
Stop building before deploy
gino-m Jun 18, 2024
e9b4629
Decouple scripts
gino-m Jun 19, 2024
f600bfb
Refactor scripts
gino-m Jun 20, 2024
084fe8d
Remove unused dep
gino-m Jun 20, 2024
c0b2562
Update CI config
gino-m Jun 20, 2024
d843f67
Merge branch 'master' of https://github.com/google/ground-platform in…
gino-m Jun 20, 2024
8800617
Install dep deps
gino-m Jun 20, 2024
8e4fed5
Refactor ci and build
gino-m Jun 20, 2024
7d74e76
Fix typo
gino-m Jun 20, 2024
469be18
Add CR
gino-m Jun 20, 2024
3030339
Add more notes
gino-m Jun 20, 2024
a615261
Add script
gino-m Jun 20, 2024
7cf40da
Add docs for build-and-deply
gino-m Jun 20, 2024
2405481
Tweak README
gino-m Jun 20, 2024
190db61
Remove login scripts
gino-m Jun 20, 2024
e8b55ee
Fix firestore config docs
gino-m Jun 20, 2024
216731a
Merge branch 'master' into gino-m/patch/decouple-scripts
gino-m Jun 20, 2024
9405f32
Rename "ci" script to avoid ambiguity
gino-m Jun 20, 2024
fa1874b
updated package-lock
rfontanarosa Jun 20, 2024
f7e0311
Rename "ci" script to avoid ambiguity
gino-m Jun 20, 2024
31a8137
Merge branch 'gino-m/patch/decouple-scripts' of https://github.com/go…
gino-m Jun 20, 2024
70f0948
Add ci-all to proto
gino-m Jun 20, 2024
5d7a286
Don't build on ci-all on root
gino-m Jun 20, 2024
d48f6ad
Manually fix package lock
gino-m Jun 20, 2024
2a43a3d
Remove extra whitespace
gino-m Jun 20, 2024
8bba47b
Remove unused
gino-m Jun 20, 2024
567a5f6
Missing CR
gino-m Jun 20, 2024
3f04275
clean++
gino-m Jun 20, 2024
c5736e5
Fix typio
gino-m Jun 24, 2024
88a3c43
Reformat
gino-m Jun 24, 2024
d9e5eb9
Merge branch 'gino-m/1443/npm-script-fixes' into gino-m/1758/update-i…
gino-m Jun 24, 2024
bc6b5e6
Merge branch 'gino-m/patch/decouple-scripts' into gino-m/1758/update-…
gino-m Jun 24, 2024
86ef1d6
Fix build error
gino-m Jun 24, 2024
b6d0b93
Merge branch 'gino-m/1758/update-import-geojson' of https://github.co…
gino-m Jun 24, 2024
6bafff4
Add build-all scripts
gino-m Jun 24, 2024
c743f47
Fix build
gino-m Jun 24, 2024
f5d2d9e
Merge branch 'master' of https://github.com/google/ground-platform in…
gino-m Jun 24, 2024
9eacdb2
Move deps to dev
gino-m Jun 24, 2024
4435801
Restore mis-merged code
gino-m Jun 24, 2024
2f614df
Add convenience scripts
gino-m Jun 24, 2024
778949a
Refactor and fix import GeoJSON test
gino-m Jun 24, 2024
742d902
Tests WIP
gino-m Jun 24, 2024
8f63ac2
Run build-and-test in debugger
gino-m Jun 25, 2024
7342999
Fix unit tests
gino-m Jun 25, 2024
3a24adb
Add comments
gino-m Jun 25, 2024
b9a637e
Format
gino-m Jun 25, 2024
f98e844
Add tsdoc
gino-m Jun 25, 2024
3ccea9f
Merge branch 'gino-m/1758/update-import-geojson' of https://github.co…
gino-m Jun 25, 2024
108f6c2
Move relevant deps to dev
gino-m Jun 25, 2024
329b28b
Tweak functions deploy script
gino-m Jun 25, 2024
e86fd07
Regenerate package-locks
rfontanarosa Jun 25, 2024
ed5b21b
Merge branch 'rfontanarosa/fix-package-dependencies2' of https://gith…
gino-m Jun 25, 2024
6593acc
Add missing dep
gino-m Jun 25, 2024
a0a88ca
Add convenience npm script to build and deploy
gino-m Jun 26, 2024
850852d
Merge branch 'master' of https://github.com/google/ground-platform in…
gino-m Jun 26, 2024
3ccc107
Merge branch 'master' of https://github.com/google/ground-platform in…
gino-m Jun 26, 2024
736bf48
Fix emu script
gino-m Jun 26, 2024
f9c3b31
Ensure Firebaser is initialized
gino-m Jun 26, 2024
4d33610
Test numbers
gino-m Jun 26, 2024
1f83ef9
Fix multipolygons, tests WIP
gino-m Jun 26, 2024
1fb86ca
Add color diff to jasmine test matchers
gino-m Jun 27, 2024
7a3cfaa
Merge branch 'gino-m/patch/color-diff' into gino-m/1758/update-import…
gino-m Jun 27, 2024
cf0696d
Fix tests
gino-m Jun 27, 2024
4db1832
Clean up tests
gino-m Jun 27, 2024
9e7e186
Fix lint errors
gino-m Jun 27, 2024
a7c4193
More test cleanup
gino-m Jun 27, 2024
d86197f
Fix broken tests
gino-m Jun 27, 2024
c422ae0
Merge branch 'master' into gino-m/1758/update-import-geojson
gino-m Jun 27, 2024
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
7 changes: 6 additions & 1 deletion functions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"lint": "eslint --ext .js,.ts src/",
"lint:fix": "npm run lint -- --fix",
"shell": "firebase functions:shell",
"emulators": "firebase emulators:start --only functions,firestore --project $npm_config_project",
"emulators": "firebase emulators:start --only functions,firestore --project local",
"deploy": "firebase login && firebase deploy --project $npm_config_project --only functions",
"logs": "firebase functions:log",
"test": "jasmine --config=jasmine.json",
Expand All @@ -25,6 +25,7 @@
"dependencies": {
"@fast-csv/format": "4.3.5",
"@ground/lib": "file:../lib",
"@ground/proto": "file:../proto",
"@terraformer/wkt": "2.1.2",
"busboy": "1.5.0",
"cookie-parser": "^1.4.6",
Expand All @@ -49,14 +50,18 @@
"@types/busboy": "^1.5.0",
"@types/cookie-parser": "^1.4.4",
"@types/cors": "2.8.12",
"@types/geojson": "^7946.0.14",
"@types/jasmine": "^4.3.5",
"@types/jsonstream": "0.8.30",
"@types/terraformer__wkt": "2.0.0",
"firebase-functions-test": "^3.3.0",
"firebase-tools": "13.6.0",
"form-data-encoder": "^4.0.2",
"formdata-node": "^6.0.3",
"gts": "^5.3.1",
"jasmine": "^5.1.0",
"prettier": "^2.8.1",
"source-map-support": "^0.5.21",
"ts-mocha": "^10.0.0",
"typescript": "4.8.4",
"wkt": "0.1.1"
Expand Down
2 changes: 1 addition & 1 deletion functions/src/common/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {EmulatorIdToken} from '../handlers';
// This is the only cookie not stripped by Firebase CDN.
// https://firebase.google.com/docs/hosting/manage-cache#using_cookies
export const SESSION_COOKIE_NAME = '__session';
const OWNER_ROLE = 'OWNER';
export const OWNER_ROLE = 'OWNER';
const DATA_COLLECTOR_ROLE = 'DATA_COLLECTOR';

/**
Expand Down
6 changes: 5 additions & 1 deletion functions/src/common/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {Datastore} from './datastore';
import {initializeApp, getApp} from 'firebase-admin/app';
import {getFirestore} from 'firebase-admin/firestore';

let datastore: Datastore;
let datastore: Datastore | undefined;

export function initializeFirebaseApp() {
try {
Expand All @@ -35,3 +35,7 @@ export function getDatastore(): Datastore {
}
return datastore;
}

export function resetDatastore() {
datastore = undefined;
}
15 changes: 3 additions & 12 deletions functions/src/common/datastore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@

import * as functions from 'firebase-functions';
import {firestore} from 'firebase-admin';
import {GeoPoint} from 'firebase-admin/firestore';
import {DocumentData, GeoPoint} from 'firebase-admin/firestore';

/**
*
*/
type pseudoGeoJsonGeometry = {
type: string;
coordinates: any;

Check warning on line 26 in functions/src/common/datastore.ts

View workflow job for this annotation

GitHub Actions / Check

Unexpected any. Specify a different type
};

/**
Expand Down Expand Up @@ -138,17 +138,8 @@
return this.fetchDoc_(`${survey(surveyId)}/sheets/config`);
}

async insertLocationOfInterest(surveyId: string, loi: any) {
const loiDoc = {
...loi,
geometry: Datastore.toFirestoreMap(loi.geometry),
};
const docRef = this.db_.doc(survey(surveyId));
const doc = await docRef.get();
if (!doc.exists) {
throw new Error(`${survey(surveyId)} not found`);
}
await docRef.collection('lois').add(loiDoc);
async insertLocationOfInterest(surveyId: string, loiDoc: DocumentData) {
await this.db_.doc(survey(surveyId)).collection('lois').add(loiDoc);
}

async countSubmissionsForLoi(
Expand All @@ -175,7 +166,7 @@
await loiRef.update({properties});
}

static toFirestoreMap(geometry: any) {

Check warning on line 169 in functions/src/common/datastore.ts

View workflow job for this annotation

GitHub Actions / Check

Unexpected any. Specify a different type
return Object.fromEntries(
Object.entries(geometry).map(([key, value]) => [
key,
Expand All @@ -184,7 +175,7 @@
);
}

static toFirestoreValue(value: any): any {

Check warning on line 178 in functions/src/common/datastore.ts

View workflow job for this annotation

GitHub Actions / Check

Unexpected any. Specify a different type

Check warning on line 178 in functions/src/common/datastore.ts

View workflow job for this annotation

GitHub Actions / Check

Unexpected any. Specify a different type
if (value === null) {
return null;
}
Expand Down Expand Up @@ -212,7 +203,7 @@
*
* @returns GeoJSON geometry object (with geometry as list of lists)
*/
static fromFirestoreMap(geoJsonGeometry: any): any {

Check warning on line 206 in functions/src/common/datastore.ts

View workflow job for this annotation

GitHub Actions / Check

Unexpected any. Specify a different type

Check warning on line 206 in functions/src/common/datastore.ts

View workflow job for this annotation

GitHub Actions / Check

Unexpected any. Specify a different type
const geometryObject = geoJsonGeometry as pseudoGeoJsonGeometry;
if (!geometryObject) {
throw new Error(
Expand All @@ -227,7 +218,7 @@
return geometryObject;
}

static fromFirestoreValue(coordinates: any) {

Check warning on line 221 in functions/src/common/datastore.ts

View workflow job for this annotation

GitHub Actions / Check

Unexpected any. Specify a different type
if (coordinates instanceof GeoPoint) {
// Note: GeoJSON coordinates are in lng-lat order.
return [coordinates.longitude, coordinates.latitude];
Expand All @@ -236,7 +227,7 @@
if (typeof coordinates !== 'object') {
return coordinates;
}
const result = new Array<any>(coordinates.length);

Check warning on line 230 in functions/src/common/datastore.ts

View workflow job for this annotation

GitHub Actions / Check

Unexpected any. Specify a different type

Object.entries(coordinates).map(([i, nestedValue]) => {
const index = Number.parseInt(i);
Expand Down
103 changes: 96 additions & 7 deletions functions/src/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@
* limitations under the License.
*/

import * as cors from 'cors';
import cors from 'cors';
import {DecodedIdToken} from 'firebase-admin/auth';
import {https, Response} from 'firebase-functions';
import {getDecodedIdToken} from './common/auth';
import {INTERNAL_SERVER_ERROR, UNAUTHORIZED} from 'http-status-codes';
import * as cookieParser from 'cookie-parser';
import cookieParser from 'cookie-parser';
import HttpStatus from 'http-status-codes';

const corsOptions = {origin: true};
const corsMiddleware = cors(corsOptions);
Expand Down Expand Up @@ -59,7 +60,7 @@ async function requireIdToken(

function onError(res: any, err: any) {
console.error(err);
res.status(INTERNAL_SERVER_ERROR).send('Internal error');
res.status(INTERNAL_SERVER_ERROR).end(`Internal error: ${err.message}`);
}

export type HttpsRequestHandler = (
Expand All @@ -68,13 +69,101 @@ export type HttpsRequestHandler = (
idToken: DecodedIdToken
) => Promise<any>;

/**
* A synchronous HTTPS request handler. The HTTPS request is closed as soon as the handler resolves.
*/
export function onHttpsRequest(handler: HttpsRequestHandler) {
return https.onRequest((req: https.Request, res: Response) =>
corsMiddleware(req, res, () =>
cookieParser()(req, res, () =>
requireIdToken(req, res, (idToken: DecodedIdToken) =>
handler(req, res, idToken).catch((error: any) => onError(res, error))
)
cookieParser()(
req,
res,
async () =>
await requireIdToken(req, res, async (idToken: DecodedIdToken) => {
try {
await handler(req, res, idToken);
} catch (error) {
onError(res, error);
}
})
)
)
);
}

/** A function which is to be called by HTTPS callbacks on failure. */
export type ErrorHandler = (httpStatusCode: number, message: string) => void;

/**
* A callback-based HTTPS request handler. Functions of this type are expected to call
* `done()` on completion or `error()` on failure. The function itself may return before
* work is completed, but the HTTPS request will not complete until one of those two
* callbacks are invoked.
*/
export type HttpsRequestCallback = (
req: https.Request,
res: Response<any>,
user: DecodedIdToken,
done: () => void,
error: ErrorHandler
) => void;

export async function invokeCallbackAsync(
callback: HttpsRequestCallback,
req: https.Request,
res: Response<any>,
user: DecodedIdToken
) {
await new Promise((resolve, reject) =>
invokeCallback(
callback,
req,
res,
user,
() => {
res.status(HttpStatus.OK).end();
resolve(undefined);
},
(errorCode: number, message: string) => {
res.status(errorCode).end(message);
reject(`${message} (HTTP status ${errorCode})`);
}
)
);
}

function invokeCallback(
callback: HttpsRequestCallback,
req: https.Request,
res: Response<any>,
user: DecodedIdToken,
done: () => void,
error: ErrorHandler
) {
try {
callback(req, res, user, done, error);
} catch (e: any) {
console.error('Unhandled exception', e);
error(HttpStatus.INTERNAL_SERVER_ERROR, e.toString());
}
}

/**
* Call an asynchronous HTTPS request handler. Handlers of this type are expected to call
* `done()` on completion or `error()` on failure. The handler itself may return before
* work is completed, but the HTTPS request will not complete until one of those two
* callbacks are invoked.
*/
export function onHttpsRequestAsync(callback: HttpsRequestCallback) {
return https.onRequest((req: https.Request, res: Response) =>
corsMiddleware(req, res, () =>
cookieParser()(
req,
res,
async () =>
await requireIdToken(req, res, async (idToken: DecodedIdToken) => {
await invokeCallbackAsync(callback, req, res, idToken);
})
)
)
);
Expand Down
Loading
Loading