I am trying to get and set the forwarded/replied state of an email message in the Graph API. This is the represented in OWA by the little icon in the right column.
It seems there is not a first class way to access this information, at least it does not come out in the unfiltered JSON dump.
Google suggests this is stored in the extended properties for PidTagLastVerbExecuted or PidTagIconIndex, however attempts to access these just give back 404:
https://graph.microsoft.com/beta/me/mailFolders/{id}/messages?$select=SingleValueExtendedProperties&$expand=SingleValueExtendedProperties($filter%3Did+eq+'String+0x1081')
Other extended properties like 0x0070 do work, so it seems the syntax is correct, and 0x1081 comes from here https://learn.microsoft.com/en-us/office/client-developer/outlook/mapi/pidtaglastverbexecuted-canonical-property
This information is stored, you can see it in OWA, the Outlook apps, and you can see it in IMAP.
Is there some way to do this? It seems strange this basic information about the email state is not made available.
Your specifying the wrong datatype that property is defined as a Long in the documentation (but the doco is for MAPI) so its actually an Integer in EWS and Graph eg this is something i used to return both PidTagLastVerbExecuted and PidTagLastVerbExecutedTime (which gives you the time of the last action)for a particular message
/v1.0/users('user#domaincom')/MailFolders/AllItems/messages/?$select=ReceivedDateTime,Sender,Subject,IsRead,inferenceClassification,InternetMessageId,parentFolderId,hasAttachments,webLink,InternetMessageHeaders&$Top=1000&$filter=internetMessageId+eq+%27%3cSG2PR04MB3223962312D5B46D0C9CA1B5C89C0%40SG2PR04MB3223.apcprd04.prod.outlook.com%3e%27&$expand=SingleValueExtendedProperties($filter=(Id%20eq%20'Integer%200x1081')%20or%20(Id%20eq%20'SystemTime%200x1082'))
Related
I am developing a series of Slack apps for my workspace, and some of them are meant to interact with the content (messages) delivered by the other apps : extracting content IDs that may be referred to by other messages
A concrete example :
Suppose I have an app A "FindUser" that is capable of giving me the user profile when a slack user types find me#example.com, and it replies in the thread with a formatted view of the user profile
I am developing an app B "EditTags", which basically gives me a right click option with "edit tags" (see Slack's Interactive Components/Actions), the idea being that a user could first ask app A to find a user, and then right click on the reply from App A and click the "edit tags" action given by the other app. What this app B does it actually retrieve the tags for the user mentionned by the previous message from app A, and in another reply to the thread it gives some controls to either delete an existing tag OR it shows a select with autocomplete to add new tags.
The B app needs to retrieve the user ID that the A app mentionned previously. So I need some way to pass that data directly in the slack message. When looking at the examples, slack does not seem to provide a way to add arbitrary "metadata" to a message, am I wrong ? Do you have workaround for this ? I mean I could totally send the user ID say, in the footer, so I can just read the footer, but I was planning to use the footer for something else... Is there a way to pass metadata hrough properties that would be hidden to the end user ?
Although this does not feel relevant, I am building a slack nodeJS app using the node slack sdk (and especially the #slack/interactive-messages package)
For the most part the Slack API does not provide any official means to attach custom data / meta data to messages. But with some simple "hacks" it is still possible. Here is how:
Approach
The basic approach is to use an existing field of the message as container for your data. Obviously you want to pick a field that is not directly linked to Slack functionality.
Some field are not always needed, so you can just use that field as data container. Or if its needed, you can include the functional value of that field along with your custom data in the data container.
For example for message buttons you could use the value field of a button and structure your code in a way that you do not need it in its original function. Usually its sufficient to know which button the user client (via the name field), so the value field is free to be used for your custom data. Or you can include the functional value of your button along with the custom data in a data container (e.g. a JSON string) in that field.
Serialization
All messages are transported through HTTP and mostly encoded as UTF-8 in JSON. So you want to serialize / de-serialize your data accordingly, especially if its binary data. If possible I would recommend to use JSON.
Length
The maximum allowed length of most fields is documented in the official Slack API documentation. e.g. for the value field for message buttons can contain up to 2.000 characters. Keep in mind that you need to consider the length of your data after serialization. e.g. if you convert binary data into Base64 so it can be transported with HTTP you will end up with about 1.33 characters for every byte.
Contents
In general I would recommend to keep your data container as small as possible and not include the actual data, but only IDs. Here are two common approaches:
Include IDs of your data objects and load the actual objects
from a data store when the request is later processed.
Include the ID of server session and when processing the request you
can restore the corresponding server session which contains all data
objects.
In addition you might need to include functional values so that the functionality of the field you are using still works (e.g. value of a menu option, see below)
Implementation
Dialogs
Dialogs provide an official field for custom data called state. Up to 3.000 characters.
Message buttons
For Message buttons you can use the message action fields / value. Up to 2.000 characters. Its also possible to use the name field, but I would advise against it, because the maximum allowed length of that field is not documented.
Message menus
For Message menus you can use the value field of an option or the name field of the menu action.
Usually the value field is the better approach, since you have a documented max length of 2.000 and it gives you more flexibility. However, you will need to combine you custom data with the actual functional value for each option. Also, this will not work for dynamic select elements (like users), where you can not control the value field.
When using the name field note, keep in mind that the maximum allowed length of name is not documented, so you want to keep you data as short as possible. Also, if you want to use more than one menu per attachment you need to include the actual name of the menu into your data container.
Normal message attachments
Normal message attachments do not contain any suitable field to be used as container for custom data, since all fields are linked to Slack functionality.
Technically you could use the fallback field, but only if you are 100% sure that your app is never used on a client that can not display attachments. Otherwise your data will be displayed to the user.
when getting back references from Yammer through the dev api, they can be of a few different types. Is there any documentation somewhere that describes the JSON model of returned objects?
Right now I have got the following from just reading the returned JSON.
Type:
- "user"
- "guide"
- "group"
- "thread"
- "topic"
But there could be other types I'm not expecting which could be sent in the future. Is there a list somewhere that describes indepth all the possible return types from the Yammer API?
There's not currently any documentation resource that will provide that information. It's also possible for additional reference types to be added later.
To deal with references robustly, you'll need to add code to handle the reference types you know about and do something reasonable for reference types you don't recognize.
The something reasonable may vary, but a good start would be to somehow log the reference and otherwise ignore it.
I'm trying to understand the plug-in sample from here.
There's this condition:
// The InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
Speaking generally, not just with regard to this sample, on what prior knowledge should I base my decision to access a specific property? How could I have known to test whether the InputParameters contains a "Target" key (I assume I'm not supposed to guess it)?
And on what basis could I have known to ask whether the "Target" mapped value is of Entity type, and not some other type?
I found this post from 2 years ago, and I've found this webpage, saying (emphasis is mine):
Within a plugin, the values in context.InputParameters and
context.OutputParameters depend on the message and the stage that you
register the plugin on. For example, "Target" is present in
InputParameters for the Create and Update messages, but not the
SetState message. Also, OutputParameters only exist in a Post stage,
and not in a Pre stage. There is no single source of documentation
that provides the complete set of InputParameters and OutputParameters
by message and stage.
From my searchings, a single source still doesn't exist, but maybe the possible values can be found using the Dynamics Online platform, somewhere deep down the Settings menu, maybe? Any source would be great.
I know this is an "old" question that already has been answered, but I think this can be helpful. I've built a small web page that contains all the messages with all the Input/Output parameters. You can access it from here:
The best practice for doing this is to use a strongly typed approach. If, for example, you want to know which propertes are available on a CreateRequest, you would do:
var createReq = new CreateRequest() { Parameters = context.InputParameters };
createReq.Target; // Has type Entity
Take a look at the full blog post explaining this approach: Tip: Proper handling of Plugin InputParameters
Original answer:
It depends on which request we are talking about. See Understand the data context passed to a plug-in on MSDN.
As an example, take a look at CreateRequest. One property of
CreateRequest is named Target, which is of type Entity. This is the
entity currently being operated upon by the platform. To access the
data of the entity you would use the name “Target” as the key in the
input parameter collection. You also need to cast the returned
instance.
Note that not all requests contain a Target property that is of type
Entity, so you have to look at each request or response. For example,
DeleteRequest has a Target property, but its type is EntityReference.
In summary: Look at the actual request, e.g the CreateRequest.
In 2011 someone actually generated typed properties based on the message type. Kind of neat: https://xrmpalmer.wordpress.com/2013/05/27/crm2011-plugin-inputparameter-and-outputparameter-helper/
It would show you want parameters are possible per message.
I am having a similar problem to the one described in this previously asked question, but I am looking for a bit more detail in the answer as my lack of experience in this area doesn't allow me to fill in some of the blanks:
Tag Outlook MailItem with ID number before send without causing TNEF (RTF) send
Like the asker of that question, I would like to set a User Property, say it's named "XXXX", to a MailItem while the user is composing it, so that when the user later revisits that same MailItem in his or her Sent Items folder I could read the "XXXX" property's value again.
My additional questions would be as follows:
Dmitry Streblechenko suggests using MailItem.PropertyAccessor.SetProperty, but wherever I see that used I see people using a schema link to represent the property. What would be the correct schema link to use if I want my property still to be known as "XXXX"? In other words, what would be the correct syntax to use in Dmitry's suggestion?
I gather I could use a ".GetProperty" call to read the property later from the Sent Items, but the problem is that our add-in has been around for years, and users sent items are already full of MailItems with the original UserProperty "XXXX" in them. Will I still be able to use UserProperties to get property "XXXX" even if I use .PropertyAccessor.SetProperty to set them?
Alternatively, if I kept using the original code to set UserProperties while composing the message, but I then used .PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-C000-000000000046}/8582000B", false) during the ItemSend, like the original poster is suggesting, then I understand the UserProperties are not sent out with the message, which is fine by me, but will they still be available when revisiting the message in the Sent Items folder? Eugene Astafiev suggests that it's safe to use that .SetProperty call, but he doesn't clarify whether it affects what happens to the message at the Sender's end.
My personal preference would be a solution that would a) allow me to send the item without having to force Outlook in any way to send the message in any particular format and b) be able to continue to access the properties in the users' inboxes as we always have through the MailItem's UserProperties, but I am aware that I may be asking for something impossible here.
You need a property in the PS_INTERNET_HEADERS namespace. E.g. http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/x-my-prop.
Yes if you specify the full DASL name.
Yes, the user property will still be there in the Sent Items folder.
JSON API REST endpoint with permissions-restricted fields
I am working on a JSON API-compliant REST api. Some endpoints contain fields that should be restricted (read-only or not available) for certain users.
What is the best way to architect the api to allow that certain users have access to certain fields, while others do not? By "best", I mean:
Most compliant with REST standards, ideally JSON API standards
Most clarity in terms of preventing bugs and confusion on behalf of clients consuming the API
I am considering the following options, each with their set of concerns/ questions. I would be more than grateful for any other solutions!
Option 1: Return null on restricted fields for users without permissions
Different data values would be returned per-user. Is this strictly anti-REST?
Lack of distinction between null meaning "null value" and null meaning "You don't have access to this"
In REST/ JSON API architecture, is it okay for an endpoint to return different data per user, based on permissions? I have the impression that this would be contrary to the spirit of resource-based REST architecture, but I could not find anything specific to point to in any doc or standard (e.g. JSON API). Also applies to Option 2.
Is there any paradigm for adding some sort of "You don't have access" flag in the resource's metadata?
Option 2: Exclude restricted fields entirely for users without permissions
Different data values would be returned per-user. Is this strictly anti-REST?
Possibility of "undefined" errors in client, when trying to retrieve field value
Option 3: Move restricted field(s) onto another endpoint, available as an ?include='field_name' relation for those with permission
Example: /api/entity includes attribute field "cost" which is only available to Admin users. Admin users can request cost data via GET /api/entity?include=cost. For all users, "cost" is exposed as a relation in the resource object, with a "type" and "id".
This is the option I am leaning toward. The main con here is endpoint clutter. I have a lot of relations that would need to be made into separate endpoints, simply to support a permissions-quarantined data on an already-existing endpoint.
In the JSON API specs, I am having trouble determining if it's ok for an endpoint to exist as a relation only, e.g. can we have /api/entity/1/cost, but NOT have a top-level api endpoint, /api/cost. My assumption is that if a resource has a "type" (in this case, the relation type being 'cost'), it also has to live on a top-level endpoint.
In this scenario, the client could get a 401: Unauthorized error response if a non-admin user tries to GET /api/entity?include=cost or GET /api/cost/:id
Note: I have already built a separate permissions schema so that the client can determine which CRUD privileges the user has, per top-level endpoint, before making any requests. Permission sets are indexed by resource type.
Any help on the matter would be very much appreciated! And if anything needs to be clarified, feel free to ask.
I would definitely not use undefined or null to indicate fields that the user is not allowed to see. To me, that feels like a lie and represents that the data is really not there. They would have to really know your API in order to get a grasp of what is really going on.
I would recommend something more like your 3rd option, except I would make it a different endpoint altogether. So in your example, the endpoints would be:
/api/entity/1/cost
and for admins
/api/admin/entity/1/cost
or something like that.
This way your server code for the admin endpoint could just be focused on authenticating this admin user and getting them back all the fields that they have visibility on. If a non admin user tries to hit that route, reject them with an unauthorized status code.
I'm not saying that you should not implement the GET param to be able to specify fields as well. You can if you want to, but I don't think it just won't be necessary in this case.