Search code examples
swiftvaporleaf

Updating multiples files with Vapor properly


I'm working on a project with vapor and I'm trying to make a function who edit an item with multiples pictures and I don't know how to make it properly for making update the pictures.

Currently, my func is really really lengthy (200 lines :o and I want to add others pictures) and I didn't how to do more properly.

Thanks you for any help :)

''''

func editItemPostHandler(_ req: Request) throws
-> EventLoopFuture<Response> {
    
    
    let updateData =
    try req.content.decode(CreateItemFormData.self)
    
    return Item
        .find(req.parameters.get("itemID"), on: req.db)
        .unwrap(or: Abort(.notFound)).flatMap { item in
            // 3
            item.title = updateData.title
            item.price = updateData.price
            item.description = updateData.description
            item.condition = updateData.condition
            item.weight = updateData.weight
            
            item.$category.id = updateData.categoryID
            item.$size.id = updateData.sizeID
            item.$genderCollection.id = updateData.collectionGenderID
            item.$brand.id = updateData.brandID
            
            if !updateData.picture.isEmpty && !updateData.frontPicture.isEmpty {
                
                let imageName = "\(UUID()).jpg"
                let NewPath =
                req.application.directory.workingDirectory +
                imageFolder + imageName
                
                let frontPictureImageName = "\(UUID()).jpg"
                let frontPictureNewPath =
                req.application.directory.workingDirectory +
                imageFolder + frontPictureImageName
                
                return req.fileio
                    .writeFile(.init(data: updateData.picture), at: NewPath)
                    .flatMap {
                        
                        return req.fileio
                            .writeFile(.init(data: updateData.frontPicture), at: frontPictureNewPath)
                            .flatMap {
                                
                                
                                return Item
                                    .find(req.parameters.get("itemID"), on: req.db)
                                    .unwrap(or: Abort(.notFound)).flatMapThrowing
                                { item in
                                    
                                    
                                    let filename = item.pictures
                                    // 3 3. Construct the path of the picture.
                                    let oldPicturePath = req.application.directory
                                        .workingDirectory + imageFolder + filename
                                    
                                    
                                    let frontPicturefilename = item.frontPicture
                                    // 3 3. Construct the path of the picture.
                                    let oldFrontPicturePath = req.application.directory
                                        .workingDirectory + imageFolder + frontPicturefilename
                                    
                                    
                                    do {
                                        try FileManager.default.removeItem(atPath: oldPicturePath)
                                        try FileManager.default.removeItem(atPath: oldFrontPicturePath)
                                        
                                    }
                                    
                                    item.pictures = imageName
                                    item.frontPicture = frontPictureImageName
                                    
                                    return item
                                }
                                .flatMap {
                                    
                                    (item: Item) -> EventLoopFuture<Response> in
                                    
                                    guard let id = item.id else {
                                        let error = Abort(.internalServerError)
                                        return req.eventLoop.future(error: error)
                                    }
                                    
                                    
                                    // 5
                                    let redirect = req.redirect(to: "/items/\(id)")
                                    return item.save(on: req.db).transform(to: redirect)
                                }
                            }
                    }
            }
            
            else if !updateData.picture.isEmpty {
                
                let imageName = "\(UUID()).jpg"
                let NewPath =
                req.application.directory.workingDirectory +
                imageFolder + imageName
                
                return req.fileio
                    .writeFile(.init(data: updateData.picture), at: NewPath)
                    .flatMap {
                        
                        
                        return Item
                            .find(req.parameters.get("itemID"), on: req.db)
                            .unwrap(or: Abort(.notFound)).flatMapThrowing
                        { item in
                            
                            
                            let filename = item.pictures

                            let oldPicturePath = req.application.directory
                                .workingDirectory + imageFolder + filename
                            
                            do {
                                try FileManager.default.removeItem(atPath: oldPicturePath)
                            }
                            
                            item.pictures = imageName
                            
                            return item
                        }
                        .flatMap {
                            
                            (item: Item) -> EventLoopFuture<Response> in
                            
                            guard let id = item.id else {
                                let error = Abort(.internalServerError)
                                return req.eventLoop.future(error: error)
                            }
                            
                            
                            // 5
                            let redirect = req.redirect(to: "/items/\(id)")
                            return item.save(on: req.db).transform(to: redirect)
                        }
                    }
                
                
                
            }
            
            else if !updateData.frontPicture.isEmpty {
                
                let frontPictureImageName = "\(UUID()).jpg"
                let frontPictureNewPath =
                req.application.directory.workingDirectory +
                imageFolder + frontPictureImageName
                
                return req.fileio
                    .writeFile(.init(data: updateData.frontPicture), at: frontPictureNewPath)
                    .flatMap {
                        
                        
                        return Item
                            .find(req.parameters.get("itemID"), on: req.db)
                            .unwrap(or: Abort(.notFound)).flatMapThrowing
                        { item in
                            
                            
                            let frontPicturefilename = item.frontPicture
                            // 3 3. Construct the path of the picture.
                            let oldFrontPicturePath = req.application.directory
                                .workingDirectory + imageFolder + frontPicturefilename
                            
                            do {
                                try FileManager.default.removeItem(atPath: oldFrontPicturePath)
                            }
                            
                            item.frontPicture = frontPictureImageName
                            
                            return item
                        }
                        .flatMap {
                            
                            (item: Item) -> EventLoopFuture<Response> in
                            
                            guard let id = item.id else {
                                let error = Abort(.internalServerError)
                                return req.eventLoop.future(error: error)
                            }
                            
                            
                            let redirect = req.redirect(to: "/items/\(id)")
                            return item.save(on: req.db).transform(to: redirect)
                        }
                    }
            }
            
            else {
                
                guard let id = item.id else {
                    let error = Abort(.internalServerError)
                    return req.eventLoop.future(error: error)
                }

                let redirect = req.redirect(to: "/items/\(id)")
                return item.save(on: req.db).transform(to: redirect)
            }
        }
}

'''

Thanks you for your help.

Emmanuel


Solution

  • Update,

    I found a tricky strategy but it's allow me to have a less longer code :

    When I edit an item, firstly I give the name of the former image path to the new image path. If there is a new image (so the data of the image is not empty) I'll change the name of this path. After that, I'll try to push the data with fileIO.writeFile. If there is not data, nothing is write and the path of the image stay the same. If there is data, it will write the data, and after it will delete the old picture with : try FileManager.default.removeItem(atPath: oldPicturePath)

    '''

     func editItemPostHandler(_ req: Request) throws
    -> EventLoopFuture<Response> {
        
        
        let updateData =
        try req.content.decode(CreateItemFormData.self)
        
        return Item
            .find(req.parameters.get("itemID"), on: req.db)
            .unwrap(or: Abort(.notFound)).flatMap { item in
    
                item.title = updateData.title
                item.price = updateData.price
                item.description = updateData.description
                item.condition = updateData.condition
                item.weight = updateData.weight
                
                item.$category.id = updateData.categoryID
                item.$size.id = updateData.sizeID
                item.$genderCollection.id = updateData.collectionGenderID
                item.$brand.id = updateData.brandID
                
                    
                // 1. give the former name of itemPicture to imageName
    
                    var imageName = item.pictures
    
                // 2. if updateData.picture isn't empty, give a new name the image name       
                    if !updateData.picture.isEmpty {
                    imageName = "\(UUID()).jpg"
                    }
    
                // create a path with the name of the image 
                    let NewPath =
                    req.application.directory.workingDirectory +
                    imageFolder + imageName
                    
                     // same logic for the second picture                    
                    var frontPictureImageName = item.frontPicture
                        
                    if !updateData.frontPicture.isEmpty {
                    frontPictureImageName = "\(UUID()).jpg"
                    }
                    
                    let frontPictureNewPath =
                    req.application.directory.workingDirectory +
                    imageFolder + frontPictureImageName
                    // try to write the file with the data (if it's empty, nothing is write but the logic continue. 
                    return req.fileio
                        .writeFile(.init(data: updateData.picture), at: NewPath)
                        .flatMap {
                    // same for the second picture 
                            return req.fileio
                                .writeFile(.init(data: updateData.frontPicture), at: frontPictureNewPath)
                                .flatMap {
                                    
                                    
                                    return Item
                                        .find(req.parameters.get("itemID"), on: req.db)
                                        .unwrap(or: Abort(.notFound)).flatMapThrowing
                                    { item in
                                        
                                        
                                        let filename = item.pictures
                         // Construct the path with the old picture name.
                                        let oldPicturePath = req.application.directory
                                            .workingDirectory + imageFolder + filename
                                        
                                        
                                        let frontPicturefilename = item.frontPicture
                                        // 3 3. Construct the path of the picture.
                                        let oldFrontPicturePath = req.application.directory
                                            .workingDirectory + imageFolder + frontPicturefilename
                                        
                                        
                                        do {
                         // if the data isn't empty delete the former picture file 
    
                                            if !updateData.picture.isEmpty {
    
                                            try FileManager.default.removeItem(atPath: oldPicturePath)
                                            }
                         // same for the second picture
                                            if !updateData.frontPicture.isEmpty {
    
                                                try FileManager.default.removeItem(atPath: oldFrontPicturePath)
                                            }
    
                                            
                                        }
                                        
                                        item.pictures = imageName
                                        item.frontPicture = frontPictureImageName
                                        
                                        return item
                                    }
                                    .flatMap {
                                        
                                        (item: Item) -> EventLoopFuture<Response> in
                                        
                                        guard let id = item.id else {
                                            let error = Abort(.internalServerError)
                                            return req.eventLoop.future(error: error)
                                        }
                                        
                                        
                                        // save the new item
                                        let redirect = req.redirect(to: "/items/\(id)")
                                        return item.save(on: req.db).transform(to: redirect)
                                    }
                                }
                        }
                }
    }
    

    '''

    It's tricky but it allow to have less code than before and be able to add more picture to my item struct

    Here's my item struct :

    '''

     struct CreateItemFormData: Content {
    
    let collectionGenderID: UUID
    let categoryID: UUID
    let sizeID : UUID
    let brandID : UUID
    let title: String
    let price: String
    let description: String
    let condition: String
    let weight: String
    var picture: Data
    var frontPicture: Data
    
     }
    

    '''

    Thanks you, and if you have better solution, it's always welcome. :)

    Have a good day, Emmanuel