This repository has been archived by the owner on Mar 5, 2024. It is now read-only.
forked from mudkipme/nodebb-plugin-checkin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
library.js
211 lines (184 loc) · 7.58 KB
/
library.js
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
const nconf = require.main.require('nconf');
const _ = require.main.require('lodash');
const User = require.main.require('./src/user');
const db = require.main.require('./src/database');
const Notifications = require.main.require('./src/notifications');
const routeHelpers = require.main.require('./src/routes/helpers');
const controllerHelpers = require.main.require('./src/controllers/helpers');
const sakamotoSanUID = 2086; // 办公用猫账号 UID
const checkinConfig = nconf.get('checkin') || {
postReward: true,
rewards: [
{
firstReward: 20,
minReward: 5,
maxReward: 9
},
{
continuousDay: 7,
firstReward: 40,
minReward: 10,
maxReward: 19
}
]
};
const checkingIn = new Set();
const Checkin = {
async getNavigation(items) {
items.push({
route: '/checkin',
title: '[[checkin:check-in]]',
enabled: true,
iconClass: 'fa-id-badge',
textClass: 'visible-xs-inline',
text: '[[checkin:check-in]]'
});
return items;
},
async load({ router, middleware }) {
const render = async function (req, res, next) {
try {
const data = await doCheckin(req.uid);
res.render('checkin', {
title: '[[checkin:check-in]]',
breadcrumbs: controllerHelpers.buildBreadcrumbs([
{
text: '[[checkin:check-in]]'
}
]),
...data
});
} catch (err) {
next(err);
}
};
routeHelpers.setupPageRoute(router, '/checkin', middleware, [middleware.ensureLoggedIn], render);
},
async postCreate({ post, data }) {
if (!checkinConfig.postReward) {
return { post, data };
}
const today = dateKey(Date.now());
const [checkedIn, checkinPendingReward] = await Promise.all([
db.isSortedSetMember(`checkin-plugin:${today}`, data.uid),
User.getUserField(data.uid, 'checkinPendingReward')
]);
if (checkedIn && checkinPendingReward > 0) {
await Promise.all([
User.incrementUserReputationBy(data.uid, checkinPendingReward),
User.setUserField(data.uid, 'checkinPendingReward', 0)
]);
const noti = await Notifications.create({
bodyShort: `[[checkin:post-message, ${checkinPendingReward}]]`,
bodyLong: `[[checkin:post-message, ${checkinPendingReward}]]`,
nid: 'checkin_' + data.uid,
from: data.uid,
path: '/checkin'
});
await Notifications.push(noti, data.uid);
}
return { post, data };
},
async appendUserFieldsWhitelist(data) {
data.whitelist.push('checkinContinuousDays');
data.whitelist.push('checkinPendingReward');
return data;
}
};
async function doCheckin(uid) { // doCheckIn 原始逻辑已移动到 doRealCheckin
const sakamotoSanCheckinResult = await doRealCheckin(sakamotoSanUID, false); // 为 SakamotoSan 签到一下,获取签到结果
const force = sakamotoSanCheckinResult.continuousDay === 1 // 如果猫先生断签了,用户签到时则强制忽略断签
return await doRealCheckin(uid, force); // 签一下用户
}
async function doRealCheckin(uid, forceYesterdayCheckedIn) {
if (!uid) {
throw new Error('[[error:not-logged-in]]');
}
const now = Date.now();
const today = dateKey(now);
const yesterday = dateKey(now - 864e5);
const checkedIn = await db.isSortedSetMember(`checkin-plugin:${today}`, uid);
let reward = 0;
if (!checkedIn) {
if (checkingIn.has(uid)) {
// This is rough check and might have some problem with multiple NodeBB instance
throw new Error('[[checkin:too-busy]]');
}
try {
checkingIn.add(uid);
const [rank, checkedInYesterday, continuousDays, total] = await Promise.all([
db.increment(`checkin-plugin:rank:${today}`), // 处理一下办公用猫的 rank
db.isSortedSetMember(`checkin-plugin:${yesterday}`, uid),
User.getUserField(uid, 'checkinContinuousDays'),
db.sortedSetCard(`checkin-plugin:user:${uid}`)
]);
if (forceYesterdayCheckedIn) { // 是否强制设置连签状态
checkedInYesterday = true;
}
const continuousDay = checkedInYesterday ? (parseInt(continuousDays) || 0) + 1 : 1;
for (let item of checkinConfig.rewards) {
if (continuousDay >= (item.continuousDay || 0)) {
reward = (rank === 1 || rank === 2) ? item.firstReward
: item.minReward + Math.floor(Math.random() * (item.maxReward - item.minReward + 1))
}
}
await Promise.all([
db.sortedSetAdd(`checkin-plugin:${today}`, rank, uid),
db.sortedSetAdd(`checkin-plugin:user:${uid}`, now, today),
db.sortedSetAdd('checkin-plugin:continuous', continuousDay, uid),
db.sortedSetAdd('checkin-plugin:total', total + 1, uid),
User.setUserFields(uid, {
checkinContinuousDays: continuousDay,
checkinPendingReward: reward
}),
User.incrementUserReputationBy(uid, reward)
]);
checkingIn.delete(uid);
}
catch (e) {
checkingIn.delete(uid);
throw e;
}
}
const [total, rank, userData, todayList, continuousList, totalList] = await Promise.all([
db.sortedSetCard(`checkin-plugin:user:${uid}`),
db.sortedSetScore(`checkin-plugin:${today}`, uid),
User.getUserFields(uid, ['checkinContinuousDays', 'checkinPendingReward']),
db.getSortedSetRangeWithScores(`checkin-plugin:${today}`, 0, 9),
db.getSortedSetRevRangeWithScores('checkin-plugin:continuous', 0, 9),
db.getSortedSetRevRangeWithScores('checkin-plugin:total', 0, 9)
]);
const uids = _.map(_.concat(todayList, continuousList, totalList), 'value');
const users = _.keyBy(await User.getUsersFields(uids, ['username', 'userslug']), 'uid')
const [todayMembers, continuousMembers, totalMembers] = [todayList, continuousList, totalList]
.map(list => list.filter(item => users[item.value] !== undefined).filter(item => users[item.value].uid !== sakamotoSanUID)) // 过滤 SamamotoSan 的 UID
.map(list => list.map(item => ({
username: users[item.value].username,
userslug: users[item.value].userslug,
score: item.score - 1
})));
var continuousCheckInBreaked = "未知";
if (forceYesterdayCheckedIn) {
continuousCheckInBreaked = "是";
} else {
continuousCheckInBreaked = "否";
}
const rankFixed = rank - 1;
return {
checkedIn,
postReward: checkinConfig.postReward && parseInt(userData.checkinPendingReward) > 0,
rankFixed,
continuousDay: userData.checkinContinuousDays,
reward,
total,
todayMembers,
continuousMembers,
totalMembers,
continuousCheckInBreaked
};
}
function dateKey(timestamp) {
const date = new Date(timestamp);
return date.getFullYear() + `${date.getMonth() + 1}`.padStart(2, '0') + `${date.getDate()}`.padStart(2, '0');
}
module.exports = Checkin;