IHP Api Reference
Copyright(c) digitally induced GmbH 2020
Safe HaskellNone

IHP.Controller.FileUpload

Description

This modules provides high-level file and image upload functionality.

All uploaded files are saved to the uploads directory. Given e.g. an User entity with id = 550e8400-e29b-11d4-a716-446655440000, the file is saved to /uploads/users/550e8400-e29b-11d4-a716-446655440000/picture.jpg. If the directory does not exists, it will be created.

Synopsis

Documentation

fileOrNothing :: (?context :: ControllerContext) => ByteString -> Maybe (FileInfo ByteString) Source #

Returns a file upload from the request as a ByteString.

Returns Nothing when the file is not found in the request body.

Example:

Given a form like this:

<form method="POST" action={SubmitMarkdownAction}>
    <input
        type="file"
        name="markdown"
        accept="text/markdown, text/plain"
    >
</form>

The file can be accessed within the action like this:

action SubmitMarkdownAction = do
    let content :: Text =
            fileOrNothing "markdown"
            |> fromMaybe (error "no file given")
            |> (.fileContent)
            |> cs -- content is a LazyByteString, so we use `cs` to convert it to Text

See filesByName if multiple files can be uploaded by the user in a single form submission.

See storeFile to upload the file to S3 or similar cloud storages.

filesByName :: (?context :: ControllerContext) => ByteString -> [FileInfo ByteString] Source #

Like fileOrNothing but allows uploading multiple files in the same request

Example:

For uploading multiple files we need to set the multiple attribute on the file input:

<form method="POST" action={SubmitMarkdownAction}>
    <input
        type="file"
        name="markdown"
        accept="text/markdown, text/plain"
        multiple
    >
</form>

When the user selects multiple files, we can access them like this:

action SubmitMarkdownAction = do
    let contents :: [Text] =
            filesByName "markdown"
            |> map (.fileContent)
            |> map cs -- content is a LazyByteString, so we use `cs` to convert it to Text

Use forEach to store multiple files inside the cloud storage:

action SubmitMarkdownAction = do
    let markdownFiles = filesByName "markdown"

    forEach markdownFiles \file -> do
        storeFile file "notes"

        pure ()

data ImageUploadOptions Source #

Options to be used together with uploadImageWithOptions

Example:

ImageUploadOptions { convertTo = "jpg", imageMagickOptions = "-resize '1024x1024^' -gravity north -extent 1024x1024 -quality 85% -strip" }

Constructors

ImageUploadOptions 

Fields

  • convertTo :: Text

    The file extension to be used when saving the file, e.g. "jpg" or "png".

  • imageMagickOptions :: Text

    Command line options passed to imagemagick. Can used for e.g. resizing, rotating, file size reduction.

uploadImageWithOptions :: forall (fieldName :: Symbol) record (tableName :: Symbol). (?context :: ControllerContext, SetField fieldName record (Maybe Text), KnownSymbol fieldName, HasField "id" record (Id (NormalizeModel record)), Show (PrimaryKey (GetTableName (NormalizeModel record))), tableName ~ GetTableName record, KnownSymbol tableName) => ImageUploadOptions -> Proxy fieldName -> record -> IO record Source #

Saves an uploaded image file to the uploads directory and writes the relative path to the given record attribute.

Given e.g. an User entity with id = 550e8400-e29b-11d4-a716-446655440000, the file is saved to /uploads/users/550e8400-e29b-11d4-a716-446655440000/picture.jpg.

Before saving, the image is converted using imagemagick. You can supply custom image magick options using the options attribute.

If the upload directory does not exists, it will be created.

Example: Uploading a user profile picture

let profilePictureOptions = ImageUploadOptions
        { convertTo = "jpg"
        , imageMagickOptions = "-resize '1024x1024^' -gravity north -extent 1024x1024 -quality 85% -strip"
        }

user
    |> fill @["firstname", "lastname", "pictureUrl"]
    |> uploadImageWithOptions profilePictureOptions #pictureUrl
    >>= ifValid \case
        Left user -> render EditView { .. }
        Right user -> do
            user <- user |> updateRecord
            redirectTo EditUserAction { .. }

The uploaded image path is now stored in #pictureUrl.

uploadImageFile :: forall (fieldName :: Symbol) record (tableName :: Symbol). (?context :: ControllerContext, SetField fieldName record (Maybe Text), KnownSymbol fieldName, HasField "id" record (Id (NormalizeModel record)), Show (PrimaryKey (GetTableName (NormalizeModel record))), tableName ~ GetTableName record, KnownSymbol tableName) => Text -> Proxy fieldName -> record -> IO record Source #

Saves an uploaded image file to the uploads directory.

Given e.g. an User entity with id = 550e8400-e29b-11d4-a716-446655440000, the file is saved to /uploads/users/550e8400-e29b-11d4-a716-446655440000/picture.jpg.

No transformation or validation is applied to the given uploaded file. If you need this, take a look at uploadImageWithOptions.

Example: Uploading a user profile picture

let profilePictureOptions = ImageUploadOptions
        { convertTo = "jpg"
        , imageMagickOptions = "-resize '1024x1024^' -gravity north -extent 1024x1024 -quality 85% -strip"
        }

user
    |> fill @["firstname", "lastname", "pictureUrl"]
    |> uploadImageFile "png" #pictureUrl
    >>= ifValid \case
        Left user -> render EditView { .. }
        Right user -> do
            user <- user |> updateRecord
            redirectTo EditUserAction { .. }

uploadPng :: forall (fieldName :: Symbol) record. (?context :: ControllerContext, SetField fieldName record (Maybe Text), HasField "id" record (Id' (GetTableName (GetModelByTableName (GetTableName record)))), Show (PrimaryKey (GetTableName (GetModelByTableName (GetTableName record)))), KnownSymbol fieldName, KnownSymbol (GetTableName record)) => Proxy fieldName -> record -> IO record Source #

Saves an uploaded png file. No validation or transformation applied. See uploadImageFile for details.

uploadSVG :: forall (fieldName :: Symbol) record. (?context :: ControllerContext, SetField fieldName record (Maybe Text), HasField "id" record (Id' (GetTableName (GetModelByTableName (GetTableName record)))), Show (PrimaryKey (GetTableName (GetModelByTableName (GetTableName record)))), KnownSymbol fieldName, KnownSymbol (GetTableName record)) => Proxy fieldName -> record -> IO record Source #

Saves an uploaded svg file. No validation or transformation applied. See uploadImageFile for details.