nodebb-plugin-niki-loyalty 1.5.6 → 1.5.8

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
@@ -4,6 +4,7 @@ const user = require.main.require('./src/user');
4
4
  const posts = require.main.require('./src/posts');
5
5
  const routeHelpers = require.main.require('./src/controllers/helpers');
6
6
  const nconf = require.main.require('nconf');
7
+ const meta = require.main.require('./src/meta');
7
8
  const socketHelpers = require.main.require('./src/socket.io/index');
8
9
  const SocketPlugins = require.main.require('./src/socket.io/plugins');
9
10
  const groups = require.main.require('./src/groups');
@@ -45,6 +46,48 @@ const REWARDS = [
45
46
 
46
47
  const TEST_MODE_UNLIMITED = false;
47
48
 
49
+ // =========================
50
+ // 📦 AYARLARI DB'DEN YÜKLE
51
+ // =========================
52
+ async function loadAndApplySettings() {
53
+ try {
54
+ const saved = await new Promise((resolve) => {
55
+ meta.settings.get('niki-loyalty', (err, settings) => {
56
+ resolve(err ? {} : (settings || {}));
57
+ });
58
+ });
59
+
60
+ if (!saved || Object.keys(saved).length === 0) return;
61
+
62
+ // Genel
63
+ if (saved.dailyCap) SETTINGS.dailyCap = parseInt(saved.dailyCap, 10) || SETTINGS.dailyCap;
64
+
65
+ // Aksiyonlar
66
+ ['login', 'new_topic', 'reply', 'read', 'like_given', 'like_taken'].forEach(key => {
67
+ if (saved[key + '_points'] !== undefined && saved[key + '_points'] !== '')
68
+ ACTIONS[key].points = parseFloat(saved[key + '_points']);
69
+ if (saved[key + '_limit'] !== undefined && saved[key + '_limit'] !== '')
70
+ ACTIONS[key].limit = parseInt(saved[key + '_limit'], 10);
71
+ });
72
+
73
+ // Ödüller
74
+ for (let i = 0; i < REWARDS.length; i++) {
75
+ if (saved['reward' + i + '_name']) REWARDS[i].name = saved['reward' + i + '_name'];
76
+ if (saved['reward' + i + '_cost'] !== undefined && saved['reward' + i + '_cost'] !== '')
77
+ REWARDS[i].cost = parseInt(saved['reward' + i + '_cost'], 10);
78
+ }
79
+
80
+ // Grup Bonusları
81
+ if (saved.bonus_premium !== undefined && saved.bonus_premium !== '')
82
+ GROUP_BONUSES['Premium'] = parseInt(saved.bonus_premium, 10);
83
+ if (saved.bonus_vip !== undefined && saved.bonus_vip !== '')
84
+ GROUP_BONUSES['VIP'] = parseInt(saved.bonus_vip, 10);
85
+
86
+ } catch (err) {
87
+ console.error('[NIKI] Ayarlar yüklenirken hata:', err);
88
+ }
89
+ }
90
+
48
91
  // =========================
49
92
  // 🛠 YARDIMCI FONKSİYONLAR
50
93
  // =========================
@@ -275,6 +318,16 @@ Plugin.init = async function (params) {
275
318
  const router = params.router;
276
319
  const middleware = params.middleware;
277
320
 
321
+ // DB'den ayarları yükle
322
+ await loadAndApplySettings();
323
+
324
+ // ADMIN PANEL ROTALARI
325
+ function renderAdmin(req, res) {
326
+ res.render('admin/plugins/niki-loyalty', { title: 'Niki Loyalty Ayarları' });
327
+ }
328
+ router.get('/admin/plugins/niki-loyalty', middleware.admin.buildHeader, renderAdmin);
329
+ router.get('/api/admin/plugins/niki-loyalty', renderAdmin);
330
+
278
331
  // 1) HEARTBEAT (Artık "Okuma" Puanı veriyor)
279
332
  // Client-side script her 30-60 saniyede bir bu adrese istek atmalıdır.
280
333
  router.post('/api/niki-loyalty/heartbeat', middleware.ensureLoggedIn, async (req, res) => {
@@ -559,6 +612,15 @@ Plugin.addScripts = async function (scripts) {
559
612
  return scripts;
560
613
  };
561
614
 
615
+ Plugin.addAdminNavigation = async function (header) {
616
+ header.plugins.push({
617
+ route: '/plugins/niki-loyalty',
618
+ icon: 'fa-coffee',
619
+ name: 'Niki Loyalty',
620
+ });
621
+ return header;
622
+ };
623
+
562
624
  Plugin.addNavigation = async function (nav) {
563
625
  nav.push({
564
626
  route: '/niki-wallet',
@@ -890,6 +952,16 @@ Plugin.adminGetStats = async function (socket, data) {
890
952
  };
891
953
  };
892
954
 
955
+ // 6) AYARLARI YENİDEN YÜKLE (Admin panelden kaydet sonrası)
956
+ Plugin.reloadSettings = async function (socket) {
957
+ const uid = socket.uid;
958
+ if (!uid) throw new Error('Giriş yapmalısınız.');
959
+ const isAdmin = await user.isAdministrator(uid);
960
+ if (!isAdmin) throw new Error('Yetkisiz Erişim');
961
+ await loadAndApplySettings();
962
+ return { success: true };
963
+ };
964
+
893
965
  // Soket'e kaydet (Client: socket.emit('plugins.niki.getUsers', ...))
894
966
  if (SocketPlugins) {
895
967
  SocketPlugins.niki = {
@@ -898,7 +970,8 @@ if (SocketPlugins) {
898
970
  getStats: Plugin.adminGetStats,
899
971
  scanQR: Plugin.socketScanQR,
900
972
  getKasaHistory: Plugin.socketKasaHistory,
901
- managePoints: Plugin.adminManagePoints
973
+ managePoints: Plugin.adminManagePoints,
974
+ reloadSettings: Plugin.reloadSettings
902
975
  };
903
976
  }
904
977
 
package/niki-prize.txt CHANGED
@@ -5,7 +5,7 @@
5
5
  <i class="fa fa-diamond gold-icon"></i>
6
6
  <span class="widget-title">GÜNLÜK HEDEF</span>
7
7
  </div>
8
- <span class="points-badge" id="widget-user-points">...</span>
8
+ <span class="points-badge" id="widget-user-points">0 ⭐</span>
9
9
  </div>
10
10
 
11
11
  <div class="progress-container">
@@ -13,8 +13,8 @@
13
13
  <div class="progress-bar-fill" id="widget-daily-progress" style="width: 0%;"></div>
14
14
  </div>
15
15
  <div class="progress-text">
16
- <span id="widget-daily-text" class="status-text">Yükleniyor...</span>
17
- <span class="target">Hedef: ...</span>
16
+ <span id="widget-daily-text" class="status-text">0/35 Puan</span>
17
+ <span class="target">Hedef: 35</span>
18
18
  </div>
19
19
  </div>
20
20
  </div>
@@ -24,45 +24,45 @@
24
24
  <div class="icon-box purple-theme"><i class="fa fa-sign-in"></i></div>
25
25
  <div class="item-details">
26
26
  <span class="item-name">Günlük Giriş 👋</span>
27
- <span class="item-sub" id="w-count-login">Giriş Yapılmadı</span>
27
+ <span class="item-sub" id="w-count-login">0/1 Giriş</span>
28
28
  </div>
29
- <div class="item-reward">...</div>
29
+ <div class="item-reward">+5</div>
30
30
  </div>
31
31
 
32
32
  <div class="list-item" id="item-new-topic">
33
33
  <div class="icon-box blue-theme"><i class="fa fa-pencil"></i></div>
34
34
  <div class="item-details">
35
35
  <span class="item-name">Yeni Konu 📝</span>
36
- <span class="item-sub" id="w-count-new_topic">...</span>
36
+ <span class="item-sub" id="w-count-new_topic">0/1 Konu</span>
37
37
  </div>
38
- <div class="item-reward">...</div>
38
+ <div class="item-reward">+5</div>
39
39
  </div>
40
40
 
41
41
  <div class="list-item" id="item-reply">
42
42
  <div class="icon-box green-theme"><i class="fa fa-commenting"></i></div>
43
43
  <div class="item-details">
44
44
  <span class="item-name">Yorum Yazma 💬</span>
45
- <span class="item-sub" id="w-count-reply">...</span>
45
+ <span class="item-sub" id="w-count-reply">0/2 Yorum</span>
46
46
  </div>
47
- <div class="item-reward">...</div>
47
+ <div class="item-reward">+5</div>
48
48
  </div>
49
49
 
50
50
  <div class="list-item" id="item-read">
51
51
  <div class="icon-box orange-theme"><i class="fa fa-book"></i></div>
52
52
  <div class="item-details">
53
53
  <span class="item-name">Konu Okuma 👀</span>
54
- <span class="item-sub" id="w-count-read">...</span>
54
+ <span class="item-sub" id="w-count-read">0/10 Okuma</span>
55
55
  </div>
56
- <div class="item-reward">...</div>
56
+ <div class="item-reward">+1</div>
57
57
  </div>
58
58
 
59
59
  <div class="list-item" id="item-like">
60
60
  <div class="icon-box pink-theme"><i class="fa fa-heart"></i></div>
61
61
  <div class="item-details">
62
62
  <span class="item-name">Beğeni Etkileşimi ❤️🌟</span>
63
- <span class="item-sub" id="w-count-like">...</span>
63
+ <span class="item-sub" id="w-count-like">0/2 Beğeni</span>
64
64
  </div>
65
- <div class="item-reward">...</div>
65
+ <div class="item-reward">+2.5 / +5</div>
66
66
  </div>
67
67
  </div>
68
68
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-niki-loyalty",
3
- "version": "1.5.6",
3
+ "version": "1.5.8",
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
@@ -4,11 +4,18 @@
4
4
  "description": "Niki The Cat Coffee Loyalty System",
5
5
  "url": "https://forum.ieu.app",
6
6
  "library": "./library.js",
7
+ "modules": {
8
+ "../admin/plugins/niki-loyalty.js": "static/lib/admin.js"
9
+ },
7
10
  "hooks": [
8
11
  {
9
12
  "hook": "static:app.load",
10
13
  "method": "init"
11
14
  },
15
+ {
16
+ "hook": "filter:admin.header.build",
17
+ "method": "addAdminNavigation"
18
+ },
12
19
  {
13
20
  "hook": "filter:navigation.available",
14
21
  "method": "addNavigation"
@@ -0,0 +1,35 @@
1
+ 'use strict';
2
+
3
+ define('admin/plugins/niki-loyalty', ['settings', 'alerts'], function (Settings, alerts) {
4
+ var ACP = {};
5
+
6
+ ACP.init = function () {
7
+ Settings.load('niki-loyalty', $('#niki-loyalty-settings'));
8
+
9
+ $('#save').on('click', function () {
10
+ Settings.save('niki-loyalty', $('#niki-loyalty-settings'), function () {
11
+ // Sunucu tarafında ayarları anında uygula
12
+ socket.emit('plugins.niki.reloadSettings', {}, function (err) {
13
+ if (err) {
14
+ return alerts.alert({
15
+ type: 'danger',
16
+ alert_id: 'niki-loyalty-error',
17
+ title: 'Hata',
18
+ message: 'Ayarlar kaydedildi ama sunucuya uygulanamadı. NodeBB\'yi yeniden başlatın.',
19
+ timeout: 5000,
20
+ });
21
+ }
22
+ alerts.alert({
23
+ type: 'success',
24
+ alert_id: 'niki-loyalty-saved',
25
+ title: 'Ayarlar Kaydedildi',
26
+ message: 'Niki Loyalty ayarları kaydedildi ve anında uygulandı.',
27
+ timeout: 2500,
28
+ });
29
+ });
30
+ });
31
+ });
32
+ };
33
+
34
+ return ACP;
35
+ });
@@ -0,0 +1,135 @@
1
+ <div class="acp-page-container">
2
+ <div class="col-12 col-md-10 col-lg-8 px-0 mx-auto">
3
+
4
+ <div class="d-flex justify-content-between align-items-center mb-4">
5
+ <h4 class="fw-bold mb-0"><i class="fa fa-coffee text-warning"></i> Niki Loyalty Ayarları</h4>
6
+ <button id="save" class="btn btn-primary btn-sm">
7
+ <i class="fa fa-save"></i> Kaydet
8
+ </button>
9
+ </div>
10
+
11
+ <form id="niki-loyalty-settings">
12
+
13
+ <!-- GENEL AYARLAR -->
14
+ <div class="card mb-4">
15
+ <div class="card-header fw-bold"><i class="fa fa-cog"></i> Genel Ayarlar</div>
16
+ <div class="card-body">
17
+ <div class="row">
18
+ <div class="col-md-6 mb-3">
19
+ <label class="form-label fw-semibold">Günlük Maksimum Puan Limiti</label>
20
+ <input type="number" class="form-control" data-key="dailyCap" placeholder="35">
21
+ <div class="form-text">Bir kullanıcının günde kazanabileceği maksimum puan.</div>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </div>
26
+
27
+ <!-- PUAN TABLOSU -->
28
+ <div class="card mb-4">
29
+ <div class="card-header fw-bold"><i class="fa fa-star text-warning"></i> Puan Tablosu</div>
30
+ <div class="card-body">
31
+ <div class="table-responsive">
32
+ <table class="table table-hover align-middle mb-0">
33
+ <thead>
34
+ <tr>
35
+ <th style="width:30%">Aksiyon</th>
36
+ <th style="width:35%">Puan</th>
37
+ <th style="width:35%">Günlük Limit</th>
38
+ </tr>
39
+ </thead>
40
+ <tbody>
41
+ <tr>
42
+ <td><i class="fa fa-sign-in text-purple"></i> Günlük Giriş</td>
43
+ <td><input type="number" step="0.5" class="form-control form-control-sm" data-key="login_points" placeholder="5"></td>
44
+ <td><input type="number" class="form-control form-control-sm" data-key="login_limit" placeholder="1"></td>
45
+ </tr>
46
+ <tr>
47
+ <td><i class="fa fa-pencil text-primary"></i> Yeni Konu</td>
48
+ <td><input type="number" step="0.5" class="form-control form-control-sm" data-key="new_topic_points" placeholder="5"></td>
49
+ <td><input type="number" class="form-control form-control-sm" data-key="new_topic_limit" placeholder="1"></td>
50
+ </tr>
51
+ <tr>
52
+ <td><i class="fa fa-commenting text-success"></i> Yorum Yazma</td>
53
+ <td><input type="number" step="0.5" class="form-control form-control-sm" data-key="reply_points" placeholder="5"></td>
54
+ <td><input type="number" class="form-control form-control-sm" data-key="reply_limit" placeholder="2"></td>
55
+ </tr>
56
+ <tr>
57
+ <td><i class="fa fa-book text-warning"></i> Konu Okuma</td>
58
+ <td><input type="number" step="0.5" class="form-control form-control-sm" data-key="read_points" placeholder="1"></td>
59
+ <td><input type="number" class="form-control form-control-sm" data-key="read_limit" placeholder="10"></td>
60
+ </tr>
61
+ <tr>
62
+ <td><i class="fa fa-heart text-danger"></i> Beğeni Atma</td>
63
+ <td><input type="number" step="0.5" class="form-control form-control-sm" data-key="like_given_points" placeholder="2.5"></td>
64
+ <td><input type="number" class="form-control form-control-sm" data-key="like_given_limit" placeholder="2"></td>
65
+ </tr>
66
+ <tr>
67
+ <td><i class="fa fa-star text-info"></i> Beğeni Alma</td>
68
+ <td><input type="number" step="0.5" class="form-control form-control-sm" data-key="like_taken_points" placeholder="5"></td>
69
+ <td><input type="number" class="form-control form-control-sm" data-key="like_taken_limit" placeholder="2"></td>
70
+ </tr>
71
+ </tbody>
72
+ </table>
73
+ </div>
74
+ <div class="form-text mt-2">Placeholder'daki değerler varsayılan değerlerdir. Boş bırakırsanız varsayılan kullanılır.</div>
75
+ </div>
76
+ </div>
77
+
78
+ <!-- ÖDÜLLER -->
79
+ <div class="card mb-4">
80
+ <div class="card-header fw-bold"><i class="fa fa-gift text-danger"></i> Ödüller</div>
81
+ <div class="card-body">
82
+ <div class="table-responsive">
83
+ <table class="table table-hover align-middle mb-0">
84
+ <thead>
85
+ <tr>
86
+ <th style="width:60%">Ödül Adı</th>
87
+ <th style="width:40%">Gerekli Puan</th>
88
+ </tr>
89
+ </thead>
90
+ <tbody>
91
+ <tr>
92
+ <td><input type="text" class="form-control form-control-sm" data-key="reward0_name" placeholder="Ücretsiz Kahve ☕"></td>
93
+ <td><input type="number" class="form-control form-control-sm" data-key="reward0_cost" placeholder="250"></td>
94
+ </tr>
95
+ <tr>
96
+ <td><input type="text" class="form-control form-control-sm" data-key="reward1_name" placeholder="%60 İndirimli Kahve"></td>
97
+ <td><input type="number" class="form-control form-control-sm" data-key="reward1_cost" placeholder="180"></td>
98
+ </tr>
99
+ <tr>
100
+ <td><input type="text" class="form-control form-control-sm" data-key="reward2_name" placeholder="%30 İndirimli Kahve"></td>
101
+ <td><input type="number" class="form-control form-control-sm" data-key="reward2_cost" placeholder="120"></td>
102
+ </tr>
103
+ <tr>
104
+ <td><input type="text" class="form-control form-control-sm" data-key="reward3_name" placeholder="1 Kurabiye 🍪"></td>
105
+ <td><input type="number" class="form-control form-control-sm" data-key="reward3_cost" placeholder="60"></td>
106
+ </tr>
107
+ </tbody>
108
+ </table>
109
+ </div>
110
+ </div>
111
+ </div>
112
+
113
+ <!-- GRUP BONUSLARI -->
114
+ <div class="card mb-4">
115
+ <div class="card-header fw-bold"><i class="fa fa-users text-success"></i> Grup Katılım Bonusları</div>
116
+ <div class="card-body">
117
+ <div class="row">
118
+ <div class="col-md-6 mb-3">
119
+ <label class="form-label fw-semibold">Premium Grup Bonusu</label>
120
+ <input type="number" class="form-control" data-key="bonus_premium" placeholder="30">
121
+ <div class="form-text">Premium grubuna katılan kullanıcıya verilecek bonus puan.</div>
122
+ </div>
123
+ <div class="col-md-6 mb-3">
124
+ <label class="form-label fw-semibold">VIP Grup Bonusu</label>
125
+ <input type="number" class="form-control" data-key="bonus_vip" placeholder="60">
126
+ <div class="form-text">VIP grubuna katılan kullanıcıya verilecek bonus puan.</div>
127
+ </div>
128
+ </div>
129
+ </div>
130
+ </div>
131
+
132
+ </form>
133
+
134
+ </div>
135
+ </div>