Replace/overwrite image (avatar) on upload

I´m trying to update a user avatar via frontend upload. How can I overwrite the existing profile picture (and convert the uploaded on to .jpg if necessary)?

my controller looks like this:

<?php

return function ($kirby, $page) {

  $alerts  = [];
  $success = '';

  if ($kirby->request()->is('post') === true && get('submit')) {

$uploads = $kirby->request()->files()->get('file');

if (count($uploads) > 1) {
  $alerts['exceedMax'] = 'You may only upload 1 file.';
  return compact('alerts', 'success');
}

$kirby->user();

foreach ($uploads as $upload) {

  try {
    $name = crc32($upload['name'].microtime()). '_' . $upload['name'];
    $file = $kirby->user()->createFile([
      'source'   => $upload['tmp_name'],
      'filename' => 'profile.jpg',
      'template' => 'avatar',
      'overwrite' => true
    
    ]);
    $success = 'Your file upload was successful';
  } catch (Exception $e) {
    $alerts[$upload['name']] = $e->getMessage();
  }
}
  }

  return compact('alerts', 'success');
};

Hm, there is no replace method for the user avatar. The API checks if an avatar already exists. If yes, it is deleted before the new avatar is uploaded. That’s how you can also achieve that.

Here is the API route for reference:

/kirby/config/api/routes/users.php

    [
        'pattern' => 'users/(:any)/avatar',
        'method'  => 'POST',
        'action'  => function (string $id) {
            if ($avatar = $this->user($id)->avatar()) {
                $avatar->delete();
            }

            return $this->upload(function ($source, $filename) use ($id) {
                return $this->user($id)->createFile([
                    'filename' => 'profile.' . F::extension($filename),
                    'template' => 'avatar',
                    'source'   => $source
                ]);
            }, $single = true);
        }
    ],

well, i´m pretty sure this is not very elegant: when i implement it like this i get the error “The extensions for “…” is missing”:

<?php

return function ($kirby, $page) {

  $alerts  = [];
  $success = '';

  if ($kirby->request()->is('post') === true && get('submit')) {

    $uploads = $kirby->request()->files()->get('file');

    // we only want 1 file
    if (count($uploads) > 1) {
      $alerts['exceedMax'] = 'You may only upload 1 file.';
      return compact('alerts', 'success');
    }

    // authenticate as user
    $kirby->user();

    foreach ($uploads as $upload) {

      try {
        $name = crc32($upload['name'].microtime()). '_' . $upload['name'];
        $file = $kirby->user()->createFile([
          'source'   => $upload['tmp_name'],
          'pattern' => 'users/(:any)/avatar',
          'method'  => 'POST',
          'action'  => function (string $id) {
            if ($avatar = $this->user($id)->avatar()) {
                $avatar->delete();
            }

            return $this->upload(function ($source, $filename) use ($id) {
                return $this->user($id)->createFile([
                    'filename' => 'profile.' . F::extension($filename),
                    'template' => 'avatar',
                    'source'   => $source
                ]);
            }, $single = true);
        }
        
        ]);
        $success = 'Your file upload was successful';
      } catch (Exception $e) {
        $alerts[$upload['name']] = $e->getMessage();
      }
    }
  }

  return compact('alerts', 'success');
};

I didn’t mean to say you should use the pattern or a route in your code, that was only as a reference how this is done in the Panel.

Ah, got it. adding only this line already did the job:

if ($avatar = $this->user()->avatar()) {
          $avatar->delete();
      }

Hm, I’m working on the same task at the moment - updating the user avatar from the frontend - and can’t get it to work at the moment even after going over your code.

if ($kirby->request()->is('POST') && get('update')) {

  $avatar = $kirby->request()->files()->get('avatar');

  if (!empty($avatar['name'])) {
    try {
      //DELETE EXISTING AVATAR
      if ($previousAvatar = $this->user()->avatar()) {
        $previousAvatar->delete();
      }
      //CREATE NEW AVATAR
      $name = crc32($avatar['name'].microtime()). '_' . $avatar['name'];
      $file = $kirby->user()->createFile([
        'source'   => $avatar['tmp_name'],
        'filename' => 'profile.'.F::extension($avatar['name']),
        'template' => 'avatar'
      ]);
    } catch (Exception $e) {
      $error = true;
      $message = "Could not update avatar!<br/>";
    }
  }
}

The file is being requested correctly (which I’ve checked by echoing the filename), but I’m still getting my error message.

What do you mean?

Sorry for the vague statement. What I meant is that the problem does not appear to be connected to the actual front end form code, as the corresponding file request in the controller seems to be processed correctly and I can retrieve the file name etc. correctly there.
But I seem to be doing something wrong in the actual controller code (posted above). The previous avatar is being deleted alright, but the upload of the new one fails.

EDIT: Fixed it! There was a permission error on the server I had overlooked. The code above works as intended.