i am using Angular with firebase/firestore and i have an authentication system with the google oauth and everytime when i log in and try to create a document in firestore it deletes it afterwards apparently. The logs say:
#firebase/firestore: Firestore (5.0.3) [Connection]: WebChannel received: {"documentDelete":{"document":"projects/website/databases/(default)/documents/users/Tplww82foIN36hb8mcmSOaAPXbU2","readTime":"2018-05-21T05:35:42.653774Z","removedTargetIds":[2]}}
But i executed this code:
this.db.doc('users/' + user.uid).set({
uid: user.uid,
email: user.email,
name: user.displayName,
photoUrl: user.photoURL,
roles: {}
}, {merge: true});
Am i missing something obvious? Do i need to provide more logs/code in order to figure this out? Thank you very much :D
It was an easy solution actually: Every observable/promise takes their time, and i signed myself out before it was done creating the documents.
Related
This code i used to store users in firebase.
this.db
.doc('/users/' + user.uid)
.set({
name: user.displayName,
email: user.email,
})
.then(() => console.log('user saved successfully'))
.catch((reason: any) => console.log('user save failed:', reason));
Users also have a isAdmin property that gets set elsewhere.
When I login as a new user, the user gets a name and email.
If i make the user admin i can visit admin only pages.
issue is, if i refresh on an admin page i get kicked of the page.
I think the issue is the set method, since it doesnt contain the isAdmin property
When I use update instead of set, it works fine when I refresh, but now I cant create new records for new users.
What is the best way to tackle this?
You're looking to merge the data in your set call with the existing data (if any), which you can do by specifying set options:
this.db
.doc('/users/' + user.uid)
.set({
name: user.displayName,
email: user.email,
}, { merge: true }) // 👈
Also see: https://firebase.google.com/docs/firestore/manage-data/add-data#set_a_document
I'm trying to learn about Cloud Functions for Firebase. I followed a tutorial to create an auth trigger and it worked great, but now I need to pass the username that the user wants to use to my auth event. How do I do this? Did I maybe use the wrong trigger here and instead needed an HTTP trigger?
exports.newUserSignup = functions.auth.user().onCreate(user => {
console.log('user created', user.email, user.uid);
const doc = admin.firestore().collection('users').doc();
return doc.set({
createDate: admin.firestore.FieldValue.serverTimestamp(),
modifiedDate: admin.firestore.FieldValue.serverTimestamp(),
username: 'NEED TO FIGURE THIS OUT',
email: user.email,
stat: 1,
uid: user.uid,
rowpointer: doc.id,
});
});
There is no way to pass additional information to the auth.user().onCreate trigger, and unfortunately there is no way to trigger when the account gets updated.
Your current options are:
Create the document from within your application code after the account has been created.
Pass all information to a Callable or HTTP Cloud Function, and let that handle both the account creation and the writing to Firestore.
Both are completely valid options, so pick the one that seems most reasonable to you.
Also see:
How to complete login only after functions.auth.user().onCreate is finished
Firebase Cloud Function - null user.displayName onCreate
firebase cloud function authentication: onCreate event doesn't contain displayName
Firebase functions user().onCreate: Pass parameters
So I have been at this the entire day and I still cannot figure it out or find any help online. I am pretty sure it's something very small I am missing. I will do my best to explain my issue.
I have a Vue.js SPA with Firestore and Firebase-Authentication. Today I noticed some weird behaviour from my app and I think it has something to do with cache. So I have SignUp component in which I have the following:
firebase
.auth()
.createUserWithEmailAndPassword(this.email, this.password)
.then(
function(user) {
firebase
.firestore()
.collection("users")
.doc(user.user.uid)
.set({
firstname: _this.fName,
lastname: _this.lName,
username: _this.uName,
email: user.user.email
})
.then(() => {
_this.$store.commit('setCurrentUser', {email: user.user.email, uid: user.user.uid})
_this.$router.replace("/HomeUserPage");
})
.catch(function(error) {
console.log("Error signing up:", error);
});
},
function(err) {
console.log(err.message, "this is an error");
}
)
I also have my SignOut handler like this in another component:
firebase
.auth()
.signOut()
.then(() => {
this.$router.replace("Login");
})
.catch(function(error) {
console.log(error);
});
My problem is the following: Whenever I log out and try to create a new user(Sign Up), it works perfect the first time. Then I log out, and try to Sign Up one more user and what happens now is I get the user created, however, the call to the firestore database in the callback of .createUserWithEmailAndPassword is not executed, hence, my route doesn't change and my data doesn't get populated.
What I have found so far: This is doesn't happen if I reload the page after logout(Hence, why I think the problem is coming from cache).
Do you have any thoughts why this is happening, is it expected behaviour and I am just expected to reload the page after each logout ?
Okay, I figured it out. Apparently, it's a bug as Doug mentioned above, so I went to post it on Github and it has been already reported:
https://github.com/firebase/firebase-js-sdk/issues/3218
It was a problem in the older version (7.15), which has been fixed now (7.16). So just updated my Firebase SDK and all works as expected now.
Summary:
I am using javascript generated by aws-amplify to send queries and mutation to an AWS graphql endpoint with dynamodb backend. The queries/mutations function well enough (they create, get and delete records as intended). But they constantly throw an error in the process:
"Query condition missed key schema element: authorId (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException;"
My code can't be too bad, or else why does it function so well? Still, I would like to get rid of this annoying error, or at least understand it. Why is this error happening?
Details:
My api is generated from the exact schema.graphql file provided in the aws-sample "aws-appsync-chat"
https://github.com/aws-samples/aws-appsync-chat
The relevant part of the model is here...
type User
#model
#auth(rules: [{ allow: owner, ownerField: "id", queries: null }]) {
id: ID!
username: String!
conversations: [ConvoLink] #connection(name: "UserLinks")
messages: [Message] #connection(name: "UserMessages")
createdAt: String
updatedAt: String
}
Sadly, that sample does not really use queries and mutations generated by amplify. Instead, it uses a hand written schema in the file: src/graphql.js. That's right. Generated queries/mutations are included in the project, but not actually used. This was super disappointing to me. But my faith was restored (somewhat), when I managed to rewrite the javascript logic to make it function (more or less) using queries and mutations that were generated by amplify.
Anyway, the first step I took was to write the logic for (1) querying the users table to see if a record exists already for the currently authroized user, and (2) creating the record if the authorized user is not there. For bonus points, I also wrote logic for (3) deleting the user record from the database.
Working inside a vuejs component, I wrote these methods...
methods: {
async DeleteUserRecord() {
try {
let id = store.state.user.username;
const input = { id: id };
await API.graphql(graphqlOperation(deleteUser, { input }));// works but throws errors
} catch (err) {
console.log('Error deleting user record:', err)
}
},
async GetUserRecord() {
try {
let id = store.state.user.username;
const result = await API.graphql(graphqlOperation(getUser, { id }));// works but throws errors
console.log(result);
} catch (err) {
console.log('Error getting user record:', err)
}
},
async CreateUserRecord() {
let username = store.state.user.username;
try {
const result = await API.graphql(graphqlOperation(createUser, { input:{ id:username, username: username } })) // works but throws error
console.log(result);
} catch (err) {
console.log('Error creating user record:', err)
}
}
}
All three seem to work, but they do throw errors, see attached screenshot for details.
Always the same error:
"Query condition missed key schema element: authorId (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException;"
The error must be related to the auth rules in the model. But remember that my code does work, so my code is not complete crap.
Can anyone explain this error to me? Is it a bug in AWS? Or is my code written incorrectly?
---------------------------------- UPDATE BELOW -------------------------------
I still do not understand why this error occurs, but I have made some progress in understanding it.
As illustrated by the screenshots, the getUser query generated by amplify WILL work if I remove the part that asks for a user's messages.
The authorId that appears in the error message must come from the data model of the Message objects.
Notice that the graphql schema uses a named connection to link the messages to the user, with a keyField of "authorId".
So, I could probably get rid of the error by fiddling with the specification of the connection in the data model.
But wait. These are the default queries generated by amplify simply by feeding it a schema that comes EXACTLY from an aws-sample project. Shouldn't these queries work well enough without my editing them?
I got the same issue, as you.
I found the working example in the github https://github.com/aws-amplify/amplify-cli/pull/1358
type Post #model {
id: ID!
name: String!
comments: [Comment] #connection(name: "PostComments", keyField: "postId", sortField: "statusDate")
}
type Comment #model(queries: null) {
id: ID!
post: Post! #connection(name: "PostComments", keyField: "postId", sortField: "statusDate")
postId: ID!
statusDate: String!
}
The KeyField MUST be the same on the both end of #connection attribute. In the example form the github tutorial the missing part is "authorId" from the User type:
type User
#model
#auth(rules: [{ allow: owner, ownerField: "id", queries: null }]) {
id: ID!
username: String!
conversations: [ConvoLink] #connection(name: "UserLinks")
messages: [Message] #connection(name: "UserMessages", keyField: "authorId")
createdAt: String
updatedAt: String
}
Moreover, it would be better to make authorId as an non null value in the Message type, because message cannot be posted without author.
type Message #model #auth(rules: [{ allow: owner, ownerField: "authorId" }]) {
id: ID!
author: User #connection(name: "UserMessages", keyField: "authorId")
authorId: String!
content: String!
conversation: Conversation! #connection(name: "ConvoMsgs")
messageConversationId: ID!
createdAt: String
updatedAt: String
}
Is it possible to update a user and the custom claims at the same time?
I can update the custom claims via the example in docs
admin.auth().setCustomUserClaims(uid, {admin: true}).then(() => {
});
I can update the user with
firebase.auth().updateUser(request.body.user.uid, {
displayName: request.body.user.username,
email: request.body.user.email
})
I thought it would be as simple as this example below but it keeps leaving the custom claims as undefined
const customClaims = {
admin: true,
accessLevel: 9
};
firebase.auth().updateUser(request.body.user.uid, {
displayName: request.body.user.username,
email: request.body.user.email,
customClaims: customClaims
})
Is there a way to do both at the same time? Or do they have to be separate?
The updateUser method is documented to take a string uid and an UpdateRequest object. As you can see from the linked API docs, UpdateRequest doesn't have a customClaims property, or anything that lets you update the claims in the same call. You can always file a feature request if this is important to your use case.