I have two collection type Organizations and Employees.
Its a one to many relationship between Organization and Employee.
I want to add new employee in organization through rest api call in strapi.
Strapi doesn't provide :
http://localhost:1337/organizations/{id}/employees
How to do the update?
There is no already built in solution to do it.
But in Strapi you can create your own controller to match that route and handle all the logic needed in there.
You can check the info about custom controllers here
As Christian said, you will have to create your own route in your Organization API.
Create your route.
Path — api/organization/config/routes.json
{
"routes": [
{
"method": "POST",
"path": "/organizations/:id/employees",
"handler": "organization.cusom",
"config": {
"policies": []
}
},
...
]
}
Create the controller function.
To do so, I will copy the function from the default create one:
https://strapi.io/documentation/3.0.0-beta.x/concepts/controllers.html#core-controllers
Path — `api/organization/controllers/organizaion.js``
const { parseMultipartData, sanitizeEntity } = require('strapi-utils');
module.exports = {
async custom(ctx) {
let entity;
if (ctx.is('multipart')) {
const { data, files } = parseMultipartData(ctx);
entity = await strapi.services.employee.create(data, { files });
} else {
entity = await strapi.services.employee.create(ctx.request.body);
}
return sanitizeEntity(entity, { model: strapi.models.employee });
},
};
And set employee for the creation cause we want to create employee.
Force to use the right organization ID
module.exports = {
async custom(ctx) {
// get the id params from the URL
const {id} = ctx.params;
// force the relation to this specific organisation
ctx.request.body.organization = id;
if (ctx.is('multipart')) {
const { data, files } = parseMultipartData(ctx);
entity = await strapi.services.employee.create(data, { files });
} else {
entity = await strapi.services.employee.create(ctx.request.body);
}
return sanitizeEntity(entity, { model: strapi.models.employee });
},
};
Related
Assign new key and value to object does not work
Here is the post where i would like to add a new key name CreatedUser and wanted to assign object/array but it does not work. Please help on it
here is my code
newPost = new PostsModel({
title,
content,
price,
recreater
});
}
await newPost.save();
let aggregateMatch = null;
let user = null;
if(recreater) {
aggregateMatch = { $match: { _id: ObjectId(recreater) } };
user = await UsersModel.aggregate([
{
$sort: {
timestamp: -1
}
},
aggregateMatch
])
newPost.createdUser = user;
}
console.log("posts", newPost) //Did not see createdUser key
res.out(newPost);
You can't add properties to mongoose document. You have to make it native JS object first.
const post = newPost.toObject();
post.createdUser = user;
I am using axios and express.js API to connect to my mongo DB. I have a .get() request that works for one collection and doesn't work for any other collection. This currently will connect to the database and can access one of the collections called users. I have another collection setup under the same database called tasks, I have both users and tasks setup the same way and being used the same way in the code. The users can connect to the DB (get, post) and the tasks fails to connect to the collection when calling the get or the post functions. When viewing the .get() API request in the browser it just hangs and never returns anything or finishes the request.
any help would be greatly appreciated!
The project is on GitHub under SCRUM-150.
API connection
MONGO_URI=mongodb://localhost:27017/mydb
Working
methods: {
//load all users from DB, we call this often to make sure the data is up to date
load() {
http
.get("users")
.then(response => {
this.users = response.data.users;
})
.catch(e => {
this.errors.push(e);
});
},
//opens delete dialog
setupDelete(user) {
this.userToDelete = user;
this.deleteDialog = true;
},
//opens edit dialog
setupEdit(user) {
Object.keys(user).forEach(key => {
this.userToEdit[key] = user[key];
});
this.editName = user.name;
this.editDialog = true;
},
//build the alert info for us
//Will emit an alert, followed by a boolean for success, the type of call made, and the name of the
//resource we are working on
alert(success, callName, resource) {
console.log('Page Alerting')
this.$emit('alert', success, callName, resource)
this.load()
}
},
//get those users
mounted() {
this.load();
}
};
Broken
methods: {
//load all tasks from DB, we call this often to make sure the data is up to date
load() {
http
.get("tasks")
.then(response => {
this.tasks = response.data.tasks
})
.catch(e => {
this.errors.push(e);
});
},
//opens delete dialog
setupDelete(tasks) {
this.taskToDelete = tasks;
this.deleteDialog = true;
},
//opens edit dialog
setupEdit(tasks) {
Object.keys(tasks).forEach(key => {
this.taskToEdit[key] = tasks[key];
});
this.editName = tasks.name;
this.editDialog = true;
},
//build the alert info for us
//Will emit an alert, followed by a boolean for success, the type of call made, and the name of the
//resource we are working on
alert(success, callName, resource) {
console.log('Page Alerting')
this.$emit('alert', success, callName, resource)
this.load()
}
},
//get those tasks
mounted() {
this.load();
}
};
Are you setting any access controls in the code?
Also refer to mongoDB's documentation here:
https://docs.mongodb.com/manual/core/collection-level-access-control/
Here is my solution:
In your app.js, have this:
let mongoose = require('mongoose');
mongoose.connect('Your/Database/Url', {
keepAlive : true,
reconnectTries: 2,
useMongoClient: true
});
In your route have this:
let mongoose = require('mongoose');
let db = mongoose.connection;
fetchAndSendDatabase('yourCollectionName', db);
function fetchAndSendDatabase(dbName, db) {
db.collection(dbName).find({}).toArray(function(err, result) {
if( err ) {
console.log("couldn't get database items. " + err);
}
else {
console.log('Database received successfully');
}
});
}
I'm trying to insert a many-to-many table with web api odata controls.
And I' ve created controls with scaffolding odata controllers with ef.
Everything is great. I can query the user table like this:
GET http://localhost:51875/odata/Users(1)?$expand=Roles
{
"odata.metadata": "http://localhost:51875/odata/$metadata#Users/#Element",
"Roles": [
{
"ID": 20,
"Name": "Admin"
}
],
"ID": 1,
"UserName": "user",
"Password": "pass",
"EnteredDate": "2017-12-07T14:55:22.24",
"LastLoginDate": null,
"Active": true
}
I've inserted the record 'Admin' manually. How can I add a new role for user?
I've tried,
PATCH http://localhost:51875/odata/Users(1)
{
"Roles": [
{
url : "http://localhost:51875/odata/Roles(10)"
}
],
}
it did not work. Can you help me?
Bit late perhaps but there is an answer to this, it is described on: learn.microsoft.com/...
Add the following CreateRef method to your UserController:
[AcceptVerbs("POST", "PUT")]
public IHttpActionResult CreateRef([FromODataUri] int key, string navigationProperty, [FromBody] Uri link)
{
var user = Db.Users
.FirstOrDefault(p => p.Id == key); //Get User by id
if (user == null)
{
return NotFound();
}
switch (navigationProperty)
{
case "Roles":
// You'll have to impement this 'getkey' method somehow.
// You could implement it yourself or take a look on the webpage I linked earlier.
var relatedKey = GetKeyFromUri(link);
var role = Db.Roles
.FirstOrDefault(f => f.Id == relatedKey); //Get Role by id
if (role == null)
{
return NotFound();
}
user.Roles.Add(role);
break;
default:
return StatusCode(HttpStatusCode.NotImplemented);
}
Db.SaveChanges();
return StatusCode(HttpStatusCode.NoContent);
}
Now you can add roles to a user with the following HTTP request:
PUT [...]/api/User(2)/Roles/$ref
Content-Type: application/json
Content-Length: 54
{ "#odata.id": "[...]/api/Role(4)/" }
Personally I don't find this method particularly nice but it is the standard. You could also do this with a custom 'AddRoles' action as you mention in your comment.
I have successfully created one route in ember-cli-mirage, but am having trouble loading the related data.
The API should be returning JSON API compliant data.
I'm not really sure if there are any good methods or not for debugging mirage's request interception. Here is my config.js
export default function() {
this.urlPrefix = 'https://myserver/';
this.namespace = 'api/v1';
this.get('/machines', function(db, request) {
return {
data: db.machines.map(attrs => (
{
type: 'machines',
id: attrs.id,
attributes: attrs
}
))
};
});
this.get('/machines/:id', function(db, request){
let id = request.params.id;
debugger;
return {
data: {
type: 'machines',
id: id,
attributes: db.machines.find(id),
relationships:{
"service-orders": db["service-orders"].where({machineId: id})
}
}
};
});
this.get('/machines/:machine_id/service-orders', function(db, request){
debugger; // this never gets caught
});
}
Most of this is working fine (I think). I can create machines and service orders in the factory and see the db object being updated. However, where my application would normally make a call to the api for service-orders: //myserver/machines/:machine_id/service-orders, the request is not caught and nothing goes out to the API
EDIT:
This is the route that my Ember app is using for /machines/:machine_id/service-orders:
export default Ember.Route.extend(MachineFunctionalRouteMixin, {
model: function() {
var machine = this.modelFor('machines.show');
var serviceOrders = machine.get('serviceOrders');
return serviceOrders;
},
setupController: function(controller, model) {
this._super(controller, model);
}
});
And the model for machines/show:
export default Ember.Route.extend({
model: function(params) {
var machine = this.store.find('machine', params.machine_id);
return machine;
},
setupController: function(controller, model) {
this._super(controller, model);
var machinesController = this.controllerFor('machines');
machinesController.set('attrs.currentMachine', model);
}
});
Intuitively, I would think that machine.get('serviceOrders'); would make a call to the API that would be intercepted and handled by Mirage. Which does not seem to be the case
Is it possible to create new Meteor collections on-the-fly? I'd like to create foo_bar or bar_bar depending on some pathname which should be a global variable I suppose (so I can access it throughout my whole application).
Something like:
var prefix = window.location.pathname.replace(/^\/([^\/]*).*$/, '$1');
var Bar = new Meteor.Collection(prefix+'_bar');
The thing here is that I should get my prefix variable from URL, so if i declare it outside of if (Meteor.isClient) I get an error: ReferenceError: window is not defined. Is it possible to do something like that at all?
Edit : Using the first iteration of Akshats answer my project js : http://pastie.org/6411287
I'm not entirely certain this will work:
You need it in two pieces, the first to load collections you've set up before (on both the client and server)
var collections = {};
var mysettings = new Meteor.Collection('settings') //use your settings
//Startup
Collectionlist = mysettings.find({type:'collection'});
Collectionlist.forEach(function(doc) {
collections[doc.name] = new Meteor.Collection(doc.name);
})'
And you need a bit to add the collections on the server:
Meteor.methods({
'create_server_col' : function(collectionname) {
mysettings.insert({type:'collection', name: collectionname});
newcollections[collectionname] = new Collection(collectionname);
return true;
}
});
And you need to create them on the client:
//Create the collection:
Meteor.call('create_server_col', 'My New Collection Name', function(err,result) {
if(result) {
alert("Collection made");
}
else
{
console.log(err);
}
}
Again, this is all untested so I'm just giving it a shot hopefully it works.
EDIT
Perhaps the below should work, I've added a couple of checks to see if the collection exists first. Please could you run meteor reset before you use it to sort bugs from the code above:
var collections = {};
var mysettings = new Meteor.Collection('settings')
if (Meteor.isClient) {
Meteor.startup(function() {
Collectionlist = mysettings.find({type:'collection'});
Collectionlist.forEach(function(doc) {
eval("var "+doc.name+" = new Meteor.Collection("+doc.name+"));
});
});
Template.hello.greeting = function () {
return "Welcome to testColl.";
};
var collectionname=prompt("Enter a collection name to create:","collection name")
create_collection(collectionname);
function create_collection(name) {
Meteor.call('create_server_col', 'tempcoll', function(err,result) {
if(!err) {
if(result) {
//make sure name is safe
eval("var "+name+" = new Meteor.Collection('"+name+"'));
alert("Collection made");
console.log(result);
console.log(collections);
} else {
alert("This collection already exists");
}
}
else
{
alert("Error see console");
console.log(err);
}
});
}
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
Collectionlist = mysettings.find({type:'collection'});
Collectionlist.forEach(function(doc) {
collections[doc.name] = new Meteor.Collection(doc.name);
});
});
Meteor.methods({
'create_server_col' : function(collectionname) {
if(!mysettings.findOne({type:'collection', name: collectionname})) {
mysettings.insert({type:'collection', name: collectionname});
collections[collectionname] = new Meteor.Collection(collectionname);
return true;
}
else
{
return false; //Collection already exists
}
}
});
}
Also make sure your names are javascript escaped.
Things got much easier:
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
db.createCollection("COLLECTION_NAME", (err, res) => {
console.log(res);
});
Run this in your server method.