I have a script that I want to run through the Heroku CLI. It's just a simple script to create a user in a postgressql database with Sequelize.
This is the script:
const argv = require('yargs').argv;
const Sequelize = require('sequelize');
const sqlizr = require('sqlizr');
require('dotenv').load();
// Check params
if (!argv.username) { throw new Error('username is required!'); }
if (!argv.password) { throw new Error('password is required!'); }
if (!argv.clientId) { throw new Error('client id is required!'); }
// Init db connection
const sequelize = new Sequelize(
process.env.DB_DATABASE,
process.env.DB_USER,
process.env.DB_PASS,
{
host: process.env.DB_HOST,
port: 5432,
dialect: 'postgres',
logging: false
}
)
var client_id = argv.clientId;
if(argv.clientId === -1){
client_id = 0;
}
console.log(sequelize)
sqlizr(sequelize, 'api/models/**/*.js');
// Check if user exists
console.log('Check is user exists...');
sequelize.models.USERS.count({
where: {
USERNAME: argv.username
}
})
.then(result => {
if (result > 0) {
console.error('user already exists!');
process.exit(1);
}
})
.then(() => {
console.log('Creating user...');
sequelize.models.USERS.create({
USERNAME: argv.username,
PASSWORD: argv.password,
CLNT_ID: client_id,
EMAIL: 'email#email.com',
PHONE: '123456789'
})
.then(result => {
console.log('User created successfully!');
})
.catch(error => {
console.error('Could not create user!', error);
})
.finally(result => {
process.exit(1);
});
});
Everything goes well if I execute this command locally:
node bin/createUser.js --username admin --password admin --clientId -1
But If i try to run this through the Heroku CLI like this:
heroku run bin/createUser.js --username admin --password admin --clientId -1
I get this in the terminal:
bin/createUser.js: line 4: syntax error near unexpected token `('
bin/createUser.js: line 4: `const yargs = require('yargs');'
I can't figure out what I'm doing wrong here. Hopefully someone can help me and explain why this is happening
You forgot to specify node in the command, so I suspect that Heroku is trying to run createUser.js as if it were a shell script.
You may need to install a node.js buildpack to be able to run the program on Heroku, but try:
heroku run node bin/createUser.js --username admin --password admin --clientId -1
Related
I have a node js api that connects with sequelize to a mySQL database. I wrote a script to reset the database every time tests are ran. I am building a CI/CD pipeline and whenever the script is ran i get the following message:
throw new SequelizeErrors.ConnectionError(err);
^
ConnectionError [SequelizeConnectionError]: Connection lost: The server closed the connection.
...
parent: Error: Connection lost: The server closed the connection.
...
at TCP.<anonymous> (node:net:709:12) {
fatal: true,
code: 'PROTOCOL_CONNECTION_LOST'
},
original: Error: Connection lost: The server closed the connection.
This is the part of the pipeline that fails:
tests:
runs-on: ubuntu-20.04
env:
MYSQL_DEVELOPMENT_USER: root
MYSQL_DEVELOPMENT_PASSWORD: ${{ secrets.RootPassword }}
MYSQL_DEVELOPMENT_HOST: localhost
MYSQL_DEVELOPMENT_DATABASE: test
...
- uses: mirromutth/mysql-action#v1.1
with:
mysql root password: ${{ secrets.RootPassword }}
mysql database: test
- name: api testing
run: cd api && npm run test
...
This is the npm run test
"test": "npm run resetDevDb && cross-env NODE_ENV=test jest --verbose"
"resetDevDb" : "cross-env NODE_ENV=development node db/scripts/reset-development-db.js"
The reset database Script:
const resetDb = async () => {
await sequelize.authenticate();
await Book.sync({ force: true });
await Author.sync({ force: true });
await User.sync({ force: true });
await Promise.all(
users.map(async (user) => {
await User.create(user);
})
);
await Promise.all(
books.map(async (book) => {
await Book.create(book);
})
);
await Promise.all(
authors.map(async (author) => {
await Author.create(author);
})
);
console.log("Database reseted");
};
The sequelize config:
const developmentConfig = {
dialect: "mysql",
database: process.env.MYSQL_DEVELOPMENT_DATABASE,
username: process.env.MYSQL_DEVELOPMENT_USER,
password: process.env.MYSQL_DEVELOPMENT_PASSWORD,
host: process.env.MYSQL_DEVELOPMENT_HOST,
logging: console.log,
};
And initialization
const { database, username, password, ...options } = require("./config.js");
const { Sequelize } = require("sequelize");
const sequelize = new Sequelize(database, username, password, options);
module.exports = sequelize;
I have ran this exact pipeline with (I believe) the exact same config and was working fine. After changing the remote repository a few times (And adding the secret.RootPassword) to the new repository I started getting this connection error. From some by hand debugging I figure the error ocurrs during the Book.sync({ force: true }) but I'm not sure if it has something to do with the miromutth/mysql action. Thanks!
Note: When I run npm run test locally everything works great, all the tables drop and are created again and filled, and the tests run and pass normally.
Edit -
Success! I should have RTFM it seems. Using the environmental variables seems to be required to be EXACT to the manual.
Fixed code:
# PostgreSQL Database Infomation
PGDATABASE_TEST = user_db
PGDATABASE = user_db
PGUSER = postgres
PGPASSWORD = password
# PostgreSQL Host and Port Infomation
PGHOST = localhost
PGPORT = 5432
--
I'm using .env variables to connect to a Postgres Database.
When submitting data via Postman to a Express API I receive an error stating the following:
throw new ErrorHandler(error.statusCode, error.message)
^
ErrorHandler: password authentication failed for user "tito"
at UserService.createUserAccount (/home/tito/Documents/GitHub/***/server/services/user.service.js:11:19)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async createUserAccount (/home/tito/Documents/GitHub/***/server/controllers/user.controller.js:11:18) {
status: 'error',
statusCode: undefined
}
As you can see, its using my OS username rather than .env set one. When running node with sudo I get the auth error with root.
My db.js:
require("dotenv").config();
const { Pool } = require("pg");
// Check which Database to use. Live is safe.
const isProduction = process.env.NODE_ENV === 'PRODUCTION';
const database = process.env.NODE_ENV === 'TEST' ? process.env.PG_TEST_DATABASE : process.env.PG_DATABASE;
// Request to Database contructed
const connectionString = `postgresql://${process.env.PG_USER}:${process.env.PG_PASS}#${process.env.PG_HOST}:${process.env.PG_PORT}/${database}`;
// Setup Pool.
const pool = new Pool ({
connectionString: isProduction ? process.env.DATABASE_URL : connectionString,
ssl: isProduction ? { rejectUnauthorized: false } : false
});
console.log(`Ready at : ${connectionString}`)
module.exports = {
query: (text, params) => pool.query(text, params),
end: () => pool.end()
}
My .env:
# Express API Port.
PORT = 5000
# Enviroment - TEST for local. PRODUCTION for live.
NODE_ENV = PRODUCTION
# PostgreSQL Database Infomation
PG_TEST_DATABASE = user_db
PG_DATABASE = user_db
PG_USER = postgres
PG_PASS = password
# PostgreSQL Host and Port Infomation
PG_HOST = localhost
PG_PORT = 5432
My UserService:
const {
createUserAccount_DB
} = require("../db/user.db");
const { ErrorHandler } = require("../helpers/error")
class UserService {
createUserAccount = async (user) => {
try {
return await createUserAccount_DB(user);
} catch (error) {
throw new ErrorHandler(error.statusCode, error.message)
}
}
}
module.exports = new UserService();
And my createUserAccount:
const userService = require("../services/user.service");
const { ErrorHandler } = require("../helpers/error");
const createUserAccount = async (req, res) => {
console.log("Create Account API Triggered");
const { user_name, user_pass, user_email } = req.body;
// const hashedPassword = hashedPassword(password);
const user = await userService.createUserAccount({
user_name,
user_pass,
user_email
});
res.status(201).json({
status: "success",
user,
})
};
Success! I should have RTFM it seems. Using the environmental variables seems to be required to be EXACT to the manual.
Fixed code:
# PostgreSQL Database Infomation
PGDATABASE_TEST = user_db
PGDATABASE = user_db
PGUSER = postgres
PGPASSWORD = password
# PostgreSQL Host and Port Infomation
PGHOST = localhost
PGPORT = 5432
I am making a sign up page and am using express to communicate.
As such, I have an express.js file that when it gets a post it will run a function on my mysql.js file.
Express.js:
//Defining node js libraries
import Express from "express"
import cors from "cors"
import bodyParser from "body-parser"
const app = Express()
const port = 3000
//Import sql connection function
import { run_db } from "./mysql.js"
// We are using our packages here
app.use( bodyParser.json() ); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true}));
app.use(cors())
//Route that handles login logic
app.post('/login', (req, res) =>{
const json_db_value = {
"email": req.body.email.toString(),
"password": req.body.password.toString(),
"username": req.body.username.toString()
}
run_db(json_db_value)
})
//Start your server on a specified port
app.listen(port, ()=>{
console.log(`Server is running on port ${port}`)
})
And here is my mysql.js file
//Import mySql library
import mysql from "mysql"
//Runs sql code through db
export let run_db = (insert_values) => {
//Create connection to database
const db_connect = mysql.createConnection({
host: "localhost",
user: "root",
password: "*******",
database: "store_user_info"
})
//Sql code to execute
const sql_code =
`INSERT INTO Users (email,password,username)
VALUES (
${"'"+insert_values.email+"'"},
${"'"+insert_values.password+"'"},
${"'"+insert_values.username+"'"}
)`
//Run sql code and fetch result
db_connect.connect((err) => {
if (err) throw err
db_connect.query("SELECT * FROM Users",(err,result) => {
if (err) throw err
for (let i=0;i<Object.keys(result).length;i++) {
if (result[i].email===insert_values.email || result[i].username===insert_values.username) {
console.log("email/username is taken")
return
}else {
console.log("email/username is avaliable")
insert_values_to_db()
return
}
}
})
})
let insert_values_to_db = () => {
db_connect.connect((err) => {
if (err) throw err
db_connect.query(sql_code,(err,result) => {
if (err) throw err
})
})
}
}
For the first connect, I make sure the email and username are still avaliable, and then i runs the sql code to insert them into the database. I'm pretty sure that is what's causing the error, but is there another way to run 2 sql connects on the same db?
Try using mysql2 which should be api compatible. Then do mysql.createPool instead of createConnection.
Also your code is incorrect. You shouldn't do db_connect.connect multiple times. That's where your error is coming from. You should only connect once (but you should probably use a pool because they are better and don't timeout and stuff).
So you should do this:
//Import mySql library
import mysql from "mysql2"
//Runs sql code through db
export let run_db = (insert_values) => {
//Create connection to database
const db_connect = mysql.createPool({
host: "localhost",
user: "root",
password: "*******",
database: "store_user_info"
})
//Sql code to execute
const sql_code =
`INSERT INTO Users (email,password,username)
VALUES (
${"'"+insert_values.email+"'"},
${"'"+insert_values.password+"'"},
${"'"+insert_values.username+"'"}
)`
//Run sql code and fetch result
let insert_values_to_db = () => {
if (err) throw err
db_connect.query(sql_code,(err,result) => {
if (err) throw err
})
}
if (err) throw err
db_connect.query("SELECT * FROM Users",(err,result) => {
if (err) throw err
for (let i=0;i<Object.keys(result).length;i++) {
if (result[i].email===insert_values.email || result[i].username===insert_values.username) {
console.log("email/username is taken")
return
}else {
console.log("email/username is avaliable")
insert_values_to_db()
return
}
}
})
}
I'm using gulp to move some folders in a remote directory via scp. Actually if I declare the password in the gulpfile it works fine. I rather want the password is required every time I try to run this task by the prompt, and not to put it visible in the file.
How can I do that?
My gulp task:
var scp = require('gulp-scp2');
gulp.task('deploy', function(done) {
return gulp.src("./dist/**")
.pipe(scp({
host: 'localhost',
username: 'saifer',
dest: '/home/saifer/'
}))
.on('error', function(err) {
console.log(err);
});
});
Starting the task this way obviously throws an error like:
Error: Authentication failure. Available authentication methods: publickey,gssapi-keyex,gssapi-with-mic,password
I'm looking for something to add the scp's passing object to let the gulp taks ask for a password before trying to connect
I believe prompting is an unrelenting problem. You should solve it with a separate module(or just with readline module from standard library). The solution below uses the prompt module:
const util = require('util')
const prompt = require('prompt')
var schema = {
properties: {
password: {
hidden: true
}
}
};
prompt.start();
util.promisify(prompt.get)(schema).then(({ password }) => {
var scp = require('gulp-scp2');
gulp.task('deploy', function(done) {
return gulp.src("./dist/**")
.pipe(scp({
host: 'localhost',
username: 'saifer',
dest: '/home/saifer/',
password
}))
.on('error', function(err) {
console.log(err);
});
});
});
const sql = require("mssql");
var sqlconfig = {
server:"192.168.200.5",
database:"DATA",
user: "labo",
password: "*********",
connectionTimeout: 30000,
port: 1433,
dialect: "mssql",
dialectOptions: {
"instanceName": "SQLEXPRESS"
},
};
new sql.ConnectionPool(sqlconfig).connect().then(pool => {
console.log(pool); return pool.query('select * from data where id = 2')
}).then(result=> {
console.dir(result)
}).catch(err => {
console.log(err);
})
Problem: Return Login failed for user 'Labo' ELOGIN when trying to login to Microsoft SQL Server using node.js.
What I have tried: Grab the example codes on npm to find the avoid extra problems. Error still persisted.
What I suspect: The username I inserted was "labo" but the one returned from err was 'Labo' (with capitalized 'L'). Is this a bug?
This is my code