Skip to content

Plugin Development

Have a question about building a plugin? Ask here
424 Topics 1.9k Posts
  • Getting a valid session for a Socket.IO app

    8
    1 Votes
    8 Posts
    4k Views
    yariplusY

    Okay! It works perfect now that I GET the Cookie first. It was pretty easy using the OkHttp3 library, which was already a dependent of SocketIO, so I didn't have to add any more dependencies.

    I'm not sure if this is useful to anyone else, but here is my test app.

    package com.radiofreederp.nodebbapp; import io.socket.client.Ack; import io.socket.client.IO; import io.socket.client.Manager; import io.socket.client.Socket; import io.socket.emitter.Emitter; import io.socket.engineio.client.Transport; import okhttp3.*; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.net.URISyntaxException; import java.util.Arrays; import java.util.List; import java.util.Map; public class NodeBBApp { private String url; private OkHttpClient client = new OkHttpClient(); private String cookie; private Socket socket; NodeBBApp(String url) { this.url = url; } private void getCookie() throws IOException { Request request = new Request.Builder().url(url).build(); Response response = client.newCall(request).execute(); cookie = response.headers().get("Set-Cookie"); } private void connectSocket() throws URISyntaxException { socket = IO.socket(url); // Send the session cookie with requests. socket.io().on(Manager.EVENT_TRANSPORT, new Emitter.Listener() { @Override public void call(Object... args) { Transport transport = (Transport)args[0]; transport.on(Transport.EVENT_REQUEST_HEADERS, new Emitter.Listener() { @Override public void call(Object... args) { @SuppressWarnings("unchecked") Map<String, List<String>> headers = (Map<String, List<String>>)args[0]; headers.put("Cookie", Arrays.asList(cookie)); } }); } }); socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() { @Override public void call(Object... objects) { JSONObject data = new JSONObject(); try { data.put("tid", 45); data.put("after", 1); data.put("direction", 1); } catch (JSONException e) { e.printStackTrace(); } socket.emit("topics.loadMore", data, new Ack() { @Override public void call(Object... objects) { System.out.println("Response:"); if (objects.length == 2 && objects[0] == null) { JSONObject data = (JSONObject)objects[1]; try { JSONArray posts = data.getJSONArray("posts"); for (int i = 0; i < posts.length(); i++) { System.out.println(((JSONObject)posts.get(i)).get("content")); } } catch (JSONException e) { e.printStackTrace(); } } socket.close(); } }); } }); socket.connect(); } public static void main(String [] args) { NodeBBApp app = new NodeBBApp("http://www.yaricraft.com/"); try { app.getCookie(); app.connectSocket(); } catch (IOException e) { e.printStackTrace(); } catch (URISyntaxException e) { e.printStackTrace(); } } }
  • This topic is deleted!

    2
    0 Votes
    2 Posts
    104 Views
  • How redirect on user page

    1
    0 Votes
    1 Posts
    1k Views
    D

    Suppose to be in my controller.js and I need to redirect user on the user page.

    ...
    var username=user//it's the username
    res.render('/user/'+username);

    but I obtain an error :

    Object #<IncomingMessage> has no method 'csrfToken'

    "/vagrant/nodebb/public/templates"

    Anyone can help me?

  • Don't create topic based on post text?

    3
    0 Votes
    3 Posts
    2k Views
    F

    Wow awesome, that seems to have done the trick 👍

    Thank you so much for the help.

  • Hook: user is online

    Unsolved
    3
    0 Votes
    3 Posts
    2k Views
    julianJ

    @Nicolas Sorry about the delay 😆

    Consider listening to this socket call, which is sent to all connected clients, it seems.

    socket.on('event:user_status_change', function() { console.log(arguments); });
  • Issues writing a bot plugin

    16
    0 Votes
    16 Posts
    6k Views
    S

    @djensen47 yep I noticed that after reading your OP more carefully. The intention of my bot was a 100% configurable bot that would be able to perform actions based on certain events happening and possibly having filters applied to it. It would be waaaay overkill for your use case.

    It works in theory but I lost motivation and no one seemed interested in it at the time. If it was actually finished it could easily perform tasks like what you're writing a separate plugin for.

  • Resources for plugin development

    1
    0 Votes
    1 Posts
    1k Views
    A

    It has been about a year since I develop a nodebb plugin. I would like to get into plugin development again to add a few features to my makerspace community forum. I know that plugin APIs must have changed a bit since then. Is the developer documentation the best place to start looking to get up to date information about the latest patterns and API's we can use? Are there any other resources I should look at that would help me get up to speed again?

  • Widgets zones in themes

    Solved
    9
    1 Votes
    9 Posts
    4k Views
    E

    @nicolas search for theme exodus.its persona fork with widgets, it not finished but it can help you to see the code

  • two plugin error

    7
    0 Votes
    7 Posts
    2k Views
    ?

    @sanatisharif this explains it then.
    Someone tried to visit your forum over the app and NodeBB did not found the requsted file/URL.

  • Accessing nodeBB functions via Cron Jobs

    7
    0 Votes
    7 Posts
    2k Views
    A

    Thanks, that should do the trick! 🙂

    Gonna post my cronjob as soon as it's ready. Can take a few days, because of christmas.

  • 1 Votes
    11 Posts
    4k Views
    L

    I did a try and i liked it 🙂

    It would be awesome if you could choose what category works that way and what category works on the standard forum way 🙂

  • Disallow editing password, email, ...

    Unsolved
    6
    0 Votes
    6 Posts
    2k Views
    julianJ

    @baris possibly a regression?

  • Checking Group Membership of UID

    Solved
    4
    0 Votes
    4 Posts
    2k Views
    A

    Thanks to both of you for your quick help!

    Both solution do work indeed. As baris pointed out, my failure was returning values from async functions.

    Here is a working example for each solution:

    var Groups = module.parent.require('./groups'); Groups.isMember(uid, 'administrators', function(err, isMember) { if (err) { next(err); } if (isMember) { winston.info('user is an administrator'); Groups.join('administrators', uid); } else { winston.info('user is no administrator'); Groups.leave('administrators', uid); } }); var User = module.parent.require('./user'); var Groups = module.parent.require('./groups'); User.isAdministrator(uid, function(err, isAdmin) { if (err) { next(err); } if (isAdmin) { winston.info('user is an administrator'); Groups.join('administrators', uid); } else { winston.info('user is no administrator'); Groups.leave('administrators', uid); } });
  • 0 Votes
    3 Posts
    1k Views
    S

    Ooops! I'm sorry haha, this headache is giving me coding troubles. Thanks!

  • Saving settings back to the server

    Solved
    4
    0 Votes
    4 Posts
    2k Views
    ferikF

    Very complete answer, thank you.

  • Populating a select in an admin template

    Solved
    2
    0 Votes
    2 Posts
    1k Views
    yariplusY

    You can do that by registering a new settings plugin. Just add the registerPlugin call before you do your settings.sync()

    In the plugin, map the name/value pairs to an array using jQuery, then add the current value to the array.

    settings.registerPlugin({ types: ['mySelect'], // This is your data-type for the <select> set: function (element, value, trim) { // Here we set the options based on the name/value pairs that were saved previously. element = $(element); if (value) value.forEach(function (mapping) { if (mapping.name === 'value') { element.val(mapping.value); }else{ element.append('<option value="'+mapping.value+'">'+mapping.name+'</option>'); } }); ////////////////// // Here you probably want to append any default options if they don't already exist. ////////////////// }, get: function (element, trim, empty) { // Here we get the mapping for saving into the database. element = $(element); var value = []; element.children().each(function (i, option) { option = $(option); value.push({name:option.text(),value:option.attr('value')}); // Get the text and value of each <option> }); value.push({name:'value',value:element.val()}); // Get the current value. // return the mapping. return value; } });

    In the template, you would just do this:

    <select data-type="mySelect" data-key="something"></select>
  • Adding new input field in group mange panel in ACP

    Unsolved
    1
    0 Votes
    1 Posts
    873 Views
    R

    Hi,

    Is there any "clean" way to add input field in group manage panel in ACP?
    Some hook, or function?

    Thanks in advance.

  • Building settings page

    Solved
    4
    0 Votes
    4 Posts
    1k Views
    julianJ

    @ferik

    Plugin exposing its own server-side routes ACP page javascript, can make your ajax call here
  • 0 Votes
    3 Posts
    2k Views
    Tanguy Bodin-HullinT

    Hello Julian. Thank you for your very useful answer.
    The plugin was an old version.
    I just did uninstall then reinstall the last nodebb-api-write plugin (version 3.1.5) on our instance, but now I get the following error :
    /admin/plugins/write-api Introuvable (not found)

  • Reset cache

    Solved
    4
    0 Votes
    4 Posts
    3k Views
    P

    @baris refactored the post tools and topic tools to load on demand for perf reasons, so I think the plugin needs to be updated for this change