what does `program.parse(process.argv)` do in commander.js? - javascript

I want to user commander.js and inquirer.js to ask questions and collect the answer to create a User instance:
// index.js
const mongoose = require('mongoose');
const User = require('./model/user')
const {addUser,listAllUsers,findUserByEmail,updateUser,deleteUser} = require('./model_methods/user_methods')
const { program } = require('commander');
var inquirer = require('inquirer');
// connect to DB
const db = mongoose.connect('mongodb://localhost:27017/myImportantDates', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const questions = [
{
type: 'input',
name: 'email',
message: 'user email'
},
{
type: 'input',
name: 'name',
message: 'user name'
},
{
type: 'input',
name: 'password',
message: 'user password'
},
];
program
.version('0.0.1')
.description('The important dates app');
program
.command('add')
.alias('a')
.description('Add a user')
.action(
inquirer
.prompt(questions)
.then( answers => {
addUser(answers)
})
.catch(err =>{
console.log(error)
})
)
program.parse(process.argv);
When I run it with node index.js add, the questions array ask one question and quit:
#DESKTOP-5920U38:/mnt/c/Users/myApp$ node index.js add
? user email
#DESKTOP-5920U38:/mnt/c/Users/myApp$
When I delete program.parse(process.argv), however, everything works fine, it can return me the new User instance.
I check the documents: https://github.com/tj/commander.js/
Still have no idea what happened. Does anybody know more about this??
What I found just now is that if I put program.parse(process.argv) in the beginning like this in the first set up of the program instance:
program
.version('0.0.1')
.description('The important dates app')
.parse(process.argv);
It works too. But I still don't know why the order matters.

In Node.js, process.argv is an array containing the command line arguments passed when the Node.js process was launched. So, program.parse(process.argv) parses the the command line options for arguments, which is bypassing your inquierer.js prompt. You can leave it out.

program.parse(process.argv) is called after setting up your program. It takes the command line arguments (process.argv) and parses them using your declared program, displaying errors or calling action handlers etc.
Based on your example code, an issue is the action handler takes a function parameter. e.g.
.action(() => {
// code goes here
});

Related

How to make GraphQL playground not display selected options?

I have this view in the playground:
But when I try to add another option to select, I hit CTRL + space and I see every single possible option, even the ones already selected.
How can I stop that from happening? In the dropdown I'd like to see only the options I still can select, not the ones already selected.
Here's my index.ts
const app = express();
(async () => {
const schema = await buildSchema({ resolvers: [ UserResolvers ] });
const server = new ApolloServer({ schema });
server.applyMiddleware({ app });
createConnection({
type: 'mysql',
...dbData,
entities: [
Availability,
Chat,
Meeting,
Message,
Offer,
Tag,
User,
],
synchronize: true,
logging: true,
})
.then(() => {
app.listen({ port: 4000 }, () => {
console.log(
`🚀 Server ready at http://localhost:4000${ server.graphqlPath }`,
);
});
})
.catch((error) => console.log(error));
})();
There is no option to change this behavior. You can open an issue in the GraphiQL repo (GraphQL Playground is effectively deprecated and will be merged into GraphiQL) to request this feature.
However, it's also unlikely that such a feature will ever be supported. Duplicate field names are perfectly valid in GraphQL. In addition, it's not uncommon to request the same field multiple times using a different alias and a different set of arguments for each instance of the field:
query {
activeUsers: users(isActive: true) {
...UserFragment
}
inactiveUsers: users(isActive: false) {
...UserFragment
}
}
In that context, omitting a field from the list of suggestions just because it was already included in the selection set doesn't really make sense.

Node.js Express input validation for two strings between a ':' to be accepted

I have implemented a page where students can enter in a their Coursework Name with its intended milestones. However, I want to add validation that will only allow users to enter using the following method, two strings with a ':' between them. For example - 'Coursework : Milestone'. Any length of string accepted, as long as it ensures there are two strings with a ':' to separate them in the middle as seen in the example. I am very new to Node.js, Express, jQuery and Handlebars and I have searched for ways to do this but none seemed useful. Below is the only code needed.
in the controller file, a section for creating a new input data
const Task = require('../models/task');
create: function(req, res) {
Task
.create(req.body)
.then(result => {
// result.sort(sortTask)
res.json(result)
})
.catch(err => res.json(err));
}
the model file, task.js, for reference
//dependency
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
//data inputted into the database, coursework/milestones section, validation included
const taskSchema = new Schema({
task: {
type: String,
},
completed: {
type: Boolean,
default: false
},
addedAt: {
type: Date,
default: Date.now()
},
});
const Task = module.exports = mongoose.model('Task', taskSchema);
jQuery code to allow these actions to work, in the public folder, eventListeners.js file
$(document).ready(function() {
//index page events
//click even for creating a milestone/coursework
$('#create').on('click', function(e) {
createTask(e);
});
//keypress event that allows milestone?coursework to be created on 'Enter'
$('#task').keypress(function(e) {
if (e.key === 'Enter') {
createTask(e);
}
});
the index.hbs file input section
<input type="text" class="form-control" placeholder="Coursework : Milestone" id="task" autofocus>
RegExp.prototype.test() is what you're looking for. In your use case:
/:/.test(<user input>)

MERN Stack: How to prevent a User from registering (being added to an array) multiple times?

Semi-new developer building a project using the MERN stack.
The app has two models, one for Users and one for Tournaments. Tournament model has an attribute called participants which is an array.
I wrote an Express backend route so that a User can register for Tournaments.participants[].
This looks like:
router.post('/:id', (req, res) => {
Tournament.findById(req.params.id)
.then(tournament => {
tournament.participants.push(req.body);
return tournament.save();
})
.then(savedTournament => res.json(savedTournament))
.catch(err => res.json(err));
});
However, a User can just keep clicking Sign Up and I'd have a bunch of duplicate users, so I'm trying to write a conditional that will disable Sign Up if the user is already in Tournament.participants[].
I tried writing a conditional inside the Express route using Array.includes(req.body) but couldn't hack it.
Looked something like
Tournament.findById(req.params.id)
.then(tournament => {
if (tournament.participants.includes(req.body) {
return res.status(400).json({ msg: "This user already signed up for this tournament" });
} else {
tournament.participants.push(req.body);
return tournament.save();
}
})
.then(savedTournament => res.json(savedTournament))
.catch(err => res.json(err));
I tried different variations as well, like if (tournament.participants.includes(!req.body)) then push(req.body), etc.
And I also tried just rendering a different button if the participants.includes(user) but I believe this should be done on the backend anyway.. I'm open to suggestions.
Can anyone help me out?
In general, you can't use the native comparison operators with objects, includes included:
const foo = { id: 1 };
const bar = [{ id: 1 }];
console.log(bar.includes(foo)); // outputs `false`
You should use some kind of item id in order to check if its already exists:
function isIdIncluded(arr, id) {
return arr.some(x => x.id === id)
}
const foo = { id: 1 };
const bar = [{ id: 1 }];
console.log(isIdIncluded(bar, 1)); // outputs `true`
I assume you are keeping the users's _id in the participants array, and your tournament schema is similar to this:
const tournamentSchema = new mongoose.Schema({
name: String,
participants: Array,
});
Now if you send a request with this body:
{
"user": "5e97255a342f395774f30162" //the user id who wants to participate
}
You can use this code (I just changed the req.body to req.body.user)
Tournament.findById(req.params.id)
.then((tournament) => {
if (tournament.participants.includes(req.body.user)) {
return res.status(400).json({ msg: "This user already signed up for this tournament" });
} else {
tournament.participants.push(req.body.user);
return tournament.save();
}
})
.then((savedTournament) => res.json(savedTournament))
.catch((err) => res.status(500).json(err));
Now when a user first time participates a tournament, the document will be like this:
{
"participants": [
"5e97255a342f395774f30162"
],
"_id": "5e97255a342f395774f30161",
"name": "Chess Tournament"
}
And when the same user tries, the response will be like this with a 400 status code.
{
"msg": "This user already signed up for this tournament"
}
Also please note that, the user id shouldn't be send in the request body, but it must be the user's id who is logged in.

Feathers-mongoose : Get by custom attribute in feathers-mongoose

I have a very basic feathers service which stores data in mongoose using the feathers-mongoose package. The issue is with the get functionality. My model is as follows:
module.exports = function (app) {
const mongooseClient = app.get('mongooseClient');
const { Schema } = mongooseClient;
const messages = new Schema({
message: { type: String, required: true }
}, {
timestamps: true
});
return mongooseClient.model('messages', messages);
};
When the a user runs a GET command :
curl http://localhost:3030/messages/test
I have the following requirements
This essentially tries to convert test to ObjectID. What i would
like it to do is to run a query against the message attribute
{message : "test"} , i am not sure how i can achieve this. There is
not enough documentation for to understand to write or change this
in the hooks. Can some one please help
I want to return a custom error code (http) when a row is not found or does not match some of my criterias. How can i achive this?
Thanks
In a Feathers before hook you can set context.result in which case the original database call will be skipped. So the flow is
In a before get hook, try to find the message by name
If it exists set context.result to what was found
Otherwise do nothing which will return the original get by id
This is how it looks:
async context => {
const messages = context.service.find({
...context.params,
query: {
$limit: 1,
name: context.id
}
});
if (messages.total > 0) {
context.result = messages.data[0];
}
return context;
}
How to create custom errors and set the error code is documented in the Errors API.

client.catch is not a function and role keeps making "new role" instead of name I specify?

I might just be missing something simple, but I've never had this error before and I don't think I edited it enough to cause this problem since it was last functional. The code block below keeps giving me this error at the top of the file:
(node:17592) UnhandledPromiseRejectionWarning: TypeError: client.catch is not a function
I have specified client = new Discord.Client();
The other issue I am having is that I am trying to get the role that is being made by the bot to be the name of the two players/users (challenger vs target format) after the target has accepted the challenge posed by the challenger. It just makes a role named "new role" instead. Any help with either of these problems?
if (message.channel.id === '541736552582086656') return challenged.send("Do you accept the challenge? Please reply with 'accept' or 'deny'.")
.then((newmsg) => {
newmsg.channel.awaitMessages(response => response.content, {
max: 1,
time: 150000,
errors: ['time'],
}).then((collected) => {
// Grabs the first (and only) message from the collection.
const reply = collected.first();
if (reply.content === 'accept'){
reply.channel.send(`You have ***accepted *** the challenge from ${challenger}. Please wait while your battlefield is made...`);
message.author.send(`${target} has accepted your challenge! Please wait while the channel is made for your brawl...`)
var server = message.guild;
var permsName = `${target} vs ${challenger}`;
var name = `${target} vs ${challenger}`;
message.guild.createRole({
data: {
name: permsName,
hoist: true,
color: "#00fffa",
permissions: [] }
}).then(role => {
target.addRole(data, permsName)
challenger.addRole(role, permsName)
// client.catch error occurring below
.catch(error => client.catch(error))
}).catch(error => client.catch(error)).then(
server.createChannel(name, "text")).then(
(channel) => {
channel.setParent("542070913177485323")
})
} else if (reply.content === 'deny') {
reply.channel.send("You have ***denied *** the challenge.")
} else {
reply.channel.send("Your response wasn't valid.");
}
})
})
}
module.exports.help = {
name: "challenge"
}
I have tried looking up the problem and I don't see anything that has helped so far with either issue. They might be related since the catch is after the add role part? Thanks in advance for the help!
Curious if there's a template you copied for this bot? The Discord.Client object does not have any catch method, so calling client.catch() is not going to work.
To clarify, this is fine:
challenger.addRole(role, permsName)
.catch(error => /* do something with this error */);
What can you do with the error? You could print it to console, I suppose:
challenger.addRole(role, permsName)
.catch(error => console.error(error));
But you can't call client.catch(error), because that's not a real method - you can check out the docs for the Client object here.
Regarding the role name, you just have a small error: you don't want to wrap your options object in { data: }, your options object is the data. Just pass them in directly, like so:
message.guild.createRole({
name: permsName,
hoist: true,
color: "#00fffa",
permissions: []
}).then(role => {
Hope that helps!

Categories