7.12: Deleting Photos

We've spent a lot of time on uploading and displaying photos - let's delete them!!

Deleting Photos in the API

First, let's add a method in our PhotoService for deleting photos from Cloudinary. We already have a generic method for deleting entities from the database, so we don't have to write one in our PhotoService.

In IPhotoService.cs add the following method signatures:

object DeletePhotoFromCloudinary(string publicId);
Task<Photo> GetPhotoEntity(int id);

We're adding another GetPhoto method - previously, we were returning a DTO - this time we need to return an actual entity so we can delete it from the database.

Now, let's implement them in our PhotoService concrete class:

public async Task<Photo> GetPhotoEntity(int id)
{
    return await _context.Photos.FirstOrDefaultAsync(p => p.Id == id);
}

public object DeletePhotoFromCloudinary(string publicId)
{
    var deleteParams = new DeletionParams(publicId);
    return _cloudinary.Destroy(deleteParams).Result;
}

In the .API project, open up the PhotosController and add a new method called DeletePhoto()

[HttpDelete("{id}")]
public async Task<IActionResult> DeletePhoto(int userId, int id)
{
    if (userId != int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value))
        return Unauthorized();

    var photoFromRepo = await _photoService.GetPhotoEntity(id);

    if (photoFromRepo == null)
        return NotFound();

    if (photoFromRepo.IsMain)
        return BadRequest("You cannot delete your main photo");

    if (photoFromRepo.PublicId != null)
    {
        var result = _photoService.DeletePhotoFromCloudinary(photoFromRepo.PublicId).ToString();

        if (result == "ok")
            _userService.Delete(photoFromRepo);
    }

    if (photoFromRepo.PublicId == null)
    {
        _userService.Delete(photoFromRepo);
    }

    if (await _photoService.SaveAll())
        return Ok();

    return BadRequest("Failed to delete the photo");
}

Test out the API to see if you're able to successfully delete a photo.

Get a fresh token from the /auth/login endpoint.

Send a DELETE request to http://localhost:5000/api/users/{userId}/photos/{photoId}

You should get a 200 OK response:

Deleting Photos in Angular

First, we'll add a method to the user.service.ts file:

deletePhoto(userId: number, id: number) {
    return this._http.delete(this.baseUrl + 'users/' + userId + '/photos/' + id);
}

Now, we can use it in the photo-editor.component.ts:

deletePhoto(id: number) {
    this._alertify.confirm('Are you sure you want to delete this?', () => {
      this._userService.deletePhoto(this._authService.decodedToken.nameid, id).subscribe(() => {
        this.photos.splice(_.findIndex(this.photos, { id: id }), 1);
        this._alertify.success('Photo successfully deleted.');
      }, error => {
        this._alertify.error('Failed to delete.');
      });
    });
}

And, we can use it in the 'photo-editor.component.html` file:

<div class="row">
  <div class="col-md-2" *ngFor="let photo of photos">
    <img class="thumbnail" src="{{ photo.url }}" alt="{{ photo.description }}">
    <div class="row justify-content-center">
      <button
        type="button"
        class="btn btn-sm btn-secondary"
        (click)="setMainPhoto(photo)"
        [ngClass]="photo.isMain ? 'btn-secondary active' : 'btn-default'"
        [disabled]="photo.isMain">Main</button>
      <button 
        type="button"
        class="btn btn-sm btn-warning"
        (click)="deletePhoto(photo.id)"                                 <!-- Added -->
        [disabled]="photo.isMain">                                      <!-- Added -->
        <i class="fa fa-trash-o"></i></button>
    </div>
  </div>
</div>

Wrap-up

Great job! Everything should be working now. Feel free to play around in the app a bit and try uploading and deleting photos and see if you find any bugs. If you do - try to figure out how to fix it.

We've done quite a bit in this module and we've learned a lot!

Last updated