FeathersJs: Check if user is item creator or creator of associated item - feathersjs

I have two services: posts and comments. Every post can have multiple comments. User 1 creates a post, user 2 creates a comment inside this post. Both users should be able to update, patch or delete the created comment. How do I correctly qualify both users to modify the comment created by user 2?
Posts model
{
userId: { type: DataTypes.INTEGER, allowNull: false },
text: { type: DataTypes.TEXT, allowNull: false },
};
posts.associate = function (models) {
posts.hasMany(models.comments, { onDelete: 'CASCADE' });
}
Comments model
{
userId: { type: DataTypes.INTEGER, allowNull: false },
postId: { type: DataTypes.INTEGER, allowNull: false },
text: { type: DataTypes.TEXT, allowNull: false },
};
comments.associate = function (models) {
comments.belongsTo(models.posts);
}
Posts can only be deleted by the post-creator, so setField from the feathers-authentication-hooks does a good job in this case. But how do I qualify the post-creator to manage comments inside his post?

Related

Sequelize M:N association not updating through table record

When I try to update a recipe with associated tags using the through option, no record is updated in the joining table in the mysql database I'm connected to.
Here are my models definitions:
export const Recipe = sequelize.define('Recipe', {
// Model attributes are defined here
title: {
type: DataTypes.STRING,
allowNull: false
},
image: {
type: DataTypes.STRING,
allowNull: true
},
prepTime: {
type: DataTypes.DOUBLE,
allowNull: false
},
cookTime: {
type: DataTypes.DOUBLE,
allowNull: false
},
totalTime: {
type: DataTypes.DOUBLE,
allowNull: false
},
servings: {
type: DataTypes.INTEGER,
allowNull: false
},
rating: {
type: DataTypes.INTEGER,
allowNull: false
},
notes: {
type: DataTypes.STRING, allowNull: true
},
}, {
// Other model options go here
tableName: 'Recipes'
});
export const Tag = sequelize.define('Tag', {
// Model attributes are defined here
name: {
type: DataTypes.STRING,
allowNull: false
},
}, {
// Other model options go here
tableName: 'Tags'
});
export const RecipeTag = sequelize.define('RecipeTag', {
// Model attributes are defined here
}, {
// Other model options go here
timestamps: false,
tableName: 'RecipeTags'
});
Here are my associations:
Recipe.belongsToMany(Tag, {
through: RecipeTag,
foreignKey: 'recipeId',
as: 'tags'
})
Tag.belongsToMany(Recipe, {
through: RecipeTag,
foreignKey: 'tagId',
as: 'recipes'
})
Here is the update call:
Recipe.update(args, {
include: [{
model: Tag,
through: RecipeTag,
as: 'tags',
where: {
recipeId: args.id
}
}],
where: {
id: args.id
},
});
Only one update mysql call is executed on the Recipes table. Is it possible to update the RecipeTags through table record in the same update call?

Sequelize relations foreign key constraint

I have a post route that is using the sequelize create method to add an event to the database. I have defined the tables for user and event as such:
Events
const Events = sequelize.define('Events', {
Event_id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
name: {
type: DataTypes.STRING,
allowNull: false
},
month: {
type: DataTypes.STRING,
allowNull: false
},
day:{
type:DataTypes.INTEGER,
allowNull: false
},
year: {
type: DataTypes.INTEGER,
allowNull: false
},
important:{
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
},
description:{
type: DataTypes.STRING,
allowNull: true
}
});
return Events;
}
User
const User = sequelize.define('Users', {
user_id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
name: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false
},
password: {
type: DataTypes.STRING,
allowNull: false
}
}, {});
User.associate = function(models){
User.hasMany(models.Events, {as: 'user'})
}
return User;
}
The post route seems to run correctly with the exception on sequelize not being able to attach the user Id to the event that is created do to
"Cannot add or update a child row: a foreign key constraint fails (planitdb.events, CONSTRAINT events_ibfk_1 FOREIGN KEY (UserUserId) REFERENCES users (user_id) ON DELETE SET NULL ON UPDATE CASCADE)"
I am not sure I understand exactly why this is happening. I am thinking I need to define the relation in the Events table as well? If that is the case, I am not sure I understand what type of relationship the Events table has with the User table. Or is the relationship a single event to a single user?
Any help would be greatly appreciated.
Your events object does not contain a mapping for user_id. This object needs to include a user_id field and this needs to be populated prior to attempting to insert a record to the events table.
EDIT - including sequelize relations solution:
Instead of this:
const Events = sequelize.define('Events', {...});
User.associate = function(models){
User.hasMany(models.Events, {as: 'user'})
}
Try:
const Events = sequelize.define('Events', {...});
const User = sequelize.define('User', {...});
User.hasMany(Events, {as: 'user'});
or:
const Events = sequelize.define('Events', {});
const User = sequelize.define('User', {...});
Events.belongsTo(User,{
foreignKey: 'user_id',
constraints: false,
as: 'user'
});

sequelize - how to update an association in n-m relation including join table

I have two tables (user, tag) that are connected to each other with a belongsToMany relationship through a join entity (user_tag):
sequelize.define('tag', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
type: {
type: DataTypes.STRING
}
}, {
classMethods: {
associate: function (models) {
this.belongsToMany(models.user, {as: "users", through: models.user_tag });
},
}
}
sequelize.define('user', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
name: {
type: DataTypes.STRING,
},{
classMethods: {
associate: function (models) {
this.belongsToMany(models.tag, { as:"tags", through: models.user_tags });
}
}
}
sequelize.define('user_tag', {
type: DataTypes.STRING,
param1: DataTypes.INTEGER,
priority: DataTypes.INTEGER
}, {
freezeTableName: true,
paranoid: true
});
Now, a user can update all his tags, including all the specific information on the join entity (user_tag) for example priority and param1.
I'm aware of setAssociation [ e.g. user.setTag(myTags) ], however, how do I set the matching param1 and priority properties?
According to Sequelize's documentation when adding a new relationship with belongsToMany, you can pass in additional attributes to the option object and that data will get added to the through model.
user.setTag(myTags, { param1: 1, priority: 1 });

Sequelize hasMany association issue

In my application a user can have several module which is stored in the user_has_module table. This means that for each user_has_module row, I want to include module where the module_id matches.
module
Module = sequelize.define('module', {
academy_id: {
type: DataTypes.INTEGER,
primaryKey: true
},
module_id: {
type: DataTypes.INTEGER,
primaryKey: true
},
module_module_type_id: DataTypes.INTEGER,
sort_number: DataTypes.INTEGER,
score_to_pass: DataTypes.INTEGER
}, {
freezeTableName: true
})
user_has_module
User_has_module = sequelize.define('user_has_module', {
user_id: {
type: DataTypes.INTEGER,
primaryKey: true
},
module_id: {
type: DataTypes.INTEGER,
primaryKey: true
},
academy_team_id: {
type: DataTypes.INTEGER,
primaryKey: true
},
academy_id: {
type: DataTypes.INTEGER,
primaryKey: true
},
sort_number: DataTypes.INTEGER,
is_complete: DataTypes.INTEGER,
score_to_pass: DataTypes.INTEGER,
is_open: DataTypes.INTEGER,
deadline: DataTypes.DATE
}, {
freezeTableName: true
})
My relation
User_has_module.belongsTo(Module, {foreignKey: 'module_id'});
Now what I want to do is join them on module.module_id = user_has_module.module_id.
My problem is that module has, as you can see, two primary key, and when sequelize joins these two tables, it chooses academy_id as its primary key.
My question is, is there a way to tell Sequelize that in this relation it has to choose the primary key module_id from module?
I think you don't need a model called User_has_module.
I assume you have one model called User and one model call Module.
So you should have designed something like this:
var User = sequelize.define("User", {
name: DataTypes.STRING
}, {
classMethods: {
associate: function(models) {
User.hasMany(models.Module);
}
}
});
And for your Module:
var Module = sequelize.define("Module", {
name: DataTypes.STRING
}, {
classMethods: {
associate: function(models) {
Module.belongsToMany(models.User);
}
}
});
To get a User with its Modules you can do this:
models.User.findAll({ include: [models.Module]}).then(function(users){
console.log(users);
});
Hope I got your question right and it helps.
Cheers

Set safe-deleting mode for relations table in Sequelize.js

So, assume we have that Sequelize model:
var User = sequelize.define("User", {
id: {
type: DataTypes.STRING(45),
allowNull: false,
primaryKey: true
},
password: {
type: DataTypes.STRING(60),
allowNull: false
},
email: {
type: DataTypes.STRING(45),
allowNull: false,
unique: true
},
firstName: {
type: DataTypes.STRING(45),
allowNull: true,
defaultValue: null
}
},
{
tableName: 'profiles',
classMethods: {
associate: function(models) {
User.belongsToMany(User, {through: 'friends', as:'friend'});
}
}
});
after calling associate() method, it will create an extra table friends with columns userId, friendId, createdAt and updatedAt. The case is I need to use this table with safe-deleting mode, in other words, I have to add 'deleted' column somehow. I tried to use paranoid: true in belongsToMany's attributes, didn't work. Is there any ways to do it?
Maybe you can create an model/table which name is Friend. And you can set paranoid: true in that model. And when you deleted an User, it keeps User's friend relation was keeping in that model.
I hope it works. :)