feathers.js - discard hook not working in authentication.js - feathersjs

I am using Feathers.js for the backend.
This is the original response from POST /authentication
{
"accessToken": "XXXXX",
"authentication": {
"strategy": "local",
"accessToken": "XXXXX",
"payload": {
"iat": 1616402936,
"exp": 1616489336,
"aud": "https://yourdomain.com",
"iss": "feathers",
"sub": "c15ef318-68fc-471c-9710-52f14d87abda",
"jti": "57d103e1-c81b-4fc6-8bbe-952b74aaf8e3"
}
},
"user": {
"id": "c15ef320-68fc-471c-9710-52f14d87ccda",
"email": "abc.abc#abc.com",
}
}
I want to discard the accessToken field from the response, so I modified authentication.js as:
const { AuthenticationService, JWTStrategy } = require('#feathersjs/authentication');
const { LocalStrategy } = require('#feathersjs/authentication-local');
const { expressOauth } = require('#feathersjs/authentication-oauth');
const { discard, iff, isProvider, lowerCase } = require('feathers-hooks-common')
module.exports = app => {
const authentication = new AuthenticationService(app);
authentication.register('jwt', new JWTStrategy());
authentication.register('local', new LocalStrategy());
authentication.hooks = {
before: {
create: [lowerCase('email')],
update: [lowerCase('email')],
patch: [lowerCase('email')],
},
after: {
create: [discard('accessToken')]
}
};
app.use('/authentication', authentication);
app.configure(expressOauth());
};
But nothing changes after I've changed the code to the above one.
What is wrong here?

Following the API documentation on registering hooks it should be app.service('/authentication').hooks(hooks):
const { AuthenticationService, JWTStrategy } = require('#feathersjs/authentication');
const { LocalStrategy } = require('#feathersjs/authentication-local');
const { expressOauth } = require('#feathersjs/authentication-oauth');
const { discard, iff, isProvider, lowerCase } = require('feathers-hooks-common')
module.exports = app => {
const authentication = new AuthenticationService(app);
authentication.register('jwt', new JWTStrategy());
authentication.register('local', new LocalStrategy());
app.use('/authentication', authentication);
app.service('/authentication').hooks({
before: {
create: [lowerCase('email')],
update: [lowerCase('email')],
patch: [lowerCase('email')],
},
after: {
create: [discard('accessToken')]
}
});
app.configure(expressOauth());
};

The hook function should be put in the last.
...
module.exports = app => {
const authentication = new AuthenticationService(app);
authentication.register('jwt', new JWTStrategy());
authentication.register('local', new LocalStrategy());
app.use('/authentication', authentication);
app.configure(expressOauth());
app.service('authentication').hooks({
before: {
create: [lowerCase('email')],
update: [lowerCase('email')],
patch: [lowerCase('email')],
},
after: {
create: [
discard('authentication')
]
}
});
};

Related

how to solve "You may need an appropriate loader to handle this file type"?

I'm using react with typescript and redux-toolkit when I want to show the user who is logged in this error occurs error
here's the use Selector in layout.tsx:
const {user} = useSelector((state:any) => state.user);
and here's the display in html (also layout.tsx):
<Link className="anchor" to='/profile'>{user?.name}</Link>
my Reducer ,userSlice.tsx:
export const userSlice = createSlice({
name: "user",
initialState: {
user: null,
},
reducers: {
setUser: (state,action) => {
state.user= action.payload;
},
},
});
export const { setUser } = userSlice.actions;
and this a part of the protectedRoute.tsx the part which I want to retrieve the username:
const getUser = async () => {
try {
dispatch(showLoading());
const response = await axios.post(
"/api/users/user",
{ token: localStorage.getItem("token") },
{
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
}
);
dispatch(hideLoading());
if (response.data.success) {
dispatch(setUser(response.data.data));
} else {
navigate("/login");
}
} catch (error) {
dispatch(hideLoading());
navigate("/login");
}
};
useEffect(() => {
if (!user) {
getUser();
}
}, [user]);
if (localStorage.getItem("token")) {
return props.children;
} else {
return <Navigate to="/login" />;
}

Can't use $elemMatch"

When i am trying to hit the api for this part of code on postman i get error of Can't use $elemMatch I search but can't find any solution for that:-
const accessChat = asyncHandler(async (req, res) => {
const { userId } = req.body;
if (!userId) {
return res.status(400).json({err:'UserId param not sent with request'});
}
var isChat = await Chat.find({
isGroupChat: false,
$and: [
{ users: { $elemMatch: { $eq: req.user._id } } },
{ users: { $elemMatch: { $eq: userId } } },
],
})
.populate("users", "-password")
.populate("latestMessage");
isChat = await User.populate(isChat, {
path: "latestMessage.sender",
select: "name pic email",
});
if (isChat.length > 0) {
res.send(isChat[0]);
} else {
var chatData = {
chatName: "sender",
isGroupChat: false,
users: [req.user._id, userId],
};
try {
const createdChat = await Chat.create(chatData);
const FullChat = await Chat.findOne({ _id: createdChat._id }).populate(
"users",
"-password"
);
res.status(200).json(FullChat);
} catch (error) {
res.status(400);
throw new Error(error.message);
}
}
});
Error image is attached
https://i.stack.imgur.com/HXvTR.png

Retrieving data from MongoDB ánd MySQL simultaneously

I am trying to retrieve data from my MongoDB database which stores chat conversations. This works fine and returns what I want. However, I only save userIDs in MongoDB, so I need to query profile picture, username etc from my MySQL database. I tried the following:
app.get('/api/retrieveAllChats', (req, res) => {
var Conversation = mongoose.model('Conversation', ConversationSchema);
var ChatMessage = mongoose.model('Message', ChatMessageSchema);
var userID = req.query.userID.toString()
var members = []
var conversationData = []
var retrieveAllChats = new Promise(function(resolve, reject) {
Conversation.aggregate([{ $match: { "members.uID": userID } }, { $lookup: { foreignField: "c_ID", from: "messages", localField: "_id", as: "messages" } }, { "$unwind": "$messages" }, { "$sort": { "messages.t": -1 } }, { "$group": { "_id": "$_id", "lastMessage": { "$first": "$messages" }, "allFields": { "$first": "$$ROOT" } } }, { "$replaceRoot": { "newRoot": { "$mergeObjects": [ "$allFields", { "lastMessage": "$lastMessage" } ] } } }, { "$project": { "messages": 0 } }], function (err, conversations) {
if (err) return handleError(err);
conversations.forEach((conversation, i) => {
return new Promise(function (resolveConversations, rejectConversations) {
var membersPromise = conversation.members.forEach((member, x) => {
return new Promise(function (resolveUserData, rejectUserData) {
getUserData(member["uID"], function(userData) {
members.push({userID: member["uID"], joinDate: member["j"], userName: userData["userName"], userDisplayName: userData["userDisplayName"], userVerified: userData["userVerified"], userProfilePicURL: userData["userProfilePicURL"]})
console.log("userData: ", userData)
conversations[i].members[x].userData = userData
conversationData = conversations
resolveUserData({userID: member["uID"], joinDate: member["j"], userName: userData["userName"], userDisplayName: userData["userDisplayName"], userVerified: userData["userVerified"], userProfilePicURL: userData["userProfilePicURL"]})
})
})
})
resolveConversations()
})
})
resolve()
})
}).catch(error => {
console.log(error)
res.json({ errorCode: 500 })
})
retrieveAllChats.then(function() {
res.header("Content-Type",'application/json');
res.send(JSON.stringify(conversationData, null, 4));
})
})
However, the conversationData array is always empty. So I need a way to resolve the retrieveAllChats promise and pass the data I added to the existing conversations object to return it with all information I need. Any ideas on how I can do this? (getUserData is a function to retrieve the MySQL data, this one works fine and returns what I want)
You are trying to do async operation inside forEach which wouldn't work. You need to either use for...of or Promise.all.
Also, you can make this code much cimpler by using .exec() at the end of running any query or aggregation as that is supported by mongoose. Something like this should work. Make sure you change your routte line to this to tell it is an async function
app.get("/api/retrieveAllChats", async (req, res) => {
core logic
const conversions = await Conversation.aggregate([{"$match": {"members.uID": userID}}, {"$lookup": {"foreignField": "c_ID", "from": "messages", "localField": "_id", "as": "messages"}}, {"$unwind": "$messages"}, {"$sort": {"messages.t": -1}}, {"$group": {"_id": "$_id", "lastMessage": {"$first": "$messages"}, "allFields": {"$first": "$$ROOT"}}}, {"$replaceRoot": {"newRoot": {"$mergeObjects": ["$allFields", {"lastMessage": "$lastMessage"}]}}}, {"$project": {"messages": 0}}]);
for(const conversation of conversations) {
for(const member of conversation.members) {
// add your promise call here and either await it or use then to get the promise value.
}
}

Vue. Js Laravel count elements of JSON

I would like to display the number of tasks elements in JSON, but I do not know how to go about it.
I want to make something like this:
Tasks to do 2/12 (where 2 - tasks with flag 1, 12 - all tasks)
I tried using the lenght function, but I got the information function lenght is not defined, similarly with the slice function.
[
{
"id":1,
"clients_id":1,
"products_id":1,
"tasks_id":1,
"project_name":"Some project",
"created_at":null,
"updated_at":null,
"clients":{
"id":1,
"client_name":"Some client",
"contact_name":"Some client",
"client_phone":"123123123",
"client_mail":"clientmail#mailclient.com",
"client_nip":"1112223333",
"client_logo":"logo.jpg",
"updated_at":"2019-04-11 09:45:11",
"created_at":"-0001-11-30 00:00:00"
},
"products":{
"id":1,
"product_name":"Some product",
"product_description":"Really nice product bro",
"product_price":"999$",
"updated_at":"2019-04-08 14:35:13",
"created_at":null
},
"tasks":[
{
"id":1,
"project_id":1,
"task_name":"First task",
"task_description":"its very hard task",
"task_due":"2099-01-12 00:00:00",
"status":0,
"created_at":null,
"updated_at":"2019-04-11 14:09:08"
},
{
"id":2,
"project_id":1,
"task_name":"fix task 1",
"task_description":"or something else",
"task_due":"2201-01-12 00:00:00",
"status":1,
"created_at":null,
"updated_at":"2019-04-11 14:10:11"
}
]
}]
<script>
export default {
mounted() {
let app = this;
let id = app.$route.params.id;
app.id = id;
axios.get('/api/v1/projects/' + id)
.then(function (resp) {
app.project = resp.data;
})
.catch(function () {
alert("Could not load your projects")
});
},
data: function () {
return {
//client_id: null,
project: {
id: '',
clients_id: '',
products_id: '',
tasks_id: '',
project_name: '',
updated_at: '',
created_at: '',
clients: ''
},
task: {
status: ''
}
//client: []
}
},
methods: {
saveForm() {
var app = this;
var newproject = app.project;
axios.patch('/api/v1/projects/' + app.id, newproject)
.then(function (resp) {
app.$router.replace('/c/');
})
.catch(function (resp) {
console.log(resp);
alert("Could not create your company");
});
},
taskDone(taskid, projectid){
var app = this;
{{app}};
var newtask = app.task;
var flag = 1;
axios.patch('/api/v1/tasks/' + taskid + '?status='+flag)
.then(function (resp) {
app.$router.push('/pr/view/' + projectid);
location.reload();
})
.catch(function (resp) {
console.log(resp);
alert("Could not create your company");
});
},
taskUnDone(taskid, projectid){
var app = this;
{{app}};
var newtask = app.task;
var flag = 0;
axios.patch('/api/v1/tasks/' + taskid + '?status='+flag)
.then(function (resp) {
app.$router.push('/pr/view/' + projectid);
location.reload();
})
.catch(function (resp) {
console.log(resp);
alert("Could not create your company");
});
}
}
}
</script>
You could create a computed function that returns the length of tasks filtered by status of 1.
computed() {
status() {
const tasks = this.project.tasks;
const complete = tasks.filter(task => task.status === 1);
return `${complete.length}/${tasks.length}`;
}
}
Then use status as a "variable" in your markup.
<p>Tasks done: {{ status }}</p>

How to Use nodes callback when i want to build a JSON Object Like Below

I have just started coding with node.js, I understand that node.js is asynchronous but not sure how to deal with this problem.
I'm querying mysql and building a JSON as follows:
var mysql = require('mysql');
var async = require('async');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : '',
database : 'hungryna_hungry_database',
insecureAuth : true
});
var obj={
"zone":[],
};
var zonearray=new Array();
connection.query('SELECT id,name FROM zone LIMIT 100', function(err, rows) {
var ck=new Array();
for(i=0; i < rows.length; i++){
var zoneObj={};
var zone=rows[i];
zoneObj.id=zone.id;
zoneObj.name=zone.name;
ck.push({
"id":zoneObj.id,
"name":zoneObj.name
});
build_actor(zoneObj.id,function(err,area){
if(!err){
//zonearray=ck;
//obj.zone=zonearray;
console.log(JSON.stringify(ck));
}
});
}
});
function build_actor(zoneid,cb){
connection.query('SELECT id,name FROM area WHERE zone_id='+zoneid+';',
function(err, a) {
var ak =new Array();
for(var i in a)
{
ak.push({
"id":a[i].id,
"name":a[i].name
});
}
cb (null,ak);
});
My output is below:
[{"id":1,"name":"Gulshan-Banani-Baridhara-DOHS"},{"id":2,"name":"Uttara"},{"id":
4,"name":"Dhanmondi-Lalmatia-Mohammadpur"}]
[{"id":1,"name":"Gulshan-Banani-Baridhara-DOHS"},{"id":2,"name":"Uttara"},{"id":
4,"name":"Dhanmondi-Lalmatia-Mohammadpur"}]
[{"id":1,"name":"Gulshan-Banani-Baridhara-DOHS"},{"id":2,"name":"Uttara"},{"id":
4,"name":"Dhanmondi-Lalmatia-Mohammadpur"}]
Output I want is below:
{
"zone1":[
{
"id":1,
"name":"a",
"area":[
{
"id":1,
"name":"area1"
},
{
"id":2,
"name":"area2"
}
]
},
{
"id":2,
"name":"b",
"area":[
{
"id":1,
"name":"area1"
},
{
"id":2,
"name":"area2"
}
]
}
]
}