-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdatabase.rules.json
436 lines (436 loc) · 22.9 KB
/
database.rules.json
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
{
"rules": {
".read": false,
".write": false,
"members": {
".read": "auth.token.email.endsWith('@link.cuhk.edu.hk') && root.child('executives').child(auth.token.email.replace('@link.cuhk.edu.hk', '')).exists()",
".write": "auth.token.email.endsWith('@link.cuhk.edu.hk') && root.child('executives').child(auth.token.email.replace('@link.cuhk.edu.hk', '')).exists()",
".indexOn": "memberStatus/since",
"$sid": {
".read": "auth.token.email.endsWith('@link.cuhk.edu.hk') && auth.token.email.replace('@link.cuhk.edu.hk', '') === $sid",
".write": "auth.token.email.endsWith('@link.cuhk.edu.hk') && auth.token.email.replace('@link.cuhk.edu.hk', '') === $sid && (!data.child('memberStatus').child('since').exists() || data.child('memberStatus').child('until').val() < now)",
".validate": "newData.child('updatedAt').val() !== data.child('updatedAt').val() && newData.hasChildren(['sid', 'name', 'studentStatus', 'createdAt', 'updatedAt']) && (newData.hasChildren(['memberStatus']) || !data.hasChildren(['memberStatus']))",
"sid": {
".validate": "newData.isString() && newData.val().matches(/^\\d*$/) && newData.val().length < 16 && newData.val() === $sid"
},
"name": {
".validate": "newData.hasChildren(['eng'])",
"chi": {
".validate": "!newData.exists() || (newData.isString() && newData.val().length < 64)"
},
"eng": {
".validate": "newData.isString() && newData.val().length < 128"
},
"$other": {
".validate": false
}
},
"gender": {
".validate": "!newData.exists() || (newData.isString() && newData.val().matches(/^((fe)?male|other)$/))"
},
"dob": {
".validate": "!newData.exists() || newData.isString() && newData.val().matches(/^\\d{4}-\\d{2}-\\d{2}$/)"
},
"email": {
".validate": "!newData.exists() || (newData.isString() && newData.val().matches(/^.+@.+$/) && newData.val().length < 324)"
},
"phone": {
".validate": "!newData.exists() || (newData.isString() && newData.val().matches(/^\\+?\\d+(-\\d+)*$/) && newData.val().length < 64)"
},
"studentStatus": {
".validate": "newData.hasChildren(['college', 'major', 'entryDate', 'gradDate'])",
"college": {
".validate": "newData.isString() && newData.val().matches(/^(CC|NA|UC|SC|WYS|WS|SH|MC|CW|NO)$/)"
},
"major": {
".validate": "newData.isString() && newData.val().matches(/^.+$/) && newData.val().length < 128"
},
"entryDate": {
".validate": "newData.isString() && newData.val().matches(/^\\d{4}-\\d{2}-\\d{2}$/)"
},
"gradDate": {
".validate": "newData.isString() && newData.val().matches(/^\\d{4}-\\d{2}-\\d{2}$/)"
},
"$other": {
".validate": false
}
},
"memberStatus": {
".validate": "newData.hasChildren(['since', 'lastRenewed', 'until']) && auth !== null && auth.token !== null && auth.token.email.endsWith('@link.cuhk.edu.hk') && root.child('executives').child(auth.token.email.replace('@link.cuhk.edu.hk', '')).exists()",
"since": {
".validate": "(!data.exists() && newData.isNumber() && ((newData.val() > now - 1000 && newData.val() < now + 1000) || !data.parent().parent().exists())) || data.val() === newData.val()"
},
"lastRenewed": {
".validate": "((!data.exists() || newData.parent().child('until').val() > data.parent().child('until').val()) && newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000) || (newData.parent().child('until').val() <= data.parent().child('until').val() && data.val() === newData.val())"
},
"until": {
".validate": "newData.isNumber() || data.val() === newData.val()"
},
"$other": {
".validate": false
}
},
"createdAt": {
".validate": "(!data.exists() && newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000) || data.val() === newData.val()"
},
"updatedAt": {
".validate": "newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000"
},
"$other": {
".validate": false
}
}
},
"executives": {
".read": "auth !== null && auth.token !== null && auth.token.email.endsWith('@link.cuhk.edu.hk') && root.child('executives').child(auth.token.email.replace('@link.cuhk.edu.hk', '')).exists()",
".write": "auth !== null && auth.token !== null && auth.token.email.endsWith('@link.cuhk.edu.hk') && root.child('executives').child(auth.token.email.replace('@link.cuhk.edu.hk', '')).exists()",
"$sid": {
".read": "auth !== null && auth.token !== null && auth.token.email.endsWith('@link.cuhk.edu.hk') && auth.token.email.replace('@link.cuhk.edu.hk', '') === $sid",
".validate": "newData.child('updatedAt').val() !== data.child('updatedAt').val() && newData.hasChildren(['sid', 'displayName', 'title', 'createdAt', 'updatedAt'])",
"sid": {
".validate": "newData.isString() && newData.val().matches(/^\\d*$/) && newData.val().length < 16 && newData.val() === $sid"
},
"displayName": {
".validate": "newData.isString() && newData.val().length < 128"
},
"title": {
".validate": "newData.isString() && newData.val().length < 128"
},
"createdAt": {
".validate": "(!data.exists() && newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000) || data.val() === newData.val()"
},
"updatedAt": {
".validate": "newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000"
},
"$other": {
".validate": false
}
}
},
"publicMessages": {
".read": "auth !== null && auth.token !== null && auth.token.email.endsWith('@link.cuhk.edu.hk') && root.child('executives').child(auth.token.email.replace('@link.cuhk.edu.hk', '')).exists()",
".write": "auth !== null && auth.token !== null && auth.token.email.endsWith('@link.cuhk.edu.hk') && root.child('executives').child(auth.token.email.replace('@link.cuhk.edu.hk', '')).exists()",
".validate": "newData.hasChildren(['library', 'welcome', 'member', 'registered', 'expired', 'visitor'])",
"library": {
".read": true,
".validate": "newData.child('updatedAt').val() !== data.child('updatedAt').val() && newData.hasChildren(['message', 'updatedAt'])",
"message": {
".validate": "newData.isString() && newData.val().length < 65536"
},
"updatedAt": {
".validate": "newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000"
}
},
"welcome": {
".read": true,
".validate": "newData.child('updatedAt').val() !== data.child('updatedAt').val() && newData.hasChildren(['message', 'updatedAt'])",
"message": {
".validate": "newData.isString() && newData.val().length < 65536"
},
"updatedAt": {
".validate": "newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000"
}
},
"member": {
".read": "auth !== null && auth.token !== null && auth.token.email.endsWith('@link.cuhk.edu.hk') && root.child('members').child(auth.token.email.replace('@link.cuhk.edu.hk', '')).exists()",
".validate": "newData.child('updatedAt').val() !== data.child('updatedAt').val() && newData.hasChildren(['message', 'updatedAt'])",
"message": {
".validate": "newData.isString() && newData.val().length < 65536"
},
"updatedAt": {
".validate": "newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000"
}
},
"expired": {
".read": "auth !== null && auth.token !== null && auth.token.email.endsWith('@link.cuhk.edu.hk') && root.child('members').child(auth.token.email.replace('@link.cuhk.edu.hk', '')).exists()",
".validate": "newData.child('updatedAt').val() !== data.child('updatedAt').val() && newData.hasChildren(['message', 'updatedAt'])",
"message": {
".validate": "newData.isString() && newData.val().length < 65536"
},
"updatedAt": {
".validate": "newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000"
}
},
"registered": {
".read": "auth !== null && auth.token !== null && auth.token.email.endsWith('@link.cuhk.edu.hk') && root.child('members').child(auth.token.email.replace('@link.cuhk.edu.hk', '')).exists()",
".validate": "newData.child('updatedAt').val() !== data.child('updatedAt').val() && newData.hasChildren(['message', 'updatedAt'])",
"message": {
".validate": "newData.isString() && newData.val().length < 65536"
},
"updatedAt": {
".validate": "newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000"
}
},
"visitor": {
".read": true,
".validate": "newData.child('updatedAt').val() !== data.child('updatedAt').val() && newData.hasChildren(['message', 'updatedAt'])",
"message": {
".validate": "newData.isString() && newData.val().length < 65536"
},
"updatedAt": {
".validate": "newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000"
}
},
"$other": {
".validate": false
}
},
"library": {
".read": "auth !== null && auth.token !== null && auth.token.email.endsWith('@link.cuhk.edu.hk') && root.child('executives').child(auth.token.email.replace('@link.cuhk.edu.hk', '')).exists()",
".write": "auth !== null && auth.token !== null && auth.token.email.endsWith('@link.cuhk.edu.hk') && root.child('executives').child(auth.token.email.replace('@link.cuhk.edu.hk', '')).exists()",
".validate": "newData.hasChildren(['series', 'series_book', 'series_borrow', 'series_keyword', 'books', 'book_borrow', 'locations', 'location_series', 'location_book', 'borrows', 'keyword_series', 'memberBorrowings'])",
"series": {
".read": true,
".validate": "newData.hasChildren(['count', 'data'])",
"count": {
".validate": "newData.isNumber()"
},
"data": {
".indexOn": ["updatedAt", "borrowCount"],
"$seriesId": {
".validate": "newData.child('updatedAt').val() !== data.child('updatedAt').val() && newData.hasChildren(['title', 'author', 'bookCount', 'borrowCount', 'keywordCount', 'createdAt', 'updatedAt']) && (newData.child('bookCount').val() === 0 || newData.hasChildren(['locations'])) && $seriesId.length < 40",
"title": {
".validate": "newData.isString() && newData.val().length < 128"
},
"author": {
".validate": "newData.isString() && newData.val().length < 128"
},
"locations": {
"$location": {
".validate": "newData.parent().parent().parent().parent().parent().child('location_series').child($location).child($seriesId).val() === newData.val()"
}
},
"bookCount": {
".validate": "newData.isNumber()"
},
"borrowCount": {
".validate": "newData.isNumber()"
},
"keywordCount": {
".validate": "newData.isNumber()"
},
"createdAt": {
".validate": "newData.isNumber() && ((!data.exists() && newData.val() > now - 1000 && newData.val() < now + 1000) || data.val() === newData.val())"
},
"updatedAt": {
".validate": "newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000"
},
"$other": {
".validate": false
}
}
},
"$other": {
".validate": false
}
},
"series_book": {
".read": true,
"$seriesId": {
".validate": "newData.parent().parent().child('series').child('data').child($seriesId).exists()",
"$bookId": {
".validate": "(!newData.exists() && newData.parent().parent().parent().child('books').child('data').child($bookId).child('seriesId').val() !== $seriesId) || (newData.val() === true && newData.parent().parent().parent().child('books').child('data').child($bookId).child('seriesId').val() === $seriesId)"
}
}
},
"series_borrow": {
"$seriesId": {
".validate": "newData.parent().parent().child('series').child('data').child($seriesId).exists()",
"$borrowId": {
".validate": "newData.val() === true && newData.parent().parent().parent().child('borrows').child('data').child($borrowId).child('seriesId').val() === $seriesId"
}
}
},
"series_keyword": {
".read": true,
"$seriesId": {
".validate": "newData.parent().parent().child('series').child('data').child($seriesId).exists()",
"$keyword": {
".validate": "(newData.val() === true || !newData.exists()) && newData.exists() === newData.parent().parent().parent().child('keyword_series').child($keyword).child($seriesId).exists()"
}
}
},
"books": {
".read": true,
".validate": "newData.hasChildren(['count', 'data'])",
"count": {
".validate": "newData.isNumber()"
},
"data": {
".indexOn": ["seriesId", "isbn"],
"$bookId": {
".validate": "newData.child('updatedAt').val() !== data.child('updatedAt').val() && data.child('status').val() !== 'deleted' && newData.hasChildren(['seriesId', 'volume', 'language', 'status', 'location', 'borrowCount', 'isbn', 'createdAt', 'updatedAt']) && $bookId.length < 40",
"seriesId": {
".validate": "(!data.exists() || newData.val() === data.val()) && newData.isString() && newData.parent().parent().parent().parent().child('series_book').child(newData.val()).child($bookId).val() === true && (!data.exists() || newData.parent().parent().parent().parent().child('series_volume').child(data.val()).child($bookId).val() === null)"
},
"volume": {
".validate": "newData.isString() && newData.val().length < 16"
},
"language": {
".validate": "newData.isString() && newData.val().length < 32"
},
"status": {
".validate": "newData.isString() && newData.val().matches(/^(on-loan)|(on-shelf)|(lost)|(deleted)$/)"
},
"location": {
".validate": "newData.isString() && (newData.parent().child('status').val() === 'deleted' || newData.parent().parent().parent().parent().child('location_book').child(newData.val()).child($bookId).exists()) && (!data.exists() || (newData.val() === data.val() && newData.parent().child('status').val() !== 'deleted') || !newData.parent().parent().parent().parent().child('location_book').child(data.val()).child($bookId).exists())"
},
"borrowCount": {
".validate": "newData.isNumber()"
},
"isbn": {
".validate": "newData.isString() && newData.val().length < 16"
},
"createdAt": {
".validate": "newData.isNumber() && ((!data.exists() && newData.val() > now - 1000 && newData.val() < now + 1000) || data.val() === newData.val())"
},
"updatedAt": {
".validate": "newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000"
},
"$other": {
".validate": false
}
}
},
"$other": {
".validate": false
}
},
"book_borrow": {
"$bookId": {
".validate": "newData.parent().parent().child('books').child('data').child($bookId).exists()",
"$borrowId": {
".validate": "newData.val() === true && newData.parent().parent().parent().child('borrows').child('data').child($borrowId).child('bookId').val() === $bookId"
}
}
},
"locations": {
".read": true,
".validate": "newData.hasChildren(['data'])",
"data": {
"$location": {
".validate": "newData.child('updatedAt').val() !== data.child('updatedAt').val() && newData.hasChildren(['bookCount', 'updatedAt']) && $location.length < 16",
"bookCount": {
".validate": "newData.isNumber()"
},
"updatedAt": {
".validate": "newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000"
},
"$other": {
".validate": false
}
}
},
"$other": {
".validate": false
}
},
"location_series": {
".read": true,
"$location": {
".validate": "newData.parent().parent().child('locations').child('data').child($location).exists()",
"$seriesId": {
".validate": "newData.isNumber() && newData.parent().parent().parent().child('series').child('data').child($seriesId).child('locations').child($location).val() === newData.val()"
}
}
},
"location_book": {
".read": true,
"$location": {
".validate": "newData.parent().parent().child('locations').child('data').child($location).exists()",
"$bookId": {
".validate": "(!newData.exists() || newData.val() === true) && newData.exists() === (newData.parent().parent().parent().child('books').child('data').child($bookId).child('location').val() === $location && newData.parent().parent().parent().child('books').child('data').child($bookId).child('status').val() !== 'deleted')"
}
}
},
"borrows": {
".validate": "newData.hasChildren(['count', 'data'])",
"count": {
".validate": "newData.isNumber()"
},
"data": {
".indexOn": ["updatedAt", "returnTime"],
"$borrowId": {
".read": "auth.token.email.endsWith('@link.cuhk.edu.hk') && auth.token.email.replace('@link.cuhk.edu.hk', '') === data.child('sid').val()",
".validate": "newData.child('updatedAt').val() !== data.child('updatedAt').val() && newData.hasChildren(['sid', 'seriesId', 'bookId', 'borrowTime', 'dueDate', 'renewCount', 'createdAt', 'updatedAt']) && !data.child('returnTime').exists() && $borrowId.length < 40",
"sid": {
".validate": "(data.val() === newData.val() || (!data.exists() && newData.isString() && root.child('members').child(newData.val()).child('memberStatus').exists() && root.child('members').child(newData.val()).child('memberStatus').child('since').val() < now && now < root.child('members').child(newData.val()).child('memberStatus').child('until').val())) && newData.parent().parent().parent().parent().child('memberBorrowings').child(newData.val()).child('borrows').child($borrowId).val() === true"
},
"seriesId": {
".validate": "(data.val() === newData.val() || (!data.exists() && newData.isString())) && newData.parent().parent().parent().parent().child('series_borrow').child(newData.val()).child($borrowId).val() === true"
},
"bookId": {
".validate": "(data.val() === newData.val() || (!data.exists() && newData.isString())) && newData.parent().parent().parent().parent().child('book_borrow').child(newData.val()).child($borrowId).val() === true"
},
"borrowTime": {
".validate": "data.val() === newData.val() || (!data.exists() && newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000)"
},
"dueDate": {
".validate": "newData.isString() && newData.val().matches(/\\d{4}-\\d{2}-\\d{2}/)"
},
"renewCount": {
".validate": "newData.isNumber() && (newData.val() === data.val() || (newData.parent().child('dueDate').val() !== data.parent().child('dueDate').val() && ((data.exists() ? newData.val() === data.val() + 1 : newData.val() === 0))))"
},
"returnTime": {
".validate": "newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000"
},
"createdAt": {
".validate": "newData.isNumber() && ((!data.exists() && newData.val() > now - 1000 && newData.val() < now + 1000) || data.val() === newData.val())"
},
"updatedAt": {
".validate": "newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000"
},
"$other": {
".validate": false
}
}
},
"$other": {
".validate": false
}
},
"keyword_series": {
".read": true,
"$keyword": {
"$seriesId": {
".validate": "(newData.val() === true || !newData.exists()) && newData.exists() === newData.parent().parent().parent().child('series_keyword').child($seriesId).child($keyword).exists()"
}
}
},
"memberBorrowings": {
"$sid": {
".read": "auth.token.email.endsWith('@link.cuhk.edu.hk') && auth.token.email.replace('@link.cuhk.edu.hk', '') === $sid",
".validate": "newData.child('updatedAt').val() !== data.child('updatedAt').val() && newData.hasChildren(['borrowCount', 'currentBorrowCount', 'updatedAt']) && (newData.child('borrowCount').val() === 0 || newData.hasChild('borrows')) && (newData.child('currentBorrowCount').val() === 0 || newData.hasChild('currentBorrows')) && (data.exists() || (root.child('members').child($sid).child('memberStatus').exists() && root.child('members').child($sid).child('memberStatus').child('since').val() < now && now < root.child('members').child($sid).child('memberStatus').child('until').val()))",
"borrowCount": {
".validate": "newData.isNumber()"
},
"borrows": {
"$borrowId": {
".validate": "newData.val() === true && newData.parent().parent().parent().parent().child('borrows').child('data').child($borrowId).child('sid').val() === $sid"
}
},
"currentBorrowCount": {
".validate": "newData.isNumber()"
},
"currentBorrows": {
"$borrowId": {
".validate": "!newData.exists() || (newData.val() === true && newData.parent().parent().parent().parent().child('borrows').child('data').child($borrowId).exists())"
}
},
"updatedAt": {
".validate": "newData.isNumber() && newData.val() > now - 1000 && newData.val() < now + 1000"
},
"$other": {
".validate": false
}
}
},
"$other": {
".validate": false
}
},
"$other": {
".validate": false
}
}
}