-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfirestore.rules
More file actions
130 lines (109 loc) · 4.87 KB
/
firestore.rules
File metadata and controls
130 lines (109 loc) · 4.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Helper function to get user's housing company ID
function getUserHousingCompanyId() {
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.housingCompanyId;
}
// Helper function to get user's role
function getUserRole() {
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role;
}
// Helper function to check if user is authenticated
function isAuthenticated() {
return request.auth != null;
}
// Helper function to check if user is admin
function isAdmin() {
return isAuthenticated() && getUserRole() == 'admin';
}
// Helper function to check if user is admin or maintenance
function isAdminOrMaintenance() {
return isAuthenticated() && (getUserRole() == 'admin' || getUserRole() == 'maintenance');
}
// ========== FAULT REPORTS ==========
match /faultReports/{reportId} {
// Read: authenticated users can read reports from their housing company
allow read: if isAuthenticated()
&& resource.data.housingCompanyId == getUserHousingCompanyId();
// Create: authenticated users can create reports
// - Must set their own uid as createdBy
// - Must use their housing company ID
// - Status must be 'open'
allow create: if isAuthenticated()
&& request.resource.data.createdBy == request.auth.uid
&& request.resource.data.housingCompanyId == getUserHousingCompanyId()
&& request.resource.data.status == 'open'
&& request.resource.data.keys().hasAll(['buildingId', 'title', 'description', 'status', 'createdBy', 'housingCompanyId', 'createdAt', 'updatedAt']);
// Update: users can update their own report details only
// Allow ONLY description, imageUrls, allowMasterKeyAccess, hasPets, updatedAt when status is created/open
// Block status/comment updates from client
allow update: if isAuthenticated()
&& resource.data.createdBy == request.auth.uid
&& request.resource.data.housingCompanyId == resource.data.housingCompanyId
&& (resource.data.status == 'created' || resource.data.status == 'open')
&& request.resource.data.status == resource.data.status
&& request.resource.data.diff(resource.data).affectedKeys().hasOnly([
'description',
'imageUrls',
'allowMasterKeyAccess',
'hasPets',
'updatedAt'
])
&& !request.resource.data.diff(resource.data).affectedKeys().hasAny([
'status',
'updatedBy',
'resolvedAt',
'comment',
'createdBy',
'housingCompanyId'
]);
// Delete: disabled for residents
allow delete: if false;
}
// ========== HOUSING COMPANIES ==========
match /housingCompanies/{companyId} {
// Read: admins can read companies they created
// Users can read their own housing company
allow read: if isAuthenticated() && (
(isAdmin() && resource.data.createdByAdminId == request.auth.uid) ||
resource.id == getUserHousingCompanyId()
);
// Create: ONLY through Cloud Functions (admin only)
allow create: if false;
// Update: ONLY through Cloud Functions (admin only, for invite codes)
allow update: if false;
// Delete: ONLY through Cloud Functions (admin only)
allow delete: if false;
}
// ========== ANNOUNCEMENTS ==========
match /announcements/{announcementId} {
// Read: authenticated users can read announcements from their housing company
allow read: if isAuthenticated()
&& resource.data.housingCompanyId == getUserHousingCompanyId();
// Create & Update & Delete: ONLY through Cloud Functions
allow create, update, delete: if false;
}
// ========== USER PROFILES ==========
match /users/{userId} {
// Read: users can read their own profile OR profiles from same housing company
allow read: if isAuthenticated() && (
request.auth.uid == userId ||
resource.data.housingCompanyId == getUserHousingCompanyId()
);
// Create: ONLY through Cloud Functions (during signup)
allow create: if false;
// Update: users can update their own profile (limited fields)
// Cannot change role, housingCompanyId, or createdAt
allow update: if isAuthenticated()
&& request.auth.uid == userId
&& (!request.resource.data.diff(resource.data).affectedKeys().hasAny(['role', 'housingCompanyId', 'createdAt', 'email']));
// Delete: ONLY through Cloud Functions (admin)
allow delete: if false;
}
// Deny all other collections by default
match /{document=**} {
allow read, write: if false;
}
}
}