Polymer 1.x: Deep link databinding to Firebase - data-binding

I want to databind a settings object to deep links in my Firebase via a firebase-document element as follows:
my-element.html
<firebase-document location="<my-firebase>/users/uid/settings"
data="{{settings}}"</firebase-document>
...
<paper-input label="Name" value="{{settings.name}}"></paper-input>
<paper-input label="Email" value="{{settings.email}}"></paper-input>
...
settings: {
type: Object,
notify: true,
value: {},
...
When I enter values in the paper-input fields in my app for name and email, I expect to see the Firebase values update. But, instead, they do not update.
What is the best-practice method to accomplish this deep-link databinding?
Edit
I just noticed there are 35 open issues with the firebase-element and this codelab appears to bypass using it for the same reasons. If the element isn't fully ready yet, please just state that. Also, the imports seem unusual based on the language here:
Components that want to use firebase should depend on firebase-element and import firebase.html to be safe from library duplication. Such components need not use Polymer or firebase-element, but we put the import and the element in one package for convenience.
It's hard to understand what the above paragraph is trying to say. So an example would help.

The OP code only works to edit an existing record. It does not work to create a new record at the endpoint (e.g., /settings in this case).
To do that, you must add an initial value when it doesn't otherwise exist at the Firebase endpoint as follows:
Test for the presence of an initial firebase value using on-firebase-value="_firebaseLoaded".
If none, (conditionally) add one inside the _firebaseLoaded method.
my-element.html
<firebase-document location="https://my-firebase.firebaseio.com/settings"
data="{{settings}}" on-firebase-value="_firebaseLoaded"></firebase-document>
...
<paper-input label="Name" value="{{settings.name}}"></paper-input>
...
settings: {
type: Object,
notify: true,
value: {},
}
...
_firebaseLoaded: function() {
if(!this.settings) {
this.set('settings', {});
}
},
Also, this post might be helpful reading.

Related

Nuxt/algolia's AlgoliaDocSearch component does not return elements

I am using the #nuxt/algolia package and using the component. I've also setup the runtime config as shown below. However queries do not return anything (they say, "no results for "). When I look at the chrome network tab I can see the queries are coming back as status 200 and the correct index name is being called, but when I click on the failure and the web page opens there is an error {"message":"indexName is not valid","status":400}.
The weird thing here is that I have custom js code that uses the same env variables including the indexName and that code works. What am I doing wrong?
algolia: {
apiKey: process.env.ALGOLIA_SEARCH_API_KEY,
applicationId: process.env.ALGOLIA_APPLICATION_ID,
docSearch: {
indexName: process.env.ALGOLIA_INDEX
}
},
<template>
<AlgoliaDocSearch />
</template>
I have other js custom code that is able to both query and update indexes with the same env variables.

Setting up 'Trigger Email' Firebase Extension

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.

Resolving an Error 400 with Firebase/Firestore and VueJS

I am attempting to write an ordering app using Google Firebase as the database to store everything. I attempted to test the connection but keep getting GET and POST HTTP 400 errors when I submit test data.
I have installed v8.0.0 via NPM. My firebase.js file is as follows:
import firebase from 'firebase/app'
import 'firebase/firestore'
import { firebaseConfig } from '#/firebaseConfig';
firebase.initializeApp(firebaseConfig);
const db = firebase.firestore();
export const dbMenuRef = db.collection("menu");
Fire security purposes I keep the object Google generates for configuration containing the keys and such in a separate file. I even tried putting the object in the firebase.js file and still got these errors.
The data is structured as follows:
newOrder: {
customerName: 'John Doe',
customerPhone: '1-800-DRUIDIA',
items:[{
itemUPC: '1234567890',
itemDesc: 'A generic item',
itemDist: 'The one we always use'
}, {
itemUPC: '0987654321',
itemDesc: 'Another Generic Item',
itemDist: 'The other one we use'
}]
}
Data is two-way bound to a form. This is working properly and I have the newOrder object displayed in the component. This is working just fine as the JSON looks like above.
The following VueJS method is triggered by clicking a "Submit Order" button.
addOrder() {
dbMenuRef.add(this.newOrder)
}
Edit: I am using Firefox Developer Edition latest version.
Second Edit: This apparently works in Chrome, but not Firefox DE.
It looks like you are passing array as a value to items key. If you use dbMenuRef.add, you might want to add as sub-collections. Instead, you can use .set if you want to have the entire document added (please refer the documentation here. Can you try:
addOrder() {
dbMenuRef
.doc(this.orderID)
.set(this.newOrder)
}

How to check permissions of an entity on create in appsync

Sorry for the unspecific title. However, I am having a hard time to describe it.
I am using aws-appsync with aws cognito for authentication.
I've followed the amplify docs about the #auth annotation to handle permissions for mutations and queries.
Here is an example of my schema.
A user can create an entry and share it with others. However, they should only read the entry and should not have permissions to edit it.
An entry also has multiple notes. (And some more fields)
type Entry #model #versioned #auth (rules: [
{ allow: owner },
{ allow: owner, ownerField: "shared", queries: [get, list], mutations: []}
]) #searchable {
id: ID!
date: AWSDate
updated_at: AWSDateTime
text: String
notes: [Note] #connection(name: "EntryNotes")
shared: [String]!
}
And here is the note
type Note #model #versioned #auth (rules: [{ allow: owner }]) {
id: ID!
text: String
track: Track!
diary: DiaryEntry #connection(name: "EntryNotes")
}
This works fine so far. But the problem is the Note connection.
Because if you create a note you would create it like this:
mutation makeNote {
createNote (input: {
text: "Hello there!"
noteEntryId: "444c80ee-6fd9-4267-b371-c2ed4a3ccda4"
}) {
id
text
}
}
The problem is now, that you can create notes for entries that you do not have access to. If you somehow find out which id they have.
Is there a way to check if you have permissions to the entry before creating the note?
Currently, the best way to do this is via custom resolvers within the Amplify CLI. Specifically, you are able to use AppSync pipeline resolvers to perform the authorization check before creating the note. Your pipeline resolver would contain two functions. The first would look up the entry and compare the owner to the $ctx.identity. The second function would handle writing the record to DynamoDB. You can use the same logic found in build/resolvers/Mutation.createNote.re(q|s).vtl to implement the second function by copying it into the top level resolvers/ directory and then referencing it from your custom resource. After copying the logic, you will want to disable the default createNote mutation by changing #model to #model(mutations: { update: "updateNote", delete: "deleteNote" }).
For more information on how to setup custom resolvers see https://aws-amplify.github.io/docs/cli/graphql#add-a-custom-resolver-that-targets-a-dynamodb-table-from-model. For more information on pipeline resolvers (slightly different than the example in the amplify docs) see https://docs.aws.amazon.com/appsync/latest/devguide/pipeline-resolvers.html. Also see the CloudFormation reference docs for AppSync https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-reference-appsync.html.
Looking towards the future, we are working on a design that would allow you to define auth rules that span #connections. When this is done, it will automatically configure this pattern but there is not yet a set release date.

Meteor.user() not fully loaded after login

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.

Resources