Im Using Quasar and Firebase
I Get FirebaseError: Missing or insufficient permissions. error on console
error
Script:
// gets from the firebase
const path = "/newpage";
this.$auth.onAuthStateChanged(authUser => {
if (authUser) {
this.$bind('userz', this.$db.collection('users'));
this.$db.collection('users').doc(authUser.uid).get()
.then(snapshot => {
const userData = snapshot.data();
console.log(userData);
(this.$route.path !== path);
this.$router.push(path).catch(err => {});
this.livePaper = false;
})} else {
this.livePaper = true;
console.log('user logged out');
this.$router.push('/Login').catch(err => {});
}
})
},
whenever I put
```this.$bind('userz', this.$db.collection('users'));```
missing permission happens
but when i remove the bind
It has no errors
though
I want to get the username: value in the field and put it on my nav
firebase - username
``` <li v-for="(users, uid) in userz" :key="uid">
{{users.username}} <q-btn v-on:click="livePaper = true" label="Sign Out" #click="logOut()" color="green"/>
```
But i cant get it unless i remove
```this.$db.collection('users').doc(authUser.uid).get()
.then(snapshot => {
const userData = snapshot.data();
console.log(userData);```
again when i remove it missing permission happens again.
what should I do
Whole Code:
<template>
<q-layout view="hHh lpR fFf">
<q-header elevated class="bg-primary text-white">
<q-toolbar>
<q-btn v-if="!livePaper" dense flat round icon="menu" #click="left = !left" />
<q-toolbar-title>
<q-avatar>
<img src="https://cdn.quasar.dev/logo/svg/quasar-logo.svg">
</q-avatar>
Title
</q-toolbar-title>
<div class="q-pa-md hid" v-if="!livePaper">
<li v-for="(users, uid) in userz" :key="uid">
{{users.username}} <q-btn v-on:click="livePaper = true" label="Sign Out" #click="logOut()" color="green"/>
</li>
</div>
</q-toolbar>
</q-header>
<q-drawer v-if="!livePaper" show-if-above v-model="left" side="left" bordered>
<!-- drawer content -->
<q-scroll-area style="height: calc(100% - 150px); margin-top: 150px; border-right: 1px solid #ddd">
<q-list padding>
<q-item clickable v-ripple>
<q-item-section avatar>
<q-icon name="inbox" />
</q-item-section>
<q-item-section>
Inbox
</q-item-section>
</q-item>
<q-item clickable v-ripple>
<q-item-section avatar>
<q-icon name="star" />
</q-item-section>
<q-item-section>
Star
</q-item-section>
</q-item>
<q-item clickable v-ripple>
<q-item-section avatar>
<q-icon name="send" />
</q-item-section>
<q-item-section>
Send
</q-item-section>
</q-item>
<q-item clickable v-ripple>
<q-item-section avatar>
<q-icon name="drafts" />
</q-item-section>
<q-item-section>
Drafts
</q-item-section>
</q-item>
<q-item #click="icon = true" clickable v-ripple>
<q-item-section avatar>
<q-dialog v-model="icon">
<q-card style="width: 570px; max-width: 80vw;" class= "q-pa-xl ">
<q-card-section class="row items-center q-pb-none ">
<div class="text-h6">Sign Up</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-separator />
<q-card-section >
<q-input filled v-model="usrnm" label="Username" id="usrnm" lazy-rules
:rules="[ val => val && val.length > 0 || 'Please type something']"
/>
<q-input filled v-model="eml" label="Email" id="eml" lazy-rules
:rules="[ val => val && val.length > 0 || 'Please type something']"
/>
<q-input
filled
type="password"
v-model="pswrd"
id="pswrd"
label="Password"
lazy-rules
:rules="[ val => val && val.length > 0 ||'Please type a real age'
]"
/>
<div>
<q-btn label="Sign Up" type="submit" color="primary" #click="signUps()" />
</div>
</q-card-section>
</q-card>
</q-dialog>
<q-icon name="person_add" />
</q-item-section>
<q-item-section>
Sign Up
</q-item-section>
</q-item>
</q-list>
</q-scroll-area>
<q-img class="absolute-top" src="https://cdn.quasar.dev/img/material.png" style="height: 150px">
<div class="absolute-bottom bg-transparent">
<q-avatar v-ripple size="56px" class="q-mb-sm">
<img src="https://cdn.quasar.dev/img/boy-avatar.png">
</q-avatar>
<div class="text-weight-bold"></div>
<div>#rstoenescu</div>
</div>
</q-img>
</q-drawer>
<q-page-container>
<router-view />
</q-page-container>
</q-layout>
</template>
<script>
export default {
data () {
return {
left: false,
userz: [],
livePaper: false,
icon: false,
eml: '',
pswrd: '',
usrnm: '',
index: 0
}
},
created() {
// gets from the firebase
const path = "/newpage";
this.$auth.onAuthStateChanged(authUser => {
if (authUser) {
this.$db.collection('users').doc(authUser.uid)
.get()
.then(snapshot => {
const userData = snapshot.data();
console.log(userData);
(this.$route.path !== path);
this.$router.push(path).catch(err => {});
this.$bind('userz', this.$db.collection('users').doc(authUser.uid));
this.$bind('userz', this.$db.collection('users'));
this.livePaper = false;
})} else {
this.livePaper = true;
console.log('user logged out');
this.$router.push('/Login').catch(err => {});
}
})
},
methods: {
logOut(){
this.$auth.signOut();
this.livePaper = true;
},
signUps() {
this.$auth.createUserWithEmailAndPassword(this.eml, this.pswrd).then(cred => {
return this.$db.collection('users').doc(cred.userz.uid).set({
email: this.eml,
username: this.usrnm
});
this.isEdit = false
this.text = ''
this.yr = ''
}).then;(() => {
});
// ...
}
}
}
</script> ```
This might be a duplicate thread of
firestore: PERMISSION_DENIED: Missing or insufficient permissions, at least this is where i got help for this problem.
After setting up the rules in a proper way, the error will disappear. I had the same problem with the quasar firebase sample app too.
Here are the docs for your the firebase rules that contain all the details for setting up the rules:
https://firebase.google.com/docs/firestore/security/get-started
basically the line
allow read, write: if false;
is the problem, you could change it to the following to allow only signed in users to access the database:
allow read, write: if request.auth != null;
the following code is not recommendable because it enables unauthenticated access to your database, so don't use it unless you are in a testing scenario:
allow read, write: if false;
Related
// I am trying to print out the database elements to react typescript home page, but when i print // it out it prints out
// [Object] [Object].
function HomePage(){
const [games, setGames] = useState< IGame []>([]);
useEffect(() => {
GameService.GetAllGames().then((data) => setGames(data));
}, []);
function onClickCreateADivWithGamesInfromation(){
const div = document.createElement('div');
const informationAboutGames = document.createElement('information');
informationAboutGames.innerText = `
${games.map((game, index) => {
return <GamesItem key={index} {...game} />
})}`;
JSON.stringify(informationAboutGames);
div.appendChild(informationAboutGames);
document.body.appendChild(div);
}
return(
<div>
<header>
<h1 className='text-center mb-5 '>Electric games</h1>
</header>
<br />
<main>
<div className='text-center'>
<h3 className='text-center'>Show all games</h3>
<button className='btn btn-primary' onClick={onClickCreateADivWithGamesInfromation} >Show all</button>
</div>
I try to delete the row but I can't I have already tested my model and my controller but with the element-ui table I can't, help please ?
im using Inertiajs with Ziggy route , laravel 9 and vue3
the error : Cannot read properties of undefined (reading 'id')
i try delete the row directly without model the same problem
the Script :
const props = defineProps({
clients: Array,
client: Object,
})
const confirmingClientDeletion = ref(false)
const form = useForm()
const confirmClientDeletion = () => {
confirmingClientDeletion.value = true
setTimeout(250)
}
const deleteClient = () => {
form.delete(route('clients.destroy', props.client.id), {
preserveScroll: true,
onSuccess: () => closeModal(),
onFinish: () => form.reset(),
})
}
const closeModal = () => {
confirmingClientDeletion.value = false
form.reset()
}
the template :
<div class="px-2">
<div class="md:container-2xl rounded-lg bg-white shadow-lg text-gray-700 text-l font-medium mb-4">
<div class="p-12 content-center">
<el-table :data="clients" style="width: 100%">
<el-table-column prop="id" label="id" width="180" />
<el-table-column prop="companyname" label="Raison Sociale" width="180" />
<el-table-column prop="town" label="Ville" width="120" />
<el-table-column prop="created_at" label="Date de creation" width="150" />
<el-table-column fixed="right" label="Operations" width="200">
<template #default>
<el-button size="small">Modifier</el-button>
<el-button size="small" type="danger" #click="confirmClientDeletion">Supprimer</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
<DialogModal :show="confirmingClientDeletion" #close="closeModal">
<template #title> Suppression des clients </template>
<template #content> Vous êtes sûr de vouloir supprimer définitivement le client? </template>
<template #footer>
<SecondaryButton #click="closeModal"> Annuler </SecondaryButton>
<DangerButton
class="ml-3"
:class="{ 'opacity-25': form.processing }"
:disabled="form.processing"
#click="deleteClient"
>
Supprimer client
</DangerButton>
</template>
</DialogModal>
Destroy function in The controller :
public function destroy(Client $client)
{
$client->delete();
return redirect()->route('clients.index');
}
I have a profile page that displays the user info. The page shows the user name / email and a button to create a list.
I can also edit the name and email correctly, and it reflects in the firebase instantaneously. Ok. I get the user data and I can edit it.
What I'm trying to do now is to show the lists that the user has created.
Look, this user has created one list, and what is returned to me is that he doesn't have lists.
I'll try to shorten the code as much as possible:
<script>
imports.....
import { db } from '../../firebase.config.js'
let listings = []
let auth = getAuth()
// fetch the user's listings
const fetchUserListings = async () => {
const listingsRef = collection(db, 'listings')
const q = query(
listingsRef,
where('userRef', '==', auth.currentUser.uid),
orderBy('timestamp', 'desc')
)
const querySnap = await getDocs(q)
querySnap.forEach((doc) => {
return listings.push({
id: doc.id,
data: doc.data()
})
})
}
fetchUserListings()
</script>
<!-- display the user's listings -->
<div>
{#if listings.length > 0}
<p class="listingText">My lists</p>
{#each listings as listing}
<ListingItem listing={listing.data} id={listing.id} />
{/each}
{:else}
<p class="noListings">You have no lists</p>
{/if}
</div>
My ListItem component:
<script>
export let listing
export let id
export let handleDelete
import DeleteIcon from '../../static/assets/svg/deleteIcon.svg'
</script>
<li class="categoryListing">
<a href={`/category/${listing.type}/${id}`} class="categoryListingLink">
<img src={listing.imgUrls[0]} alt={listing.name} class="categoryListingImg" />
<div class="categoryListingDetails">
<p class="categoryListingLocation">
{listing.location}
</p>
<p class="CategoryListingName">
{listing.name}
</p>
<p class="categoryListingPrice">
${listing.offer ? listing.discountedPrice : listing.regularPrice}
{listing.type === 'rent' ? '/ por mês' : ''}
</p>
<div class="categoryListingInfoDiv">
<img src="/assets/svg/bedIcon.svg" alt="cama" />
<p class="categoryListingInfoText">
{listing.bedrooms > 1 ? `${listing.bedrooms} camas` : `${listing.bedrooms} cama`}
</p>
<img src="/assets/svg/bathtubIcon.svg" alt="banheiro" />
<p class="categoryListingInfoText">
{listing.bathrooms > 1
? `${listing.bathrooms} banheiros`
: `${listing.bathrooms} banheiro`}
</p>
</div>
</div>
</a>
{#if handleDelete}
<DeleteIcon
class="removeIcon"
fill="rgb(231, 76, 60)"
onClick={() => {
handleDelete(listing.id, listing.name)
}}
/>
{/if}
</li>
Just when you think you've reached the simplest part, it's still tough.
Update:
I think that the problem is in firebase. The "docs" are empty:
Now I am in serious trouble!
querySnap.forEach((doc) => {
return listings.push({
id: doc.id,
data: doc.data()
})
})
I see two things here. The less important: The .forEach() method returns undefined, so the return is redundant. The more important: the .push() alone won't automatically trigger updates. Have a look at this section in the Docs
Did you try logging listings? I assume the data is there, it's just not displayed, so I propose to change this part to
querySnap.forEach((doc) => {
listings = [...listings, {
id: doc.id,
data: doc.data()
}]
})
or
querySnap.forEach((doc) => {
listings.push({
id: doc.id,
data: doc.data()
})
listings = listings
})
So i am using bootstrap-vue, and precisely i am using the Form-tag as it's what i exactly needs. The issue is that the dropdown is as the long as the list of options.
Here's what i mean :
Tag button
& the
Dropdown
What i actually want is a similar css to overflow:scroll but i can't seem to make it work.
here's the code :
<template>
<div>
<b-form-group label="Tagged input using dropdown">
<b-form-tags v-model="value" no-outer-focus class="mb-2">
<template v-slot="{ tags, disabled, addTag, removeTag }">
<ul v-if="tags.length > 0" class="list-inline d-inline-block mb-2">
<li v-for="tag in tags" :key="tag" class="list-inline-item">
<b-form-tag
#remove="removeTag(tag)"
:title="tag"
:disabled="disabled"
variant="info"
>{{ tag }}</b-form-tag>
</li>
</ul>
<b-dropdown size="sm" variant="outline-secondary" block menu-class="w-100">
<template v-slot:button-content>
<b-icon icon="tag-fill"></b-icon> Choose tags
</template>
<b-dropdown-form #submit.stop.prevent="() => {}">
<b-form-group
label-for="tag-search-input"
label="Search tags"
label-cols-md="auto"
class="mb-0"
label-size="sm"
:description="searchDesc"
:disabled="disabled"
>
<b-form-input
v-model="search"
id="tag-search-input"
type="search"
size="sm"
autocomplete="off"
></b-form-input>
</b-form-group>
</b-dropdown-form>
<b-dropdown-divider></b-dropdown-divider>
<b-dropdown-item-button
v-for="option in availableOptions"
:key="option"
#click="onOptionClick({ option, addTag })"
>
{{ option }}
</b-dropdown-item-button>
<b-dropdown-text v-if="availableOptions.length === 0">
There are no tags available to select
</b-dropdown-text>
</b-dropdown>
</template>
</b-form-tags>
</b-form-group>
</div>
</template>
<script>
export default {
data() {
return {
options: ['Apple', 'Orange', 'Banana', 'Lime', 'Peach', 'Chocolate', 'Strawberry'],
search: '',
value: []
}
},
computed: {
criteria() {
// Compute the search criteria
return this.search.trim().toLowerCase()
},
availableOptions() {
const criteria = this.criteria
// Filter out already selected options
const options = this.options.filter(opt => this.value.indexOf(opt) === -1)
if (criteria) {
// Show only options that match criteria
return options.filter(opt => opt.toLowerCase().indexOf(criteria) > -1);
}
// Show all options available
return options
},
searchDesc() {
if (this.criteria && this.availableOptions.length === 0) {
return 'There are no tags matching your search criteria'
}
return ''
}
},
methods: {
onOptionClick({ option, addTag }) {
addTag(option)
this.search = ''
}
}
}
</script>
If you could please help me... Thank you
Well, i did it with adding a div with the following css
#test{
max-height:500px;
overflow:auto;
}
here's the code if anyone need it :
<template>
<div>
<b-form-group label="Tagged input using dropdown">
<b-form-tags v-model="value" no-outer-focus class="mb-2">
<template v-slot="{ tags, disabled, addTag, removeTag }">
<ul v-if="tags.length > 0" class="list-inline d-inline-block mb-2">
<li v-for="tag in tags" :key="tag" class="list-inline-item">
<b-form-tag
#remove="removeTag(tag)"
:title="tag"
:disabled="disabled"
variant="info"
>{{ tag }}</b-form-tag>
</li>
</ul>
<b-dropdown size="sm" variant="outline-secondary" block menu-class="w-100">
<template v-slot:button-content>
<b-icon icon="tag-fill"></b-icon> Choose tags
</template>
<div id="test">
<b-dropdown-form #submit.stop.prevent="() => {}">
<b-form-group
label-for="tag-search-input"
label="Search tags"
label-cols-md="auto"
class="mb-0"
label-size="sm"
:description="searchDesc"
:disabled="disabled"
>
<b-form-input
v-model="search"
id="tag-search-input"
type="search"
size="sm"
autocomplete="off"
></b-form-input>
</b-form-group>
</b-dropdown-form>
<b-dropdown-divider></b-dropdown-divider>
<b-dropdown-item-button
v-for="option in availableOptions"
:key="option"
#click="onOptionClick({ option, addTag })"
>
{{ option }}
</b-dropdown-item-button>
<b-dropdown-text v-if="availableOptions.length === 0">
There are no tags available to select
</b-dropdown-text>
</div>
</b-dropdown>
</template>
</b-form-tags>
</b-form-group>
</div>
</template>
<script>
export default {
data() {
return {
options: ['Apple', 'Orange', 'Banana', 'Lime', 'Peach', 'Chocolate', 'Strawberry'],
search: '',
value: []
}
},
computed: {
criteria() {
// Compute the search criteria
return this.search.trim().toLowerCase()
},
availableOptions() {
const criteria = this.criteria
// Filter out already selected options
const options = this.options.filter(opt => this.value.indexOf(opt) === -1)
if (criteria) {
// Show only options that match criteria
return options.filter(opt => opt.toLowerCase().indexOf(criteria) > -1);
}
// Show all options available
return options
},
searchDesc() {
if (this.criteria && this.availableOptions.length === 0) {
return 'There are no tags matching your search criteria'
}
return ''
}
},
methods: {
onOptionClick({ option, addTag }) {
addTag(option)
this.search = ''
}
}
}
</script>
I am teaching myself how to code by building a little project site but have been stuck for a few days trying to figure out how to update users' profile and account information. I am able to figure out how to retrieve and display the information but am having difficulty in getting them to update it
Goal:
Update the account email that they use at login
Update their full name stored in firestore (I figured this one out)
Update the document id of their user in Firestore (which is used for their profile slug)
So far I have been able to figure out how to display all three in the form fields, but only how to update the user's full name in Firestore with point 1 and 3 still escaping me.
For Goal 2 I used "Update a document" from Firestore documentation here https://firebase.google.com/docs/firestore/manage-data/add-data which works successfully
For updating user email I attempted to use the update email method from here https://firebase.google.com/docs/auth/web/manage-users
Screenshot of document in Firestore
<template>
<v-container fill-height>
<v-layout justify-center align-center v-if="profile">
<v-flex xs12 sm8 md8 style="max-width: 600px">
<v-card >
<v-toolbar dark color="primary">
<v-toolbar-title>Profile</v-toolbar-title>
</v-toolbar>
<v-flex class="ml-3 my-4">
<v-avatar size="75px" class="mr-2" >
<img
class="img-circle elevation-2 "
src="https://raw.githubusercontent.com/vuetifyjs/docs/dev/static/doc-images/lists/1.jpg"
>
</v-avatar>
<v-btn color="primary" >Upload</v-btn>
<v-btn>Delete</v-btn>
</v-flex>
<v-spacer></v-spacer>
<v-divider></v-divider>
<v-spacer></v-spacer>
<v-card-text>
<v-form>
<v-text-field
prepend-icon="person"
required
v-model="profile.fullname"
name="fullname"
label="Full Name"
type="text">
</v-text-field>
<v-text-field
v-if="user"
prepend-icon="email"
required
v-model="user.email"
name="email"
label="Email"
type="text">
</v-text-field>
<v-text-field
v-model="this.profile.id"
hint="Create a unique URL for your profile. Many people use their first and last name. <br> [Ex: reel.ly/misha.collins]"
persistent-hint
id="username"
prepend-icon="link"
name="username"
required
label="Profile URL "
type="text">
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<!-- <p class="red-text center" v-if="feedback">{{ feedback }}</p> -->
<v-btn flat #click.native="updatemyProfile" color="primary">Save</v-btn>
</v-card-actions>
</v-card>
<!-- <v-card style="margin-top: 30px" class="elevation-2">
<v-toolbar dark color="primary">
<v-toolbar-title>Billing</v-toolbar-title>
</v-toolbar>
<v-card-text>
<v-form>
</v-form>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<p class="red-text center" v-if="feedback">{{ feedback }}</p>
<v-btn flat #click.native="updateBilling" color="primary">Update Account</v-btn>
</v-card-actions>
</v-card> -->
</v-flex>
</v-layout>
</v-container>
</template>
<script>
import db from '#/firebase/init'
import firebase from 'firebase'
import slugify from 'slugify'
export default {
name: 'Account',
data () {
return {
user: null,
profile: null,
feedback: null,
docid: null
}
},
created () {
let ref = db.collection('users')
// get current profile to list full name
ref.where('user_id', '==', firebase.auth().currentUser.uid).get()
.then(snapshot => {
snapshot.forEach(doc => {
this.profile = doc.data(),
this.profile.id = doc.id
})
})
// get current user to list email
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.user = user
// console.log(this.user)
} else {
this.user.uid = null
}
})
},
methods: {
updatemyProfile() {
// working to change fullname but not document id
let ref = db.collection('users')
// get current profile
ref.where('user_id', '==', firebase.auth().currentUser.uid).get()
.then(snapshot => {
snapshot.forEach(doc => {
this.profile = doc.data(),
this.profile.id = doc.id
})
})
var docRef = db.collection("users").doc(this.profile.id)
return docRef.update({
id: this.profile.id, // this is adding an id field and assigning this.profile.id value to it instead of updating the document id of the user
fullname: this.profile.fullname
})
// update email address
var user = firebase.auth().currentUser
user.updateEmail(this.user.email).then(function() {
console.log("success")
}).catch(function(error) {
// An error happened.
})
}
}
}
</script>
Any help is much appreciated!
Look at this bit of code at the end of your function:
var docRef = db.collection("users").doc(this.profile.id)
return docRef.update({
id: this.profile.id,
fullname: this.profile.fullname
})
// update email address
var user = firebase.auth().currentUser
user.updateEmail(this.user.email).then(function() {
console.log("success")
}).catch(function(error) {
// An error happened.
})
You're returning early from the function with the return keyword after you call the update() method, which means that any code after that in the function (the update of email address) won't get run.