nodebb-plugin-ezoic-infinite 1.6.96 → 1.6.98

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
@@ -7,96 +7,124 @@ const db = require.main.require('./src/database');
7
7
  const SETTINGS_KEY = 'ezoic-infinite';
8
8
  const plugin = {};
9
9
 
10
- async function getSettings() {
11
- return await meta.settings.get(SETTINGS_KEY);
10
+ function normalizeExcludedGroups(value) {
11
+ if (!value) return [];
12
+ if (Array.isArray(value)) return value;
13
+ return String(value).split(',').map(s => s.trim()).filter(Boolean);
12
14
  }
13
15
 
14
- /**
15
- * Vérifie l'exclusion par groupe avec gestion du format NodeBB
16
- */
17
- async function isUserExcluded(uid, excludedGroups) {
18
- if (!uid || uid <= 0) return false;
19
- if (!excludedGroups || (Array.isArray(excludedGroups) && excludedGroups.length === 0)) return false;
20
-
21
- const excludedList = Array.isArray(excludedGroups) ? excludedGroups : [excludedGroups];
22
- const userGroups = await groups.getUserGroupsNames([uid]);
23
-
24
- // userGroups[0] contient le tableau des noms de groupes de l'utilisateur
25
- return excludedList.some(g => userGroups[0].includes(g));
16
+ function parseBool(v, def = false) {
17
+ if (v === undefined || v === null || v === '') return def;
18
+ if (typeof v === 'boolean') return v;
19
+ const s = String(v).toLowerCase();
20
+ return s === '1' || s === 'true' || s === 'on' || s === 'yes';
26
21
  }
27
22
 
28
23
  async function getAllGroups() {
29
- let names = await db.getSortedSetRange('groups:createtime', 0, -1);
30
- if (!names || !names.length) {
31
- names = await db.getSortedSetRange('groups:visible:createtime', 0, -1);
32
- }
33
- const filtered = names.filter(name => !groups.isPrivilegeGroup(name));
34
- const data = await groups.getGroupsData(filtered);
35
- const valid = data.filter(g => g && g.name);
36
- valid.sort((a, b) => String(a.name).localeCompare(String(b.name), undefined, { sensitivity: 'base' }));
37
- return valid;
24
+ let names = await db.getSortedSetRange('groups:createtime', 0, -1);
25
+ if (!names || !names.length) {
26
+ names = await db.getSortedSetRange('groups:visible:createtime', 0, -1);
27
+ }
28
+ const filtered = names.filter(name => !groups.isPrivilegeGroup(name));
29
+ const data = await groups.getGroupsData(filtered);
30
+ // Filter out nulls (groups deleted between the sorted-set read and getGroupsData)
31
+ const valid = data.filter(g => g && g.name);
32
+ valid.sort((a, b) => String(a.name).localeCompare(String(b.name), undefined, { sensitivity: 'base' }));
33
+ return valid;
38
34
  }
35
+ let _settingsCache = null;
36
+ let _settingsCacheAt = 0;
37
+ const SETTINGS_TTL = 30000; // 30s
39
38
 
40
- plugin.init = async ({ router, middleware }) => {
41
- async function render(req, res) {
42
- const settings = await getSettings();
43
- const allGroups = await getAllGroups();
44
-
45
- res.render('admin/plugins/ezoic-infinite', {
46
- title: 'Ezoic Infinite Ads',
47
- ...settings,
48
- // On s'assure que les checkbox sont bien cochées dans l'admin
49
- enableCategoryAds_checked: settings.enableCategoryAds === 'on' ? 'checked' : '',
50
- enableBetweenAds_checked: settings.enableBetweenAds === 'on' ? 'checked' : '',
51
- enableMessageAds_checked: settings.enableMessageAds === 'on' ? 'checked' : '',
52
- allGroups,
53
- });
54
- }
55
-
56
- router.get('/admin/plugins/ezoic-infinite', middleware.admin.buildHeader, render);
57
- router.get('/api/admin/plugins/ezoic-infinite', render);
58
-
59
- // API consommée par le client.js
60
- router.get('/api/plugins/ezoic-infinite/config', async (req, res) => {
61
- const settings = await getSettings();
62
- const excluded = await isUserExcluded(req.uid, settings.excludedGroups);
63
-
64
- res.json({
65
- excluded,
66
- // Pool Accueil
67
- enableCategoryAds: settings.enableCategoryAds === 'on',
68
- showFirstCategoryAd: settings.showFirstCategoryAd === 'on',
69
- categoryPlaceholderIds: settings.categoryPlaceholderIds || "",
70
- intervalCategories: parseInt(settings.intervalCategories, 10) || 5,
71
-
72
- // Pool Topics (Catégories)
73
- enableBetweenAds: settings.enableBetweenAds === 'on',
74
- showFirstTopicAd: settings.showFirstTopicAd === 'on',
75
- placeholderIds: settings.placeholderIds || "",
76
- intervalPosts: parseInt(settings.intervalPosts, 10) || 10,
77
-
78
- // Pool Messages (Topics)
79
- enableMessageAds: settings.enableMessageAds === 'on',
80
- showFirstMessageAd: settings.showFirstMessageAd === 'on',
81
- messagePlaceholderIds: settings.messagePlaceholderIds || "",
82
- messageIntervalPosts: parseInt(settings.messageIntervalPosts, 10) || 10,
83
- });
84
- });
39
+ async function getSettings() {
40
+ const now = Date.now();
41
+ if (_settingsCache && (now - _settingsCacheAt) < SETTINGS_TTL) return _settingsCache;
42
+ const s = await meta.settings.get(SETTINGS_KEY);
43
+ _settingsCacheAt = Date.now();
44
+ _settingsCache = {
45
+ // Between-post ads (simple blocks) in category topic list
46
+ enableBetweenAds: parseBool(s.enableBetweenAds, true),
47
+ showFirstTopicAd: parseBool(s.showFirstTopicAd, false),
48
+ placeholderIds: (s.placeholderIds || '').trim(),
49
+ intervalPosts: Math.max(1, parseInt(s.intervalPosts, 10) || 6),
50
+
51
+ // Home/categories list ads (between categories on / or /categories)
52
+ enableCategoryAds: parseBool(s.enableCategoryAds, false),
53
+ showFirstCategoryAd: parseBool(s.showFirstCategoryAd, false),
54
+ categoryPlaceholderIds: (s.categoryPlaceholderIds || '').trim(),
55
+ intervalCategories: Math.max(1, parseInt(s.intervalCategories, 10) || 4),
56
+
57
+ // "Ad message" between replies (looks like a post)
58
+ enableMessageAds: parseBool(s.enableMessageAds, false),
59
+ showFirstMessageAd: parseBool(s.showFirstMessageAd, false),
60
+ messagePlaceholderIds: (s.messagePlaceholderIds || '').trim(),
61
+ messageIntervalPosts: Math.max(1, parseInt(s.messageIntervalPosts, 10) || 3),
62
+
63
+ excludedGroups: normalizeExcludedGroups(s.excludedGroups),
64
+ };
65
+ return _settingsCache;
66
+ }
67
+
68
+ async function isUserExcluded(uid, excludedGroups) {
69
+ if (!uid || !excludedGroups.length) return false;
70
+ const userGroups = await groups.getUserGroups([uid]);
71
+ return (userGroups[0] || []).some(g => excludedGroups.includes(g.name));
72
+ }
73
+
74
+ plugin.onSettingsSet = function (data) {
75
+ // Invalider le cache dès que les settings de ce plugin sont sauvegardés via l'ACP
76
+ if (data && data.hash === SETTINGS_KEY) {
77
+ _settingsCache = null;
78
+ }
85
79
  };
86
80
 
87
81
  plugin.addAdminNavigation = async (header) => {
88
- header.plugins.push({
89
- route: '/plugins/ezoic-infinite',
90
- icon: 'fa-ad',
91
- name: 'Ezoic Infinite'
92
- });
93
- return header;
82
+ header.plugins = header.plugins || [];
83
+ header.plugins.push({
84
+ route: '/plugins/ezoic-infinite',
85
+ icon: 'fa-ad',
86
+ name: 'Ezoic Infinite Ads'
87
+ });
88
+ return header;
94
89
  };
95
90
 
96
- plugin.onSettingsSet = async (data) => {
97
- if (data.plugin === 'ezoic-infinite') {
98
- // Optionnel : purger un cache si nécessaire
99
- }
91
+ plugin.init = async ({ router, middleware }) => {
92
+ async function render(req, res) {
93
+ const settings = await getSettings();
94
+ const allGroups = await getAllGroups();
95
+
96
+ res.render('admin/plugins/ezoic-infinite', {
97
+ title: 'Ezoic Infinite Ads',
98
+ ...settings,
99
+ enableBetweenAds_checked: settings.enableBetweenAds ? 'checked' : '',
100
+ enableMessageAds_checked: settings.enableMessageAds ? 'checked' : '',
101
+ allGroups,
102
+ });
103
+ }
104
+
105
+ router.get('/admin/plugins/ezoic-infinite', middleware.admin.buildHeader, render);
106
+ router.get('/api/admin/plugins/ezoic-infinite', render);
107
+
108
+ router.get('/api/plugins/ezoic-infinite/config', async (req, res) => {
109
+ const settings = await getSettings();
110
+ const excluded = await isUserExcluded(req.uid, settings.excludedGroups);
111
+
112
+ res.json({
113
+ excluded,
114
+ enableBetweenAds: settings.enableBetweenAds,
115
+ showFirstTopicAd: settings.showFirstTopicAd,
116
+ placeholderIds: settings.placeholderIds,
117
+ intervalPosts: settings.intervalPosts,
118
+ enableCategoryAds: settings.enableCategoryAds,
119
+ showFirstCategoryAd: settings.showFirstCategoryAd,
120
+ categoryPlaceholderIds: settings.categoryPlaceholderIds,
121
+ intervalCategories: settings.intervalCategories,
122
+ enableMessageAds: settings.enableMessageAds,
123
+ showFirstMessageAd: settings.showFirstMessageAd,
124
+ messagePlaceholderIds: settings.messagePlaceholderIds,
125
+ messageIntervalPosts: settings.messageIntervalPosts,
126
+ });
127
+ });
100
128
  };
101
129
 
102
- module.exports = plugin;
130
+ module.exports = plugin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.6.96",
3
+ "version": "1.6.98",
4
4
  "description": "Production-ready Ezoic infinite ads integration for NodeBB 4.x",
5
5
  "main": "library.js",
6
6
  "license": "MIT",