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 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) return;
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) return;
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) return;
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) return;
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
- //YENİ EKLENEN KISIM: Kullanıcıya Bildirim Gönder (Socket Emit)
104
- if (socketHelpers && socketHelpers.server) {
105
- socketHelpers.server.sockets.in('uid_' + uid).emit('event:niki_award', {
106
- title: 'Tebrikler! 🥳',
107
- message: `${rule.name} işleminden <strong style="color:#ffd700">+${pointsToGive} Puan</strong> kazandın!`,
108
- newTotal: parseFloat((await user.getUserField(uid, 'niki_points')) || 0)
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
- // data = { post: { pid, uid, ... }, uid: <like atan>, ... }
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) return;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-niki-loyalty",
3
- "version": "1.2.7",
3
+ "version": "1.2.9",
4
4
  "description": "Niki The Cat Coffee Loyalty System - Earn points while studying on IEU Forum.",
5
5
  "main": "library.js",
6
6
  "nbbpm": {
package/plugin.json CHANGED
@@ -5,14 +5,38 @@
5
5
  "url": "https://forum.ieu.app",
6
6
  "library": "./library.js",
7
7
  "hooks": [
8
- { "hook": "static:app.load", "method": "init" },
9
- { "hook": "filter:navigation.available", "method": "addNavigation" },
10
- { "hook": "filter:scripts.get", "method": "addScripts" },
11
-
12
- { "hook": "action:user.loggedIn", "method": "onLogin" },
13
- { "hook": "action:topic.save", "method": "onTopicCreate" },
14
- { "hook": "action:post.save", "method": "onPostCreate" },
15
- { "hook": "action:post.upvote", "method": "onUpvote" }
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"
@@ -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 - Logo ile)
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
- <img src="${logoUrl}" alt="Niki" style="width: 28px; height: 28px; border-radius: 50%; object-fit: cover;">
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').addClass('show');
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').removeClass('show');
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
- }, 300);
73
+ }, 400);
48
74
  }, 4000);
49
75
 
50
76
  // Widget'ı da bounce animasyonu ile canlandır
51
- $('#niki-floating-widget .niki-widget-content').addClass('niki-bounce');
52
- setTimeout(function () {
53
- $('#niki-floating-widget .niki-widget-content').removeClass('niki-bounce');
54
- }, 500);
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 + ' / 28');
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, 8, 'item-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: