Mention channel using ms graph api - java

I am working with ms graph and i need to integrate with ms teams. In one case i have to send a message to a channel which will contain a channel mention (#). Currently i have found how to tag a specific user using java but i cant figure out how to mention the whole channel. It is posible to do so in ms graph and if yes how?
To be more specific here is an example. Assume that i have a team named TestTeam and this team has a channel named testChannel. i need to send a message where will contain #testChannel and will send a notification to everyone in this channel.
Also in slack api i am able to do this action by using "<!channel>" in my message.
This is the code i am using in order to tag a user:
static void send_message(String text, String mentionName, String channelName, String teamName, String accessToken) {
ensureGraphClient(accessToken);
Team team = getTeam(accessToken, teamName);
Channel channel = getChannel(accessToken, channelName, team);
User user = getUser(accessToken, mentionName);
if (userInChannel(user, team, channel)) {
ChatMessage chatMessage = new ChatMessage();
ItemBody body = new ItemBody();
body.contentType = BodyType.HTML;
body.content = String.format("%s. <at id=\"1\">%s</at> ", text, mentionName);
chatMessage.body = body;
ChatMessageMention m = new ChatMessageMention();
m.id = 1;
IdentitySet st = new IdentitySet();
Identity ide = new Identity();
ide.id = user.id;
ide.displayName = user.displayName;
st.user = ide;
m.mentioned = st;
m.mentionText = mentionName;
List<ChatMessageMention> cmmt = new LinkedList<>();
cmmt.add(m);
chatMessage.mentions = cmmt;
graphClient.teams(team.id).channels(channel.id).messages()
.buildRequest()
.post(chatMessage);
}
}
I also tried something similar in order to tag channels but it did not worked:
body.contentType = BodyType.HTML;
body.content = String.format("%s. <at id=\"1\">%s</at> ", text, "myChannel");
chatMessage.body = body;
ChatMessageMention m = new ChatMessageMention();
m.id = 1;
IdentitySet st = new IdentitySet();
Identity ide = new Identity();
ide.id = "19%xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%40thread.tacv2";
ide.displayName = "myChannel";
st.user = ide;
m.mentioned = st;
m.mentionText = "myChannel";
List<ChatMessageMention> cmmt = new LinkedList<>();
cmmt.add(m);
chatMessage.mentions = cmmt;
graphClient.teams(team.id).channels(channel.id).messages()
.buildRequest()
.post(chatMessage);

Introduction:
After playing around with it, here is the final result. And this is not final answer, but hope to lead for solution.
Lets start some introduction.
First lets define our post url:
POST https://graph.microsoft.com/beta/teams/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/channels/19:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx#thread.tacv2/messages
Now lets mentioning a user in graph api:
{
"body": {
"contentType": "html",
"content": "Hello World <at id=\"0\">Maytham Fahmi</at>"
},
"mentions": [
{
"id": 0, <- the index here should be the same as in the content message
"mentionText": "Maytham Fahmi",
"mentioned": {
"user": {
"displayName": "Maytham Fahmi",
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" <- this should be user user object id
}
}
}
]
}
This is tested and working via Graph Api.
Now I come to the interested part. Sending to channel with channel mentioning looks like this:
{
"body": {
"contentType": "html",
"content": "Hello World <at id=\"0\">General</at>"
},
"mentions": [
{
"id": 0, <- the index here should be the same as in the content message
"mentionText": "General",
"mentioned": {
"conversation": {
"id": "19:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx#thread.tacv2",
"displayName": "General",
"conversationIdentityType#odata.type": "#Microsoft.Teams.GraphSvc.conversationIdentityType",
"conversationIdentityType": "channel"
}
}
]
}
The results in teams, that is sent from channel mentioning
This is also working from Graph api explorer.
The answer:
So as we can see for user mentioning we use User object under IdentitySet instance which works fine for user. I have testing it C# using Microsoft.Graph.
Here is comes the problem Conversation object does not exist under IdentitySet in C# using Microsoft.Graph. I am pretty sure this is the case for Java as well. If you have that object in Java then you should be able to make it. It is perhaps not in C#.
I have red different places, and sadly channel mentioning objects is not implemented in code yet, looks like a bug or a feature they will fix over time.
A work around solution is, you have graph api json payloads, you can make a Java client to post Jsons to the url with and your job is done.
Note: I have look at our solution, it does not support mentioning as well.
Inspiration links:
https://learn.microsoft.com/en-us/graph/api/channel-post-message?view=graph-rest-1.0&tabs=csharp#permissions
https://learn.microsoft.com/en-us/graph/api/resources/chatmessagemention?view=graph-rest-1.0
Note in case you need to send notification in general, you could use webhooks.

Related

How to create a deep insert structure using Olingo Client?

How to POST the following JSON structure using Apache OLINGO client? What is the best way to build up this structure? Are there any examples?
{
"itemNumber": "ITEM1"
"lines": [
{
componentNumber": "COMPONENT1"
},
{
componentNumber": "COMPONENT2"
}
]
}
The following Java example using the Olingo Client works for me to post the following JSON structure:
{
"itemNumber": "ITEM1"
"lines": [
{
componentNumber": "COMPONENT1"
},
{
componentNumber": "COMPONENT2"
}
]
}
Java code using OLINGO CLient
public void deepInsertExample(){
//Initiate the ODATA client
ODataClient client = ODataClientFactory.getClient();
client.getConfiguration();
getClient().getObjectFactory();
//Initiate the Client Object Factory
ClientObjectFactory factory = getClient().getObjectFactory();
//Create Line Item 1
ClientEntity lineItem1 = factory.newEntity(new FullQualifiedName("ODATA.LineItem"));
lineItem1.getProperties()
.add(factory.newPrimitiveProperty("componentNumber", factory.newPrimitiveValueBuilder().buildString("COMPONENT2")));
//Create Line Item 2
ClientEntity lineItem2 = factory.newEntity(new FullQualifiedName("ODATA.LineItem"));
lineItem2.getProperties()
.add(factory.newPrimitiveProperty("componentNumber", factory.newPrimitiveValueBuilder().buildString("COMPONENT1")));
//Initiate the entity set
ClientEntitySet entitySet = factory.newEntitySet();
//Add Line Item 1 and Line Item 2 to the Enity
entitySet.getEntities().add(lineItem1);
entitySet.getEntities().add(lineItem2);
//Create the Lines LInk
ClientLink linesLink = factory.newDeepInsertEntitySet("Lines", entitySet);
ClientComplexValue complexValueCreate = factory.newComplexValue("Lines");
complexValueCreate.getNavigationLinks().add(linesLink);
//Create the Item object
ClientEntity item = factory.newEntity(new FullQualifiedName("ODATA.Item"));
item.getProperties()
.add(factory.newPrimitiveProperty("itemNumber", factory.newPrimitiveValueBuilder().buildString("ITEM1")));
//Add the Lines(Entity Set) link to Item Object
item.addLink(linesLink);
//Post the Item
URI absoluteUri = client.newURIBuilder("URL").build();
ODataEntityCreateRequest<ClientEntity> request = client.getCUDRequestFactory()
.getEntityCreateRequest(absoluteUri, item);
request.setAccept("application/json;odata.metadata=minimal");
request.execute();
}
You will have to specify the the NavigationPropertyName in the deep part. So for your sample payload it would look like
{
"itemNumber": "ITEM1",
"lines": {
"componentNumber":"COMPONENT1",
"componentNumber":"COMPONENT2",
}
}
You can refer to this post in SO to get details about n level nesting
The above answer asuumes that your NavigationProperty is named lines, you can substitute it with the right name by looking at service/$metadata
The answer assumes that you are trying to do deep inserts in a odata2 service, for OData4 the concept remains the same but syntax might vary a bit. Please refer to the payload descripted in documentation in case of OData 4

How can I send an object as part of the JSON Web Token?

I'm trying to create a web token using the jjwt library, but I can't figure out how to send an object as one of the claims. If I parse the object or manually create the string the entire string is coming through as the value instead of a separate JSON object. For instance, I want to send something that looks like this:
{
"iss": "NQoFK1NLVelFWOBQtQ8A",
"iat": 1511963669,
"user": {
"id": "exampleuser",
"email": "example#mail.com",
"name": "A User",
}
}
But all I've been able to create is:
{
"iss": "NQoFK1NLVelFWOBQtQ8A",
"iat": 1511963669,
"user": "{\"id\": \"example#mail.com\",\"email\": \"example#mail.com\",\"name\": \"A User\"}"
}
Welcome to StackOverflow!
This feature will be natively supported by JJWT when using Jackson in the upcoming JJWT 0.11.0 release (and you can read the docs for this feature too). But it is not available natively in 0.10.X and earlier.
Prior to 0.11.0, and assuming you're using Jackson, you'll have to do this yourself manually with the ObjectMapper:
// when creating:
User user = getUser();
ObjectMapper objectMapper = new ObjectMapper(); // or use an existing one
String json = objectMapper.writeValueAsString(user);
byte[] bytes = json.getBytes(StandardCharsets.UTF_8)
String base64 = Encoders.BASE64.encode(bytes);
String jws = Jwts.builder()
...
.claim("userJsonBase64", base64)
...
.compact();
//when parsing:
String userJsonBase64 = Jwts.parser()....parseClaimsJws(jws).getBody().get("userJsonBase64", String.class);
bytes = Decoders.BASE64.decode(userJsonBase64);
json = new String(bytes, StandardCharsets.UTF_8);
user = objectMapper.readValue(json, User.class);
Thank you for your answer, that will be a nice feature to have, once it's available. I wanted to follow up and post a workaround that I found, in case it helps anyone else in the meantime. I was able to create the JSON I needed using a Java HashMap (I found out the hard way that a Scala Map does not work) and then passing that as the value of the claim:
val user: util.Map[String, String] = new util.HashMap[String,
String]() user.put("id", email.value) user.put("email", email.value)
user.put("name", name.displayName)
...
val jws: String = Jwts.builder()
.claim("user", user)
.signWith(key).compact()

What is the recommended way to paginate using SPQR?

Building a graphQL API with SQPR. I have a large data collections and would like to load data page by page. What is the recommended way to do this with SQPR and how would it look from the client side (query)?
Also, keeping in mind Apollo client for angular as a potential client library. Now testing with graphiql.
ended up using this
#GraphQLQuery(name = "projects", description = "Return a paginated Projects results")
public List<Project> getAll(
#GraphQLArgument(name = "offset",defaultValue = "0", description = "Offset item from beginning of data") int offset,
#GraphQLArgument(name = "limit", defaultValue = "10", description = "Limit the size of fetched results") int limit
) { ... }
if anyone can comment or add a different solution...
G.

Pulling JSON data from URL in Android 2017

Before I get started, could I just point out I've spent the last 5 hours going in circles here. I've tried what seems like every StackOverflow method out there to pull what seems like a simple int from an API. This seems like it should be way easier, but isn't.
What I'm trying to achieve is pull the JSON info from this URL:
http://api.apixu.com/v1/current.json?key=ENTERKEYHERE&q=leeds
And then gather the category "temp_c", which should be something along the lines of "7.0". Below is an example of how a call looks:
{
"location": {
"name": "Leeds",
"region": "West Yorkshire",
"country": "United Kingdom",
"lat": 53.81,
"lon": -1.54,
"tz_id": "Europe/London",
"localtime_epoch": 1509670055,
"localtime": "2017-11-03 0:47"
},
"current": {
"last_updated_epoch": 1509669008,
"last_updated": "2017-11-03 00:30",
"temp_c": 7,
"temp_f": 44.6,
"is_day": 0,
"condition": {
"text": "Partly cloudy",
"icon": "//cdn.apixu.com/weather/64x64/night/116.png",
"code": 1003
},
"wind_mph": 4.3,
"wind_kph": 6.8,
"wind_degree": 150,
"wind_dir": "SSE",
"pressure_mb": 1015,
"pressure_in": 30.4,
"precip_mm": 0,
"precip_in": 0,
"humidity": 93,
"cloud": 75,
"feelslike_c": 5.8,
"feelslike_f": 42.4,
"vis_km": 10,
"vis_miles": 6
}
}
I've successfully gotten the data to pull into an app during random points in the night, however have been unable to pull the specific piece of data at all. Currently, my app won't pull it at all and I'm not sure what I did before.
I'm truly sorry if this is a question deemed "duplicate", but I can assure you that for someone trying to learn the language, none of the answers fully explain how to do this using the newer API's (Some of the answers seem to no longer work in API 23+)
I'm not looking for a detailed app with loads of methods, just a simple way of pulling the JSON data and selecting a specific category. I'd be extremely grateful if you could explain how to do this as I plan on adapting the code in the future for other sources. Thank you!
You should use an AsyncTask or AsyncTaskLoader so the UI-Thread doesn't lag during loading. Search for this term or use the UI thread, but then it will lag during the load. Eitherways, call this function, with url being your url:
public static String getResponse(URL url) throws IOException {
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
InputStream in = urlConnection.getInputStream();
Scanner scanner = new Scanner(in);
scanner.useDelimiter("\\A");
boolean hasInput = scanner.hasNext();
if (hasInput) {
return scanner.next();
} else {
return null;
}
} finally {
urlConnection.disconnect();
}
The url can be gotten by calling
url = new URL(yourAddressAsAString)
The upper functoin should return a string. Convert it into a JSON Object
JSONObject obj = null;
try {
obj = new JSONObject(yourString);
} catch (Throwable t) { }
Then call
String tempc = String.valueOf(obj.getJSONObject("current").getJSONObject("temp_c"))
To get the Object in question. Good luck!
First step take your whole Json as a String lets say String json_string and here is what you have to do (Read the comments in code for further information):
String json_string="your json string here as a normal String json object";
try {
JSONObject jsonObjectRoot=new JSONObject(json_string);
JSONObject locationObject=jsonObjectRoot.getJSONObject("location");
String name=locationObject.getString("name"); //This will return leeds
String region=locationObject.getString("region"); //This will return West YorkShire!
}catch (JSONException json_except){
//You have an exception so check if your items really exist with those names!
json_except.printStackTrace();
}
So from the above example using your own data you need to know is:
All Json code should be in a try block and catch Json exception.
To get a json object from a string just a constructor itself like new JSONObject(string);
To get any inner json object (json object within json object) we use the method outer_object.getJSONObject("string_name_of_inner_object");and continue deeper until you get your object.
To get a string within an object we use String string=json_object.getString("the_string_name_as_it_appears_in_the_object");
To get a Json Array inside an object you use JSONArray jsonArray=your_json_object.getJSONArray("array_name_as_it_appears_in_json");
I hope this will help you!

Smack - How to read a MultiUserChat's configuration?

I tried to create a multiuserchat with Java. I'm using smack library.
Here is my code to create multiuserchat:
MultiUserChat muc = new MultiUserChat(connection, "roomname#somehost");
muc.create("mynickname");
Form form = muc.getConfigurationForm();
Form submitForm = form.createAnswerForm();
submitForm.setAnswer("muc#roomconfig_roomname", "A nice formatted Room Name");
submitForm.setAnswer("muc#roomconfig_roomdesc", "The description. It should be longer.");
muc.sendConfigurationForm(submitForm);
muc.addMessageListener(mucMessageListener); // mucMessageListener is a PacketListener
Then, I tried to capture the message sent by this room created above using mucMessageListener:
private PacketListener mucMessageListener = new PacketListener() {
public void processPacket(Packet packet) {
if (packet instanceof Message) {
Message message = (Message) packet;
// this is where I got the problem
}
}
}
As the message received by other part (the user who is not the owner of this multiuserchat), can he somehow get the value set in this line above:
submitForm.setAnswer("muc#roomconfig_roomname", "A nice formatted Room Name");
You see, getting just the JID of the room is not really good for the view. I expect I could have a String which value is "A nice formatted Room Name".
How can we get that?
You can easily get its configurations like name and etc from this code:
MultiUserChatManager mucManager = MultiUserChatManager.getInstanceFor(connection);
RoomInfo info = mucManager.getRoomInfo(room.getRoom());
now you can get its informations like this:
String mucName = info.getName();
Boolean isPersistence = info.isPersistent();
and etc.
Retrieving the value of muc#roomconfig_romname is described in XEP-45 6.4. Smack provides the MultiUserChat.getRoomInfo() method to perform the query.
RoomInfo roomInfo = MultiUserChat.getRoomInfo(connection, "roomname#somehost.com")
String roomDescription = roomInfo.getDescription()
If you want to read a value of var for example title name of room in config
Form form = chat.getConfigurationForm();
String value = form.getField("muc#roomconfig_roomname").getValues().next();
then do what ever you want with value..

Categories