nodebb-plugin-gemach-directory 1.0.1 → 1.0.2

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.
Files changed (2) hide show
  1. package/library.js +81 -5
  2. package/package.json +1 -1
package/library.js CHANGED
@@ -7,13 +7,18 @@
7
7
  * חדש (SocketPlugins.gemachDirectory.submit) - הוא נשמר כ"ממתין" ולא
8
8
  * מוצג לאף אחד עד שמנהל מאשר אותו.
9
9
  * - כשמוצע גמ"ח חדש, נשלחת התראת NodeBB אמיתית (פעמון) לכל חברי קבוצת
10
- * "administrators" שלא כיבו אצל עצמם את ההתראות (ראו getNotifyPreference/
11
- * setNotifyPreference למטה - כל מנהל שולט בעצמו, לא משפיע על אחרים).
10
+ * "administrators" - כדי שמנהל ידע שיש משהו ממתין לאישור.
12
11
  * - אישור/דחייה (SocketPlugins.gemachDirectory.approve/reject) פתוחים רק
13
12
  * למנהלים (נבדק בשרת, לא רק בממשק) - אישור מעביר את הגמ"ח לרשימה
14
13
  * הציבורית באופן מיידי, דחייה מוחקת אותו לגמרי (בלי לצבור "זבל").
15
14
  * - הרשימה הציבורית (SocketPlugins.gemachDirectory.listApproved) פתוחה
16
- * לכולם, כולל גולשים לא-מחוברים.
15
+ * לכולם, כולל גולשים לא-מחוברים. כל גמ"ח מוחזר עם שם המשתמש שהעלה אותו
16
+ * (submittedByUsername/submittedByUserslug) - כדי שהלקוח יוכל להציג
17
+ * קרדיט ("מאת @שם") ולדעת אם המשתמש המחובר הוא הבעלים.
18
+ * - עריכה/מחיקה (SocketPlugins.gemachDirectory.edit/remove) פתוחים למי
19
+ * שהעלה את הגמ"ח (נבדק לפי socket.uid מול השדה submittedBy שנשמר בזמן
20
+ * ההעלאה - אי אפשר לזייף) *או* למנהל - מנהל יכול לערוך/למחוק כל גמ"ח,
21
+ * משתמש רגיל רק את שלו.
17
22
  *
18
23
  * חלק הלקוח (הצגת הרשימה, הטופס להוספה, פאנל האישור למנהל) *לא* נמצא כאן -
19
24
  * הוא קובץ נפרד (gemach-directory-client.js) שמודבק ב-Custom JS של הפורום,
@@ -142,6 +147,48 @@ function registerSocketHandlers() {
142
147
  await db.setObjectField(NOTIFY_PREFS_OBJECT, socket.uid, enabled ? '1' : '0');
143
148
  return { ok: true };
144
149
  };
150
+
151
+ // עריכת גמ"ח קיים - הבעלים (submittedBy) או מנהל בלבד. עובד גם על גמ"ח
152
+ // ממתין וגם על גמ"ח מאושר, בלי לשנות את הסטטוס שלו.
153
+ SocketPlugins.gemachDirectory.edit = async function (socket, data) {
154
+ requireLogin(socket);
155
+ const id = data && data.id;
156
+ if (!id) throw new Error('[[error:invalid-data]]');
157
+
158
+ const gemach = await db.getObject(GEMACH_KEY(id));
159
+ if (!gemach) throw new Error('[[error:no-such-gemach]]');
160
+ await requireOwnerOrAdmin(socket, gemach);
161
+
162
+ const name = sanitizeText(data && data.name, MAX_LENGTHS.name);
163
+ const city = sanitizeText(data && data.city, MAX_LENGTHS.city);
164
+ const category = sanitizeText(data && data.category, MAX_LENGTHS.category);
165
+ const contact = sanitizeText(data && data.contact, MAX_LENGTHS.contact);
166
+ const description = sanitizeText(data && data.description, MAX_LENGTHS.description);
167
+
168
+ if (!name || !city || !category || !contact) {
169
+ throw new Error('[[error:invalid-data]]');
170
+ }
171
+
172
+ await db.setObject(GEMACH_KEY(id), { name, city, category, contact, description });
173
+ return { ok: true };
174
+ };
175
+
176
+ // מחיקת גמ"ח - הבעלים או מנהל בלבד. מוחק לגמרי מכל הרשימות (ממתין/מאושר).
177
+ SocketPlugins.gemachDirectory.remove = async function (socket, data) {
178
+ requireLogin(socket);
179
+ const id = data && data.id;
180
+ if (!id) throw new Error('[[error:invalid-data]]');
181
+
182
+ const gemach = await db.getObject(GEMACH_KEY(id));
183
+ if (!gemach) return { ok: true };
184
+ await requireOwnerOrAdmin(socket, gemach);
185
+
186
+ await db.sortedSetRemove(PENDING_SET, id);
187
+ await db.sortedSetRemove(APPROVED_SET, id);
188
+ await db.delete(GEMACH_KEY(id));
189
+
190
+ return { ok: true };
191
+ };
145
192
  }
146
193
 
147
194
  async function getGemachsFromSet(setKey, newestFirst) {
@@ -149,8 +196,27 @@ async function getGemachsFromSet(setKey, newestFirst) {
149
196
  await db.getSortedSetRevRange(setKey, 0, -1) :
150
197
  await db.getSortedSetRange(setKey, 0, -1);
151
198
  if (!ids.length) return [];
152
- const gemachs = await db.getObjects(ids.map(GEMACH_KEY));
153
- return gemachs.filter(Boolean);
199
+ const gemachs = (await db.getObjects(ids.map(GEMACH_KEY))).filter(Boolean);
200
+ return attachSubmitterInfo(gemachs);
201
+ }
202
+
203
+ // מוסיף לכל גמ"ח את שם המשתמש (לקרדיט) ואת ה-userslug (לקישור לפרופיל)
204
+ // של מי שהעלה אותו - כדי שהלקוח לא יצטרך שאילתת משתמש נפרדת לכל כרטיס.
205
+ async function attachSubmitterInfo(gemachs) {
206
+ const uids = gemachs.map(g => g.submittedBy).filter(Boolean);
207
+ if (!uids.length) return gemachs;
208
+
209
+ const users = await user.getUsersFields(uids, ['uid', 'username', 'userslug']);
210
+ const byUid = {};
211
+ users.forEach((u) => { byUid[u.uid] = u; });
212
+
213
+ return gemachs.map((g) => {
214
+ const submitter = byUid[g.submittedBy];
215
+ return Object.assign({}, g, {
216
+ submittedByUsername: submitter ? submitter.username : null,
217
+ submittedByUserslug: submitter ? submitter.userslug : null,
218
+ });
219
+ });
154
220
  }
155
221
 
156
222
  async function notifyAdmins(gemach) {
@@ -187,6 +253,16 @@ async function requireAdmin(socket) {
187
253
  }
188
254
  }
189
255
 
256
+ // מרשה גישה רק למי שהעלה את הגמ"ח הזה (submittedBy) או למנהל.
257
+ async function requireOwnerOrAdmin(socket, gemach) {
258
+ requireLogin(socket);
259
+ if (String(gemach.submittedBy) === String(socket.uid)) return;
260
+ const isAdmin = await user.isAdministrator(socket.uid);
261
+ if (!isAdmin) {
262
+ throw new Error('[[error:no-privileges]]');
263
+ }
264
+ }
265
+
190
266
  // חיתוך אורך + הסרת תווי בקרה - הגנת שרת בסיסית. ההגנה האמיתית מפני
191
267
  // XSS היא ב-escaping בצד הלקוח בזמן הצגה (ראו gemach-directory-client.js),
192
268
  // כי הנתונים האלה מוזרקים שם ישירות ל-innerHTML.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-gemach-directory",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Server-side storage + admin approval queue for a community gemach directory, filterable by city and category.",
5
5
  "main": "library.js",
6
6
  "keywords": [