image upload api endpoint

Allows images to be uploaded over the API and saves them to the local
filesystem. Some faff with dates and formats in order to work round
issues with mongoose and elasticsearch not going the right thing.

Fixes #214
attach extra properties to the image

e.g. source or notes
add image put endpoint to replace images over the API

PUT /:collection/:id/image/:image_id replaces the image with image_id.

Factors out the code common to the PUT and POST requests into functions
to reduce duplication.
API endpoint to delete individual images

DEL /:collection/:id/image/:image_id will remove that image and delete
the file on the server. This only works for images stored on the server
as remote images don't have IDs
delete all images API endpoint

DELETE /:collection/:id/image will remove all images associated with a
document and remove any image files on the server too
Change findMemberships to be an instance method

Rather than having this as a private implementation we expose the method
on the instance so we can actively find memberships when we need then.

This also has the added bonus of making the method signature simpler.
When we get rid of the pre init hook we can also drop the id argument
and just use the instance's id.
Remove skipMemberships flag and manually retrieve memberships

This doesn't entirely work currently because the memberships themselves
don't have the findMemberships method. Perhaps the best thing to do
would be to stub that method on the memberships model or similar.
Fix memberships tests
Add populateMemberships method with consistent interface

The populateMemberships method handles populating the memberships on a
model by calling the findMemberships method. This method is also added
to the Membership model as a blank implementation so that all the models
behave in the same way and no conditionals are required in app.js.
Check the _id and id fields in findMemberships method

When documents are constructed from search results they only have an
'id' field. When they are newly created they only have the '_id' field,
so we check for both.
Populate memberships in search results
Handle blank embed parameter

If the embed parameter is provided but is empty then memberships should
be skipped completely.
Fix embedded memberships in joined documents

When using the ?embed parameter to specify joins the joined documents
weren't getting their memberships added.

This change uses 'getValue', which in turn calls the mpath module to get
an array of models based on the populated path. This can also be an
array of arrays if the document is nested more than one layer deep, so
we flatten the array before processing to normalize it.
Handle errors when populating joins
Check models are valid before populating memberships

Avoid errors with possibly null models by compacting the models array to
remove falsy values and filtering the array to ensure all members have
the required method.
WIP member needs to be handled on membership embeds

Also start adding some tests
WIP working implementation of single level embed instructions

This still needs to be tidied up to:

- Handle error messages as it did before
- Handle 'membership.member' embeds