Making an instagram clone and it won't let me post a picture. I keep getting this error 'Uncaught Error in snapshot listener:, [FirebaseError: Missing or insufficient permissions.]' whenever I enter the page to upload a picture. My guess is that it's coming from the onSnapshot function. I also get the 'Warning: An unhandled error was caught from submitForm(), [TypeError: null is not an object (evaluating 'currentLoggedInUser.username')]' when I press the share button. Nothing happens beyond that point. Its supposed to take me back to the homescreen afterwards:
import { View, Text, Image, TextInput, Button } from 'react-native'
import React, { useState, useEffect } from 'react'
import * as Yup from 'yup'
import { Formik } from 'formik'
import { Divider } from 'react-native-elements'
import validUrl from 'valid-url'
import {db, firebase} from '../../firebase'
const PLACEHOLDER_IMG = 'https://pacificpatiostructures.com/wp-content/uploads/2016/06/import_placeholder.png'
const uploadPostSchema = Yup.object().shape({
imageUrl: Yup.string().url().required('A URL is required'),
caption: Yup.string().max(2200, 'Caption has reached the character limit.')
})
const FormikPostUploader = ({ navigation }) => {
const [thumbnailUrl, setThumbnailUrl] = useState(PLACEHOLDER_IMG)
const [currentLoggedInUser, setCurrentLoggedInUser] = useState(null)
const getUsername = () => {
const user = firebase.auth().currentUser
const unsubscribe = db
.collection('user')
.where('owner_uid', '==', 'user.uid').limit(1).onSnapshot(
snapshot => snapshot.docs.map(doc => {
setCurrentLoggedInUser({
username: doc.data().username,
profilePicture: doc.data().profile_picture,
})
})
)
return unsubscribe
}
useEffect(() => {
getUsername()
}, [])
const uploadPostToFirebase = (imageUrl, caption) => {
const unsubscribe = db
.collection('users')
.doc(firebase.auth().currentUser.email).collection('posts')
.add({
imageUrl: imageUrl,
user: currentLoggedInUser.username,
profile_picture: currentLoggedInUser.profilePicture,
owner_uid: firebase.auth().currentUser.uid,
caption: caption,
createdAt: firebase.firestore.FieldValue.serverTimestamp(),
likes: 0,
likes_by_users: [],
comments: [],
})
.then(() => navigation.goBack())
return unsubscribe
}
return (
<Formik
initialValues={{caption: '', imageUrl: ''}}
onSubmit={values => {
uploadPostToFirebase(values.imageUrl, values.caption)
}}
validationSchema={uploadPostSchema}
validateOnMount={true}
>
{({
handleBlur,
handleChange,
handleSubmit,
values,
errors,
isValid
}) => (
<>
<View
style={{
margin: 20,
justifyContent: 'space-between',
flexDirection: 'row',
}}>
<Image source={{ uri: validUrl.isUri(thumbnailUrl) ? thumbnailUrl : PLACEHOLDER_IMG}}
style={{ width: 100, height: 100 }}/>
<View style={{ flex: 1, marginLeft: 12 }}>
<TextInput
style={{ color: 'white', fontSize: 20 }}
placeholder='Write a caption...'
placeholderTextColor='gray'
multiline={true}
onChangeText={handleChange('caption')}
onBlur={handleBlur('caption')}
value={values.caption}
/>
</View>
</View>
<Divider width = {0.2} orientation='vertical' />
<TextInput
onChange={(e) => setThumbnailUrl(e.nativeEvent.text)}
style={{ color: 'white', fontSize: 18 }}
placeholder='Enter Image Url'
placeholderTextColor='gray'
onChangeText={handleChange('imageUrl')}
onBlur={handleBlur('imageUrl')}
value={values.imageUrl}
/>
{errors.imageUrl &&(
<Text style={{ fontSize: 10, color: 'red' }}>
{errors.imageUrl}
</Text>
)}
<Button onPress={handleSubmit} title='Share' disabled={!isValid}/>
</>
)}
</Formik>
)
}
export default FormikPostUploader
Here are my security rules that I used in Cloud Firestore:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function userIsAuthenticated() {
return request.auth != null;
}
// security rule for group collection ('post')
match /{path=**}/posts/{postId} {
allow read, write: if userIsAuthenticated();
}
match /users/{userId} {
allow read, write: if userIsAuthenticated();
}
}
}
Your getUsername()
function queries user
collection which is not included in your Firestore Rules which returns Missing or insufficient permissions.
As per this documentation:
Cloud Firestore security rules evaluate each query against its potential result and fails the request if it could return a document that the client does not have permission to read. Queries must follow the constraints set by your security rules.
You should also add necessary permissions to the user
collection. See sample rule below:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function userIsAuthenticated() {
return request.auth != null;
}
// security rule for group collection ('post')
match /{path=**}/posts/{postId} {
allow read, write: if userIsAuthenticated();
}
match /users/{usersId} {
allow read, write: if userIsAuthenticated();
}
// Security Rule for `user` collection.
match /user/{userId} {
allow read, write: if userIsAuthenticated();
}
}
}