Presentation
Goal: Find when the last message of a designated was send
How: Use property of User, lastmessageID, fetch the message corresponding to this ID to find the property createdTimestamp
Problem: I'm the only one in the was doesn't have the property lastmessageID equal to null even if the user had send message a few minute ago
Question: Is it coming from my coding or from Discord.js ? Is there a way to bypass this problem ?
NOTE: I know it's cached:
When someone send a message while the bot is alive give the same result.
For the sake of the test, I summon a bot that so I give me a"fresh" message when testing
CODE SAMPLE
every "..." is to protect personal data
SCRIPT
function findID() {
var IDarray = userm.users.map((user) => user.lastMessageID)
console.log("IDarray: ", IDarray)
var ID = IDarray[0]
console.log("ID: ", ID)
msg(ID)
}
function msg(lastmsgID) {
var lastmsg = message.channel.messages.fetch(lastmsgID).then(message => time(message)).catch(console.error);
}
function time(msg){
...
}
findID();
RESULTS
WITH ME
user: [
User {
id: '...',
bot: false,
username: '...',
discriminator: '....',
avatar: '...',
flags: UserFlags { bitfield: ... },
lastMessageID: '...',
lastMessageChannelID: '...'
}
]
IDarray: [ '...' ]
ID: ...
<Wed Oct 07 2020 00:30:52 GMT+0200 (GMT+02:00)> : Recieved Message to ..., content /test <#!...>
Date as YYYY-MM-DD hh:mm:ss ==> 2020-10-07 00:30:54
RESULTS
WITH ANYONE
user: [
User {
id: '...',
bot: false,
username: '...',
discriminator: '...',
avatar: '...',
lastMessageID: null,
lastMessageChannelID: null,
flags: UserFlags { bitfield: ... }
}
]
IDarray: [ null ]
ID: null
<Wed Oct 07 2020 00:26:44 GMT+0200 (GMT+02:00)> : Recieved Message to ..., content /test <#...>
Date as YYYY-MM-DD hh:mm:ss ==> NaN-aN-aN aN:aN:aN
If you think I can improve this question by anyway, don't hesitate to tell me !
Thanks for reading !
Try client.users.fetch('uid'); to fetch the user then pull the info you need. This pulls updates the user from Discord not from the cache.
This is a problem with the cache. The bot will only give lastMessage if the message was sent after the bot is started. You would need to fetch all the messages from all the channels for it to work, or just wait for the users to post a message after to bot is started.
Related
I'm trying to send ics calendar invites to users from node.js server with the goal of getting email clients (e.g. Gmail/Outlook etc) to render them as actual invites and not just usual file attachments.
This is very similar to what Calend.ly does.
So, basically, I'm trying to get something like this in Gmail:
The flow I need is the following (on the client-side):
In my frontend app User 1 presses the schedule event button;
User 2 presses accept button.
The event gets automatically scheduled and appears in both users google calendars (without any OAuth 2.0 stuff or anything like that. Just 2 button presses).
At the same time the users get emails with event details and the .ics file attachment. But the invites should already be in their calendars.
How can I do that?
If I need to use Google Calendar API for this, then how should I at least approach this if I can't have any OAuth 2.0 stuff for my users?
What I'm currently doing is I'm generating .ics files and sending them using SendGrid. However, with .icss I can't achieve a result like in the image above. These .ics files are not invites, they are merely attachments.
So I was wondering how should I approach this at all? Is using Google Calendar API the right way to implement this? If yes, then how can it be done server-side-only without making users authenticate?
I know it's possible because Calendly does exactly this. Users just enter their emails into the input field, press submit and the event invites automatically appear in their Google calendars.
How could this be implemented?
Maybe I don't get something, but generating .ics files doesn't seem to do the trick, and at the same time Google Calendar API does not appear to be the solution as well because of OAuth2 authentication.
In their docs they say:
Your application must use OAuth 2.0 to authorize requests. No other authorization protocols are supported.
Here's the code I'm using to send emails with .ics attachments (there's also a template on SendGrid side, hence the dynamicTemplateData prop):
const SendGrid = require("#sendgrid/mail");
const attachment = {
filename: 'invite.ics',
name: 'invite.ics',
content: Buffer.from(data).toString('base64'),
disposition: 'attachment',
contentId: uuid(),
type: 'text/calendar; method=REQUEST',
};
SendGrid.send({
attachments: [attachment],
templateId,
from: {
email: config.emailSender,
name: config.emailName,
},
to: user.email,
dynamicTemplateData: {
...rest,
user,
},
headers: {
'List-Unsubscribe': `<mailto:unsubscribe.link`,
},
});
And here's how my .ics attachment files look like:
BEGIN:VCALENDAR
PRODID:-//Organization//Organization App//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:REQUEST
BEGIN:VEVENT
DTSTART:20210420T180000Z
DTEND:20210420T190000Z
DTSTAMP:20210418T201735Z
ORGANIZER;CN=Denis Yakovenko:MAILTO:test+1#gmail.com
UID:25bb4d3e-b69d-46b0-baea-489c71c48c88
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=Denis Yakovenko;X-NUM-GUESTS=0:MAILTO:test+1#gmail.com
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=John Smith;X-NUM-GUESTS=0:MAILTO:test+2#gmail.com
CREATED:20210418T201735Z
DESCRIPTION:my description
LAST-MODIFIED:20210418T201735Z
LOCATION:https://virtual.location.com
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:my summary
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR
I referenced this issue on the sendgrid repository as well as converted the solution from the ruby version to javascript.
The following worked for me successfully and Google generated the event preview.
const ics = require("ics");
const sendgrid = require("#sendgrid/mail");
const event = {
start: [2018, 5, 30, 6, 30],
duration: { hours: 6, minutes: 30 },
title: "Bolder Boulder",
description: "Annual 10-kilometer run in Boulder, Colorado",
location: "Folsom Field, University of Colorado (finish line)",
url: "http://www.bolderboulder.com/",
geo: { lat: 40.0095, lon: 105.2669 },
categories: ["10k races", "Memorial Day Weekend", "Boulder CO"],
status: "CONFIRMED",
busyStatus: "BUSY",
organizer: { name: "Admin", email: "Race#BolderBOULDER.com" },
attendees: [
{
name: "Adam Gibbons",
email: "adam#example.com",
rsvp: true,
partstat: "ACCEPTED",
role: "REQ-PARTICIPANT",
},
],
};
const { value } = ics.createEvent(event);
sendgrid.setApiKey(process.env.SENDGRID_API_KEY);
sendgrid.send({
to: "email#example.com",
from: "test#example.com",
subject: "This is an example email 3",
content: [
{
type: "text/plain",
value: "Plain Content",
},
{
type: "text/html",
value: "HTML Content",
},
{
type: "text/calendar; method=REQUEST",
value: value,
},
],
attachments: [
{
content: Buffer.from(value).toString("base64"),
type: "application/ics",
name: "invite.ics",
filename: "invite.ics",
disposition: "attachment",
},
],
});
When I authenticate using WebAuthn and my YubiKey, the response.userHandle property is always null. That is the user id and displayName that I registered the credential with does not get returned. Is this becuase of something I am doing wrong during the registration / authentication process:
async function register() {
const publicKeyCredentialCreationOptions = {
challenge: Uint8Array.from("this-is-a-test", (c) => c.charCodeAt(0)),
rp: {
name: "Webauthn Test",
id: "localhost",
},
user: {
id: Uint8Array.from("a1b2c3d4e5f6", (c) => c.charCodeAt(0)),
name: "just-a-test",
displayName: "MrUser",
},
pubKeyCredParams: [{ alg: -7, type: "public-key" }],
authenticatorSelection: {
authenticatorAttachment: "cross-platform",
},
timeout: 60000,
attestation: "direct",
};
const credential = await navigator.credentials.create({
publicKey: publicKeyCredentialCreationOptions,
});
}
This is the code I use to authenticate:
async function authenticate() {
const publicKeyCredentialRequestOptions = {
challenge: Uint8Array.from("test", (c) => c.charCodeAt(0)),
allowCredentials: [
{
id: credentialId,
type: "public-key",
transports: ["usb", "ble", "nfc"],
},
],
timeout: 60000,
};
const assertion = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions,
});
console.log(assertion);
}
What I end up with is:
{
rawId: ArrayBuffer(64),
id: "U-nitqhlORmmdltp7TLO3i18KNoWsSebFyrtc3OIRvcktvwlz-dJZCA1_1gxXrNHzqReU7xGAHdfVP75N2aJSw",
response: {
authenticatorData: ArrayBuffer(37) {}
clientDataJSON: ArrayBuffer(101) {}
signature: ArrayBuffer(71) {}
userHandle: null
}
type: "public-key"
}
As you can see: userHandle is null. Can anyone tell me why?
The userHandle can be null depending on which type of WebAuthn credential the relying party requested to be created.
The default WebAuthn behavior will create a non-discoverable credential and the userHandle returned in the assertion will be null. No data is stored on the authenticator for this type of credential so there is nothing to return.
To create a WebAuthn client-side discoverable credential, a.k.a. resident key, you must set the requireResidentKey member to true. This will store credential data on the authenticator and will return the userHandle in the assertion. Refer to the AuthenticatorSelectionCriteria in the W3C WebAuthn spec for the details.
Here is an example:
authenticatorSelection: {
authenticatorAttachment: "cross-platform",
requireResidentKey: true
},
See Yubico's WebAuthn Dev Guide to learn more about resident keys and the userHandle.
I have tried to understand what you are dealing with. I played with https://u2f.bin.coffee/ to get a feeling for the data flow. As a result of authentication I have received a response like:
Got response:
{
"keyHandle": "F74UNCdNv1d43zw7hqxYgkjR3O6dcevopiSb3jrcB3rMFRUM486LbsVExJD0R3ESC5MCb3zeFGdxvS3ksZ7sCA",
"clientData": "eyJ0eXAiOiJuYXZpZ2F0b3IuaWQuZ2V0QXNzZXJ0aW9uIiwiY2hhbGxlbmdlIjoiTXpPTjhXRHpvSDlhZHU0bTk5YWF0ZyIsIm9yaWdpbiI6Imh0dHBzOi8vdTJmLmJpbi5jb2ZmZWUiLCJjcm9zc09yaWdpbiI6ZmFsc2UsImV4dHJhX2tleXNfbWF5X2JlX2FkZGVkX2hlcmUiOiJkbyBub3QgY29tcGFyZSBjbGllbnREYXRhSlNPTiBhZ2FpbnN0IGEgdGVtcGxhdGUuIFNlZSBodHRwczovL2dvby5nbC95YWJQZXgifQ",
"signatureData": "AQAAAAUwRAIgEqi5POKKUraU97W3vbfn34DSWqXwiZwEi5g9QPPtS6MCIBbLYW1_b3aRjHQivSRZQUAfBobx6CZnQ0_VVvuu1LJJ"
}
Now I assume the keyHandle here is your authenticatorData, the clientData here is your clientDataJSON and that signatureData is your signature. Whatever this userHandle is you are missing, it does not seem to be required.
Look at this picture too:
If the userHandle were the handle, the authentication would not work with a null value. But it does if I understand your example correctly.
So I believe you are dealing with a field that is reserved for future purposes or other flows than that which you need at the moment.
I have a script which is working OK to send emails, but I have a requirement to attach the email to:
Multiple Entities (incl Projects)
Support Case
Multiple Custom records (mail merge is active)
My current script is as follows:
var emaildata = {body: field.fld_message+'<br />'+attachmentList+signature,
author: sender.entityid,
recipients: primary.email,
subject: field.fld_subject,
cc : cc_entities,
bcc : bcc_entities,
relatedRecords: {
entityId: entities,
activityId: field.claimid,
}
};
sendemail.send(emaildata);
The array variable entities contains the employees/partners I want to attach the email too, but it is not attaching to the records.
For the custom records, i have tried including this in the email data object:
customRecord: [
{id: field.submitid, recordType: 267},
{id: field.scopeid, recordType: 73 },
{id: field.assessid, recordType: 83 },
],
But sadly it is not working...
What am I doing wrong?
The email is being sent (sometimes) but not attaching.
When i tried with just ONE custom record, but was getting an Unexpected Suitescript error:
customRecord: {id: field.submitid, recordType: 267 }
I have confirmed the "id" fields are populated corrected.
var records = new Array();
records['record'] = '11'; // internal id of the record
records['recordtype'] = '250'; // record type id
nlapiSendEmail ( from,to,subject,body,cc,bcc,records,files);
It is working.`enter code here`
I am trying to create Web-hook to be notified about events that happen After creating Onfido Check for a customer from Back-end. While testing my Web-hook i am getting response as below:
{ resource_type: 'test_resource',
action: 'test_action',
object:
{ id: '1234-1234-2658-3698',
status: 'completed',
completed_at: '2018-03-12 07:06:48 +0000',
href: 'https://api.onfido.com/v2/test_sources//12343-11122-09290/reports/12345-23122-32123' } }
But i don't know What will be the Unique Key or ID (for ex. ApplicantID or CheckID ) which we can save in our database earlier while creating Applicant or while create Check on Applicant and after getting response from Webhook we could update Customer status.
In my case, I receive something like
{
payload: {
action: "check.completed",
resource_type: "check",
object: {
completed_at: "2018-08-15 13:36:30 UTC",
href: "https://api.onfido.com/v2/applicants/<applicant_id>/checks/<check_id>",
id: <check_id>,
status: "complete"
}
}
}
So, Here is applicant_id and check_id in payload.object.href field and check_id in payload.object.id field. (Something like this described in https://documentation.onfido.com/#event-object)
You can know your check_id from id field in a response from POST https://api.onfido.com/v2/applicants/{applicant_id}/checks as described here: https://documentation.onfido.com/#create-check
I have been implementing some functions of google calendar api. I have a custom calendar which have the capability to sync with google calendar. This means, you can create, and edit calendars and events from my dashboard to google calendar account. The main problem I am facing is, if I update the event directly from my google calendar. I have implemented push notifications and getting response like this:
{
"Google_channel_ID": "19835150 - 0057 - 11e6 - bc9c - 1735798 ca540",
"Google_channel_token": "calendar_id = 4e7 d5c20ht9lpfdtuukcsvgeq4 #group.calendar.google.com & user_id = 43e d7rxeqqce3fk09ahszc",
"Google_channel_expiration": "Tue,12 Apr 2016 12: 34: 36 GMT",
"Google_resource_id": "oLMEEhHAw5Xo3r2187CWykjAtm0",
"Google_resource_URI": "https: //www.googleapis.com/calendar/v3/calendars/4e7d5c20ht9lpfdtuukcsvgeq4#group.calendar.google.com/events?alt=json",
"Google_resource_state": "sync",
"Google_message_number": "1"
}
But this response is very general. For example, If I have 1000 events on this calendar, and update the complete 1000 events. I will receive always the same notification 1000. I would like to know, if it is possible to get which event id has change, so I can perform and update to my DB.
The way I init the watch is like this:
exports.watch = function(req, res){
var channel_id = uuid.v1();
var user_id = req.body.user_id;
var calendar_id = req.body.calendar_id;
authorize(user_id, function(oauth2Client){
var data = {
auth: oauth2Client,
calendarId: calendar_id,
resource: {
id: channel_id,
token: 'calendar_id='+ calendar_id + '&user_id=' + user_id,
address: 'https://api.medradr.com/google-watch',
type: 'web_hook',
params: {
ttl: '36000'
}
}
};
calendar.events.watch(data, function (err, response) {
if (err) {
console.error('The API returned an error: ' + err);
return;
}else{
res.send({ok: true, message: 'Listener created', result:response});
}
});
});
}
For people who are looking for a good way to get which events changed when the web hook triggers. When your web hook is triggered, you will get something like this:
X-Goog-Channel-ID: channel-ID-value
X-Goog-Channel-Token: channel-token-value
X-Goog-Channel-Expiration: expiration-date-and-time // In human-readable format; present only if channel expires.
X-Goog-Resource-ID: identifier-for-the-watched-resource
X-Goog-Resource-URI: version-specific-URI-of-the-watched-resource
X-Goog-Resource-State: sync
X-Goog-Message-Number: 1
On X-Goog-Resource-URI you will get something like this:
https://www.googleapis.com/calendar/v3/calendars/4e7d5c20ht9lpfdtuukcsvgeq4#group.calendar.google.com/events?alt=json
With you OAuth authentication, you can make a GET request to this URL to fetch all events that belongs to this calendar. Now the trick to know which resources have been changed is really simple. For each event you will get something like this:
{
event_id: 335,
user_id: '43ed7rxeqqce3fk09ahszc',
kind: 'calendar#event',
etag: '"2921213870180000"',
google_id: 'cpbcesg966skprb3rh1p1ud668',
status: 'confirmed',
htmlLink: 'https://www.google.com/calendar/event?eid=Y3BiY2VzZzk2NnNrcHJiM3JoMXAxdWQ2NjggNGU3ZDVjMjBodDlscGZkdHV1a2NzdmdlcTRAZw',
created: Thu Apr 14 2016 00:00:00 GMT-0500 (CDT),
updated: Thu Apr 14 2016 00:00:00 GMT-0500 (CDT),
summary: 'Testing google notifications',
description: '',
creator: 'guizarkrg#gmail.com',
organizer: '4e7d5c20ht9lpfdtuukcsvgeq4#group.calendar.google.com',
start: Sat Apr 09 2016 00:00:00 GMT-0500 (CDT),
end: Sun Apr 10 2016 00:00:00 GMT-0500 (CDT),
iCalUID: 'cpbcesg966skprb3rh1p1ud668#google.com',
event_type_id: 0,
calendar_id: 0,
timezone_id: 0,
sequence: 0,
calendar_color_id: ''
}
As you can see, the is a sequence: 0, this is incremental. This means, each time you apply some changes on your event (summary, description, start date, end date, etc). This number will be incremented +1. You can save this on your database, so each time web hook triggers, you update only events which sequence is > than saved sequence. So basically, you update the event and save the new value of sequence. Next time that web hook triggers, it will only update on your DB the events that are included in this condition.
Hope it helps, happy coding.