-
Notifications
You must be signed in to change notification settings - Fork 72
/
database.rules.bolt
122 lines (97 loc) · 2.81 KB
/
database.rules.bolt
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
path /parties {
read() { true }
index() { ["created_by", "short_id"] }
}
path /parties/{partyId} is Party {
write() { createdByCurrent(this.created_by) }
}
path /user_parties/{uid}/{partyId} {
read() { isCurrentUser(uid) }
write() { isCurrentUser(uid) }
}
type Party {
country: SpotifyCountry,
created_at: CreatedTimestamp,
created_by: CreatedUser,
fallback_playlist: Object | Null,
name: String,
playback: PlaybackState,
settings: PartySettings | Null,
short_id: PartyShortId
}
type NonEmptyString extends String {
validate() { this.length > 0 }
}
type PartyShortId extends NonEmptyString {
validate() { this.length <= 50 }
}
type PlaybackState {
last_change: CurrentTimestamp,
last_position_ms: Number,
playing: Boolean,
target_playing: Boolean | Null,
master_id: String | Null
}
type PartySettings {
allow_anonymous_voters: Boolean | Null,
allow_explicit_tracks: Boolean | Null,
allow_multi_track_add: Boolean | Null,
tv_mode_text: String | Null,
maximum_track_length: Number | Null
}
type SpotifyCountry extends String {
validate() { this.length == 2 }
}
path /tracks/{partyId} {
read() { true }
index() { ["order", "vote_count"] }
}
path /tracks/{partyId}/{trackId} is TracksPermissions {
}
path /tracks_played/{partyId}/{historyId} is TracksPermissions {
}
type TracksPermissions {
validate() { partyExists(partyId) }
write() { isPartyOwner(partyId) }
}
path /votes/{partyId} {
read() { true }
write() { canSkip(partyId) }
}
path /votes/{partyId}/{trackId}/{userId} is VotesPermissions {
}
path /votes_by_user/{partyId} {
read() { canSkip(partyId) }
write() { canSkip(partyId) }
}
path /votes_by_user/{partyId}/{userId} {
read() { isCurrentUser(userId) }
}
path /votes_by_user/{partyId}/{userId}/{trackId} is VotesPermissions {
}
type VotesPermissions {
write() {
isCurrentUser(userId) &&
(root.parties[partyId].settings == null ||
root.parties[partyId].settings.allow_anonymous_voters ||
auth.provider != "anonymous")
}
validate() { partyExists(partyId) }
}
type CurrentTimestamp extends Number {
validate() { this == now }
}
type CreatedTimestamp extends Number {
validate() { initial(this, now) }
}
type CreatedUser extends String {
validate() { initial(this, auth.uid) }
}
// Returns true if the value is intialized to init, or if it retains it's prior
// value, otherwise.
initial(value, init) { value == (prior(value) == null ? init : prior(value)) }
createdByCurrent(uid) { prior(uid) == null || isCurrentUser(prior(uid)) }
isCurrentUser(uid) { auth != null && auth.uid == uid }
isPartyOwner(id) { isCurrentUser(root.parties[id].created_by) }
partyExists(id) { root.parties[id] != null }
canSkip(partyId) { isPartyOwner(partyId) }