nodebb-plugin-niki-loyalty 1.2.7 → 1.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/library.js +56 -19
- package/package.json +1 -1
- package/plugin.json +32 -8
- package/static/lib/client.js +47 -16
package/library.js
CHANGED
|
@@ -73,24 +73,35 @@ async function awardDailyAction(uid, actionKey) {
|
|
|
73
73
|
const today = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
74
74
|
const rule = ACTIONS[actionKey];
|
|
75
75
|
|
|
76
|
-
if (!rule)
|
|
76
|
+
if (!rule) {
|
|
77
|
+
console.log(`[Niki-Loyalty] Bilinmeyen aksiyon: ${actionKey}`);
|
|
78
|
+
return { success: false, reason: 'unknown_action' };
|
|
79
|
+
}
|
|
77
80
|
|
|
78
81
|
// 1. Genel Günlük Limit Kontrolü
|
|
79
82
|
const dailyScoreKey = `niki:daily:${uid}:${today}`;
|
|
80
83
|
const currentDailyScore = parseFloat((await db.getObjectField(dailyScoreKey, 'score')) || 0);
|
|
81
|
-
if (currentDailyScore >= SETTINGS.dailyCap)
|
|
84
|
+
if (currentDailyScore >= SETTINGS.dailyCap) {
|
|
85
|
+
console.log(`[Niki-Loyalty] Günlük limit doldu. UID: ${uid}, Score: ${currentDailyScore}`);
|
|
86
|
+
return { success: false, reason: 'daily_cap_reached' };
|
|
87
|
+
}
|
|
82
88
|
|
|
83
89
|
// 2. Eylem Bazlı Limit Kontrolü
|
|
84
90
|
const actionCountKey = `niki:daily:${uid}:${today}:counts`;
|
|
85
91
|
const currentActionCount = parseInt((await db.getObjectField(actionCountKey, actionKey)) || 0, 10);
|
|
86
|
-
if (currentActionCount >= rule.limit)
|
|
92
|
+
if (currentActionCount >= rule.limit) {
|
|
93
|
+
console.log(`[Niki-Loyalty] Aksiyon limiti doldu. UID: ${uid}, Action: ${actionKey}, Count: ${currentActionCount}/${rule.limit}`);
|
|
94
|
+
return { success: false, reason: 'action_limit_reached' };
|
|
95
|
+
}
|
|
87
96
|
|
|
88
97
|
// 3. Puan Hesapla
|
|
89
98
|
let pointsToGive = rule.points;
|
|
90
99
|
if (currentDailyScore + pointsToGive > SETTINGS.dailyCap) {
|
|
91
100
|
pointsToGive = SETTINGS.dailyCap - currentDailyScore;
|
|
92
101
|
}
|
|
93
|
-
if (pointsToGive <= 0)
|
|
102
|
+
if (pointsToGive <= 0) {
|
|
103
|
+
return { success: false, reason: 'no_points_to_give' };
|
|
104
|
+
}
|
|
94
105
|
|
|
95
106
|
// 4. DB Güncellemeleri
|
|
96
107
|
await user.incrementUserFieldBy(uid, 'niki_points', pointsToGive);
|
|
@@ -100,17 +111,30 @@ async function awardDailyAction(uid, actionKey) {
|
|
|
100
111
|
// Logla
|
|
101
112
|
await addUserLog(uid, 'earn', pointsToGive, rule.name);
|
|
102
113
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
newTotal
|
|
109
|
-
|
|
114
|
+
console.log(`[Niki-Loyalty] ✅ PUAN VERİLDİ! UID: ${uid}, Action: ${actionKey}, Points: +${pointsToGive}`);
|
|
115
|
+
|
|
116
|
+
// ✅ Kullanıcıya Bildirim Gönder (Socket Emit) - Güçlendirilmiş
|
|
117
|
+
try {
|
|
118
|
+
if (socketHelpers && socketHelpers.server && socketHelpers.server.sockets) {
|
|
119
|
+
const newTotal = parseFloat((await user.getUserField(uid, 'niki_points')) || 0);
|
|
120
|
+
socketHelpers.server.sockets.in('uid_' + uid).emit('event:niki_award', {
|
|
121
|
+
title: 'Tebrikler! 🥳',
|
|
122
|
+
message: `${rule.name} işleminden <strong style="color:#ffd700">+${pointsToGive} Puan</strong> kazandın!`,
|
|
123
|
+
newTotal: newTotal
|
|
124
|
+
});
|
|
125
|
+
console.log(`[Niki-Loyalty] 📢 Socket bildirim gönderildi. UID: ${uid}`);
|
|
126
|
+
} else {
|
|
127
|
+
console.log(`[Niki-Loyalty] ⚠️ Socket server hazır değil, bildirim gönderilemedi.`);
|
|
128
|
+
}
|
|
129
|
+
} catch (socketErr) {
|
|
130
|
+
console.error(`[Niki-Loyalty] Socket emit hatası:`, socketErr.message);
|
|
110
131
|
}
|
|
111
132
|
|
|
133
|
+
return { success: true, points: pointsToGive };
|
|
134
|
+
|
|
112
135
|
} catch (err) {
|
|
113
136
|
console.error(`[Niki-Loyalty] Error awarding points for ${actionKey}:`, err);
|
|
137
|
+
return { success: false, reason: 'error', error: err.message };
|
|
114
138
|
}
|
|
115
139
|
}
|
|
116
140
|
|
|
@@ -144,39 +168,52 @@ Plugin.onPostCreate = async function (data) {
|
|
|
144
168
|
await awardDailyAction(data.post.uid, 'reply');
|
|
145
169
|
};
|
|
146
170
|
|
|
147
|
-
// 4. BEĞENİ (Like Atma ve Alma) - Spam Korumalı
|
|
171
|
+
// 4. BEĞENİ (Like Atma ve Alma) - Spam Korumalı + Debug Loglı
|
|
148
172
|
Plugin.onUpvote = async function (data) {
|
|
149
|
-
|
|
173
|
+
console.log('[Niki-Loyalty] 👍 Upvote hook tetiklendi. Data:', JSON.stringify({
|
|
174
|
+
voterUid: data.uid,
|
|
175
|
+
postPid: data.post?.pid,
|
|
176
|
+
postOwnerUid: data.post?.uid
|
|
177
|
+
}));
|
|
178
|
+
|
|
150
179
|
const pid = data.post && data.post.pid;
|
|
151
|
-
if (!pid)
|
|
180
|
+
if (!pid) {
|
|
181
|
+
console.log('[Niki-Loyalty] ⚠️ Post PID bulunamadı, işlem iptal.');
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
152
184
|
|
|
153
185
|
const today = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
154
186
|
|
|
155
187
|
// Like Atan Kazanır:
|
|
156
188
|
if (data.uid) {
|
|
157
|
-
// Bu postu bugün zaten beğenmiş mi?
|
|
158
189
|
const likeGivenKey = `niki:liked:${data.uid}:${today}`;
|
|
159
190
|
const alreadyLiked = await db.isSetMember(likeGivenKey, pid.toString());
|
|
160
191
|
|
|
192
|
+
console.log(`[Niki-Loyalty] Like Atan: UID=${data.uid}, PID=${pid}, Daha önce beğenmiş mi=${alreadyLiked}`);
|
|
193
|
+
|
|
161
194
|
if (!alreadyLiked) {
|
|
162
|
-
await awardDailyAction(data.uid, 'like_given');
|
|
195
|
+
const result = await awardDailyAction(data.uid, 'like_given');
|
|
196
|
+
console.log('[Niki-Loyalty] like_given sonuç:', result);
|
|
163
197
|
await db.setAdd(likeGivenKey, pid.toString());
|
|
164
|
-
// 24 saat sonra expire olsun
|
|
165
198
|
await db.expire(likeGivenKey, 86400);
|
|
166
199
|
}
|
|
167
200
|
}
|
|
168
201
|
|
|
169
202
|
// Like Alan Kazanır (Post sahibi):
|
|
170
203
|
if (data.post && data.post.uid && data.post.uid !== data.uid) {
|
|
171
|
-
// Bu post için bugün zaten puan almış mı?
|
|
172
204
|
const likeTakenKey = `niki:liked_taken:${data.post.uid}:${today}`;
|
|
173
205
|
const alreadyTaken = await db.isSetMember(likeTakenKey, pid.toString());
|
|
174
206
|
|
|
207
|
+
console.log(`[Niki-Loyalty] Like Alan: UID=${data.post.uid}, PID=${pid}, Daha önce puan almış mı=${alreadyTaken}`);
|
|
208
|
+
|
|
175
209
|
if (!alreadyTaken) {
|
|
176
|
-
await awardDailyAction(data.post.uid, 'like_taken');
|
|
210
|
+
const result = await awardDailyAction(data.post.uid, 'like_taken');
|
|
211
|
+
console.log('[Niki-Loyalty] like_taken sonuç:', result);
|
|
177
212
|
await db.setAdd(likeTakenKey, pid.toString());
|
|
178
213
|
await db.expire(likeTakenKey, 86400);
|
|
179
214
|
}
|
|
215
|
+
} else {
|
|
216
|
+
console.log('[Niki-Loyalty] ⚠️ Like alan kontrol edilemedi. Post owner:', data.post?.uid, 'Voter:', data.uid);
|
|
180
217
|
}
|
|
181
218
|
};
|
|
182
219
|
|
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -5,14 +5,38 @@
|
|
|
5
5
|
"url": "https://forum.ieu.app",
|
|
6
6
|
"library": "./library.js",
|
|
7
7
|
"hooks": [
|
|
8
|
-
{
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
{
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
{
|
|
9
|
+
"hook": "static:app.load",
|
|
10
|
+
"method": "init"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"hook": "filter:navigation.available",
|
|
14
|
+
"method": "addNavigation"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"hook": "filter:scripts.get",
|
|
18
|
+
"method": "addScripts"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"hook": "action:user.loggedIn",
|
|
22
|
+
"method": "onLogin"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"hook": "action:topic.save",
|
|
26
|
+
"method": "onTopicCreate"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"hook": "action:post.save",
|
|
30
|
+
"method": "onPostCreate"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"hook": "action:post.upvote",
|
|
34
|
+
"method": "onUpvote"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"hook": "action:post.updatePostVoteCount",
|
|
38
|
+
"method": "onUpvote"
|
|
39
|
+
}
|
|
16
40
|
],
|
|
17
41
|
"staticDirs": {
|
|
18
42
|
"static": "./static"
|
package/static/lib/client.js
CHANGED
|
@@ -14,19 +14,39 @@ $(document).ready(function () {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// -------------------------------------------------------------
|
|
17
|
-
// 🔔 NİKİ TOAST BİLDİRİM FONKSİYONU (Sol Alt -
|
|
17
|
+
// 🔔 NİKİ TOAST BİLDİRİM FONKSİYONU (Sol Alt - Inline Stiller)
|
|
18
18
|
// -------------------------------------------------------------
|
|
19
19
|
function showNikiToast(message) {
|
|
20
20
|
// Mevcut toast'ı kaldır
|
|
21
21
|
$('.niki-toast').remove();
|
|
22
22
|
|
|
23
23
|
// Logo yolunu al (plugin'in static klasöründen)
|
|
24
|
-
const logoUrl = config.relative_path + '/plugins/nodebb-plugin-niki-loyalty/static/logo.png';
|
|
24
|
+
const logoUrl = (config && config.relative_path ? config.relative_path : '') + '/plugins/nodebb-plugin-niki-loyalty/static/logo.png';
|
|
25
25
|
|
|
26
|
-
// Toast HTML'i oluştur
|
|
26
|
+
// Toast HTML'i oluştur (Inline stiller ile)
|
|
27
27
|
const toastHtml = `
|
|
28
|
-
<div class="niki-toast"
|
|
29
|
-
|
|
28
|
+
<div class="niki-toast" style="
|
|
29
|
+
position: fixed;
|
|
30
|
+
bottom: 90px;
|
|
31
|
+
left: 25px;
|
|
32
|
+
background: linear-gradient(135deg, #4E342E 0%, #3E2723 100%);
|
|
33
|
+
color: #fff;
|
|
34
|
+
padding: 12px 20px;
|
|
35
|
+
border-radius: 16px;
|
|
36
|
+
font-size: 14px;
|
|
37
|
+
font-weight: 600;
|
|
38
|
+
box-shadow: 0 8px 25px rgba(0,0,0,0.3);
|
|
39
|
+
display: flex;
|
|
40
|
+
align-items: center;
|
|
41
|
+
gap: 12px;
|
|
42
|
+
z-index: 9999;
|
|
43
|
+
opacity: 0;
|
|
44
|
+
transform: translateY(20px) scale(0.9);
|
|
45
|
+
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
|
46
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
47
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
48
|
+
">
|
|
49
|
+
<img src="${logoUrl}" alt="Niki" style="width: 32px; height: 32px; border-radius: 50%; object-fit: cover; border: 2px solid rgba(255,255,255,0.2);">
|
|
30
50
|
<span>${message}</span>
|
|
31
51
|
</div>
|
|
32
52
|
`;
|
|
@@ -34,24 +54,35 @@ $(document).ready(function () {
|
|
|
34
54
|
// Body'ye ekle
|
|
35
55
|
$('body').append(toastHtml);
|
|
36
56
|
|
|
37
|
-
// Animasyon için kısa gecikme
|
|
57
|
+
// Animasyon için kısa gecikme - görünür yap
|
|
38
58
|
setTimeout(function () {
|
|
39
|
-
$('.niki-toast').
|
|
59
|
+
$('.niki-toast').css({
|
|
60
|
+
'opacity': '1',
|
|
61
|
+
'transform': 'translateY(0) scale(1)'
|
|
62
|
+
});
|
|
40
63
|
}, 50);
|
|
41
64
|
|
|
42
65
|
// 4 saniye sonra kaldır
|
|
43
66
|
setTimeout(function () {
|
|
44
|
-
$('.niki-toast').
|
|
67
|
+
$('.niki-toast').css({
|
|
68
|
+
'opacity': '0',
|
|
69
|
+
'transform': 'translateY(20px) scale(0.9)'
|
|
70
|
+
});
|
|
45
71
|
setTimeout(function () {
|
|
46
72
|
$('.niki-toast').remove();
|
|
47
|
-
},
|
|
73
|
+
}, 400);
|
|
48
74
|
}, 4000);
|
|
49
75
|
|
|
50
76
|
// Widget'ı da bounce animasyonu ile canlandır
|
|
51
|
-
$('#niki-floating-widget .niki-widget-content')
|
|
52
|
-
|
|
53
|
-
$('
|
|
54
|
-
|
|
77
|
+
const $widget = $('#niki-floating-widget .niki-widget-content');
|
|
78
|
+
if ($widget.length) {
|
|
79
|
+
$widget.css('transform', 'scale(1.1)');
|
|
80
|
+
setTimeout(function () {
|
|
81
|
+
$widget.css('transform', 'scale(1)');
|
|
82
|
+
}, 300);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
console.log('[Niki-Loyalty] Toast gösterildi:', message);
|
|
55
86
|
}
|
|
56
87
|
|
|
57
88
|
// Fonksiyonu global yap (Konsoldan test için)
|
|
@@ -253,7 +284,7 @@ $(document).ready(function () {
|
|
|
253
284
|
|
|
254
285
|
let dailyScore = parseFloat(data.dailyScore);
|
|
255
286
|
let scoreText = Number.isInteger(dailyScore) ? dailyScore : dailyScore.toFixed(1);
|
|
256
|
-
$('#widget-daily-text').text(scoreText + ' /
|
|
287
|
+
$('#widget-daily-text').text(scoreText + ' / 35');
|
|
257
288
|
|
|
258
289
|
// 3. DETAYLI SAYAÇLAR (Counts)
|
|
259
290
|
const c = data.counts || {}; // Backend'den gelen sayaç objesi
|
|
@@ -273,10 +304,10 @@ $(document).ready(function () {
|
|
|
273
304
|
}
|
|
274
305
|
}
|
|
275
306
|
|
|
276
|
-
// Tek Tek Güncelle
|
|
307
|
+
// Tek Tek Güncelle (library.js ACTIONS ile eşleştirildi)
|
|
277
308
|
setProgress('w-count-new_topic', c.new_topic, 1, 'item-new-topic');
|
|
278
309
|
setProgress('w-count-reply', c.reply, 2, 'item-reply');
|
|
279
|
-
setProgress('w-count-read', c.read,
|
|
310
|
+
setProgress('w-count-read', c.read, 10, 'item-read');
|
|
280
311
|
|
|
281
312
|
// Like (Alma ve Atma toplamı 4 limit demiştik, burada basitleştirip toplamı gösteriyoruz)
|
|
282
313
|
// Backend'de like_given ve like_taken ayrı tutuluyor, ikisini toplayalım:
|