I'm trying to add a new comment to a work item which mentions a user, but using the traditional "#adamh" as you would do on the website does not seem to work via the API.
The data updates fine, however the "#adamh" is just plain text, I need to be able to somehow chuck an identity into here. Can anyone point me in the right direction?
Thanks!
A snippet is here
const vsts = require('vso-node-api');
const item = require('vso-node-api/WorkItemTrackingApi')
const ti = require('vso-node-api/interfaces/WorkItemTrackingInterfaces');
// your collection url
const collectionUrl = "https://myArea.visualstudio.com/defaultcollection";
// ideally from config
const token = "helloWorld";
async function run() {
let authHandler = vsts.getPersonalAccessTokenHandler(token);
let connection = new vsts.WebApi(collectionUrl, authHandler);
let itemTracking = await connection.getWorkItemTrackingApi();
//Add all task data to new array
let taskData = await itemTracking.getWorkItems([15795,15796])
let newData = taskData[0]
let wijson = [
{
"op": "add",
"path": "/fields/System.History",
"value": "#adamh"
}
];
const updateItem = itemTracking.updateWorkItem(null, wijson, 15795).catch(err => {
console.log(err)
}).then(() => console.log("updated"))
return newData
}
const express = require('express')
const app = express()
app.get('/', async (req, res) => {
let data = await run()
res.send(data)
})
app.listen(3000, () => console.log('Example app listening on port 3000!'))
You can use the format shown here as part of the text value for your new comment:
...
This will create a mention link to that user. The link text can be the person's name or any other text you choose to put there. An email alert will be sent to the mentioned user if your system is configured to do so (same as in the UI).
To get your users' userid strings, you can follow the method shown here.
You can use the # to notify another team member about the discussion. Simply type # and their name.
It's using the #mention control , the person you #mention will receive an email alert with your comment and a link to the work item, commit, changeset, or shelveset.
There is not any public API shows how this work in VSTS, you could try to use F12 in google browser to track the process. Another workaround is directly using API to send a notification to the user you want to mention at.
Related
I have viewed all the articles on here, and haven't done any javascript coding in the past. Hoping someone can help me.
I have a class called rank and of course the parse _User class. I have added a pointer to the _User class to the rank class (the column name is called user_rank, which allows me to give a user a rank - seems simple enough.
What I am trying to achieve, is to use Cloud Code to change a user's rank as the administrator of the app (so it's something I do in my admin app, not the user does in their app).
This is what I have, but all I get is an error 101 'Object not found'. I have no doubt I am doing this all wrong, but I have tried to piece together responses from other posts with no success.
Any help is greatly appreciated.
Updated code with Davi's change below - now throwing error schema mismatch for _User.user_rank; expected Pointer but got String
Parse.Cloud.define("setUserRank", async (request, response) => {
let { userObjectId, rankObjectId } = request.params;
const userQuery = new Parse.Query(Parse.User);
const rankQuery = new Parse.Query('rank');
// Get the user object to change the rank of
try{
let user = await userQuery.get(userObjectId, { useMasterKey: true});
let rank = await rankQuery.get(rankObjectId, { useMasterKey: true});
console.log(user);
console.log("Running");
const rankRelation = user.relation('user_rank');
rankRelation.add(user_rank);
user.save(null, { useMasterKey: true});
return ("User Rank Changed"));
} catch (err) {
throw new Error(err.message)
}
});
I think the problem happens because of this line:
const rankQuery = new Parse.Query(Parse.rank);
In the case of you custom classes, you need to pass the class name as a string:
const rankQuery = new Parse.Query('rank');
I'd like to create a simple Firefox extension to write a simple message to the Javascript console when a push notification is received from any site. I see there is a notification show event that seems like it should work although I can't seem to find an example of it in use. Is this possible?
I'm not sure that that API would handle your use case because the event is not global. It is placed on the object e.g.
var notify = new Notification("Hi there!").addEventListener('show', e => console.log("We showed it! ", e));
I can't think of a better solution if you want to watch for global events than what is mentioned in https://stackoverflow.com/a/36868084/4875295 -- Monkey Patching!
Copying the code from that answer for posterity:
function setNotificationCallback(callback) {
const OldNotify = window.Notification;
const newNotify = (title, opt) => {
callback(title, opt);
return new OldNotify(title, opt);
};
newNotify.requestPermission = OldNotify.requestPermission.bind(OldNotify);
Object.defineProperty(newNotify, 'permission', {
get: () => {
return OldNotify.permission;
}
});
window.Notification = newNotify;
}
I am building a slackbot that will remind people in my organisation to perform certain admin (hours expenses etc) every week. I know this can be very easily done by each person creating a recurring reminder. What i want is to create a bot that will send a preconfigured message to people every week. I've looked online extensively, and haven't yet found out how slackbot can send a message without an event or being otherwise prompted.
I'm currently testing this on a local ngrok server with the following backend:
const { WebClient } = require('#slack/web-api');
const { createEventAdapter } = require('#slack/events-api');
const slackSigningSecret = process.env.SLACK_SIGNING_SECRET;
const slackToken = process.env.SLACK_TOKEN;
const port = process.env.SLACK_PORT || 3000;
const slackEvents = createEventAdapter(slackSigningSecret);
const slackClient = new WebClient(slackToken);
slackEvents.on('app_mention', (event) => {
console.log(`Got message from user ${event.user}: ${event.text}`);
(async () => {
try {
await slackClient.chat.postMessage({ channel: event.channel, text: `Hello <#${event.user}>! Have you completed your Time sheets for this week yet?` })
} catch (error) {
console.log(error.data)
}
})();
});
slackEvents.on('error', console.error);
slackEvents.start(port).then(() => {
console.log(`Server started on port ${port}`)
});
Once this reminder is done, i intend to build upon it (more features, just need a beginning) so please don't recommend alternative ways my organisation can send reminders to people.
You can try using the chat.scheduleMessage method instead (https://api.slack.com/methods/chat.scheduleMessage). Since you won't rely on an event you may want to store the necessary conversations ids so that they're ready when the app needs to call the method.
Working on a Teams chatbot (V4/Node) and need to address GDPR.
In short, users of the chatbot need to be able to export or delete their personal data stored by the chatbot. Personal data is any information which is related to an identified or identifiable natural person. So also a user-ID in a state object.
I read a blog about GDPR and bots but this one does not address the Teams channel. And it is about V3
The personal data given by the user in dialogs (written by me) is
the easy part. I will write some dialogs to show and delete them
(like Bill does in his answer).
The content in the actual conversations is part of the Teams platform and will\should be adressed in Teams itself.
The bit I don't know how to address is the data for the bot to actually run (Bot state etc). What if a user needs to delete the fact that he or she participated in a certain conversation. That is probably stored in some state objects (in my case in Blob storage). But which ones?
I would appreciate some ideas\guidance in how to address this.
Disclaimer: I'm not a GDPR expert but I believe the following to be sufficient.
From a bot standpoint the data stored is the same in Teams channel. You have the conversation state and user state data which is typically (and in most of the examples) set up using Blob storage. I use the conversationState and userState nomenclature for these items.
In my use case, I am storing account number in userState and user name/email in conversationState. Note that there are other things that the bot stores (particularly in conversationState I believe) around the state of the dialog and other bot specific things that are rather meaningless generally but I don't know if they would be considered part of GDPR. Regardless we will be wiping these entire objects out.
To do that, I created a dialog to manage the user profile which displays the key information stored (I'm specifically accessing account number, user name, and email) and then prompts the user for if they want to delete the information. It looks like this in nodejs.
const { ConfirmPrompt, ComponentDialog, WaterfallDialog } = require('botbuilder-dialogs');
const { ActivityTypes } = require('botbuilder');
const WATERFALL_DIALOG = 'waterfallDialog';
const CONFIRM_PROMPT = 'confirmPrompt';
class manageProfileDialog extends ComponentDialog {
constructor(dialogId, userDialogStateAccessor, userState, appInsightsClient, dialogState, conversationState) {
super(dialogId);
this.dialogs.add(new ConfirmPrompt(CONFIRM_PROMPT));
this.dialogs.add(new WaterfallDialog(WATERFALL_DIALOG, [
this.showInfoAndPrompt.bind(this),
this.confirmDelete.bind(this)
]));
this.initialDialogId = WATERFALL_DIALOG;
// State accessors
this.userDialogStateAccessor = userDialogStateAccessor;
this.userState = userState;
this.dialogState = dialogState;
this.conversationState = conversationState;
this.appInsightsClient = appInsightsClient;
} // End constructor
async showInfoAndPrompt(step) {
this.appInsightsClient.trackEvent({name:'manageProfileDialog', properties:{instanceId:step._info.values.instanceId, channel: step.context.activity.channelId}});
this.appInsightsClient.trackMetric({name: 'showInfoAndPrompt', value: 1});
const userProfile = await this.userDialogStateAccessor.get(step.context, {});
const conversationData = await this.dialogState.get(step.context, {});
if (!userProfile.accountNumber & !conversationData.userEmail & !conversationData.userFullName & !conversationData.orderType) {
this.appInsightsClient.trackEvent({name:'manageProfileDialogEnd', properties:{instanceId:step._info.values.instanceId, channel: step.context.activity.channelId}});
this.appInsightsClient.trackMetric({name: 'confirmDelete', value: 1});
await step.context.sendActivity(`I don't have any of your information stored.`);
return await step.endDialog();
} else {
var storedData = '';
if (userProfile.accountNumber) {
storedData += ` \n**Account Number:** ${userProfile.accountNumber}`;
}
if (conversationData.userFullName) {
storedData += ` \n**Name:** ${conversationData.userFullName}`;
}
if (conversationData.userEmail) {
storedData += ` \n**Email:** ${conversationData.userEmail}`;
}
if (conversationData.orderType) {
storedData += ` \n**Default order type:** ${conversationData.orderType}`;
}
await step.context.sendActivity(`Here is the informaiton I have stored: \n ${storedData} \n\n I will forget everything except your account number after the end of this conversation.`);
await step.context.sendActivity({ type: ActivityTypes.Typing });
await new Promise(resolve => setTimeout(resolve, process.env.DIALOG_DELAY));
return await step.prompt(CONFIRM_PROMPT, `I can clear your information if you don't want me to store it or if you want to reneter it. Would you like me to clear your information now?`,['Yes','No']);
}
}
async confirmDelete(step) {
this.appInsightsClient.trackEvent({name:'manageProfileDialogEnd', properties:{instanceId:step._info.values.instanceId, channel: step.context.activity.channelId}});
if (step.result) {
const userProfile = await this.userDialogStateAccessor.delete(step.context, {});
const conversationData = await this.dialogState.delete(step.context, {});
await step.context.sendActivity(`OK, I have cleared your information.`);
return await step.endDialog();
} else {
await step.context.sendActivity(`OK, I won't clear your information. You can ask again at any time.`);
this.appInsightsClient.trackMetric({name: 'confirmDelete', value: 1});
return await step.endDialog();
}
}
}
module.exports.ManageProfileDialog = manageProfileDialog;
One thing I am uncertain of regarding GDPR is if you are storing transcripts or activity data elsewhere in the course of running the bot. For example, I am storing conversation transcripts in CosmosDB, which could include things like names and email addresses if they were provided during the course of the conversation. I don't have a good way to clear this information even if I wanted to. Also, I am storing LUIS traces and other information in Application Insights, which in many cases includes the activity which may have things like user name or ID attached. I'm not even sure it would be possible to delete those traces from Application Insights. I do not know if these fall under the realm of GDPR since they are operational, but if that is a potential concern just be careful about what you are storing in your logging and/or transcript applications.
I'm trying to post directly to facebook/twitter without prompting the user with a UIViewController using the following code:
// 1. Create the service
var facebook = new FacebookService {
ClientId = "<App ID from developers.facebook.com/apps>",
RedirectUrl = new System.Uri ("<Redirect URL from developers.facebook.com/apps>")
};
// 2. Create an item to share
var item = new Item { Text = "Xamarin.Social is the bomb.com." };
item.Links.Add (new Uri ("http://github.com/xamarin/xamarin.social"));
// 3. Present the UI on iOS
var shareController = facebook.GetShareUI (item, result => {
// result lets you know if the user shared the item or canceled
DismissViewController (true, null);
});
PresentViewController (shareController, true, null);
BUT the Xamarin.Social instructions say:
As an alternative to presenting the share UI, you can share items directly using the **ShareItemAsync** method of the service.
https://github.com/xamarin/Xamarin.Social
I can't find any examples or explicit tutorials on how to use this. Can anyone help me on this please?
If you look at the source of Xamarin.Social, internally ShareItemAsync is used anyways to carry out the requests. GetShareUI is just a wrapper around ShareItemAsync.
From the source of ShareViewController (which gets the UI), you can see how they are using ShareItemAsync to carry out the requests. Here's the snippet for you.
try {
service.ShareItemAsync (item, account).ContinueWith (shareTask => {
StopSharing ();
.
.
.
.
.
}, TaskScheduler.FromCurrentSynchronizationContext ());
}
So all you need to do is create the item, get hold of the account and call the method on the service, something like this
var item = new Item { Text = "Xamarin.Social is the bomb.com." };
item.Links.Add (new Uri ("http://github.com/xamarin/xamarin.social"));
var account = facebook.GetAccountsAsync().FirstOrDefault();
facebook.ShareItemAsync(item, account);