loopback redis based sessions - node.js

first i would like to say that i have already seen questions regarding related issues but did not find the answer.
I want to use redis for session in loopback, but req is not available in code.
server/server.js
var redis = require("redis");
var session = require('express-session');
var redisStore = require('connect-redis')(session);
var client = redis.createClient();
var app = module.exports = loopback();
app.use(session({
secret: '0`3VTw;hQ|3/`:95ZYu{0J82O>{}7JC/',
// create new redis store.
store: new redisStore({ host: 'localhost', port: 6379, client: client,ttl : 260}),
saveUninitialized: false,
resave: false
}));
I want to implement Redis Based express sessions on loopback application but i cant find the way to do it without writing the whole route controller myself.
I am currently extending the model and creating a remoteMethod() but i cannot access "req" in anyway.
this is my TrmptUsers Model code (see line 3)
common/models/trmpt-users.js
module.exports = function(TrmptUsers) {
TrmptUsers.login = function(username, password, cb) {
console.log(TrmptUsers.app.session); //i want access to req variable to work with redis here.
var ursalt = security.gen_salt(username);
password = security.decrypt256(password, ursalt);
TrmptUsers.findOne({fields:{usrPwd:true,usrAccessToken:true},where:{and:[{usr_username:username}]}},function(err,result){
security.verifyPassword(password, result.usrPwd, function(err, verify) {
if (verify) {
User.generateVerificationToken(username, cb)
cb(null,result.usrAccessToken);
}
else {
cb({status:401,message:"Invalid Username/Password"},null);
}
});
});
}
TrmptUsers.remoteMethod(
'login',
{
accepts: [
{arg: 'username', type: 'string', required: 'true'},
{arg: 'password', type: 'string', required: 'true'},
],
returns: {arg: 'accesstoken', type: 'string'}
}
);
};

I found a solution to all my problems above a long time ago, since someone up-voted it i think they might want an answer so I am posting one here.
server/server.js
var redis = require("redis");
var session = require('express-session');
var redisStore = require('connect-redis')(session);
app.use(session({
secret: 'hello',
store: new redisStore({ host: 'localhost', port: 6379, client: client,ttl : 3600}),//1 hour
saveUninitialized: false,
resave: false
}));
then when you create your models slc:loopback model you get an option to add req object to your parameters.
model-specific.json
...
"methods": {
"userLogin": {
"isStatic": true,
"accepts": [
{
"arg": "req",
"type": "object",
"required": true,
"description": "",
"http": {
"source": "req"
}
},
{
"arg": "username",
"type": "string",
"required": true,
"description": "Username"
},
{
"arg": "password",
"type": "string",
"required": true,
"description": "Password"
}
],
"returns": [
{
"arg": "accessToken",
"type": "string",
"root": false,
"description": ""
}
],
...
Then just use req.session in any way you want and remember to install redis-server first.

Related

How to Config next-images with existing next.config.js file

I want to use the npm package next-images in my nextjs app.
After reading the documentation for next-images, it says you need to create a next.config.js file with the following code:
const withImages = require('next-images')
module.exports = withImages()
However I already have a next.config.js file, currently it has code inside it that looks like this:
var fs = require('fs');
const nextConfig = {
reactStrictMode: true,
images: {
remotePatterns: [
{
protocol: "http",
hostname: "**",
},
{
protocol: "https",
hostname: "**",
},
],
},
env: {
customSnipcartJS: fs.readFileSync('public/file2.js').toString(),
snipcartInstallJS: fs.readFileSync('public/file1.js').toString()
}
}
module.exports = nextConfig
So my question is, how do I merge the required config code for next-images with my existing configuration I already have in my next.config.js
In case someone else runs in to something like this I found a solution.
I managed to get this to work, you can pass your custom next config in to the withImages method.
So this now works.
var fs = require('fs');
const withImages = require('next-images');
module.exports = withImages({
reactStrictMode: true,
images: {
disableStaticImages: true,
remotePatterns: [
{
protocol: "http",
hostname: "**",
},
{
protocol: "https",
hostname: "**",
},
],
},
env: {
customSnipcartJS: fs.readFileSync('public/file2.js').toString(),
snipcartInstallJS: fs.readFileSync('public/file1.js.js').toString()
}
})

Trouble connecting express api to nuxt app and mongodb

It's been seriously 10 days since i'm trying to deploy my web app online. i've gone back and forth between heroku and digital ocean. nothing solved. i've asked questions here all i get is a long post with technical terms i' not able to understand. Here's my problem :
i have a nuxt app with express.js in the backend and mongodb as the database. At first i had trouble with configuring host and port for my nuxt app. once i fixed it, anoither problem appeared : i'm not receiving data from the database. i don't if it's something related to database connection or with the express api configuration.
here's my nuxt config
export default {
ssr: false,
head: {
titleTemplate: 'Lokazz',
title: 'Lokazz',
meta: [
{ charset: 'utf-8' },
{
name: 'viewport',
content: 'width=device-width, initial-scale=1'
},
{
hid: 'description',
name: 'description',
content:
'Lokazz'
}
],
link: [
{
rel: 'stylesheet',
href:
'https://fonts.googleapis.com/css?family=Work+Sans:300,400,500,600,700&subset=latin-ext'
}
]
},
css: [
'swiper/dist/css/swiper.css',
'~/static/fonts/Linearicons/Font/demo-files/demo.css',
'~/static/fonts/font-awesome/css/font-awesome.css',
'~/static/css/bootstrap.min.css',
'~/assets/scss/style.scss'
],
plugins: [
{ src: '~plugins/vueliate.js', ssr: false },
{ src: '~/plugins/swiper-plugin.js', ssr: false },
{ src: '~/plugins/vue-notification.js', ssr: false },
{ src: '~/plugins/axios.js'},
{ src: '~/plugins/lazyLoad.js', ssr: false },
{ src: '~/plugins/mask.js', ssr: false },
{ src: '~/plugins/toastr.js', ssr: false },
],
buildModules: [
'#nuxtjs/vuetify',
'#nuxtjs/style-resources',
'cookie-universal-nuxt'
],
styleResources: {
scss: './assets/scss/env.scss'
},
modules: ['#nuxtjs/axios', 'nuxt-i18n','vue-sweetalert2/nuxt', '#nuxtjs/auth-next', "bootstrap-vue/nuxt"],
bootstrapVue: {
bootstrapCSS: false, // here you can disable automatic bootstrapCSS in case you are loading it yourself using sass
bootstrapVueCSS: false, // CSS that is specific to bootstrapVue components can also be disabled. That way you won't load css for modules that you don't use
},
i18n: {
locales: [
{ code: 'en', file: 'en.json' },
],
strategy: 'no_prefix',
fallbackLocale: 'en',
lazy: true,
defaultLocale: 'en',
langDir: 'lang/locales/'
},
router: {
linkActiveClass: '',
linkExactActiveClass: 'active',
},
server: {
port: 8080, // default: 3000
host: '0.0.0.0' // default: localhost
},
auth: {
strategies: {
local: {
token: {
property: "token",
global: true,
},
redirect: {
"login": "/account/login",
"logout": "/",
"home": "/page/ajouter-produit",
"callback": false
},
endpoints: {
login: { url: "/login", method: "post" },
logout: false, // we don't have an endpoint for our logout in our API and we just remove the token from localstorage
user:false
}
}
}
},
};
here's my package.json
{
"name": "martfury_vue",
"version": "1.3.0",
"description": "Martfury - Multi-purpose Ecomerce template with vuejs",
"author": "nouthemes",
"private": true,
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate"
},
"config": {
"nuxt": {
"host": "0.0.0.0",
"port": "8080"
}
},
}
here's my repository.js file
import Cookies from 'js-cookie';
import axios from 'axios';
const token = Cookies.get('id_token');
const baseDomain = 'https://lokazzfullapp-8t7ec.ondigitalocean.app';
export const customHeaders = {
'Content-Type': 'application/json',
Accept: 'application/json'
};
export const baseUrl = `${baseDomain}`;
export default axios.create({
baseUrl,
headers: customHeaders
});
export const serializeQuery = query => {
return Object.keys(query)
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(query[key])}`)
.join('&');
};
an example of an api call i make locally that works without a problem :
import Repository, { serializeQuery } from '~/repositories/Repository.js';
import { baseUrl } from '~/repositories/Repository';
import axios from 'axios'
const url = baseUrl;
export const actions = {
async getProducts({ commit }, payload) {
const reponse = await axios.get(url)
.then(response => {
commit('setProducts', response.data);
return response.data;
})
.catch(error => ({ error: JSON.stringify(error) }));
return reponse;
},
}
here's my index.js (express file)
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose')
const cors = require('cors');
//const url = 'mongodb://localhost:27017/lokazz'
const url = 'mongodb+srv://lokazz:zaki123456#cluster0.hsd8d.mongodb.net/lokazz?retryWrites=true&w=majority'
const jwt = require('jsonwebtoken')
const con = mongoose.connection
mongoose.connect(url, {useNewUrlParser:true}).then(()=>{
const app = express();
// middlleware
app.use(express.json())
app.use(cors());
//products routes
const products = require('./product/product.router');
app.use('/', products)
//users routes
const users = require('./user/user.router');
app.use('/', users)
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Server started on port ${port}`));
}).catch(error => console.log(error.reason));
con.on('open', () => {
console.log('connected...')
})
My directory structure
the error i get after the api request, meaning it's not receving any data.
ebd1ecd.js:2 TypeError: Cannot read properties of undefined (reading 'username')
at f.<anonymous> (c88240c.js:1)
at f.t._render (ebd1ecd.js:2)
at f.r (ebd1ecd.js:2)
at wn.get (ebd1ecd.js:2)
at new wn (ebd1ecd.js:2)
at t (ebd1ecd.js:2)
at f.In.$mount (ebd1ecd.js:2)
at init (ebd1ecd.js:2)
at ebd1ecd.js:2
at v (ebd1ecd.js:2)
idk if it's a problem with mongodb connection cluster or the api call.

configuring base url nuxt for digital ocean deployement

i'm building ecommerce web app using nuxt and node.js/express. when i'm building locally i have no problem making axios api calls. base url is configured as the following
const baseDomain = 'http://localhost:8080/';
then all i do is
async getProducts({ commit }, payload) {
const reponse = await Repository.get(
`${baseUrl}/products?${serializeQuery(payload)}`
)
.then(response => {
commit('setProducts', response.data);
return response.data;
})
.catch(error => ({ error: JSON.stringify(error) }));
return reponse;
},
now the problem is when i move my whole app to digital ocean, i tried the following changes
const baseDomain = 'https://0.0.0.0:8080/';
my nuxt.js config
export default {
ssr: false,
head: {
titleTemplate: 'Lokazz',
title: 'Lokazz',
meta: [
{ charset: 'utf-8' },
{
name: 'viewport',
content: 'width=device-width, initial-scale=1'
},
{
hid: 'description',
name: 'description',
content:
'Lokazz'
}
],
link: [
{
rel: 'stylesheet',
href:
'https://fonts.googleapis.com/css?family=Work+Sans:300,400,500,600,700&amp;subset=latin-ext'
}
]
},
css: [
'swiper/dist/css/swiper.css',
'~/static/fonts/Linearicons/Font/demo-files/demo.css',
'~/static/fonts/font-awesome/css/font-awesome.css',
'~/static/css/bootstrap.min.css',
'~/assets/scss/style.scss'
],
plugins: [
{ src: '~plugins/vueliate.js', ssr: false },
{ src: '~/plugins/swiper-plugin.js', ssr: false },
{ src: '~/plugins/vue-notification.js', ssr: false },
{ src: '~/plugins/axios.js'},
{ src: '~/plugins/lazyLoad.js', ssr: false },
{ src: '~/plugins/mask.js', ssr: false },
{ src: '~/plugins/toastr.js', ssr: false },
],
buildModules: [
'#nuxtjs/vuetify',
'#nuxtjs/style-resources',
'cookie-universal-nuxt'
],
styleResources: {
scss: './assets/scss/env.scss'
},
modules: ['#nuxtjs/axios', 'nuxt-i18n','vue-sweetalert2/nuxt', '#nuxtjs/auth-next', "bootstrap-vue/nuxt"],
bootstrapVue: {
bootstrapCSS: false, // here you can disable automatic bootstrapCSS in case you are loading it yourself using sass
bootstrapVueCSS: false, // CSS that is specific to bootstrapVue components can also be disabled. That way you won't load css for modules that you don't use
},
i18n: {
locales: [
{ code: 'en', file: 'en.json' },
],
strategy: 'no_prefix',
fallbackLocale: 'en',
lazy: true,
defaultLocale: 'en',
langDir: 'lang/locales/'
},
router: {
linkActiveClass: '',
linkExactActiveClass: 'active',
},
server: {
port: 8080, // default: 3000
host: '0.0.0.0' // default: localhost
/// this one works fine , the digital ocean support team told me to do this.
},
auth: {
strategies: {
local: {
token: {
property: "token",
global: true,
},
redirect: {
"login": "/account/login",
"logout": "/",
"home": "/page/ajouter-produit",
"callback": false
},
endpoints: {
login: { url: "/login", method: "post" },
logout: false, // we don't have an endpoint for our logout in our API and we just remove the token from localstorage
user:false
}
}
}
},
};
package.json file
{
"name": "martfury_vue",
"version": "1.3.0",
"description": "Martfury - Multi-purpose Ecomerce template with vuejs",
"author": "nouthemes",
"private": true,
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate"
},
"config": {
"nuxt": {
"host": "0.0.0.0",
"port": "8080"
}
},
}
server index.js config
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose')
const cors = require('cors');
const url = 'mongodb+srv://****************************' // this works fine i manage to pull data from the cluster without a problem
const jwt = require('jsonwebtoken')
mongoose.connect(url, {useNewUrlParser:true}).then(()=>{
const app = express();
// middlleware
app.use(express.json())
app.use(cors());
//products routes
const products = require('./product/product.router');
app.use('/', products)
//users routes
const users = require('./user/user.router');
app.use('/', users)
const port = process.env.PORT || 8080;
app.listen(port, () => console.log(`Server started on port ${port}`));
}).catch(error => console.log(error.reason));
const con = mongoose.connection
con.on('open', () => {
console.log('connected...')
})
here's my github repo and file structure. the server and api folder is lokazz_api.
I would recommend you use Environment variables for this.
Install dotenv in your project and then configure it in your nuxt.config.js file.
Create a .env file in your root directory, and then set a key-value pair like this:
VUE_APP_BASE_URL="<value>"
Note you need to prefix your keys with VUE_APP.
Your .env should look like this:
VUE_APP_BASE_URL="http://localhost:8080/"
You can modify your variable to this: const baseDomain = process.env.BASE_URL;
Remember to add the .env file in the .gitignore file.
On your digital ocean terminal, you can create a .env file using the touch .env command, and then use Vim or Nano to modify the file.
If your project runs fine with an .env file, it should work as good on production.
DO NOT commit .env but rather aim to your Digitalocean dashboard and look in the settings. You should see a place where you can input your pair and then proceed.
As shown here: https://docs.digitalocean.com/products/app-platform/how-to/use-environment-variables/#using-bindable-variables-within-environment-variables

SequelizeDatabaseError UPDATE using PostgreSQL

I have 5 endpoint with 4 methods implemented. For GET, POST, DELETE all of them goes well. I don't understand why PUT method doesn't work. In my case, I need to update column first_name and last_name but it send me error like this:
{
"name": "SequelizeDatabaseError",
"parent": {
"length": 221,
"name": "error",
"severity": "ERROR",
"code": "42703",
"where": "PL/pgSQL function last_updated() line 3 at assignment",
"file": "d:\\pginstaller_13.auto\\postgres.windows-x64\\src\\pl\\plpgsql\\src\\pl_exec.c",
"line": "5170",
"routine": "exec_assign_value",
"sql": "UPDATE \"actors\" SET \"first_name\"=$1,\"last_name\"=$2,\"updatedAt\"=$3 WHERE \"actor_id\" = $4",
"parameters": [
"Anne ",
"Anne",
"2020-10-29 02:54:11.642 +00:00",
"200"
]
},
"original": {
"length": 221,
"name": "error",
"severity": "ERROR",
"code": "42703",
"where": "PL/pgSQL function last_updated() line 3 at assignment",
"file": "d:\\pginstaller_13.auto\\postgres.windows-x64\\src\\pl\\plpgsql\\src\\pl_exec.c",
"line": "5170",
"routine": "exec_assign_value",
"sql": "UPDATE \"actors\" SET \"first_name\"=$1,\"last_name\"=$2,\"updatedAt\"=$3 WHERE \"actor_id\" = $4",
"parameters": [
"Anne ",
"Anne",
"2020-10-29 02:54:11.642 +00:00",
"200"
]
},
"sql": "UPDATE \"actors\" SET \"first_name\"=$1,\"last_name\"=$2,\"updatedAt\"=$3 WHERE \"actor_id\" = $4",
"parameters": [
"Anne ",
"Anne",
"2020-10-29 02:54:11.642 +00:00",
"200"
]
}
This is how i tested in Postman
And this is my models:
const actor = (sequelize, DataTypes) => {
const Actor = sequelize.define('actor', {
actor_id: {
type: DataTypes.INTEGER,
primaryKey: true,
unique: true,
autoIncrement: true,
allowNull: false,
},
first_name: {
type: DataTypes.STRING(45),
allowNull: false,
},
last_name: {
type: DataTypes.STRING(45),
allowNull: false,
},
createdAt: {
type: DataTypes.DATE,
},
updatedAt: {
type: DataTypes.DATE,
},
});
return Actor;
};
export default actor;
Help me, please. I have searched all around for the answer but still stuck.
UPDATE:
Here is my code when instantiate Sequelize:
import Sequelize from 'sequelize';
const sequelize = new Sequelize(
process.env.DATABASE,
process.env.DATABASE_USER,
process.env.DATABASE_PASSWORD,
{
dialect: 'postgres',
},
);
const models = {
Actor: sequelize.import('./actor'),
};
export { sequelize };
export default models;
And this is my app.js:
import 'dotenv/config';
import cors from 'cors';
import express from 'express';
import path from 'path';
import models, { sequelize } from './models';
import routes from './routes';
const app = express();
// Application-Level Middleware
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(async (req, res, next) => {
req.context = {
models,
me: await models.Actor,
};
next();
});
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(express.static(path.join(__dirname, 'public')));
// Routes
app.get('/', async (req, res) => {
try {
res.render('index');
} catch (error) {
res.send(error);
}
});
app.use('/actor', routes.actor);
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
// Start
sequelize.sync().then(async () => {
app.listen(process.env.PORT, () =>
console.log(`App listening on port ${process.env.PORT}!`),
);
});
module.exports = app;
Also, this is my actual table structure
[SOLVED]
This happen because I have deleted one column named "last_updated" that used as trigger when UPDATE, image . Now I disable that trigger and can successfully update.
My mistake, this DB I import from here and didn't give attention to it

NightmareJS: how to set cookie?

var Nightmare = require('nightmare');
var nightmare = Nightmare({
show: true
})
nightmare
.goto('https://mail.yandex.ru')
.type('input[name=login]', 'mylogin')
.type('input[name=passwd]', 'mypassword')
.click('button.nb-button._nb-action-button.nb-group-start')
.wait('.mail-User-Name')
.cookies.get()
.then(function (cookies) {
//actions
})
I am getting cookies after authorization, but I don't know where I must set them and how I must set them. I've tried to do .cookie.set() at the beginning, but this doesn't work.
How I can use saved cookie? Thanks.
I did the following from the node terminal:
> var Nightmare = require('nightmare')
undefined
> var nightmare = Nightmare({show:true})
undefined
> nightmare.
... goto('https://google.com').
... cookies.set('foo', 'bar').
... cookies.get().
... then((cookies) => {
... console.log(JSON.stringify(cookies, null, 4))
... })
Promise { <pending> }
> [
{
"name": "NID",
"value": "96=qo1qY9LTKh1np4OSgiyJTi7e79-_OIoIuc71hnrKWvN1JUnDLJqZlE8u2ij_4mW0-JJhWOCafo5J0j-YkZCFt8H2VHzYUom4cfEd2QLOEsHmAcT2ACx4a5xSvO0SZGZp",
"domain": ".google.de",
"hostOnly": false,
"path": "/",
"secure": false,
"httpOnly": true,
"session": false,
"expirationDate": 1502733434.077271
},
{
"name": "CONSENT",
"value": "WP.25d07b",
"domain": ".google.de",
"hostOnly": false,
"path": "/",
"secure": false,
"httpOnly": false,
"session": false,
"expirationDate": 2145916800.077329
},
{
"name": "foo",
"value": "bar",
"domain": "www.google.de",
"hostOnly": true,
"path": "/",
"secure": false,
"httpOnly": false,
"session": true
}
]
nightmare.cookies.set('key', 'value') is indeed the correct way to use it, as you can see in my result object. Perhaps https://mail.yandex.ru does not accept your cookie, because it's invalid. Please do the same and edit your question to include your results.
Edit: Apparently, OP needs to store the cookies so he can use them in another Nightmare instance. This can be achieved like this:
var Nightmare = require('nightmare')
var storedCookies // This is where we will store the cookies. It could be stored in a file or database to make it permanent
// First instance:
var nightmare1 = Nightmare({show: true})
nightmare1.
goto('https://google.com').
cookies.get().
then((cookies) => {
storedCookies = cookies
})
// Second instance:
var nightmare2 = Nightmare({show: true})
for(var i = 0; i < storedCookies.length; i++)
nightmare2.
cookies.set(storedCookies[i].name, storedCookies[i].value)
nightmare2.
goto('https://google.com')

Resources