nodebb-plugin:{name}:options structures


  • Plugin & Theme Dev

    Sorry long post with snapshots.

    I find my self saving JSON strings in the DB for few of the nodebb-plugins I wrote. I feel like this is a little fragile.
    Anyone have a better approach?

    See in this example, the options are valid JSON strings, which get parsed on plugin init.
    Screen Shot 2014-01-13 at 2.21.47 PM.png

    See in this example, the External navigation items are also stored as stringified array of objects from a hidden field, then, on admin page load, I parse then populate the fields, in the visible fields, and this is another custom-save button which doesnt submit immediately, but rather populates the new data in a new object, stringifies it, sets it on the hidden field, then $('#save'\).trigger('click'\) (edit: ugh emoji y u do dis?) which is the real saveBtn that Settings listens to its click event.

    Screen Shot 2014-01-12 at 5.38.08 PM.png

    Either way, it's either not user friendly, or not developer friendly... can we make the Settings a little smarter, which with will allow Objects/Sets to be saved in the db, with, of course, some meta data that will dictate how these new Structures will be renders in the admin/plugin/:name pages, like grouping multiple inputs under one object,

    .. i dont know ..



  • When I had the same problem in the rss plugin I just made my own save route https://github.com/barisusakli/nodebb-plugin-rss/blob/master/index.js#L232 so I could save hashes and sets.


  • GNU/Linux Admin

    While not exactly the most graceful, this is how the settings page (and by extension, most of the plugins I write) handle settings to the db:

    	require(['forum/admin/settings'], function(Settings) {
    		Settings.prepare();
    	});
    

    Once prepare()'d, the Settings module will look for all form inputs that have a data-field attribute, and save those values under the config hash. Use namespaces liberally.

    Settings.prepare() also adds an event handler to a button with the id save.

    Example input:

    <div class="form-group">
    	<label for="smartypants">
    		<input type="checkbox" data-field="nodebb-plugin-markdown:options:smartypants" id="smartypants" />
    		Use "smart" typograhic punctuation for things like quotes and dashes.
    	</label>
    </div>
    <div class="form-group">
    	<label for="langPrefix">
    		Prefix for <code>code</code> blocks
    	</label>
    	<input class="form-control" placeholder="lang-" type="text" data-field="nodebb-plugin-markdown:options:langPrefix" id="langPrefix" />
    </div>
    

    Save button:

    <button class="btn btn-lg btn-primary" id="save">Save</button>
    

  • Plugin & Theme Dev

    @julian yea, I figured that out, that's pretty straight forward and simple, but doesn't solve complex options structures.
    @baris sweet! that's what I wanted, thanks! basically, not using Setting.prepare().

    Thanks guys.

    gtg clean up teh code.


  • Plugin & Theme Dev

    ok, the custom api route works great, the one thing I don't like is that I feel like my plugin is now polluting the "global" redis (or mongo)-namespace

    Following the @baris way this is saving the plugin configs as a global object..

      db.setObject('nodebb-plugin-rss:feed:' + feed.url, feed);
      db.setAdd('nodebb-plugin-rss:feeds', feed.url);
    

    so now, some plugins have their config options in the

    #config //object
    

    and others in the global namespace.
    and in one of the plugins I am writing, it has values in both !

    is it just me or that doesn't look right?
    anyway we can nest objects in the actual #config hash? I know redis is string-based but maybe, just maybe, we can abstract that by safely JSON.stringify and JSON.parse based on VALUE typeof, Array.isArray and null|undefined checks.

    ADD: and since there is some performance hit with large numbers of fields, we can restrict that to the 'config' fields/values only. That's the redis example, not too sure about Mongo

            module.setConfigField = function(key, data, callback) {
                  // make sure it's either an Array or Object, but also 'truthy' since typeof null == 'object'
                  if (typeof value == 'object' && !!value) 
                      value = JSON.stringify(value); 
                  redisClient.hset('config', key, value, function(err, res) {
                            if(callback) {
                                    callback(err, res);
                            }
                    });
            };
    
            module.getConfigFields = function(fields, callback) {
                    redisClient.hmget('config', fields, function(err, data){
                        if (err) return callback(err, null);
                        var config = {};
                        for (var i =0; i< fields.length; i++) { 
                            // or maybe use eval
                           // IMPORTANT this is will return a NUMBER for the '0' and '1' configs stored in the DB, which means some code will need to be changed across to check
                            // i.e if ( config.allowGuestPosting === '1'  ) ==TO==> if (config.allowGuestPosting === 1) 
                            // or we backward compatibility we can check if it's a number and convert back to a string if(!isNaN(parseFloat(value)) && isFinite(value))
                            config[fields[i]] = (function(){try { return JSON.parse(data[i]); catch { return data[i]; } })()           
                        }
                    });
            };
    

  • Plugin & Theme Dev

    no opinion yet? I know you're busy, so I didn't want to pollute with another Pull Request, I made this sample Gist of what I'm thinking of. Basically just a way to allow configs to be safely saved a Objects and Arrays

    let me know.

    I'll integrate it in NodeBB src and PullRequest it, if you think that's a potential solution, otherwise, I can keep it out, in each Plugin code :sad:



  • Just had a quick chat with the others and we don't like storing json strings. I think the best way is to store them as global hashes/sets but namespace them with the plugin_id. So store all your plugin config under hashes/sets named like nodebb-plugin-<plugin_id>:myhash or nodebb-plugin-<plugin_id>:myset.

    We are aware that the mentions and markdown plugins are not following this as can be seen from https://github.com/designcreateplay/NodeBB/wiki/Database-Structure. We will fix that after 0.3.0 and store only core settings in the global config hash. Each plugin will have its own set of namespaced structures. Does that sound good?


  • Plugin & Theme Dev

    @baris sounds good. Thank you!


Log in to reply
 

Suggested Topics

| |