Skip to content

NodeBB Plugins

Discussion regarding NodeBB Plugin development.

1.8k Topics 15.0k Posts
Most Voted Plugins

Subcategories


  • Have a question about building a plugin? Ask here
    427 Topics
    2k Posts
    traarrrT

    Hi all,
    Well this is my first time writing a plugin which involves using client side hooks...
    For a start, i would want my plugin to listen to a hook which activates when the topic page is completely loaded and topic tools are loaded too.

    For which I wrote this function:

    'use strict'; /* globals document, $ */ $(document).ready(function () { function alertType(type, message) { require(['alerts'], function (alerts) { alerts[type](message); }); } console.log('nodebb-plugin-quickstart: loaded'); $(window).on('action:topic.loaded', notifyBox); function notifyBox() { console.log("in notify box"); alertType('success', "done") } });

    but this is not working... I can only see "nodebb-plugin-quickstart: loaded" on the console.

    Where am i going wrong here??

  • Need a plugin developed? Ask here!
    222 Topics
    1k Posts
    B

    @baris 👍

  • This topic is deleted!

    1
    0 Votes
    1 Posts
    30 Views
  • 0 Votes
    6 Posts
    671 Views
    murcsM

    @DownPW said in [nodebb-widget-board-stats] discrepancy to dashboard count:

    any news @murcs ?

    i just digged a little deeper for you: „our“ /var/www/nodebb/node_modules/nodebb-widget-board-stats/library.js looks like this

    'use strict'; const async = require('async'); const nconf = module.parent.require('nconf'); const db = require.main.require('./src/database'); const user = require.main.require('./src/user'); const utils = require.main.require('./src/utils'); const socketPlugins = require.main.require('./src/socket.io/plugins'); const socketRooms = require.main.require('./src/socket.io/admin/rooms'); let app; const Widget = module.exports; Widget.init = function (params, callback) { app = params.app; callback(); }; socketPlugins.boardStats = {}; socketPlugins.boardStats.get = function (socket, tid, callback) { getWidgetData(callback); }; function addDots(text) { return String(text).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1.'); }; function getWidgetData(callback) { async.parallel({ global: function (next) { db.getObjectFields('global', ['topicCount', 'postCount', 'userCount'], next); }, latestUser: getLatestUser, activeUsers: getActiveUsers, onlineUsers: Widget.updateAndGetOnlineUsers, activeWithin24h: function (next) { var now = Date.now(); db.sortedSetCount('users:online', now - 86400000, '+inf', next); }, }, function (err, results) { if (err) { return callback(err); } var data = { within24h: results.activeWithin24h, count: addDots(results.onlineUsers.onlineCount + results.onlineUsers.guestCount), members: addDots(results.onlineUsers.onlineCount), guests: addDots(results.onlineUsers.guestCount), list: joinUsers(results.activeUsers), posts: addDots(results.global.postCount ? results.global.postCount : 0), topics: addDots(results.global.topicCount ? results.global.topicCount : 0), registered: addDots(results.global.userCount ? results.global.userCount : 0), latest: joinUsers(results.latestUser), relative_path: nconf.get('relative_path'), mostUsers: { date: (new Date(parseInt(results.onlineUsers.timestamp, 10))).toDateString(), total: results.onlineUsers.total, }, }; callback(null, data); }); } function getActiveUsers(callback) { async.waterfall([ function (next) { user.getUidsFromSet('users:online', 0, 19, next); }, function (uids, next) { user.getUsersFields(uids, ['username', 'userslug', 'status'], next); }, ], function (err, data) { if (err) { return callback(err); } data = data.filter(function (a) { return a.status === 'online'; }); callback(err, data); }); } function getLatestUser(callback) { async.waterfall([ function (next) { user.getUidsFromSet('users:joindate', 0, 0, next); }, function (uids, next) { user.getUsersWithFields(uids, ['username', 'userslug'], 0, next); }, ], callback); } function joinUsers(usersData) { var str = []; for (var i = 0, ii = usersData.length; i < ii; i++) { str.push('<a href="' + nconf.get('relative_path') + '/user/' + usersData[i].userslug + '">' + usersData[i].username + '</a>'); } return str.join(', '); } Widget.updateAndGetOnlineUsers = function (callback) { callback = typeof callback === 'function' ? callback : function () {}; async.waterfall([ function (next) { next(null, socketRooms.getLocalStats().onlineRegisteredCount); }, function (onlineCount, next) { socketRooms.getTotalGuestCount(function (err, guestCount) { if (err) { return next(err); } next(null, { onlineCount: parseInt(onlineCount, 10), guestCount: parseInt(guestCount, 10), }); }); }, function (users, next) { db.getObjectFields('plugin:widget-board-stats', ['total', 'timestamp'], function (err, data) { if (err) { return next(err); } var totalUsers = users.onlineCount + users.guestCount; data.timestamp = data.timestamp || Date.now(); if (parseInt(data.total || 0, 10) <= totalUsers) { data.timestamp = Date.now(); data.total = totalUsers; db.setObject('plugin:widget-board-stats', data); } data.onlineCount = users.onlineCount; data.guestCount = users.guestCount; return next(null, data); }); }, ], callback); }; Widget.renderWidget = function (widget, callback) { getWidgetData(function (err, data) { if (err) { return callback(err); } app.render('widgets/board-stats', data, function (err, html) { if (err) { return callback(err); } widget.html = html; callback(null, widget); }); }); }; Widget.defineWidgets = function (widgets, callback) { var widget = { widget: 'board-stats', name: 'Board Stats', description: 'Classical board stats widget in real-time.', content: 'admin/board-stats', }; app.render(widget.content, {}, function (err, html) { widget.content = html; widgets.push(widget); callback(err, widgets); }); };

    which corresponds with our localized version of /var/www/nodebb/node_modules/nodebb-widget-board-stats/public/templates/widgets/board-stats.tpl

    <div component="widget/board-stats" class="widget-board-stats" style="border: 1px solid #999"> <h3 style="background: #666; font-size: 15px; font-weight: 500">Folgende Nutzende sind gerade online: <a href="{config.relative_path}/users?section=online">[komplette Liste]</a></h3> <p> Davon sind aktuell <strong component="widget/board-stats/count">{count}</strong> Nutzende aktiv (<strong component="widget/board-stats/members">{members}</strong> Registrierte + <strong component="widget/board-stats/guests">{guests}</strong>G&auml;ste).<br /> <span style="display: block; line-height: 0.5em" >&nbsp;</span> <span component="widget/board-stats/list">{list}</span> <span style="display: block; line-height: 0.5em" >&nbsp;</span> In den letzten 24 Stunden waren <strong component="widget/board-stats/within24h">{within24h}</strong> verschiedene Nutzende eingeloggt. </p> <h3 style="background: #666; font-size: 15px; font-weight: 500">Forum-Statistik</h3> <p> Unsere aktiven registrierten Mitglieder haben <strong component="widget/board-stats/posts">{posts}</strong> Beitr&auml;ge zu <strong component="widget/board-stats/topics">{topics}</strong> Themen verfasst &ndash;<strong component="widget/board-stats/registered">{registered}</strong> Mitglieder sind bei <em>schoenen-dunk.de</em> registriert.<br /> <span style="display: block; line-height: 0.5em" >&nbsp;</span> <span component="widget/board-stats/latest">{latest}</span> ist unser neuestes Mitglied.&nbsp;Herzlich Willkommen!<br /> <span style="display: block; line-height: 0.5em" >&nbsp;</span> Am {mostUsers.date} waren <strong>{mostUsers.total}</strong> Nutzende gleichzeitig online. </p> </div>

    well.  i hope this helps a bit.

    ober!schöne grüße,
    m.

  • 0 Votes
    1 Posts
    95 Views
    R

    As title, But its work on dev mode. how could I solve the problem.

  • 0 Votes
    5 Posts
    820 Views
    呆呆笨笨

    可以参考 https://nomad.justdoless.cn

  • 0 Votes
    5 Posts
    914 Views
    呆呆笨笨

    可以参考 nomad.justdoless.cn

  • 11 Votes
    74 Posts
    16k Views
    phenomlabP

    @baris thanks for this. Really appreciated. We'll wait for 3.2.0 to drop.

  • IMGUR upload issues

    5
    0 Votes
    5 Posts
    379 Views
    phenomlabP

    @DownPW said in IMGUR upload issues:

    IMGUR sucks

    News Flash - it always did

  • 0 Votes
    1 Posts
    110 Views
    Shantur RathoreS

    Hi,

    I am thinking of setting up NodeBB and Ghost and connect them with the plugin for comments.
    At the same time, I want to be able to publish some a tutorial / guide written in one of the NodeBB Topic as an article for Ghost.

    Is this something done by any plugin?

    Thanks

  • chatGPT moderation

    11
    8 Votes
    11 Posts
    1k Views
    omegaO

    AI moderating "conspiracy theories", that's a conspiracy theory confirmed! ☑ 🤣

  • ldap plugin for current version 2.5.2

    20
    0 Votes
    20 Posts
    976 Views
    q16marvinQ

    Hi,

    i have a little Change, that will also leave User when NOT in ldap group:

    groupJoin: (ldapGroup, ldapId, uid, callback) => { winston.verbose("[LDAP] groupJoin " + ldapGroup.cn + " for user " + ldapId + " uid " + uid) nodebb_ldap.createGroup(ldapGroup, (err, groupId) => { if (err) { return callback(err); } let members = ldapGroup.uniqueMember; if (!Array.isArray(members)) { members = [members]; } winston.verbose("[LDAP] groupJoin members " + members && typeof members) let found = false if (members) { members.forEach(member => { if (member && member.indexOf(ldapId) != -1) { found = true } }); } if (found) { const groupsToJoin = [groupId]; if ((master_config.admin_groups || '').split(',').includes(ldapGroup.cn)) { winston.verbose("[LDAP] joins admin group") groupsToJoin.push('administrators'); } if ((master_config.moderator_groups || '').split(',').includes(ldapGroup.cn)) { groupsToJoin.push('Global Moderators'); } return groups.join(groupsToJoin, uid, callback); } else { const groupsToUnJoin = [groupId]; winston.verbose("[LDAP] unjoins group" + ldapGroup.cn + " uid " + uid); return groups.leave(groupsToUnJoin, uid, callback); //callback(); } } ); },

    thats realy cool for use 🙂 maybe someone else will help it 🙂

  • Plugin nodebb-plugin-insult-filter

    8
    0 Votes
    8 Posts
    605 Views
    barisB

    It's published 0.4.8 https://github.com/ninenine/nodebb-plugin-beep/pull/38#issuecomment-1576843703

  • nodebb-plugin-imgur invalid CSRF

    23
    0 Votes
    23 Posts
    2k Views
    barisB

    imgur is temporarily over capacity. Please try again later is an issue on imgurs end. The plugin just sends the image and if it errors shows it in the composer.

  • How to install plugin locally?

    10
    0 Votes
    10 Posts
    4k Views
    B

    @julian But then I get the following, because it's not looking in the right place for the package.json:

    npm ERR! code ENOENT npm ERR! syscall open npm ERR! path /usr/bin/nodebb/nodebb-plugin-btcsso/package.json npm ERR! errno -2 npm ERR! enoent ENOENT: no such file or directory, open '/usr/bin/nodebb/nodebb-plugin-btcsso/package.json' npm ERR! enoent This is related to npm not being able to find a file. npm ERR! enoent npm ERR! A complete log of this run can be found in: /root/.npm/_logs/2023-05-16T09_24_17_811Z-debug-0.log
  • 0 Votes
    3 Posts
    332 Views
    PitaJP

    I suspect the error was caused by a corruption somewhere. I'd suggest deleting node_modules and reinstalling. Maybe even try clearing your npm cache.

  • 0 Votes
    6 Posts
    283 Views
    phenomlabP

    @DownPW Good call. I've done the same 🙂 Great minds and all that...

  • iFramely settings do not save under v3

    8
    0 Votes
    8 Posts
    296 Views
    barisB

    >Error: Failed to lookup view this error almost always means you need a ./nodebb build It means nodebb can't find the template to render in the build folder.

  • 0 Votes
    3 Posts
    189 Views
    phenomlabP

    @baris Perfect. Thanks

  • 4 Votes
    7 Posts
    399 Views
    DownPWD

    Very good. test ASAP 😉

  • video player

    6
    0 Votes
    6 Posts
    313 Views
    q16marvinQ

    and it works immediately, how cool is that! THANKS!

  • How to add topics_list template for widget?

    Solved
    6
    0 Votes
    6 Posts
    337 Views
    B

    This settings for widgets not work on /category and /recent page

    Set the topic IDs you want to display this widget on (separated by commas) Set the category IDs you want to display this widget on (separated by commas)

    Cat Typing GIF