Metadata Updation in Badgeyay

Badgeyay is a simple badge generator service to develop badges for technical events and conferences developed by FOSSASIA. Badgeyay is a SPA (Single Page Application) developed in ember, whose backend is in Flask. Now when user logins, he can see an option for user profile, in which all the metadata of its profile can be seen (extracted from Firebase). Now user should be able to change its metadata like profile image and username etc. So we will look how the profile image is being changed and updated in badgeyay.

Procedure

  1. Create function in frontend to listen for onclick events and initiate a file upload dialog box for selecting an image. We will use document property to initiate a dummy click event, else there will be a button with the text to upload a file and that won’t look consistent as we only need an image and nothing else on the UI.

class=“ui small circular image profile-image”>
    “{{user.photoURL}}”>
    “display: none;” id=“profileImageSelector” type=“file” onchange={{action “profileImageSelected”}}>
    

“profile-change” onclick={{action “updateProfileImage”}}>Change


</div>

 

  1. Function to upload file and initiate a dummy click event
updateProfileImage() {
    // Initate a dummy click event
    document.getElementById(‘profileImageSelector’).click();
  },

  profileImageSelected(event) {
    const reader = new FileReader();
    const { target } = event;
    const { files } = target;
    const [file] = files;
    const _this = this;

    reader.onload = () => {
      _this.get(‘sendProfileImage’)(reader.result, file.type.split(‘/’)[1]);
    };

    reader.readAsDataURL(file);
  }

 

  1. Profile update function in the main controller to call the API endpoint to upload the data to backend. This will send the payload to backend which will later upload the image to cloud storage and save in the link in the database.
updateProfileImage(profileImageData, extension) {
    const _this = this;
    const user = this.get(‘store’).peekAll(‘user’);
    user.forEach(user_ => {
      _this.set(‘uid’, user_.get(‘id’));
    });
    let profileImage = _this.get(‘store’).createRecord(‘profile-image’, {
      image   : profileImageData,
      uid   : _this.uid,
      extension : ‘.’ + extension
    });
    profileImage.save()
      .then(record => {
        user.forEach(user_ => {
          user_.set(‘photoURL’, record.photoURL);
        });
      })
      .catch(err => {
        let userErrors = profileImage.get(‘errors.user’);
        if (userErrors !== undefined) {
          _this.set(‘userError’, userErrors);
        }
      });
  }
  1. Route to update profile image from backend
@router.route(‘/profileImage’, methods=[‘POST’])
def update_profile_image():
  try:
      data = request.get_json()[‘data’][‘attributes’]
  except Exception:
      return ErrorResponse(PayloadNotFound().message, 422, {‘Content-Type’: ‘application/json’}).respond()

  if not data[‘image’]:
      return ErrorResponse(ImageNotFound().message, 422, {‘Content-Type’: ‘application/json’}).respond()

  if not data[‘extension’]:
      return ErrorResponse(ExtensionNotFound().message, 422, {‘Content-Type’: ‘application/json’}).respond()

  uid = data[‘uid’]
  image = data[‘image’]
  extension = data[‘extension’]

  try:
      imageName = saveToImage(imageFile=image, extension=extension)
  except Exception:
      return ErrorResponse(ImageNotFound().message, 422, {‘Content-Type’: ‘application/json’}).respond()

  fetch_user, imageLink = update_database(uid, imageName)
  return jsonify(UpdateUserSchema().dump(fetch_user).data)

 

This will first create a temp file with the data URI and them upload that file to cloud storage and generate the link and then update the user in the database.

def update_database(uid, imageName):
  fetch_user = User.getUser(user_id=uid)
  if fetch_user is None:
      return ErrorResponse(UserNotFound(uid).message, 422, {‘Content-Type’: ‘application/json’}).respond()
  imagePath = os.path.join(app.config.get(‘BASE_DIR’), ‘static’, ‘uploads’, ‘image’) + ‘/’ + imageName
  imageLink = fileUploader(imagePath, ‘profile/images/’ + imageName)
  fetch_user.photoURL = imageLink
  fetch_user.save_to_db()

  try:
      os.unlink(imagePath)
  except Exception:
      print(‘Unable to delete the temporary file’)

  return fetch_user, imageLink

 

Link to PR – Link

Topics Involved

  • Google Cloud Admin Storage SDK
  • Ember data

Resources

  • Firebase admin sdk documentation – Link
  • Google Cloud Storage SDK Python – Link
  • Blob Management – Link
  • Documents API – Link