简体   繁体   中英

Cloud Function updating user profile, but prevents users having same username

I currently am working on an edit profile cloud function. I have a where clause, to see if a username in my users collection is the same as the req.body.username and if that is the case block the request. The issue is; however, I am getting an error that looks like this: "> Error: Value for argument "value" is not a valid query constraint. "undefined" values are only ignored in object properties.

 at Object.validateUserInput (/Users/robterrell/Desktop/safespace/functions/node_modules/@google-cloud/firestore/build/src/serializer.js:265:19) at validateQueryValue (/Users/robterrell/Desktop/safespace/functions/node_modules/@google-cloud/firestore/build/src/reference.js:2135:18) at CollectionReference.where (/Users/robterrell/Desktop/safespace/functions/node_modules/@google-cloud/firestore/build/src/reference.js:1033:9) at exports.profileUpdate (/Users/robterrell/Desktop/safespace/functions/api/users.js:216:6) at Layer.handle [as handle_request] (/Users/robterrell/Desktop/safespace/functions/node_modules/express/lib/router/layer.js:95:5) at next (/Users/robterrell/Desktop/safespace/functions/node_modules/express/lib/router/route.js:137:13) at /Users/robterrell/Desktop/safespace/functions/util/auth.js:30:14 at processTicksAndRejections (internal/process/task_queues.js:85:5)"

The where clauses doesn't seem to be picking up if I am sending a request with a username that is already being used in my user collection as well. I am unsure of what I am currently doing wrong. I am invoking this function by sending a post request via postman. My function looks like this:

exports.profileUpdate = (req, res) => {
  if (req.user.email) {
    admin.auth().updateUser(req.user.uid, { email: req.body.email })
  }

  let document = db
    .collection('users')
    .where('username', '==', req.body.username)
  document
    .get()
    .then(snapshot => {
      if (snapshot.empty) {
        snapshot.forEach(doc => {
          const data = doc.id
          db.collection('users').doc(data).update(req.body)
        })
        return res.json({ message: 'Updated Successfully' })
      } else {
        return res
          .status(400)
          .json({ username: 'this username is already taken' })
      }
    })
    .catch(error => {
      console.error(error)
      return res.status(400).json({
        message: 'Cannot Update the value'
      })
    })
}

I am passing formData(detailsToUpdate) to my function that is triggered by hitting an endpoint with express. The function looks like this:

import React, { useState } from 'react'
import { Text, Input, Icon } from '@ui-kitten/components'
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
import { View, StyleSheet, TouchableOpacity, Image } from 'react-native'
import AsyncStorage from '@react-native-community/async-storage'
import axios from 'axios'

const updateUsername = ({ navigation, route }) => {
  const [errorMessage, setErrorMessage] = useState('')
  const { user } = route.params
  const [detailsToUpdate, setDetailsToUpdate] = useState({
    username: user.username,
    userId: user.userId
  })

  const handleProfileUpdate = async () => {
    try {
      const token = await AsyncStorage.getItem('FBIdToken')
      console.log('im running')
      const response = await axios({
        method: 'POST',
        url:
          'http://localhost:5000/safe-space-dev/us-central1/api/users/update',
        headers: { Authorization: `Bearer ${token}` },
        data: detailsToUpdate
      })
      // merges the current user data in storage w/ updated details.
      await AsyncStorage.mergeItem(
        'userDetails',
        JSON.stringify(detailsToUpdate)
      )
      alert(response.data.message)
    } catch (error) {
      setErrorMessage(error)
    }
  }

  return (
    <KeyboardAwareScrollView
      extraScrollHeight={20}
      enableOnAndroid={true}
      keyboardShouldPersistTaps='handled'
      style={{ backgroundColor: '#fff' }}
    >
      <View>
        <View
          style={{
            paddingRight: 20,
            paddingLeft: 20
          }}
        >
          <View
            style={{
              flexDirection: 'row',
              justifyContent: 'space-between',

              marginTop: 20
            }}
          >
            <TouchableOpacity
              onPress={() => {
                /* 1. Navigate to the Details route with params */
                navigation.navigate('EditProfile')
              }}
            >
              <Icon
                style={{ height: 28, width: 28 }}
                name='chevron-left'
                fill='black'
              />
            </TouchableOpacity>
            <TouchableOpacity onPress={handleProfileUpdate}>
              <Text>Done</Text>
            </TouchableOpacity>
          </View>

          <View
            style={{
              marginTop: 20,
              paddingRight: 20,
              paddingLeft: 20
            }}
          ></View>
          <View
            style={{
              height: 75
            }}
          >
            <Text category='p1' appearance='hint' style={{ fontSize: 12 }}>
              Username
            </Text>

            <Input
              value={detailsToUpdate.username}
              autoCapitalize='none'
              autoComplete={false}
              onChangeText={value =>
                setDetailsToUpdate({ ...detailsToUpdate, username: value })
              }
            />
          </View>
        </View>
      </View>
    </KeyboardAwareScrollView>
  )
}

export default updateUsername

and then here is the middleware for the for the express route:

const { admin, db } = require('./admin')

module.exports = (request, response, next) => {
  let idToken
  if (
    request.headers.authorization &&
    request.headers.authorization.startsWith('Bearer ')
  ) {
    idToken = request.headers.authorization.split('Bearer ')[1]
  } else {
    console.error('No token found')
    return response.status(403).json({ error: 'Unauthorized' })
  }
  admin
    .auth()
    .verifyIdToken(idToken)
    .then(decodedToken => {
      request.user = decodedToken
      return db
        .collection('users')
        .where('userId', '==', request.user.uid)
        .limit(1)
        .get()
    })
    .then(data => {
      request.user.username = data.docs[0].data().username
      request.user.imageUrl = data.docs[0].data().imageUrl
      request.user.dob = data.docs[0].data().dob
      request.user.userId = data.docs[0].data().userId
      return next()
    })
    .catch(err => {
      console.error('Error while verifying token', err)
      return response.status(403).json(err)
    })
}

Based on the error message, the req.body.username is undefined . Verify you're sending the correct body in the request or that it's not getting removed in other middleware.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM