Creating First Admin in Node.js App - javascript

I've created my first Node.js API and now I am at the step where I need to have initial admin when I push the code live.
My app works the way that there is one admin which can send invitations to users and users can register only with that invitation. My model looks like this:
var userSchema = new Schema({
"email" : { type: String, unique: true },
"pass" : { type: String, required: true },
"type" : { type: String, required: true },
"invitation" : String
});
Field type can have a value admin or regular. For each user creation, email/invitation check is done so users can't be created without invitation.
One of my thought was to have a check each time when database opens:
var mongoose = require("mongoose");
mongoose.connection.on('open', function(){
// get all users
User.find({}, function(err, data){
// if there are no users at all, create first admin
});
});
Credentials for first admin I would keep in env variables and fetch them like this:
var firstAdminEmail = process.env.FIRST_ADMIN_EMAIL;
var firstAdminPass = process.env.FIRST_ADMIN_PASS;
To prevent invitation check in user creation, I would create a separate function which would ignore invitation in user creation.
What do you think about this? What would be the best practice for creating that first admin?

Related

How to make sql sequelize query with nested relations where clause

Im currently working on a budget tracking web app that has the corresponding database setup
enter image description here
So basically i have multiple transactions reladed to a single account, as well as multiple accounts related to a single user
i want to come up with a sequelize query that allows me to view every transaction done by any account corresponding to a single user
Assuming that you have associations look like this:
// these definitions are simplified for demonstration purposes
User.hasMany(Account);
Account.hasMany(Transaction);
Account.belongsTo(User);
Transaction.belongsTo(Account);
We can get all user's transactions like this:
const transactions = await Transaction.findAll({
include: [{
model: Account,
required: true,
include: [{
model: User,
required: true,
where: {
id: userId // here is the condition on a certain user id
}
}]
}]
})

Refresh Tokens in MongoDB

What is the best solution to remove a refresh token from MongoDB automatically.
On login the user is given a temporary auth token which lasts 30 seconds. They are also given a permanent token, stored in MongoDB, which currently lasts until they log out.
I want to remove the permanent one at the end of every day, but I'm not sure how to do that without having a cron job running (to monitor what time it is). This seems a bit complex for such a small task. Is there a way mongo would know what the time is and then remove the refresh token?
This is how the token collection looks:
Thank you
To auto-delete the MongoDB documents after some time, you should use the TTL(time to live) collection feature documented here.
Essentially, you need to create an index on the collection that stores the token documents. For your use case, you can do something like this:
// This would delete the tokens document after 3600seconds after creation
// You can tweak the time as you wish.
db.tokens.createIndex({ "createdAt": 1 }, { expireAfterSeconds: 3600 });
NodeJS, mongodb.
Just simply create a model for each token.
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const tokenSchema = new Schema({
_userId: {
type: Schema.Types.ObjectId,
required: true,
ref: 'user'
},
token: {
type: String,
required: true
},
expireAt: {
type: Date,
default: Date.now,
index: { expires: 60*60*24 }
}
})
module.exports = mongoose.model('tokens', tokenSchema)

Impossible to create users (or custom-based roles) in Mongo on server NodeJS

I am trying to create users on my database directly from our Express server, using Mongo 3.4 for the database. Here is the code for the server for now:
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://mongo:27017/myDb';
var dbvotes = "collection1";
var dbusers = "collection2";
//Functions for users
app.post('/newUser', function(req, res, db) {
MongoClient.connect(url, function(err, db){
//Ecriture dans la base user
db.collection(dbusers).insertOne( {
"name" : req.body.name,
"surname" : req.body.surname,
"username" : username,
"password" : "pasadmin",
});
//Creation of the user in the DB
db.createUser( { 'user': username, 'pwd': "pasadmin", roles: [] });
db.close();
});
console.log("Inserted a new user in the database.");
res.send("User added. Click precedent to add a new user.");
});
However, whenever the client tries to insert a new user, it is effectively created in the user collections, but not as a user of the database as I get the following error: TypeError: db.createUser is not a function
web_1 | at /app/app.js:47:6.
I have tried to user db.addUser instead, however, this is deprecated since Mongo 2.6 and not working either, and db.adminCommand serves the same error, db.adminCommand is not a function. Before that, I struggled to create custom roles in the database with Node and decided to do it via the Mongo shell as well, but it's not an option when it comes to adding user 1 by 1 in the database.
When I use these functions in the Mongo shell, the commands are working, so I suppose it comes from the way I implemented Mongo within the server (via Docker), or due to some limitations with Javascript. Any idea what could it be?
Thanks in advance to the community!
The proper command would be:
db.addUser( username, password, { roles: [ role ] } );
Where role is some MongoDB role. More info can be found from the source file. It can also be an object in the formation of { role: <string>, db: <string> }, where role is a MongoDB role and db is the string name of the database.
You can also use db.admin().addUser. This would be the logical choice if the user has access to multiple databases or you want a central location of your users.
However, I can't imagine it's a good idea to add system users from your application unless you're developing an actual administrative tool. Normal "users" added to a database would be in your own users collection. A system user is someone who has direct access to your database.

How do I get keystoneJS to run a function once a specific model has been updated?

I want to run a function once I have a new or updated item in a specific KeystoneJS model. How do I do that? Would I add an event... is there an event already? Do I add it in the model or elsewhere?
You can use mongoose middleware as with any non-keystone project. A keystone lists schema can be accessed with .schema, e.g.
var keystone = require('keystone');
var Types = keystone.Field.Types;
var User = new keystone.List('User');
User.add({
name: { type: Types.Name, required: true, index: true },
email: { type: Types.Email, initial: true, required: true, index: true },
});
//do stuff BEFORE the user document is fully saved to the DB
User.schema.pre('save', function(next){
console.log('SAVING USER:', this);
next();
});
//do stuff AFTER the user document has been saved to the DB
User.schema.post('save', function(user){
console.log('USER WAS SAVED:', user);
});
User.defaultColumns = 'name, email';
User.register();
Take a look at mongoose middleware, since some restrictions apply, for instance when doing mass updates the middleware will not run, this is by design in mongoose and has nothing to do with keystone.
KEystoneJS uses mongoose.
When you add new model, the CRUD(change,Replace,Update, Delete) happens naturally in Admin side(http:///keystone
However for non-admin side You need to make Routes, and in routes views you can use mongoose API to do so.
any change in in keystoneJS, can be made working just by restarting the server (nam start)

Fetching different set of models using same type of collection in Backbone

I have a server response that returns the user's id, email, and an array of poll ids that belong to this user. I am trying to get the text of all of the polls belonging to a particular user. I tried passing ajax options to the fetch call, but all of the polls get fetched, not just this user's polls.
Polls is the collection of all polls from all users. A user has to be able to fetch all polls, regardless of which user they belong to (which works fine) and he should also be able to only fetch the polls that belong to them.
API for getting all polls from all users: /api/polls
API for getting a single poll: /api/polls/:poll_id
Is it possible to fetch multiple Backbone models by their ids without having to do a separate fetch request for each of them?
var polls = new Polls();
polls.fetch({
traditional: true,
data: {
poll_ids: idsArr
}
});
Background Code:
var UserSchema = new Schema({
name: String,
email: {
type: String,
required: true,
index: {
unique: true
}
},
polls: [{
type: Schema.Types.ObjectId,
ref: 'Poll'
}]
});
var PollSchema = new Schema({
name: String,
options: [{
text: String
}]
});
If I understood correctly, you need one more API like this : /api/:user_id/polls/ which returns the polls related to specific user.
Create one polls collection globally that points to /api/polls and another one inside the user model that points to /api/:user_id/polls/
var Poll = Backbone.Model.extend({
urlRoot: '/api/polls'
});
var Polls = Backbone.Collection.extend({
model: Poll
});
var User = Backbone.Model.extend({
initialize: function() {},
parse: function(response) {
this.polls = new Polls(response.usersPolls, {
url: '/api/'+ this.id +'/polls/'
});
/*remove polls info if not needed*/
return response;
}
});
var allPolls = new Polls(null, {url:'/api/polls/'})
The collection inside user model will fetch the polls related to user, and the other one will have all the polls.
You should set the urlRoot property of the poll models to /api/polls/ so that their url will be formed correctly like /api/polls/:poll_id rather than /api/:user_id/polls/:poll_id within the user specific polls collection
Another option would be to handle this entirely at client side by having single collection that fetches all the polls which has a method that accepts a user id and filters itself based on the id.
But in this scenario you'll either have to cache the polls before filtering, or fetch all the polls again when you need them after applying a filter.

Categories