Skip to content

Commit e040df7

Browse files
authored
Merge branch 'google:master' into master
2 parents 1bac06c + 39471eb commit e040df7

File tree

100 files changed

+2500
-1107
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+2500
-1107
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
name: deploy-to-firebase-on-merge
15+
name: Deploy to dev
1616
on:
1717
push:
1818
branches:

docs/Gemfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,8 @@ GEM
250250
rb-fsevent (0.11.0)
251251
rb-inotify (0.10.1)
252252
ffi (~> 1.0)
253-
rexml (3.2.8)
254-
strscan (>= 3.0.9)
253+
rexml (3.3.3)
254+
strscan
255255
rouge (3.26.0)
256256
ruby2_keywords (0.0.5)
257257
rubyzip (2.3.2)

e2e-tests/.eslintrc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"rules": {
44
"node/no-unpublished-import": ["error", {
55
"allowModules": ["jasmine"]
6-
}]
6+
}],
7+
"eqeqeq": ["error", "always", {"null": "ignore"}]
78
}
89
}

firestore/firestore.rules

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,17 @@
103103
}
104104
105105
/**
106-
* Returns true iff the user with the provided email created the specified resource.
106+
* Returns true iff the current user is the owner of the specified LOI.
107107
*/
108-
function isCreator(resource) {
109-
// TODO(#1154): Make `owner` its own field and stop assuming `creator==owner`.
110-
return resource.data.created.user.email == request.auth.token.email;
108+
function isLoiOwner(loi) {
109+
return loi.data['5'] == request.auth.uid;
110+
}
111+
112+
/**
113+
* Returns true iff the current user is the owner of the specified submission.
114+
*/
115+
function isSubmissionOwner(submission) {
116+
return submission.data['5'] == request.auth.uid;
111117
}
112118
113119
// Allow users to read, create, and write their own profiles in the db.
@@ -138,30 +144,27 @@
138144
// Allow if user has has read access to the survey.
139145
allow read: if canViewSurvey(getSurvey(surveyId));
140146
// Allow if user is owner of the new LOI and can collect data.
141-
// TODO(#1154): Require owner as well.
142-
allow create: if canCollectData(getSurvey(surveyId));
147+
allow create: if isLoiOwner(request.resource) && canCollectData(getSurvey(surveyId));
143148
// Allow if user is owner of the existing LOI or can manage survey.
144-
allow write: if isCreator(resource) || canManageSurvey(getSurvey(surveyId));
149+
allow write: if isLoiOwner(resource) || canManageSurvey(getSurvey(surveyId));
145150
}
146151
147152
// Apply passlist and survey-level ACLs to submission documents.
148153
match /surveys/{surveyId}/submissions/{submissionId} {
149154
// Allow if user has has read access to the survey.
150155
allow read: if canViewSurvey(getSurvey(surveyId));
151156
// Allow if user is owner of the new submission and can collect data.
152-
allow create: if isCreator(request.resource) && canCollectData(getSurvey(surveyId));
157+
allow create: if isSubmissionOwner(request.resource) && canCollectData(getSurvey(surveyId));
153158
// Allow if user is owner of the existing submission or can manage survey.
154-
allow write: if isCreator(resource) || canManageSurvey(getSurvey(surveyId));
159+
allow write: if isSubmissionOwner(resource) || canManageSurvey(getSurvey(surveyId));
155160
}
156161
157162
// Apply passlist and survey-level ACLs to job documents.
158163
match /surveys/{surveyId}/jobs/{jobId} {
159164
// Allow if user has has read access to the survey.
160165
allow read: if canViewSurvey(getSurvey(surveyId));
161-
// Allow if user is owner of the new submission and can collect data.
162-
allow create: if canManageSurvey(getSurvey(surveyId)) || isCreator(request.resource);
163-
// Allow if user is owner of the existing submission or can manage survey.
164-
allow write: if canManageSurvey(getSurvey(surveyId)) || isCreator(resource);
166+
// Allow if user can manage survey.
167+
allow create, write: if canManageSurvey(getSurvey(surveyId));
165168
}
166169
}
167170
}

functions/.eslintrc.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,8 @@
66
"parserOptions": {
77
"sourceType": "module"
88
},
9-
"root": true
9+
"root": true,
10+
"rules": {
11+
"eqeqeq": ["error", "always", {"null": "ignore"}]
12+
}
1013
}

functions/src/common/auth.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ import {DecodedIdToken, getAuth} from 'firebase-admin/auth';
1818
import {DocumentSnapshot} from 'firebase-admin/firestore';
1919
import {https, Response} from 'firebase-functions/v1';
2020
import {EmulatorIdToken} from '../handlers';
21+
import {GroundProtos} from '@ground/proto';
22+
import {registry} from '@ground/lib';
23+
24+
import Pb = GroundProtos.ground.v1beta1;
25+
const s = registry.getFieldIds(Pb.Survey);
2126

2227
// This is the only cookie not stripped by Firebase CDN.
2328
// https://firebase.google.com/docs/hosting/manage-cache#using_cookies
@@ -81,12 +86,13 @@ function isEmulatorIdToken(user: DecodedIdToken): boolean {
8186
function getRole(
8287
user: DecodedIdToken,
8388
survey: DocumentSnapshot
84-
): string | null {
89+
): string | number | null {
8590
if (isEmulatorIdToken(user)) {
8691
return OWNER_ROLE;
8792
}
88-
const acl = survey.get('acl');
89-
return user.email ? acl?.[user.email] : null;
93+
// TODO(#1858): Remove reference to "acl" field.
94+
const acl = survey.get(s.acl) || survey.get('acl');
95+
return acl && user.email ? acl[user.email] : null;
9096
}
9197

9298
export function canExport(
@@ -101,5 +107,9 @@ export function canImport(
101107
survey: DocumentSnapshot
102108
): boolean {
103109
const role = getRole(user, survey);
104-
return role === OWNER_ROLE || role === SURVEY_ORGANIZER_ROLE;
110+
// TODO(#1858): Remove old roles.
111+
return (
112+
!!role &&
113+
[OWNER_ROLE, SURVEY_ORGANIZER_ROLE, Pb.Role.SURVEY_ORGANIZER].includes(role)
114+
);
105115
}

functions/src/common/datastore.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
import * as functions from 'firebase-functions';
1818
import {firestore} from 'firebase-admin';
1919
import {DocumentData, GeoPoint, QuerySnapshot} from 'firebase-admin/firestore';
20+
import {registry} from '@ground/lib';
21+
import {GroundProtos} from '@ground/proto';
22+
23+
import Pb = GroundProtos.ground.v1beta1;
24+
const l = registry.getFieldIds(Pb.LocationOfInterest);
25+
const sb = registry.getFieldIds(Pb.Submission);
2026

2127
/**
2228
*
@@ -46,6 +52,12 @@ export const surveys = () => 'surveys';
4652
*/
4753
export const survey = (surveyId: string) => surveys() + '/' + surveyId;
4854

55+
/**
56+
* Returns the path of job doc with the specified id.
57+
*/
58+
export const job = (surveyId: string, jobId: string) =>
59+
`${survey(surveyId)}/jobs/${jobId}`;
60+
4961
/**
5062
* Returns the path of the survey collection in the survey with the specified id.
5163
*/
@@ -116,10 +128,14 @@ export class Datastore {
116128
return this.db_.doc(survey(surveyId)).get();
117129
}
118130

131+
fetchJob(surveyId: string, jobId: string) {
132+
return this.db_.doc(job(surveyId, jobId)).get();
133+
}
134+
119135
fetchSubmissionsByJobId(surveyId: string, jobId: string) {
120136
return this.db_
121137
.collection(submissions(surveyId))
122-
.where('jobId', '==', jobId)
138+
.where(sb.jobId, '==', jobId)
123139
.get();
124140
}
125141

@@ -133,7 +149,7 @@ export class Datastore {
133149
): Promise<QuerySnapshot<DocumentData, DocumentData>> {
134150
return this.db_
135151
.collection(lois(surveyId))
136-
.where('jobId', '==', jobId)
152+
.where(l.jobId, '==', jobId)
137153
.get();
138154
}
139155

@@ -150,14 +166,14 @@ export class Datastore {
150166
loiId: string
151167
): Promise<number> {
152168
const submissionsRef = this.db_.collection(submissions(surveyId));
153-
const submissionsForLoiQuery = submissionsRef.where('loiId', '==', loiId);
169+
const submissionsForLoiQuery = submissionsRef.where(sb.loiId, '==', loiId);
154170
const snapshot = await submissionsForLoiQuery.count().get();
155171
return snapshot.data().count;
156172
}
157173

158174
async updateSubmissionCount(surveyId: string, loiId: string, count: number) {
159175
const loiRef = this.db_.doc(loi(surveyId, loiId));
160-
await loiRef.update({submissionCount: count});
176+
await loiRef.update({[l.submissionCount]: count});
161177
}
162178

163179
async updateLoiProperties(

0 commit comments

Comments
 (0)