PageSourceSearch

https://pupwife.com/projects/chatroom/scripts/moderator.js

js pupwife.com collected 2026-09-30 15:06:53 UTC 14,607 bytes, 413 lines download raw bytes

1/**
2 * Moderator System
3 * Handles moderator privileges and admin actions
4 */
5
6window.ChatroomModerator = (function() {
7    'use strict';
8
9    let moderatorsRef = null;
10    let currentUsername = null;
11    let isModerator = false;
12    let moderatorsList = new Set();
13
14    /**
15     * Initialize moderator system
16     */
17    function init() {
18        if (typeof firebase === 'undefined' || !firebase.database) {
19            console.error('Firebase not available for moderator system');
20            return false;
21        }
22
23        moderatorsRef = firebase.database().ref('chatroom/moderators');
24
25        // Wait for username
26        const checkUsername = setInterval(() => {
27            if (window.__sharedUsername) {
28                currentUsername = window.__sharedUsername.get();
29                if (currentUsername) {
30                    clearInterval(checkUsername);
31                    checkModeratorStatus();
32                    setupModeratorListeners();
33                }
34            }
35        }, 100);
36
37        setTimeout(() => {
38            clearInterval(checkUsername);
39            if (!currentUsername) {
40                currentUsername = 'guest_' + Date.now();
41                checkModeratorStatus();
42                setupModeratorListeners();
43            }
44        }, 5000);
45
46        return true;
47    }
48
49    /**
50     * Check if current user is a moderator
51     */
52    function checkModeratorStatus() {
53        if (!currentUsername || !moderatorsRef) return;
54
55        moderatorsRef.child(currentUsername).once('value', (snapshot) => {
56            const wasModerator = isModerator;
57            isModerator = snapshot.exists() && snapshot.val() === true;
58            
59            if (isModerator !== wasModerator) {
60                updateModeratorUI();
61                if (isModerator) {
62                    console.log('✅ Moderator privileges activated for:', currentUsername);
63                }
64            }
65        });
66    }
67
68    /**
69     * Setup listeners for moderator list changes
70     */
71    function setupModeratorListeners() {
72        if (!moderatorsRef) return;
73
74        moderatorsRef.on('value', (snapshot) => {
75            moderatorsList.clear();
76            const moderators = snapshot.val();
77            
78            if (moderators) {
79                Object.keys(moderators).forEach(username => {
80                    if (moderators[username] === true) {
81                        moderatorsList.add(username);
82                    }
83                });
84            }
85
86            // Re-check current user's status
87            if (currentUsername) {
88                checkModeratorStatus();
89            }
90
91            // Update moderator badges in UI
92            updateModeratorBadges();
93        });
94    }
95
96    /**
97     * Update UI to show moderator controls
98     */
99    function updateModeratorUI() {
100        // Add moderator badge to user info
101        const userInfo = document.getElementById('user-info');
102        if (userInfo) {
103            const existingBadge = userInfo.querySelector('.moderator-badge');
104            if (isModerator && !existingBadge) {
105                const badge = document.createElement('span');
106                badge.className = 'moderator-badge';
107                badge.textContent = '👑';
108                badge.title = 'Moderator';
109                userInfo.appendChild(badge);
110            } else if (!isModerator && existingBadge) {
111                existingBadge.remove();
112            }
113        }
114
115        // Add delete buttons to messages
116        if (isModerator) {
117            addModeratorControlsToMessages();
118        }
119    }
120
121    /**
122     * Show add moderator modal
123     */
124    function showAddModModal() {
125        const username = prompt('Enter username to add as moderator:');
126        if (username && username.trim()) {
127            addModerator(username.trim());
128        }
129    }
130
131    /**
132     * Show remove moderator modal
133     */
134    function showRemoveModModal() {
135        const username = prompt('Enter username to remove as moderator:');
136        if (username && username.trim()) {
137            removeModerator(username.trim());
138        }
139    }
140
141    /**
142     * Add moderator controls to messages
143     */
144    function addModeratorControlsToMessages() {
145        document.querySelectorAll('.message .moderator-actions').forEach(function (el) {
146            el.remove();
147        });
148    }
149
150    /**
151     * Update moderator badges on usernames
152     */
153    function updateModeratorBadges() {
154        document.querySelectorAll('.message-username').forEach(usernameEl => {
155            const username = usernameEl.textContent.trim();
156            const existingBadge = usernameEl.querySelector('.mod-badge');
157            
158            if (moderatorsList.has(username)) {
159                if (!existingBadge) {
160                    const badge = document.createElement('span');
161                    badge.className = 'mod-badge';
162                    badge.textContent = '👑';
163                    badge.title = 'Moderator';
164                    usernameEl.insertBefore(badge, usernameEl.firstChild);
165                }
166            } else if (existingBadge) {
167                existingBadge.remove();
168            }
169        });
170    }
171
172    /**
173     * Delete a message (own messages or moderator)
174     */
175    function deleteMessage(messageId) {
176        if (!confirm('Are you sure you want to delete this message?')) {
177            return;
178        }
179
180        const currentDM = window.ChatroomDMs ? window.ChatroomDMs.getCurrentDM() : null;
181        
182        // Function to find and delete message by id field
183        const findAndDeleteMessage = (messagesRef) => {
184            // Query all messages to find the one with matching id
185            messagesRef.once('value').then((snapshot) => {
186                if (!snapshot.exists()) {
187                    alert('Message not found.');
188                    return;
189                }
190
191                const messages = snapshot.val();
192                let messageKey = null;
193                let message = null;
194
195                // messageId can be the Firebase key (from data-message-id) or the stored id field
196                if (messages[messageId]) {
197                    messageKey = messageId;
198                    message = messages[messageId];
199                } else {
200                    // Fallback: find by id field (legacy)
201                    for (const key in messages) {
202                        if (messages[key].id === messageId) {
203                            messageKey = key;
204                            message = messages[key];
205                            break;
206                        }
207                    }
208                }
209
210                if (!message || !messageKey) {
211                    alert('Message not found.');
212                    return;
213                }
214
215                const messageUsername = message.username || '';
216
217                // Check if user is moderator OR if message belongs to current user
218                if (!isModerator && messageUsername !== currentUsername) {
219                    alert('You can only delete your own messages.');
220                    return;
221                }
222
223                // Delete the message using the Firebase key
224                messagesRef.child(messageKey).remove().then(() => {
225                    console.log('✅ Message deleted');
226                    if (window.ChatroomModerationLog) {
227                        window.ChatroomModerationLog.logMessageDelete({
228                            messageAuthor: messageUsername,
229                            actor: currentUsername,
230                            messageText: message.text || '',
231                            messageId: messageId,
232                            channel: currentDM ? '' : (window.Chatroom ? window.Chatroom.getCurrentChannel() : 'general'),
233                            isDm: !!currentDM,
234                            source: isModerator && messageUsername !== currentUsername ? 'moderator' : 'self'
235                        });
236                    }
237                    // Remove from UI
238                    const messageEl = document.querySelector(`[data-message-id="${messageId}"]`);
239                    if (messageEl) {
240                        messageEl.remove();
241                    }
242
243                    const messagesList = document.getElementById('messages-list');
244                    if (window.ChatroomMessageGrouping && messagesList) {
245                        if (typeof window.ChatroomMessageGrouping.afterMessageRemoved === 'function') {
246                            window.ChatroomMessageGrouping.afterMessageRemoved(messagesList);
247                        } else if (typeof window.ChatroomMessageGrouping.reapplyDom === 'function') {
248                            window.ChatroomMessageGrouping.reapplyDom(messagesList);
249                        }
250                    }
251
252                    if (window.Chatroom && typeof window.Chatroom.removeMessageFromCache === 'function') {
253                        window.Chatroom.removeMessageFromCache(messageId);
254                    }
255                    if (window.ChatroomDMs && typeof window.ChatroomDMs.removeMessageFromCache === 'function') {
256                        window.ChatroomDMs.removeMessageFromCache(messageId);
257                    }
258                }).catch(error => {
259                    console.error('Error deleting message:', error);
260                    alert('Error deleting message. You may not have permission.');
261                });
262            }).catch(error => {
263                console.error('Error fetching messages:', error);
264                alert('Error fetching messages. Please try again.');
265            });
266        };
267
268        if (currentDM) {
269            // Delete DM message
270            const conversationId = [currentUsername, currentDM].sort().join('_');
271            const messagesRef = firebase.database().ref(`chatroom/dms/${conversationId}/messages`);
272            findAndDeleteMessage(messagesRef);
273        } else {
274            // Delete channel message
275            const currentChannel = window.Chatroom ? window.Chatroom.getCurrentChannel() : 'general';
276            const messagesRef = firebase.database().ref(`chatroom/channels/${currentChannel}/messages`);
277            findAndDeleteMessage(messagesRef);
278        }
279    }
280
281    /**
282     * Delete a channel (moderator only)
283     */
284    function deleteChannel(channelId) {
285        if (!isModerator) {
286            alert('You do not have permission to delete channels.');
287            return;
288        }
289
290        if (channelId === 'general') {
291            alert('Cannot delete the general channel.');
292            return;
293        }
294
295        if (!confirm(`Are you sure you want to delete the channel "${channelId}"? This cannot be undone.`)) {
296            return;
297        }
298
299        const channelRef = firebase.database().ref(`chatroom/channels/${channelId}`);
300        channelRef.remove().then(() => {
301            console.log('✅ Channel deleted:', channelId);
302            if (window.ChatroomModerationLog) {
303                window.ChatroomModerationLog.logChannelDelete({
304                    actor: currentUsername,
305                    channel: channelId
306                });
307            }
308            
309            // Switch to general if we were in the deleted channel
310            if (window.Chatroom && window.Chatroom.getCurrentChannel() === channelId) {
311                window.Chatroom.loadChannel('general');
312            }
313        }).catch(error => {
314            console.error('Error deleting channel:', error);
315            alert('Error deleting channel. You may not have permission.');
316        });
317    }
318
319    /**
320     * Add a moderator (only existing moderators can do this)
321     */
322    function addModerator(username) {
323        if (!isModerator) {
324            alert('You do not have permission to add moderators.');
325            return;
326        }
327
328        if (!username || username.trim().length === 0) {
329            alert('Please enter a valid username.');
330            return;
331        }
332
333        const cleanUsername = username.trim();
334        moderatorsRef.child(cleanUsername).set(true).then(() => {
335            console.log('✅ Moderator added:', cleanUsername);
336            alert(`Moderator "${cleanUsername}" has been added.`);
337        }).catch(error => {
338            console.error('Error adding moderator:', error);
339            alert('Error adding moderator. You may not have permission.');
340        });
341    }
342
343    /**
344     * Remove a moderator (only existing moderators can do this)
345     */
346    function removeModerator(username) {
347        if (!isModerator) {
348            alert('You do not have permission to remove moderators.');
349            return;
350        }
351
352        if (username === currentUsername) {
353            alert('You cannot remove yourself as a moderator.');
354            return;
355        }
356
357        if (!confirm(`Are you sure you want to remove "${username}" as a moderator?`)) {
358            return;
359        }
360
361        moderatorsRef.child(username).remove().then(() => {
362            console.log('✅ Moderator removed:', username);
363            alert(`Moderator "${username}" has been removed.`);
364        }).catch(error => {
365            console.error('Error removing moderator:', error);
366            alert('Error removing moderator. You may not have permission.');
367        });
368    }
369
370    /**
371     * Check if user is moderator
372     */
373    function checkIsModerator() {
374        return isModerator;
375    }
376
377    /**
378     * Check if a specific username is a moderator
379     */
380    function isUserModerator(username) {
381        return moderatorsList.has(username);
382    }
383
384    // Initialize on load
385    if (document.readyState === 'loading') {
386        document.addEventListener('DOMContentLoaded', init);
387    } else {
388        init();
389    }
390
391    // Expose functions globally for onclick handlers
392    window.ChatroomModerator = {
393        deleteMessage,
394        deleteChannel,
395        addModerator,
396        removeModerator,
397        checkIsModerator,
398        isUserModerator,
399        showAddModModal,
400        showRemoveModModal,
401        init
402    };
403
404    return {
405        deleteMessage,
406        deleteChannel,
407        addModerator,
408        removeModerator,
409        checkIsModerator,
410        isUserModerator,
411        init
412    };
413})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.