diff --git a/firebase/tests/firestore-mock-data.js b/firebase/tests/firestore-mock-data.js index 322d63eee..2fca18424 100644 --- a/firebase/tests/firestore-mock-data.js +++ b/firebase/tests/firestore-mock-data.js @@ -23,8 +23,10 @@ export const aliceAssociation = { description: "Description", followersCount: 0, members: ["alice"], + roles: [], image: "", events: [], + principalEmailAddress: "alice@gmail.com" }; export const aliceEvent = { @@ -36,7 +38,8 @@ export const aliceEvent = { description: "Description", catchyDescription: "Catchy description", price: 0.0, - date: new Date(), + startDate: new Date(), + endDate: new Date(), location: { name: "Location", address: "Address", @@ -44,6 +47,9 @@ export const aliceEvent = { longitude: 0.0, }, types: ["OTHER"], + maxNumberOfPlaces: -1, + numberOfSaved: 0, + eventPictures: [] }; export const otherUser = { @@ -69,7 +75,8 @@ export const otherEvent = { description: "Description", catchyDescription: "Catchy description", price: 0.0, - date: new Date(), + startDate: new Date(), + endDate: new Date(), location: { name: "Location", address: "Address", @@ -77,6 +84,9 @@ export const otherEvent = { longitude: 0.0, }, types: ["OTHER"], + maxNumberOfPlaces: -1, + numberOfSaved: 0, + eventPictures: [] }; export const otherAssociation = { @@ -88,8 +98,10 @@ export const otherAssociation = { description: "Description", followersCount: 0, members: ["other"], + roles: [], image: "", events: [], + principalEmailAddress: "otherassociation@gmail.com" }; export async function setupFirestore(testEnv) { diff --git a/firestore.rules b/firestore.rules index 6949f7c97..38ce6afb8 100644 --- a/firestore.rules +++ b/firestore.rules @@ -73,7 +73,7 @@ service cloud.firestore { } function validate() { // Check that the association document has the correct fields - let fields = ['uid', 'url', 'name', 'fullName', 'category', 'description', 'followersCount', 'members', 'image', 'events']; + let fields = ['uid', 'url', 'name', 'fullName', 'category', 'description', 'followersCount', 'members', 'roles', 'image', 'events', 'principalEmailAddress']; let hasCorrectNumberOfFields = request.resource.data.size() == fields.size(); let hasCorrectFields = request.resource.data.keys().hasAll(fields); @@ -86,9 +86,11 @@ service cloud.firestore { request.resource.data.description is string && request.resource.data.followersCount is int && request.resource.data.followersCount >= 0 && - request.resource.data.members is list && + request.resource.data.members is map && + request.resource.data.roles is map && request.resource.data.image is string && - request.resource.data.events is list; + request.resource.data.events is list && + request.resource.data.principalEmailAddress is string; } allow read: if isVerified(); @@ -104,9 +106,21 @@ service cloud.firestore { get(/databases/$(database)/documents/users/$(request.auth.uid)).data.joinedAssociations ); } + function onlyUpdateSaved() { + // Check that the only updated field is the numberOfSaved field + // and that it was only incremented or decremented by 1 + let newCount = request.resource.data.numberOfSaved; + let oldCount = resource.data.numberOfSaved; + + let affectedKeys = request.resource.data.diff(resource.data).affectedKeys(); + let onlySavedChanged = affectedKeys.hasOnly(['numberOfSaved']); + + return onlySavedChanged && (newCount == oldCount || newCount == oldCount + 1 || newCount == oldCount - 1); + } + function validate() { // Check that the event document has the correct fields - let fields = ['uid', 'title', 'organisers', 'taggedAssociations', 'image', 'description', 'catchyDescription', 'price', 'date', 'location', 'types']; + let fields = ['uid', 'title', 'organisers', 'taggedAssociations', 'image', 'description', 'catchyDescription', 'price', 'startDate', 'endDate', 'location', 'types', 'maxNumberOfPlaces', 'numberOfSaved', 'eventPictures']; let hasCorrectNumberOfFields = request.resource.data.size() == fields.size(); let hasCorrectFields = request.resource.data.keys().hasAll(fields); @@ -123,12 +137,18 @@ service cloud.firestore { request.resource.data.catchyDescription.size() <= 100 && request.resource.data.price is number && request.resource.data.price >= 0 && - request.resource.data.date is timestamp && + request.resource.data.startDate is timestamp && + request.resource.data.endDate is timestamp && request.resource.data.location is map && request.resource.data.location.latitude is number && request.resource.data.location.longitude is number && request.resource.data.location.name is string && - request.resource.data.types is list; + request.resource.data.types is list && + request.resource.data.maxNumberOfPlaces is int && + request.resource.data.maxNumberOfPlaces >= -1 && + request.resource.data.numberOfSaved is int && + request.resource.data.numberOfSaved >= 0 && + request.resource.data.eventPictures is list; } allow read: if isVerified(); @@ -139,8 +159,31 @@ service cloud.firestore { // To update or delete an event, the user must be an // organiser in the existing event document - allow update: if isEventOrganiser(resource.data.organisers) && validate(); + allow update: if (isEventOrganiser(resource.data.organisers) || onlyUpdateSaved()) && validate(); allow delete: if isEventOrganiser(resource.data.organisers); } + + match /eventUserPicture/{uid} { + function isAuthor() { + return isVerified() && request.auth.uid == uid; + } + + function validate() { + // Check that the eventUserPicture document has the correct fields + let fields = ['uid', 'image', 'author', 'likes']; + let hasCorrectNumberOfFields = request.resource.data.size() == fields.size(); + let hasCorrectFields = request.resource.data.keys().hasAll(fields); + + return hasCorrectNumberOfFields && hasCorrectFields && + request.resource.data.uid == uid && + request.resource.data.image is string && + request.resource.data.author is string && + request.resource.data.likes is list; + } + allow read: if isVerified(); + allow create: if isVerified() && validate(); + allow update: if isAuthor() && validate(); + allow delete: if isAuthor(); + } } } \ No newline at end of file