Create OpportunityProduct using REST - rest

I'm trying to create a new OpportunityProduct using this rest call:
XRMServices/2011/OrganizationData.svc/OpportunityProductSet
{"ProductId":"ef71ce8e-1ef3-e211-b252-984be17c47e4","Quantity":123,"ProductDescription":"Added from code - TEST123","OpportunityId":"8bdb3525-7274-e311-a90b-6c3be5be5f78"}
The call returns:
The request should be a valid top-level resource object.
This indicates that my arguments is not correct. I see to possible reasons for this:
I'm missing some required properties (How can I figure out which is required?)
It is not possible to do using rest
(both guids are returned via other call and should be correct)
Any help would be great!
Thanks
Larsi

For lookup references to other entities you need to specify both the GUID and the type. You also need to include the UOM when creating an Opportunity Product based on an existing Product. Your object should look something like this:
var entity = {};
entity.Quantity = parseFloat(4).toFixed(2);
entity.OpportunityId = {
Id: '69BB2236-B57F-E311-BB6D-6C3BE5A881A4',
LogicalName: 'opportunity'
};
entity.ProductId = {
Id: 'C8138483-DF81-E311-B542-6C3BE5A8362C',
LogicalName: 'product'
};
entity.UoMId = {
Id: 'BE0FB859-7E90-4B3E-B501-3AB3CD4DC8FC',
LogicalName: 'uom'
};

Related

Reading attributes from private key

I'm trying to use Pkcs11Interop to sign a message using the private key from a smart card certificate in a C# application. The smart card we are using contain multiple certificates - usually one is for signing, and one is for authentication. If I were using X509Certificate2, I'd filter certificates based on the X509KeyUsageFlags I'm looking for. I'm struggling to figure out how to approach this using PKCS11.
The code I'm starting with is below. When I call session.FindAllObjects, I'm getting 2 certificates in the result (which is expected, since that is how many certificates are on the smart card.)
I've tried using GetAttributeValue to read various attributes and see if I can use those to identify the correct certificate - strangely, they all return null/0 values. Querying the CKA_SENSITIVE attribute returns True (which is, again, expected), but apparently I cannot read other attributes from the objects.
Am I doing something incorrect in my usage of GetAttributeValue? Or is there some other way I should be approaching this problem?
public byte[] SignMessage(byte[] message, string pin)
{
var factories = new Pkcs11InteropFactories();
using (IPkcs11Library pkcs11Library = factories.Pkcs11LibraryFactory.LoadPkcs11Library(factories, DriverPath, AppType.SingleThreaded))
{
ISlot slot = GetSlot(pkcs11Library);
if (slot == null)
{
return null;
}
using (ISession session = slot.OpenSession(SessionType.ReadWrite))
{
session.Login(CKU.CKU_USER, pin);
var searchTemplate = new List<IObjectAttribute> {
factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY),
factories.ObjectAttributeFactory.Create(CKA.CKA_KEY_TYPE, CKK.CKK_RSA),
factories.ObjectAttributeFactory.Create(CKA.CKA_SIGN, true),
};
List<IObjectHandle> foundObjects = session.FindAllObjects(searchTemplate); // foundObjects.Count = 2!
IObjectHandle privateKey = foundObjects.FirstOrDefault();
var readResult = session.GetAttributeValue(privateKey, new List<CKA>() { CKA.CKA_LABEL });
var label = readResult[0].GetValueAsString(); // label ends up being null!
byte[] result = null;
using (IMechanism signingMechanism = session.Factories.MechanismFactory.Create(CKM.CKM_SHA256_RSA_PKCS))
{
result = session.Sign(signingMechanism, privateKey, message);
}
session.DestroyObject(privateKey);
session.Logout();
return result;
}
}
}
I came up with a solution through trial-and-error that seems to function correctly. I'm not sure if this is the correct approach, since it seems quite convoluted, so any feedback would be appreciated. I discovered that the contents of the card include a variety of objects, and a single key pair consists of three objects: a CKO_CERTIFICATE object (which seems to contain the brunt of the metadata about the certificate/keypair), a CKO_PRIVATE_KEY object and a CKO_PUBLIC_KEY object. Each of these has the CKA_ID property populated, and the objects that are part of the same key pair should have the same CKA_ID.
So I built a CertificateWrapper wrapper class to hold references to each of the three objects. I then looped over all objects on the smart card, and built CertificateWrapper objects for each unique key pair.
Then, I was able to construct an X509Certificate2 object using the CKA_VALUE attribute on the CKO_CERTIFICATE object. From there, I was able to build a X509Certificate2Collection object using an array of all of the X509Certificate2 objects I made. I could then use the .Find method (or any other method I wanted) on X509Certificate2Collection to filter down to the particular certificate I was looking for.
Once I had the X509Certificate2 object I was looking for, I was able to map it back to the CertificateWrapper object by matching the serial number from the X509Certificate2 against the CKA_SERIAL_NUMBER attribute from the CKO_CERTIFICATE object. Finally, I was able to use the CKO_PRIVATE_KEY object associated with that CKO_CERTIFICATE to do the signing operation.
Like I said, this seems very round-about, but seemed to allow me to find the correct certificate/key pair I needed for my specific workflow. Hope this explanation might be useful to someone, and I also welcome any feedback on problems with this approach and/or better ways to handle this.

SailsJS best practice to seed database with data before other Models are initialized

There is a model that all other models assume its existence.
It should be initialized before any API function is called.
The way I do this (it doesn't work):
1) Define model in api/models, let's call it Location.js
2) Add the following to bootstrap.js
var Locations = require('../api/models/Locations.js');
module.exports.bootstrap = function (cb) {
// seed the database with Locations
var locationsObj = {
country: 'Australia',
states: ['Brisbane', 'Perth', 'Sydney']
};
Location.create(locationsObj, function locationsObj(err, locations) {
if (err) {
cb(err);
}
console.log('locations created: ', locations);
});
}
Question 1
Is it the right way to do initial database seeding?
I get this error:
Locations.create(locationsObj, function locationsObj(err, locations) {
^
TypeError: Object #<bject> has no method 'create'
Question 2
How does the cb function of bootstrap work?
what if there as an error, what to do?
The sails models are globally available; so you don't need to require at bootstrap.js.
This is what I use to seed my database. (See the links I enclose to go to the gists)
Include seed function at config/models.js. The methods you declare in this file will be extended to all your models.
Link: Seed method gist
Define de data the seed will consume in your model Link: Model's seed data
Call the seed method in config/bootstrap.js using async. Link: Calling method
UPDATE
Have a look at this threat also: Best way to migrate table changes to production sailsjs tables
From Cannot unit test my model in sailsjs:
"Once Sails app is lifted, you will have your models available automatically...
And in your case, your first line overrides the User model which would be otherwise constructed by Sails.js, that's why even though you have an object it's not a Waterline model."
I know this is old but, for completeness:
You set
var Locations = ...
But but you call
Location.create()
(no 's') so you just have a typo.
in config/bootstrap.js you can write your seeds directly. Take a look at the example below.
await sails.models.role.createEach([
{
name: 'Admin',
},
{
name: 'Normal-user',
},
]);
here 'role' is name of the table created and not the model name.

MongoDB C# - update using custom strongly-typed objects not allowed?

I am trying to perform an update using strongly-typed objects. For example,
public void setAppointmentPrefs(string UserName, IEnumerable<AppointmentInfo> info)
{
var query = new QueryDocument {{ "ProviderId", UserName}};
var update = Update.Set("Prefs",prefs); // prefs.toList() gives same error
// providerprefs initialized in constructor
providerprefs.Update(query, update);
}
I receive a compiler error saying:Error 14 The best overloaded method match for 'MongoDB.Driver.Builders.Update.Set(string, MongoDB.Bson.BsonValue)' has some invalid arguments
Obviously the Mongo driver will not let me update based on my own object (whether as IEnumerable or prefs.toList()), which seems a contrast from the way it permits me to insert or query with custom objects. Surely I am missing something obvious that would permit me to avoid deserializing, weakly typing then creating a generic BsonDocument!! TIA.
You can do an Update based on your own types! Have you tried using the typed Query and Update builders?
Try something like this:
var query = Query<AppointmentInfo>.EQ(i => i.ProviderId, userName);
var update = Update<AppointmentInfo>.Set(i => i.Prefs, info.Prefs);
Not sure I got the types and everything write from your partial code, but that should give you the general idea.
Let me know if you have any further questions.
I know this has been answered but I for one don't fully understand Roberts answer.
All I did is call the "ToBsonDocument()" method for it to except the object as a parameter
So:
customObject.ToBsonDocument()
If you have an array of objects inside a document:
var query = Query.EQ("_id", ObjectId.Parse(id.ToString()));
var update = Update.Push("ArrayOfObjects", customObject.ToBsonDocument());
collection.Update(query, update);

UriPathExtensionMapping in MVC 4

How do I use UriPathExtensionMapping in MVC4? I've added the mapping in the formatter such that:
MediaTypeMappings.Add(new UriPathExtensionMapping("json", new MediaTypeHeaderValue("application/json"))
But I can't use the extension on my route unless I add a verb, such as:
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}.{extension}"
);
Then it'll recognize my desired media type, but it also starts expecting "extension" as a parameter on the action. Example:
public object Get(string extension)
{
}
Instead of just:
public object Get()
{
}
How can I resolve this?
Thanks!
I don't remember if I noticed this problem, but it might be because I explicitly specified the default value for the extension like:
var rF = routes.MapHttpRoute(
name: "DefaultApi.v1.format",
routeTemplate: "api/1/{controller}/{action}.{format}/{*id}",
defaults: new { id = RouteParameter.Optional, format = "json", version = 1 }
);
*note format = "json" in the line beginning with defaults.
I did also notice that this sometimes doesn't work on requests with trailing parameters for id, like ~/api/1/values/get.json/4.
I can't repro this problem.
You are right that, to use UriPathExtensionMapping, you will need to specify the {controller}.{ext} in your route, like what you described above. If you only specify the {controller}, and uri looks like ~/home.json, then the controller token will be mapped to home.json, which is probably not what you wanted.
However, you should not need to require an "extension" parameter in your action. If you continue seeing this problem, can you post your entire repro, including your controller, your routes and configuration set up with custom formatter? thank you.

CodeIgniter: URIs and Forms

I'm implementing a search box using CodeIgniter, but I'm not sure about how I should pass the search parameters through. I have three parameters: the search string; product category; and the sort order. They're all optional. Currently, I'm sending the parameters through $_POST to a temporary method, which forwards the parameters to the regular URI form. This works fine. I'm using a weird URI format though:
http://site.com/products/search=computer,sort=price,cat=laptop
Does anyone have a better/cleaner format of passing stuff through?
I was thinking of passing it into the products method as arguments, but since the parameters are optional things would get messy. Should I suck it up, and just turn $_GET methods on? Thanks in advance!
Query Strings
You can enable query strings in CodeIgniter to allow a more standard search function.
Config.php
$config['enable_query_strings'] = FALSE;
Once enabled, you can accept the following in your app:
http://site.com/products/search?term=computer&sort=price&cat=laptop
The benefit here is that the user will find it easy to edit the URL to make a quick change to their search, and your search uses common search functionality.
The down side of this approach is that you are going against one of the design decisions of the CodeIgniter development team. However, my personal opinion is that this is OK provided that query strings are not used for the bulk of your content, only for special cases such as search queries.
A much better approach, and the method the CI developers intended, is to add all your search parameters to the URI instead of a query string like so:
http://site.com/products/search/term/computer/sort/price/cat/laptop
You would then parse all the URI segments from the 3rd segment ("term") forward into an array of key => value pairs with the uri_to_assoc($segment) function from the URI Class.
Class Products extends Controller {
...
// From your code I assume you are calling a search method.
function search()
{
// Get search parameters from URI.
// URI Class is initialized by the system automatically.
$data->search_params = $this->uri->uri_to_assoc(3);
...
}
...
}
This would give you easy access to all the search parameters and they could be in any order in the URI, just like a traditional query string.
$data->search_params would now contain an array of your URI segments:
Array
(
[term] => computer
[sort] => price
[cat] => laptop
)
Read more about the URI Class here: http://codeigniter.com/user_guide/libraries/uri.html
If you're using a fixed number of parameters, you can assign a default value to them and send it instead of not sending the parameter at all. For instance
http://site.com/products/search/all/somevalue/all
Next, in the controller you can ignore the parameter if (parameter == 'all'.)
Class Products extends Controller {
...
// From your code I assume that this your structure.
function index ($search = 'all', $sort = 'price', $cat = 'all')
{
if ('all' == $search)
{
// don't use this parameter
}
// or
if ('all' != $cat)
{
// use this parameter
}
...
}
...
}