Selfie

Selfie is a Grails Image / File Upload Plugin. Use Selfie to attach files to your domain models, upload to a CDN, validate content, produce thumbnails.

License

License

The Apache Software License, Version 2.0
GroupId

GroupId

com.bertramlabs.plugins
ArtifactId

ArtifactId

selfie
Last Version

Last Version

2.1.4
Release Date

Release Date

Type

Type

pom.sha512
Description

Description

Selfie
Selfie is a Grails Image / File Upload Plugin. Use Selfie to attach files to your domain models, upload to a CDN, validate content, produce thumbnails.
Project URL

Project URL

https://github.com/bertramdev/selfie
Source Code Management

Source Code Management

https://github.com/bertramdev/selfie

Download selfie

Dependencies

compile (5)

Group / Artifact Type Version
org.grails : grails-core jar
org.imgscalr : imgscalr-lib jar 4.2
com.bertramlabs.plugins : karman-core jar 1.5.6
com.bertramlabs.plugins : karman-grails jar 1.5.6
org.grails : grails-plugin-domain-class jar

runtime (12)

Group / Artifact Type Version
org.springframework.boot : spring-boot-starter-logging jar
org.springframework.boot : spring-boot-autoconfigure jar
org.springframework.boot : spring-boot-starter-tomcat jar
org.grails : grails-dependencies jar
org.grails : grails-web-boot jar
org.grails.plugins : cache jar
org.grails : grails-plugin-services jar
org.grails.plugins : hibernate5 jar
org.hibernate : hibernate-core jar 5.4.0.Final
org.hibernate : hibernate-ehcache jar 5.4.0.Final
com.h2database : h2 jar
io.micronaut : micronaut-inject-groovy jar

Project Modules

There are no modules declared in this project.

Selfie

Selfie is a Grails Image / File Upload Plugin. Use Selfie to attach files to your domain models, upload to a CDN, validate content, produce thumbnails.

  • Domain Attachment
  • CDN Storage Providers (via Karman)
  • Image Resizing (imgscalr)
  • Content Type Validation
  • GORM Bindings / Hibernate User Types Support

Installation

Add The Following to your build.gradle:

dependencies {
    compile 'com.bertramlabs.plugins:selfie:2.0.1'
}

Configuration

Selfie utilizes karman for dealing with asset storage. Karman is a standardized interface for sending files up to CDN's as well as local file stores. It is also capable of serving local files.

In order to upload files, we must first designate a storage provider for these files. This can be done in the attachmentOptions static map in each GORM domain with which you have an Attachment, or this can be defined in your application.groovy.

grails {
  plugin {
    selfie {
      storage {
        path = 'uploads/:class/:id/:propertyName/' //This configures the storage path of the files being uploaded by domain class name and property name and identifier in GORM
        bucket = 'uploads'
        providerOptions {
          provider = 'local' // Switch to s3 if you wish to use s3 and install the karman-aws plugin
          basePath = 'storage'
          baseUrl  = 'http://localhost:8080/image-test/storage'
          //accessKey = "KEY" //Used for S3 Provider
          //secretKey = "KEY" //Used for S3 Provider
        }
      }
    }
  }
}

The providerOptions section will pass straight through to karmans StorageProvider.create() factory. The provider specifies the storage provider to use while the other options are specific to each provider.

In the above example we are using the karman local storage provider. This is all well and good, but we also need to be able to serve these files from a URL. Depending on your environment this can get a bit tricky.

One option is to use nginx to serve the directory and point the baseUrl to the appropriate endpoint. Another option is to use the built in endpoint provided by the karman plugin:

grails {
  plugin {
    karman {
      serveLocalStorage = true
      serveLocalMapping = 'storage' // means /storage is base path
      storagePath = 'storage'
    }
  }
}

This will provide access to files within the storage folder via the storage url mapping.

NOTE:

You can also configure which bucket or karman storage provider is used on a per domain level as well as per property level basis in config. For example the Book domain class could be configured as follows:

grails {
  plugin {
    selfie {
      domain {
        book {
          storage {
            path = 'uploads/:class/:id/:propertyName/' //This configures the storage path of the files being uploaded by domain class name and property name and identifier in GORM
            bucket = 'uploads'
            providerOptions {
              provider = 'local' // Switch to s3 if you wish to use s3 and install the karman-aws plugin
              basePath = 'storage'
              baseUrl  = 'http://localhost:8080/image-test/storage'
              //accessKey = "KEY" //Used for S3 Provider
              //secretKey = "KEY" //Used for S3 Provider
            }
          }
        }
      }
    }
  }
}

Usage

The plugin uses an embedded GORM domain class to provide an elegant DSL for uploading and attaching files to your domains. So make sure you define your static embedded=[] when using the Attachment class.

Example DSL:

import com.bertramlabs.plugins.selfie.Attachment

class Book {
  String name
  Attachment photo


  static attachmentOptions = [
    photo: [
      styles: [
        thumb: [width: 50, height: 50, mode: 'fit'],
        medium: [width: 250, height: 250, mode: 'scale']
      ]
    ]
  ]

  static embedded = ['photo'] //required

  static mapping = { }

  static constraints = {
    photo contentType: ['png','jpg'], fileSize:1024*1024 // 1mb
  }
}

Uploading Files could not be simpler. Simply use a multipart form and upload a file:

<g:uploadForm name="upload" url="[action:'upload',controller:'photo']">
  <g:textField name="name" placeholder="name"/><br/>
  <input type="file" name="photo" /><br/>
  <g:submitButton name="update" value="Update" /><br/>
</g:uploadForm>

When you bind your params object to your GORM model, the file will automatically be uploaded upon save and processed:

class PhotoController {
  def upload() {
    def photo = new Photo(params)
    if(!photo.save()) {
      println "Error Saving! ${photo.errors.allErrors}"
    }
    redirect view: "index"
  }
}

Or if you'd like to bind the MultiPartFile manually you can convert it to an Attachment as so:

class PhotoService {
  def save(String title, MultipartFile file) {
    def photo = new AttachmentValueConverter().convert(file)
    new Book(title: title, photo: photo).save()
  }
}

Things to be Done

  • Support Secure Files
  • Provide Convenience taglibs
  • Support Attachment Size closure for dynamic sizes based on other properties
  • Stream Support (if possible)
com.bertramlabs.plugins

Bertram Labs

Versions

Version
2.1.4