You shouldn't need SMTP for the sendgrid mailer. It uses the sendgrid API to send mail messages, and optionally, allows for an inbound webhook to receive messages. Have you looked at the activity logs in the sendgrid console to verify that your requests are being handled? If needed, you can add a console log to the Emailer.send
method in the nodebb-plugin-emailer-sendgrid
index.js
file if you want to debug the message handling.
razibal
Posts
-
nodebb-plugin-emailer-sendgrid not sending emails -
Propagating changes back to usersI ended up adding a child span to hold the tooltip, and just removing the child altogether anytime the event fired. Inserting a new element and then setting the tooltip was the only way to get the tooltip updated correctly (for me). Thanks for the help!
-
Propagating changes back to usersA related question, I am trying to update an existing tooltip when the event fires and it seems to work only sometimes. Currently I am setting the
title
attribute, followed by destroying the tooltip and then calling$el.tooltip(...)
. Is there another way to do this as it seems that the tooltip doesn't always get recreated with the correct text . I do see adata-original-title
attribute, so its clearly setting a tooltip, just retaining the previous text. -
Propagating changes back to usersThat works perfectly, Thanks!
-
Propagating changes back to usersSo basically fire the
event:post_edited
socket event?websockets.in(`topic_${tid}`).emit('event:post_edited', { post: { tid, pid, changed: true, content, }, topic: {}, });
-
Propagating changes back to usersIf my plugin is listening to an action filter for edited posts and, based on the content of the post, sets a custom property on the post, how do I update the view so that it's reflected in the browser in real time?
Currently, it requires a refresh to see the changes, however edited posts are automatically refreshed in real time. Is there an event I need to fire to take advantage of this refresh?
-
How do I log the user in using SSO when redirecting from my application?This is exactly what the Session Sharing plugin does: https://github.com/julianlam/nodebb-plugin-session-sharing
-
NodeBB on Android / PWA@schajuli I usually end up using BrowserStack to debug issues like this. I think they have a free tier.
You will have to use BrowserStack Local since, I assume, you're behind a corporate firewall. You should be able to inspect all network traffic and see if any errors occur. You could also try running Android Studio on your desktop, but that's a little more involved.
-
Topic create and update via API and event sequencingI've been experimenting with creating a decoupled front-end client using the API and have some questions about the sequence of events. I can create topics and reply using the REST API without any issues. However, I'm not clear on the usage of the Socket API. Should I be listening on a socket for a 'success' event? I can see some clients side functions like
updateUserBookmark
that fire when a topic is replied to, how are these triggered? How are other users that might be browsing the topic notified that a reply has been published?
Thanks -
Dark Mode ToggleI agree that this should be built into the default theme. In my case, I added it to my custom theme by adding a script in the
header.tpl
template. The scripts below should be usable as is. It's a little more complex than absolutely neccessary, but in my case I needed to be able to match the mode of the parent site. The modes are kept in sync via a watcher on local storage. The script accepts 3 modes -system, dark and light
. Thesystem
mode matches the OS mode preference. It also alllows to a page to be opened in a specific mode via a search query parameter, for example?theme=light
<script id="setTheme" async=false> function getParameterByName(name, url) { if (!url) url = window.location.href; name = name.replace(/[\[\]]/g, "\\$&"); var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), results = regex.exec(url); if (!results) return null; if (!results[2]) return ''; return decodeURIComponent(results[2].replace(/\+/g, " ")); } function getInitialColorMode() { let persistedColorPreference = getParameterByName('theme', window.location.url); if (persistedColorPreference && typeof persistedColorPreference === 'string') { window.localStorage.setItem('system-theme', persistedColorPreference); } else { persistedColorPreference = window.localStorage.getItem('system-theme'); } const hasPersistedPreference = typeof persistedColorPreference === 'string' && persistedColorPreference != 'system'; if (hasPersistedPreference) { setColors(persistedColorPreference) return persistedColorPreference; } const mql = window.matchMedia('(prefers-color-scheme: dark)'); const hasMediaQueryPreference = typeof mql.matches === 'boolean'; if (hasMediaQueryPreference) { setColors(mql.matches ? 'dark' : 'light') return mql.matches ? 'dark' : 'light'; } setColors('light') return 'light'; } function setColors(value) { if (value == 'dark') { document.documentElement.style.setProperty('--bg-color', '#191919'); document.documentElement.style.setProperty('--color', '#ffffffcc'); document.documentElement.style.setProperty('--nav-bg-color', '#151515'); document.documentElement.style.setProperty('--nav-border', '#b0b0b09c'); } else { document.documentElement.style.setProperty('--bg-color', '#fafafa'); document.documentElement.style.setProperty('--color', '#444444'); document.documentElement.style.setProperty('--nav-bg-color', '#fafafa'); document.documentElement.style.setProperty('--nav-border', '#eeeeee'); } } async function setStart() { document.documentElement.classList.toggle("dark", getInitialColorMode() == 'dark'); document.documentElement.classList.toggle("light", getInitialColorMode() != 'dark'); window.addEventListener('storage', (e) => { if (e.key != 'system-theme') { return; } else { document.documentElement.classList.toggle("dark", getInitialColorMode() == 'dark'); document.documentElement.classList.toggle("light", getInitialColorMode() != 'dark'); } }) const darkMode = window.matchMedia('(prefers-color-scheme: dark)'); darkMode.addListener((event) => { document.documentElement.classList.toggle("dark", getInitialColorMode() == 'dark') document.documentElement.classList.toggle("light", getInitialColorMode() != 'dark') }); } setStart() </script>
-
Clustered NodeBB and plugin socket methodsSo, if I understood you correctly, in order to propagate local variables across instances, I should use pubsub after receiving a hook?
Following this suggestion, I set up the flow like below.
The plugin gets triggered by the ACP save and publishes a notification for the other instances:
socketAdmin.plugins.customMod.save = async function(socket, data) { await db.set('plugins.customMod.settings', JSON.stringify(data)); // perfom required lookups and transformations to data pubsub.publish('plugins.customMod:updated', updatedData); };
And then set up a listener for applying the changes to the local variables in all instances
pubsub.on(`plugins.customMod:updated`, (async (data) => { categoryArticles = data.categoryArticles articleCategories = data.articleCategories shareCategories = data.shareCategories searchableCategories = data.searchableCategories ));
I understand why
socket.emit
should only trigger on a single instance in most cases, but perhaps it would be useful to have a way to automatically trigger on all instances? -
Clustered NodeBB and plugin socket methods@baris That's exactly what I am doing
{ "hook": "action:settings.set.customMod", "method": "updateSettings" }
However, only one instance of the plugin gets triggered. I am trying to follow the event path to debug the issue but I'm not clear on the pubsub architecture. I can see thatpubsub.js
uses Redis via a channel nameddb:${nconf.get('redis:database')}:pubsub_channel
, while thesocket.io
Redis adapter uses multiple channels prefixed with:db:${nconf.get('redis:database')}:adapter_key
? I can listen to thepubsub_channel
and see all the trafficredis db:11:pubsub_channel {"event":"analytics:publish","data":{"local":{"counters":{},"pageViews":0,"pageViewsRegistered":0,"pageViewsGuest":0,"pageViewsBot":0,"uniqueIPCount":0,"uniquevisitors":0}}} redis db:11:pubsub_channel {"event":"analytics:publish","data":{"local":{"counters":{"pageviews:byCid:122":1},"pageViews":1,"pageViewsRegistered":0,"pageViewsGuest":0,"pageViewsBot":1,"uniqueIPCount":0,"uniquevisitors":0}}}
Where does
pubsub.js
fit into the overall architecture? and a followup question, is there a mechanism to trigger execution of a method in all instances of a plugin? Either directly from the client, or by propagating the triggered hook on the one instance that received the hook would work. -
Clustered NodeBB and plugin socket methodsI've verified that both are using Redis for pubsub and the hook data is being received and emitted on both in
src/database/redis/pubsub.js
:self.emit(msg.event, msg.data);
Instance 1
instance 1 mongo-object:cache:del [ 'settings:customMod' ] instance 1 local:cache:del [ 'settings:customMod' ] instance 1 action:settings.set.customMod{ enableQuickReply: 'on', featuredTopic: '', shared: '88,89, 90, 91,105,', searchable: '88, 89, 90, 91,105,', articles: '1, 2, 102, 103, 104', hideSubCategories: 'off', hideCategoryLastPost: 'off' }
Instance 2
instance 2 mongo-object:cache:del [ 'settings:customMod' ] instance 2 local:cache:del [ 'settings:customMod' ] instance 2 action:settings.set.customMod{ enableQuickReply: 'on', featuredTopic: '', shared: '88,89, 90, 91,105,', searchable: '88, 89, 90, 91,105,', articles: '1, 2, 102, 103, 104', hideSubCategories: 'off', hideCategoryLastPost: 'off' }
However, only one instance of the plugin triggers from the hook
-
Clustered NodeBB and plugin socket methodsI'm trying to debug an issue with maintaining sync for plugin settings between nodes of a NodeBB cluster running on 2 different machines. I've set
isCluster
on both instances, however theSocketPlugins
method only triggers on one instance when the hook is fired from the client. Any suggestions on where to look would be much appreciated. -
Page/route changesMy fault. I wasn't calling
ajaxify.go
correctly. All works now. -
Page/route changesThank you! The iframed forum can now use
postMessage
to navigate directly to specific pages in my custom theme. The only missing piece is that the progress bar on the top of the page does not get triggered. Did I miss something? -
Page/route changesI'm familiar with the routing mechanism that frameworks like React and Vue use to change path without requiring a full page refresh. I can see that NodeBB also changes routes without a full refresh. How is this handled? I assume that it involves ajaxify and an API call, but if someone could point me to the relevant code, it would be much appreciated.
-
Standing desks... -
Standing desks...Yeah, I have one in my home office. It might seem counterintuitive, but I feel more refreshed at the end of the day than I would with a "normal" desk. I also pair it with an under-desk treadmill, mainly during zoomcalls. It's quite useful since it feels like I spend most of my day on calls these days.
-
NodeBB on FLOSS Weekly #773 — "Don't do the math"Building on your discussion about the commercial side of forum software in the interview, a distributed architecture could have the added benefit of opening up new markets for nodeBB. Two examples that come to mind are backend services for a commenting platform like Disqus, or a content management system (CMS).