-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathserver.coffee
200 lines (173 loc) · 5.55 KB
/
server.coffee
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
setLanguage = (lang) !->
lang ||= Db.shared.get('language')
if lang not in ['EN', 'NL', 'ES', 'FR', 'DE', 'IT']
lang = 'EN'
Db.shared.set 'language', lang
log "Hunts language set to", lang
exports.onInstall = (config) !->
setLanguage config.language||false
newHunt(3) # we'll start with 3 subjects
exports.onUpgrade = !->
# upgrade to multi language
setLanguage()
# apparently a timer did not fire (or we were out of hunts, next -> 1), correct it
if 0 < Db.shared.get('next') < App.time()
Timer.set(Math.floor(Math.random()*7200*1000), 'newHunt')
scheduleNextHunt = (delayDays) !->
if !delayDays?
delayDays = 1
maxId = Db.shared.get 'hunts', 'maxId'
if maxId>7
openHunts = 0
deltaTime = false
for i in [maxId...maxId-7]
if Db.shared.get 'hunts', i, 'photos', 'maxId'
break # a photo was posted
if i>1
deltaTime = Db.shared.get('hunts', i, 'time') - Db.shared.get('hunts', i-1, 'time')
if deltaTime is false or deltaTime>10*60*60 # probably not manually triggered, count it
openHunts++
if openHunts > 2 # at least 3 consecutive open hunts
delayDays = Math.pow(openHunts - 2, 2) # 1, 4, 9, 16, 25 days delay
now = App.time()
nextDayStart = Math.floor(now/86400)*86400 + Math.max(1, delayDays)*86400 + ((new Date).getTimezoneOffset() * 60)
nextTime = nextDayStart + (10*3600) + Math.floor(Math.random()*(12*3600))
if (nextTime-now) > 3600
Timer.cancel()
Timer.set (nextTime-now)*1000, 'newHunt'
Db.shared.set 'next', nextTime
exports.onJoin = !->
if App.userIds().length > 1 and !Db.shared.get('next')?
scheduleNextHunt()
exports.client_newHunt = exports.newHunt = newHunt = (amount = 1, cb = false) !->
return if Db.shared.get('next') is -1
# used to disable my plugins and master instances
log 'newHunt called, amount '+amount
hunts = require('hunts'+Db.shared.get('language')).hunts()
# remove hunts that have taken place already
if prevHunts = Db.shared.get('hunts')
for huntId, hunt of prevHunts
continue if !+huntId
if (pos = hunts.indexOf(hunt.subject)) >= 0
hunts.splice pos, 1
# find some new hunts
newHunts = []
while amount-- and hunts.length
sel = Math.floor(Math.random()*hunts.length)
newHunts.push hunts[sel]
hunts.splice sel, 1
if !newHunts.length
log 'no more hunts available'
Db.shared.set 'next', 1 # shows 'no more hunts for now'
if cb
cb.reply true
else
log 'selected new hunt(s): '+JSON.stringify(newHunts)
now = App.time()
for newHunt in newHunts
maxId = Db.shared.ref('hunts').incr 'maxId'
# first referencing hunts, as Db.shared.incr 'hunts', 'maxId' is buggy
Db.shared.set 'hunts', maxId,
subject: newHunt
time: 0|now
photos: {}
# schedule the next hunt when there are still hunts left (and multiple participants)
if hunts.length and App.userIds().length > 1
scheduleNextHunt (if cb then 1 else null) # always 1 when manually triggered by user
# we'll only notify when this is about a single new hunt
if newHunts.length is 1
subj = newHunts[0]
Event.create
text: "New Photo Hunt: you " + subj.charAt(0).toLowerCase() + subj.slice(1)
digest: false
highPrio: true
exports.client_removePhoto = (huntId, photoId, disqualify = false) !->
photos = Db.shared.ref 'hunts', huntId, 'photos'
return if !photos.get photoId
about = photos.get photoId, 'userId'
thisUserSubmission = App.userId() is about
if disqualify
photos.set photoId, 'disqualified', true
else
photos.remove photoId
# find a new winner if necessary
newWinner = null
if Db.shared.get('hunts', huntId, 'winner') is photoId
smId = (+k for k, v of photos.get() when +k and !v.disqualified)?.sort()[0] || null
Db.shared.set 'hunts', huntId, 'winner', smId # can also remove winner
if smId
newWinner = photos.get smId, 'userId'
if disqualify
if newWinner
addComment huntId,
u: App.userId()
a: about
w: newWinner
s: 'winnerAfterDisqualify'
highPrio: [about,newWinner]
else
addComment huntId,
u: App.userId()
a: about
s: 'disqualify'
highPrio: [about]
else if thisUserSubmission
if newWinner
addComment huntId,
u: App.userId()
w: newWinner
s: 'winnerAfterRetract'
highPrio: [newWinner]
else
addComment huntId,
u: App.userId()
s: 'retract'
lowPrio: true
else if !thisUserSubmission
if newWinner
addComment huntId,
u: App.userId()
a: about
w: newWinner
s: 'winnerAfterRemove'
highPrio: [about,newWinner]
else
addComment huntId,
u: App.userId()
a: about
s: 'remove'
highPrio: [about]
exports.client_seenExp = (exp, seen) !->
Db.personal().set 'seen', exp, seen
exports.onPhoto = (info, huntId) !->
huntId = huntId[0]
log 'got photo', JSON.stringify(info), App.userId()
# test whether the user hasn't uploaded a photo in this hunt yet
allPhotos = Db.shared.get 'hunts', huntId, 'photos'
for k, v of allPhotos
if +v.userId is App.userId()
log "user #{App.userId()} already submitted a photo for hunt "+huntId
return
hunt = Db.shared.ref 'hunts', huntId
maxId = hunt.incr 'photos', 'maxId'
info.time = 0|App.time()
hunt.set 'photos', maxId, info
notifyText = ''
if !hunt.get 'winner'
hunt.set 'winner', maxId
addComment huntId,
u: App.userId()
s: 'winner'
pushText: App.userName() + ' won!'
else
addComment huntId,
u: App.userId()
s: 'runnerUp'
pushText: App.userName() + ' added a runner-up'
lowPrio: true
addComment = (huntId, comment) !->
if comment.pushText
comment.pushText += ' (' + Db.shared.get('hunts', huntId, 'subject') + ')'
comment.legacyStore = huntId
comment.path = [huntId]
Comments.post comment