publish application settings (not documents) in Meteor - javascript

I have a couple settings which I need in my application. Now I want to make a couple of them available on the client. So I did:
Meteor.startup(function () {
Meteor.publish('settings', function () {
return {
isAuth: false
}
});
And I've a subscription like
Meteor.subscribe('settings');
This doesn't work at all, somehow I have the feeling this only works for Collections. So the question is how can I get these settings in the client. Also, these settings are needed to render stuff, so I need this data during init!

Save the settings in a shared js file
/shared/const.js:
Global.settings = {
'Something'
};
The publish/subscribe system is only ment to be used for collections.
Although on a side note isAuth doesn't really sound like a setting but a session variable./

If it's okay to put those configuration settings in code, then just do what Marco says.
If you want to specify them in a JSON configuration file, use Meteor.settings - anything in the public field in the configuration file is available on the client in Meteor.settings.public.
It is possible to do this with publish/subscribe, but it's probably overkill:
// On the server
Meteor.publish("applicationSettings", function () {
this.added("settings", "arbitrary_string", {isAuth: true});
this.ready();
});
// On the client
Settings = new Meteor.Collection("settings"); // ONLY on the client
Meteor.subscribe("applicationSettings");
// after subscription is ready,
// Settings.findOne() returns {_id: "arbitrary_string", isAuth: true}

Related

How to create a custom route in Sails JS

I'm trying to create a custom route in Sails and according to their documentation, if I add the following in config/routes.js:
'post /api/signin': 'AuthController.index',
The request would be dealt with by the index action in the AuthController but that doesn't seems to work at all. When I try the /api/login in Postman, I get nothing back.
Please note that I've added restPrefix: '/api' in my config/blueprints.js. Please note I'm using Sails 0.12.x
What am I missing here?
Since you are pointing to a controller with method index on it, you need to add it to your controllers and send a JSON response from there, (since you are using post). here is a simple example
config/routes.js
'post /api/signin': 'AuthController.index',
api/controllers/AuthController.js
module.exports = {
index: function(req, res) {
var id = req.param('id');
if(!id) {
return res.json(400, { error: 'invalid company name or token'});
}
/* validate login..*/
res.json(200, {data: "success"};
}
}
Update
Since you already have the above its probably caused by the blueprints you have.
Blueprint shortcut routes
Shortcut routes are activated by default in new Sails apps, and can be
turned off by setting sails.config.blueprints.shortcuts to false
typically in /config/blueprints.js.
Sails creates shortcut routes for any controller/model pair with the
same identity. Note that the same action is executed for similar
RESTful/shortcut routes. For example, the POST /user and GET
/user/create routes that Sails creates when it loads
api/controllers/UserController.js and api/models/User.js will
respond by running the same code (even if you override the blueprint
action)
with that being said from sails blueprint documentation, maybe turning off shortcuts and remove the prefix you've added.
possibly the shortcuts are looking elsewhere other than your controllers thus returning 404.
the prefix is being added to your blueprint connected route, hence you need /api/api/signin to access it?
Note
I am unable to replicate your issue on my computer as its working fine over here. but i have all blueprint settings turned off.
module.exports.blueprints = {
actions: false,
rest: false,
shortcuts: false,
// prefix: '',
pluralize: false,
populate: false,
autoWatch: false,
};

Session cookies not working in Electron

I'm looking at implementing a login system in an Electron[0] application which I'm building but getting stuck on the part of handling the session. Basically I want to store the users session so it is persisted between application restarts (if "Remember me" is enabled).
I have to make use of an existing back-end which works with cookie authentication and I'm not able to change anything there.
From the Electron documentation on the Session object[1] I gathered that I should be using a partition like f.e. persist:someName in order to have a persistent storage, but this is not persisted between application restarts as it seems.
The way I currently set the cookie is as follows:
// main-process/login.js
const session = require('electron').session;
const currentSession = session.fromPartition('persist:someName').cookies;
currentSession.set({
name: 'myCookie',
url: 'https://www.example.com',
value: 'loggedin=1',
expirationDate: 1531036000
}, function(error) {
console.log('Cookie set');
if (error) {
console.dir(error);
}
});
After running this, I see the Cookie set output, but when restarting the app and running the following code:
// main.js
const session = require('electron').session;
const currentSession = session.fromPartition('persist:someName').cookies;
currentSession.get({}, function(error, cookies) {
console.dir(cookies);
if (error) {
console.dir(error);
}
});
The output returned is [].
Any pointers as to what I'm doing wrong or need to do differently would be highly appreciated!
[0] http://electron.atom.io
[1] http://electron.atom.io/docs/api/session/
An alternative might be to take a look at electron-json-storage. Using this plugin, you can write JSON to a system file throughout the user experience and then recall that file on the application load to replace the user "state".

PouchDB - Lazily fetch and replicate documents

TL;DR: I want a PouchDB db that acts like Ember Data: fetch from the local store first, and if not found, go to the remote. Replicate only that document in both cases.
I have a single document type called Post in my PouchDB/CouchDB servers. I want PouchDB to look at the local store, and if it has the document, return the document and start replicating. If not, go to the remote CouchDB server, fetch the document, store it in the local PouchDB instance, then start replicating only that document. I don't want to replicate the entire DB in this case, only things the user has already fetched.
I could achieve it by writing something like this:
var local = new PouchDB('local');
var remote = new PouchDB('http://localhost:5984/posts');
function getDocument(id) {
return local.get(id).catch(function(err) {
if (err.status === 404) {
return remote.get(id).then(function(doc) {
return local.put(id);
});
}
throw error;
});
}
This doesn't handle the replication issue either, but it's the general direction of what I want to do.
I can write this code myself I guess, but I'm wondering if there's some built-in way to do this.
Unfortunately what you describe doesn't quite exist (at least as a built-in function). You can definitely fall back from local to remote using the code above (which is perfect BTW :)), but local.put() will give you problems, because the local doc will end up with a different _rev than the remote doc, which could mess with replication later on down the line (it would be interpreted as a conflict).
You should be able to use {revs: true} to fetch the doc with its revision history, then insert with {new_edits: false} to properly replicate the missing doc, while preserving revision history (this is what the replicator does under the hood). That would look like this:
var local = new PouchDB('local');
var remote = new PouchDB('http://localhost:5984/posts');
function getDocument(id) {
return local.get(id).catch(function(err) {
if (err.status === 404) {
// revs: true gives us the critical "_revisions" object,
// which contains the revision history metadata
return remote.get(id, {revs: true}).then(function(doc) {
// new_edits: false inserts the doc while preserving revision
// history, which is equivalent to what replication does
return local.bulkDocs([doc], {new_edits: false});
}).then(function () {
return local.get(id); // finally, return the doc to the user
});
}
throw error;
});
}
That should work! Let me know if that helps.

Where to add role based authentication to MeanJS app?

I have a meanjs starter template (with yeoman generator).
Where can I add specific permissions to my modules? For instance,
'use strict';
// Configuring the Articles module
angular.module('adminpanel').run(['Menus',
function(Menus) {
// Set top bar menu items
//Menus.addMenuItem('topbar', 'admin panel', 'adminpanel/', 'adminpanel');
Menus.addMenuItem('topbar', 'Admin Panel', 'adminpanel', 'dropdown', '/buildings(/create)?');
Menus.addSubMenuItem('topbar', 'adminpanel', 'List Collections', 'adminpanel/collections');
}
]);
and the routes like so
'use strict';
//Setting up route
angular.module('adminpanel').config(['$stateProvider',
function($stateProvider) {
// Adminpanels state routing
$stateProvider.
state('listCollections', {
url: '/adminpanel/collections',
templateUrl: 'modules/adminpanels/views/list-collections.client.view.html'
}).
state('showCollection', {
url: '/adminpanel/collections/:collectionName',
templateUrl: 'modules/adminpanels/views/show-collection.client.view.html'
}).
state('showCollectionItem', {
url: '/adminpanel/collections/:collectionName/:itemId',
templateUrl: 'modules/adminpanels/views/show-item.client.view.html'
});
}
]);
Are these the correct places to add role-based authentication (on the client side), with added measure on the serverside (I've already done that)?
Does anybody know how I can add an option to the Menus.(some function), such as 'admin.hasPermission', without breaking it? Any resources on this sort of thing?
Thanks for the help!
I don't believe it is right practice to put your authentication, authorization code at the client side as well as server side. They should be on the server side only.
The point is, you have to replicate your authentication and authorization code in the client, anyone can read your mechanism to handle these situation and once a loophole is discovered, it would simply be followed by your server code as well.
I believe authentication and authorization logic should be restricted to server side only. If I am up against someone professional, it would at least make his task tougher.
In case you insist, you can create a wrapper around $http service, maintain a key value pair of what role can do what, and ensure all AJAX request go through your wrapper service where you can check whether it should be allowed. If yes, you can simply forward the request using $http and if not, throw an error.
Not sure about any previous version, but with version 0.4.0 there are parameter in the client config to control the visibility:
If you set isPublic: false and add a roles array you can set the user that can see the menu entry:
// Add the dropdown listCollentcions item
Menus.addSubMenuItem('topbar', 'adminpanel', {
title: 'listCollections',
isPublic: false,
roles:['admin'],
state: 'adminpanel.listCollections'
});
The implementation is in the core module (menu.client.services.js):
// A private function for rendering decision
var shouldRender = function(user) {
if (user) {
if (!!~this.roles.indexOf('*')) {
return true;
} else {
for (var userRoleIndex in user.roles) {
for (var roleIndex in this.roles) {
if (this.roles[roleIndex] === user.roles[userRoleIndex]) {
return true;
}
}
}
}
} else {
return this.isPublic;
}
return false;
};
Maybe you can give version 0.4.0 a try or have a look at the code and try to implement it urself.

how to load documents when needed in Meteor

In my meteor app I have a couple of publish/subscribe setup. Now I need to have an other for all users in the system. Now I don't need this information all the time, only when the user opens the configuration overlay. What is the preferred way to load the data on a specific user action (click on a button for example).
I'm also wondering about pagination, in case the number of users is huge, is something like this possible ?
You can always use Meteor.call()
http://docs.meteor.com/#meteor_call
You declare Meteor.call on the client and the method on the server. You can return any data you want,
// client
Meteor.call('getData', function(error, data) {
// do something with data
})
// server
Meteor.methods({
getData: function() {
// return some data
}
});
For pagination, look into using the Reactive Tables package on Atmosphere / Meteorite.

Categories