I learned about firebase and cloud functions recently and have been able to develop simple applications with them.
I now want to expand my knowledge and really struggling with Trigger Email Extension.
On a specific event on my firebase, I want to fire an email to the user in a custom format, but I am unable to even activate the extension for now.
Can someone please explain with example please about these fields marked in the picture?
I had this question too, but got it resolved. Here's your answer:
"Email documents collection" is the collection that will be read to trigger the emails. I recommend leaving named "mail" unless you already have a collection named mail.
"Users collection (Optional)" refers to a collection (if any) that you want to use in tandem with a user auth system. I haven't had this specific use case yet, but I imagine once you understand how Trigger Email operates, it should be somewhat self-explanatory.
"Templates collection (Optional)" is helpful for templates in which you can use handlebar.js is automatically input specific information per user. (eg. <p>Hello, {{first_name}}</p> etc.) Similar to the previously mentioned collections, you can name it whatever you want.
How to create a template (I have yet to actually implement this, so take this with a grain of salt):
In your templates collection, you want to name each document with a memorable ID. Firebase gives the example:
{
subject: "#{{username}} is now following you!",
html: "Just writing to let you know that <code>#{{username}}</code> ({{name}}) is now following you.",
attachments: [
{
filename: "{{username}}.jpg",
path: "{{imagePath}}"
}
]
}
...specifying a good ID would be following. As you can see, the documents should be structured just like any other email you would send out.
Here is an example of using the above template in javascript:
firestore()
.collection("mail")
.add({
toUids: ["abc123"], // This relates to the Users Collection
template: {
name: "following", // Specify the template
// Specify the information for the Handlebars
// which can also be pulled from your users (toUids)
// if you have the data stored in a user collection.
// Of course that gets more into the world of a user auth system.
data: {
username: "ada",
name: "Ada Lovelace",
imagePath: "https://path-to-file/image-name.jpg"
},
},
})
I hope this helps. Let me know if you have an issues getting this set up.
Related
A Brief Overview of the Problem
I am trying to store JSON data on my SendGrid contacts for usage in dynamic email templates designed in the SendGrid GUI.
To start, within the SendGrid email builder I can write the following code within a codeblock:
Here is the handlebar code in that code block...
<ol>
{{#each user.accounts}}
{{#if this.isPending}}
<li>
{{this.name}} is <strong>pending activation.</strong>
</li>
{{else}}
<li>
{{this.name}} is <strong>active.</strong>
</li>
{{/if}}
{{/each}}
</ol>
When I go to preview that code & add some test data I get the following:
Here is the JSON code in that code block formatted a bit nicer...
{
"user": {
"accounts": [
{
"name": "Checking",
"isPending": false
},
{
"name": "401k",
"isPending": true
},
{
"name": "Savings",
"isPending": true
}
]
}
}
The Question
Everything mentioned above is PERFECT so far - this is exactly what I want... To populate email data based on dynamic content present on each contact the email is going to. Here is where I hit the roadblock, where is that JSON Test Data coming from on the contact when the real email is sent out? And how do I populate a contact with JSON data using the API?
As far as I can tell, there is no option to add this custom JSON data to a new contact when creating one via the API (or via the GUI, for that matter) (see API docs here)
When I set up this email to send out to my SendGrid contacts via a SendGrid automation flow, does anyone know how to populate the JSON used by my code block for showing pending/activated accounts with data specific to each user?
Thank you, I greatly appreciate any help on this!
I think that JSON data is actually only useful when you are using the API to send an email with a template. You then provide the JSON data as dynamic_template_data and it is populated in the email template.
When dealing with Automations, you need to pull the data from the contact record itself. You can get the data you have on a Contact in the Tags section of the template designer.
There are a number of fields that already exist on contacts, like first_name, last_name, email, address_line_1, etc. You can also add Custom Fields which give you further fields you can use on your contacts. Custom Fields can be created by adding new columns on an CSV upload of your contacts, by creating them in the SendGrid admin or by creating them via API.
If you are using the API to create or update your contacts, you can pass an object of custom_fields as part of the contact record in the API request. For example:
const data = {
"contacts": [
{
"email": "ryan39#lee-young.com",
"custom_fields": {
"w1": "2002-10-02T15:00:00Z",
"w33": 9.5,
"e2": "Coffee is a beverage that puts one to sleep when not drank."
}
}
]
};
Note that to set custom fields on a contact when you create/update by the API like this, you need to use the custom field ID as the key in the custom_fields object (like the example above, the IDs "w1", "w33" , "e2" were used). If you need to know those IDs, you can use the API to get all field definitions.
Once you have added Custom Fields they will also be available as Tags in the design editor, then you can use them in the email design.
The only thing is, I notice you are using an array of accounts in your example. If you need an array of arbitrary data, then I don't believe you can achieve that with contact data and automations. You can set individual custom fields for, say, a checking account, 401k and savings. But you cannot have arbitrary data in a custom field. If you really need the data to be arbitrary, then Automations might not be right for you and you should send your emails out using the send mail API and providing dynamic template data.
I have a Firebase project where I'd like for users to be able to see when other users created their profiles. My initial hope was that I could use "user.metadata.creationTime" on the frontend to pass the date into the user's extra info document and verify that it is correct by having "request.resource.data.datecreated == request.auth.metadata.creationTime" as a Database Rule, but it looks like it is not possible according to the documentation.
Is there any way I can verify that the creation date is correct on the backend?
More info edit: Below is the code that is being triggered when a user creates a new account on my profile. The three values are displayed publicly. I'm creating a niche gear for sale page so being able to see when a user first created their account could be helpful when deciding if a seller is sketchy. I don't want someone to be able to make it seem like they have been around for longer than they have been.
db.collection('users').doc(user.uid).set({
username: "Username-156135",
bio: "Add a bio",
created: user.metadata.creationTime
});
Firestore rules:
match /users/{id} {
allow get;
allow create, update: if request.resource.data.username is string &&
request.resource.data.bio is string &&
request.resource.data.created == request.auth.metadata.creationTime;
}
user.metadata.creationTime, according to the API documentation is a string with no documented format. I suggest not using it. In fact, what you're trying to do seems impossible since that value isn't available in the API documentation for request.auth.
What I suggest you do instead is use a Firebase Auth onCreate trigger with Cloud Functions to automatically create that document with the current time as a proper timestamp. Then, in security rules, I wouldn't even give the user the ability to change that field, so you can be sure it was only ever set accurately by the trigger. You might be interested in this solution overall.
I am using Meteor 0.8.2 with accounts-facebook. I set up a limited publication for the users this way:
Meteor.publish('users', function () {
return Meteor.users.find({}, {fields: {'profile.picture': 1, 'profile.gender':1, 'profile.type':1}, sort: {'profile.likes': -1}});
});
Now this works great: when I requests a user list from the client I get a list of all users, with the current user's fields all shown and only the 3 published fields for the others. Except: right after login.
When I login and type Meteor.user(), here is what I get:
_id: "uACx6sTiHSc4j4khk"
profile: Object { gender="male", type="1", picture="http://....jpg"}
This stays like that until I refresh the page using the browser button. After refreshing, Meteor.user() gives all the fields available, while Meteor.users.find() still gives the correct restrictions. (except for the current user of course)
Why does my current user not get all its fields right away? I read about a Meteor.userLoaded() method used to wait for the user to be loaded, but it seems to be obsolete in the latest version.
You're running into an interaction between the restriction of merging fields across publications, and the default user publication which sends the profile field.
First, note that there is a built-in publication that always sends the currently logged in user's entire profile field to that user:
https://github.com/meteor/meteor/blob/devel/packages/accounts-base/accounts_server.js#L1172
Second, merging of fields at more than one level deep is currently not supported:
https://github.com/meteor/meteor/issues/998
What you currently have is an issue where the default publication is sending something like the following
{
username: ...,
emails: [ ... ],
profile: {
... all fields ...
}
}
whereas the publication you have set up is sending
{
profile: {
picture: ...
gender: ...
type: ...
}
}
These get merged on the client according to the rules for how subscriptions are resolved (http://docs.meteor.com/#meteor_subscribe). In particular, see the last paragraph. Meteor knows to merge the username and email fields with the profile field. However, it doesn't do this merging at the inner level. So one of the profile fields will get chosen arbitrarily to show up in the client's collection. If the first one wins, you will see profile.likes. If the second one wins, you won't.
It's likely that this behavior is somewhat deterministic and changes depending on whether a normal login handler is called or a resume handler (i.e. when reloading the browser). Hence why it looks like it hasn't loaded.
As Andrew explained, and as I kinda thought, what happened is that there is another "hidden" publication for the current user, which conflicts with mine. All I had to do in order to fix this was to simply exclude the current user from my publication, since it is already fully published by default:
Meteor.publish('users', function () {
return Meteor.users.find({_id:{$ne: this.userId}}, {fields: {'profile.picture': 1, 'profile.gender':1, 'profile.type':1}, sort: {'profile.likes': -1}});
});
This simple $ne does it for me.
I need a little help to better understand how to do something or the best approach in Meteor.JS
In my app I currently have a user which has topics and topics have a list of posts, each topic has a comments and a posts / comments count.
I would like to add collaborators to each topic IE a user can invite someone to add posts and comments to a specific topic basically sharing or collaborating under that topic which is then private to the two or X amount of users.
What's the best approach for this when it comes to Meteor Pub/Sub and Mongo collections.
Thanks,
Almog
There are many ways to solve this. For example, instead of tying topic to a single user, add a param that would hold _ids of all users allowed to the topic:
sampleTopic = {
_id: 'fpoierj9',
title: 'Sample',
userIds: [
'opijo42',
'ik03agg',
'po32a0v',
],
};
Now, in your publish channel, show topics that contain your user Id in said array:
Meteor.publish('topics', function() {
return Topics.find({userIds: this.userId});
});
I think this question is more about best practices regarding web services and not necessarily limited to ServiceStack only. From what I've read here and on the SS wiki, the 'recommended' way to implement parent-child entities is to break them down via routes.
For example:
/Users/{UserID}
/Users/{UserID}/Entities
Where User is the logged on user, and entities are his/her items. I'm implementing jqueryui autocomplete and here is where I'm suspecting I'm not doing the right thing.
In the script the path needs the Userid, so I have to manually render it in the browser so that it reads:
type: "GET",
url: "svc/users/**8**/entities",
data: { "SearchTerm": request.term, "Format": 'json' },
This smells wrong to me. I have the UserID from the session and I can get it that way. So I wonder if there a better way to access these objects without having to render data directly into markup?
Am I doing this wrong?
On a side note: I know I could place this data in a hidden field and access it via script etc, I am just curious if there is a better/recommended way to do this via sessions while keeping the routes as is.
Generally this is done with another endpoint, Facebook for instance, uses /my/, but you could do what ever you want.
The reason being, it's very likely you will be returning different information for a user about themselves than you share about that user with someone else.
Let's pretend /user/{UserId}/books returns a user's favorite books. If I want to know what someone's favorite books are, I might be interested in the title, and a brief description, but if I want to see (and possibly manage) my list of favorite books then I might want more information, like the day I added the favorite book, or friends of mine that also like the book.
so /user/{UserId}/books returns:
{
"books":[
{ "title":"Hary Potter", "desc":"A boy who is magic..." }
]
}
however /my/books returns:
{
"books":[
{
"title":"Harry Potter",
"desc":"A boy who is magic...",
"friensWhoLikeBook":[
{ "id":1234, "name":"Bob" }
],
"personalCommentsAboutBookNotToBeShared":"This book changed my life..."
}
]
}