How do I push/upload photos to Google (Firebase) Storage?

785 Views Asked by At

Essentially my issue is I am unable to seemingly even come close to uploading photos to my Firebase Project. I am able to push user information to the Realtime Database and I successfully have integrated Firebase Authentication as well, which I use with Flask Sessions to keep users logged in. It appears that in order to save files/photos you need to use Firebase Storage, but I am unable to figure out how.

Users are able to click and "upload file" button in my '/upload-image' route and right now I have the image saved (after the user uploads it) to a folder in the same directory as my fiddl.py file.

All Following code is in my Fiddl.py file.

Here are my Firebase Initializations:
Note, storageRef is something I tried, but there is no such this as ref() in storage so I get errors. Also I have storage because I believe that references my Projects Storage.

#initialize database
firebase = pyrebase.initialize_app(json.load(open('firebase/firebaseConfig.json')))
auth = firebase.auth()
db = firebase.database()                                    
#storageRef = firebase.storage.ref()                           #Points to the root reference
app.secret_key = os.urandom(24)                                #secret key:track if user is logged in
storage = firebase.storage("gs://fiddl-dev.appspot.com")      

Here is the configs I used to store the users uploaded image in the local folder /FIDDL/Photo test. I shortened the name of the path for your convenience. Side Note I hope to add these config's to their own file for security later, still not 100% sure how these are supposed to work. Along with this is the route I have that has the user upload a photo from their device.

#temp image upload location
#TODO: put these in a private config file
app.config["IMAGE_UPLOAD"] = "/FIDDL//photosTest"
app.config["ALLOWED_IMAGE_EXTENSIONS"] = ["PNG", "JPG", "JPEG"]
app.config["MAX_IMAGE_FILESIZE"] = 1.5 * 1024 * 1024    #1,572,864 Bytes or 1572.864 KB

# Upload Image
@app.route('/upload-image', methods=["GET", "POST"])
def upload_image():
    try:
        print(session['usr'])                   #this is equal to logged in users id token->  user['idToken']
        app.logger.info("A user is already logged in")
        #TODO: add a logout button, make sure to delete session for use on logout

        # Alert Messages
        noFileName = 'Image must have a file name.'
        badFileSize = 'Image file size is too large.'
        badFileName = 'That image extension or file name is not allowed'
        dataAdded = 'User photos added to realtime database'

        if request.method == "POST":
            if request.files:
                image = request.files["image"]                          #works the same as user input emal in register, get the image file
                print(image)

                #Grab the file size
                image.seek(0, os.SEEK_END)
                file_size = image.tell()
                app.logger.info("Image File Size: ")
                app.logger.info(file_size)

                #Check the image file size
                if not allowed_image_filesize(file_size):
                    #TODO: alert user on screen of the issue
                    app.logger.info(badFileSize)
                    return redirect(request.url)
                
                #Check for file name
                if image.filename == "":
                    app.logger.info(noFileName)
                    return redirect(request.url)
                
                #Check if image has correct type
                if not allow_image(image.filename):
                    app.logger.info(badFileName)
                    return redirect(request.url)
                else:
                    filename = secure_filename(image.filename)          #create new secure file name
                    app.logger.info(filename)
                    print(auth.current_user)
                    #Add data to realtime database
                    #TODO: figure out how to store photos in firebase
                    
                 

                    #Update progress
                    app.logger.info(dataAdded)




                    #image.save(os.path.join(app.config["IMAGE_UPLOAD"], filename))  #save images to /photosTest for testing
                    #print("image saved")
                
                return redirect(request.url)
    except KeyError:
        app.logger.info("No user logged in, redirect to login")
        return redirect(url_for('login'))
    
    return render_template("upload_image.html")

Here are the rules for Firebase/Develop/Storage/Rules. I am using Firebase Authentication but am still getting the error:

    "code": 403,
    "message": "Permission denied. Could not perform this operation"
  }

Rules:

rules_version = '2';

// Grants a user access to a node matching their user ID
service firebase.storage {
  match /b/fiddl-dev.appspot.com/o {
    // Files look like: "user/<UID>/path/to/file.txt"
    match /user/{userId}/{allPaths=**} {
        allow write: if request.auth != null;
      allow read: if true; 
    }
  }
}

I know there isn't really an issue to fix here, but any point in the right direction would be super! Thanks!

1

There are 1 best solutions below

0
Carter Mooring On BEST ANSWER

TLDR Answer, including some small file checks since those, is part of the reason I had the issue. Much more detail above if needed.

To upload an Image/file to Google Firebase Storage:

firebase = pyrebase.initialize_app(json.load(open('firebase/firebaseConfig.json')))
storage = firebase.storage("gs://fiddl-dev.appspot.com")

app.config["IMAGE_UPLOAD"] = "/FIDDL//photosTest"
app.config["ALLOWED_IMAGE_EXTENSIONS"] = ["PNG", "JPG", "JPEG"]
app.config["MAX_IMAGE_FILESIZE"] = 1.5 * 1024 * 1024    #1,572,864 Bytes or 1572.864 KB

# Upload Image
@app.route('/upload-image', methods=["GET", "POST"])
def upload_image():
    try:
       if request.method == "POST":
            if request.files:
                image = request.files["image"]                          

                #Grab the file size
                image.seek(0, os.SEEK_END) # Using seek here requires another later
                file_size = image.tell()

                #Check the image file size
                if not allowed_image_filesize(file_size):
                    return redirect(request.url)
                
                #Check for file name
                if image.filename == "":
                    return redirect(request.url)
                
                #Check if image has correct type
                if not allow_image(image.filename):
                    return redirect(request.url)
                else:

                    filename = secure_filename(image.filename)  #create new secure file name        
                    image.seek(0)
                    storage.child("images/" + filename).put(image)
     except: 
          ...