Skip to content

Commit

Permalink
Closes #3 Compatibility issues with CFWheels 1.4
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Peters committed Sep 1, 2015
1 parent 52f8375 commit ab25d00
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 103 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Overrides `fileField()` to work better with `<cffile>` and [nested properties][2

## Dependencies

You must also install the [JSON Properties plugin][3] for the Attachments plugin to work.
You must also install the [JSON Properties plugin][3] (version 0.3+) for the Attachments plugin to work.

## Documentation

Expand All @@ -20,7 +20,7 @@ This plugin was created by [James Gibson][4] and [Chris Peters][5] with support

[1]: http://cfwheels.org/
[2]: http://cfwheels.org/docs/chapter/nested-properties
[3]: https://github.com/liferealized/cfwheels-json-properties
[3]: https://github.com/liquifusion/cfwheels-json-properties
[4]: http://iamjamesgibson.com/
[5]: http://www.clearcrystalmedia.com/
[5]: http://www.chrisdpeters.com/
[6]: http://liquifusion.com/
10 changes: 5 additions & 5 deletions attachments/init.cfm
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<cffunction name="init" access="public" output="false" returntype="any">
<cfset this.version = "1.1,1.1.1,1.2,1.1.3" />
<cffunction name="init" output="false">
<cfset this.version = "1.1,1.1.1,1.1.2,1.1.3,1.1.4,1.1.5,1.1.6,1.1.7,1.1.8,1.3,1.3.1,1.3.2,1.3.3,1.3.4,1.4,1.4.1,1.4.2">

<!--- setup defaults for our new methods --->
<cfset application.wheels.functions.validatesAttachmentPresenceOf = {message="[property] can't be empty"} />
<cfset application.wheels.functions.validatesAttachmentPresenceOf = { message="[property] can't be empty" }>

<cfreturn this />
</cffunction>
<cfreturn this>
</cffunction>
51 changes: 27 additions & 24 deletions attachments/model/attachments.cfm
Original file line number Diff line number Diff line change
@@ -1,40 +1,39 @@
<!---
method to use in your models init() to specify that a model property
method to use in your model's init() to specify that a model property
will allow for file uploads and processing of images
--->
<cffunction name="hasAttachment" access="public" output="false" returntype="void" mixin="model">
<cfargument name="property" type="string" required="true" hint="Name of property on the model to store JSON data related to the attached file." />
<cfargument name="url" type="string" required="false" default="/files/attachments/:model/:property/:id/:style/:filename" hint="Format in which to reference the file as a URL. Use placeholders for `:model`, `:property`, `:id`, `:style`, and `:filename`." />
<cfargument name="path" type="string" required="false" default="/files/attachments/:model/:property/:id/:style/:filename" hint="Format in which to store the file in storage. Use placeholders for `:model`, `:property`, `:id`, `:style`, and `:filename`." />
<cfargument name="styles" type="string" required="false" default="" hint="You may pass in multiple styles. The syntax is `nameOfStyle:widthxheight>`. An actual example would be `small:150x150>,medium:300x300>`. The greater than sign at the end means that the attchments plugin should keep the aspect ratio of the photo uploaded. Styles will only be run on images that your ColdFusion server can do processing on." />
<cfargument name="storage" type="string" required="false" default="filesystem" hint="Other options include `s3` and `filesystem,s3`." />
<cfargument name="blockExtensions" type="string" required="false" default="cfm,cfml,cfc,dbm,jsp,asp,aspx,exe,php,cgi,shtml" hint="List of file extensions to not allow. This is the default behavior unless overridden by `allowExtensions`. If `allowExtensions` is set, this argument is then ignored." />
<cfargument name="allowExtensions" type="string" required="false" default="" hint="List of file extensions to allow. If this is set, the `blockExtensions` argument is ignored." />
<cffunction name="hasAttachment" mixin="model" hint="Call this method in your model's `init` to specify that a property will allow for file uploads (and optionally processing of images)." output="false">
<cfargument name="property" type="string" required="true" hint="Name of property on the model to store JSON data related to the attached file.">
<cfargument name="url" type="string" required="false" default="/files/attachments/:model/:property/:id/:style/:filename" hint="Format in which to reference the file as a URL. Use placeholders for `:model`, `:property`, `:id`, `:style`, and `:filename`.">
<cfargument name="path" type="string" required="false" default="/files/attachments/:model/:property/:id/:style/:filename" hint="Format in which to store the file in storage. Use placeholders for `:model`, `:property`, `:id`, `:style`, and `:filename`.">
<cfargument name="styles" type="string" required="false" default="" hint="You may pass in multiple styles. The syntax is `nameOfStyle:widthxheight>`. An actual example would be `small:150x150>,medium:300x300>`. The greater than sign at the end means that the attchments plugin should keep the aspect ratio of the photo uploaded. Styles will only be run on images that your ColdFusion server can do processing on.">
<cfargument name="storage" type="string" required="false" default="filesystem" hint="Other options include `s3` and `filesystem,s3`.">
<cfargument name="blockExtensions" type="string" required="false" default="cfm,cfml,cfc,dbm,jsp,asp,aspx,exe,php,cgi,shtml" hint="List of file extensions to not allow. This is the default behavior unless overridden by `allowExtensions`. If `allowExtensions` is set, this argument is then ignored.">
<cfargument name="allowExtensions" type="string" required="false" default="" hint="List of file extensions to allow. If this is set, the `blockExtensions` argument is ignored.">
<cfscript>
var loc = {};
// set variables.wheels.class.attachments if it does not exist
if (!StructKeyExists(variables.wheels.class, "attachments"))
// set `variables.wheels.class.attachments` if it does not exist
if (!StructKeyExists(variables.wheels.class, "attachments")) {
variables.wheels.class.attachments = {};
}
loc.styles = ListToArray(arguments.styles, ",", false);
arguments.styles = {};
// do processing on the styles to set them up for later
// we do this now so we only do it once for each `hasAttachment()` call
if (ArrayLen(loc.styles))
{
for (loc.style in loc.styles)
{
if (ArrayLen(loc.styles)) {
for (loc.style in loc.styles) {
loc.name = ListFirst(loc.style, ":");
loc.width = ListFirst(ListLast(loc.style, ":"), "x");
loc.height = ListLast(Replace(ListLast(loc.style, ":"), ">", "", "all"), "x");
loc.preserveAspect = Find(">", loc.style) gt 0;
arguments.styles[loc.name] = {
width = loc.width
, height = loc.height
, preserveAspect = loc.preserveAspect
width=loc.width,
height=loc.height,
preserveAspect=loc.preserveAspect
};
}
}
Expand All @@ -43,16 +42,20 @@
variables.wheels.class.attachments[arguments.property] = Duplicate(arguments);
// allow for the two new types of callbacks
if (!StructKeyExists(variables.wheels.class.callbacks, "beforePostProcessing"))
if (!StructKeyExists(variables.wheels.class.callbacks, "beforePostProcessing")) {
variables.wheels.class.callbacks.beforePostProcessing = [];
}
if (!StructKeyExists(variables.wheels.class.callbacks, "afterPostProcessing"))
if (!StructKeyExists(variables.wheels.class.callbacks, "afterPostProcessing")) {
variables.wheels.class.callbacks.afterPostProcessing = [];
}
// set callbacks for this property
afterDelete("$deleteAttachments");
// Callbacks
jsonProperty(property=arguments.property, type="struct", registerCallbacks=false);
afterFind("$deserializeJSONPropertiesAfterFind");
afterCreate("$saveAttachments");
beforeValidationOnUpdate("$updateAttachments");
jsonProperty(property=arguments.property, type="struct");
beforeValidationOnUpdate("$updateAttachments,$serializeJSONProperties");
beforeDelete("$serializeJSONProperties");
afterDelete("$deleteAttachments");
</cfscript>
</cffunction>
117 changes: 48 additions & 69 deletions attachments/model/callbacks.cfm
Original file line number Diff line number Diff line change
@@ -1,91 +1,84 @@
<cffunction name="$saveAttachments" access="public" output="false" returntype="boolean">
<cffunction name="$saveAttachments" returntype="boolean" output="false">
<cfscript>
var loc = { success = true };
if (!FindNoCase("multipart", cgi.content_type))
if (!FindNoCase("multipart", cgi.CONTENT_TYPE)) {
return false;
}
if (!StructKeyExists(variables, "$attachmentsSaved"))
{
if (!StructKeyExists(variables, "$persistedProperties") || !StructKeyExists(variables.$persistedProperties, ListFirst(primaryKey())))
if (!StructKeyExists(variables, "$attachmentsSaved")) {
if (!StructKeyExists(variables, "$persistedProperties") || !StructKeyExists(variables.$persistedProperties, ListFirst(primaryKey()))) {
$updatePersistedProperties();
}
// loop over our attachements and upload each one
for (loc.attachment in variables.wheels.class.attachments)
{
for (loc.attachment in variables.wheels.class.attachments) {
loc.saved = $saveAttachment(property=loc.attachment);
if (loc.success)
if (loc.success) {
loc.success = loc.saved;
}
}
variables.$attachmentsSaved = true;
if (loc.success)
{
if (loc.success) {
$serializeJSONProperties();
this.save();
this.reload();
}
}
</cfscript>
<cfreturn loc.success />
<cfreturn loc.success>
</cffunction>

<cffunction name="$updateAttachments" access="public" output="false" returntype="boolean">
<cffunction name="$updateAttachments" returntype="boolean" output="false">
<cfscript>
var loc = { success = true };
if (!FindNoCase("multipart", cgi.content_type))
if (!FindNoCase("multipart", cgi.CONTENT_TYPE)) {
return false;
if (!StructKeyExists(variables, "$attachmentsSaved"))
{
if (!StructKeyExists(variables, "$persistedProperties") || !StructKeyExists(variables.$persistedProperties, ListFirst(primaryKey())))
}
if (!StructKeyExists(variables, "$attachmentsSaved")) {
if (!StructKeyExists(variables, "$persistedProperties") || !StructKeyExists(variables.$persistedProperties, ListFirst(primaryKey()))) {
$updatePersistedProperties();
}
// loop over our attachements and upload each one
for (loc.attachment in variables.wheels.class.attachments)
{
if (StructKeyExists(this, loc.attachment & "$attachment") && Len(form[this[loc.attachment & "$attachment"]]))
{
for (loc.attachment in variables.wheels.class.attachments) {
if (StructKeyExists(this, loc.attachment & "$attachment") && Len(form[this[loc.attachment & "$attachment"]])) {
loc.attempted = true;
this[loc.attachment & "_old"] = this.changedFrom(loc.attachment);
$deleteAttachment(loc.attachment & "_old", variables.wheels.class.attachments[loc.attachment]);
loc.saved = $saveAttachment(loc.attachment);
}
else
{
else {
loc.attempted = false;
this[loc.attachment] = this.changedFrom(loc.attachment);
loc.saved = false;
}
if (loc.success)
if (loc.success) {
loc.success = !loc.attempted || loc.saved;
}
}
variables.$attachmentsSaved = true;
if (loc.saved)
{
this.save();
this.reload();
}
}
</cfscript>
<cfreturn loc.success />
<cfreturn loc.success>
</cffunction>

<cffunction name="$saveAttachment" access="public" output="false" returntype="boolean">
<cfargument name="property" type="string" required="true" />
<cffunction name="$saveAttachment" returntype="boolean" output="false">
<cfargument name="property" type="string" required="true">
<cfscript>
var loc = {};
loc.attachment = variables.wheels.class.attachments[arguments.property];
// only try to upload something if we have the proper $attachment field
if (StructKeyExists(this, loc.attachment.property & "$attachment") && StructKeyExists(form, this[loc.attachment.property & "$attachment"]) && Len(form[this[loc.attachment.property & "$attachment"]]))
{
if (StructKeyExists(this, loc.attachment.property & "$attachment") && StructKeyExists(form, this[loc.attachment.property & "$attachment"]) && Len(form[this[loc.attachment.property & "$attachment"]])) {
loc.file = $saveFileToTempDirectory(argumentCollection=arguments);
if (IsBoolean(loc.file)) {
Expand All @@ -95,28 +88,27 @@
loc.filePath = Replace(GetTempDirectory() & loc.file.ServerFile, "\", "/", "all");
// check to make sure we don't have a bad file
if ($validateAttachmentFileType(loc.file.ServerFileExt, loc.attachment.blockExtensions, loc.attachment.allowExtensions))
{
if ($validateAttachmentFileType(loc.file.ServerFileExt, loc.attachment.blockExtensions, loc.attachment.allowExtensions)) {
this[loc.attachment.property] = $saveFileToStorage(
argumentCollection=loc.attachment
, source=loc.filePath
, fileSize=loc.file.FileSize);
if (IsImageFile(loc.filePath) && StructCount(loc.attachment.styles))
{
for (loc.style in loc.attachment.styles)
argumentCollection=loc.attachment,
source=loc.filePath,
fileSize=loc.file.FileSize
);
if (IsImageFile(loc.filePath) && StructCount(loc.attachment.styles)) {
for (loc.style in loc.attachment.styles) {
this[loc.attachment.property].styles[loc.style] = $saveImageFileWithStyle(source=loc.filePath, argumentCollection=loc.attachment, style=loc.style);
}
}
}
else
{
$file(action="delete", file=loc.filePath);
else {
FileDelete(loc.filePath);
this.addError(property=arguments.property, message="File is not a valid type.");
return false;
}
}
</cfscript>
<cfreturn true />
<cfreturn true>
</cffunction>

<cffunction name="$saveImageFileWithStyle" access="public" output="false" returntype="struct">
Expand Down Expand Up @@ -173,30 +165,17 @@
<cffunction name="$saveFileToTempDirectory" access="public" output="false">
<cfargument name="property" type="string" required="true" />
<cfscript>
// Set the file in a temp location to verify it's not evil
var fileArgs = {
action = "upload"
, fileField = this[arguments.property & "$attachment"]
, destination = GetTempDirectory()
, result = "returnValue"
, nameconflict = "overwrite"
};
try
{
return $file(argumentCollection=fileArgs);
try {
return FileUpload(GetTempDirectory(), this[arguments.property & "$attachment"], "", "overwrite");
}
catch (any e)
{
// This is only tested on CF9. If you get an error on Railo, see if there is an equivalent error to
// catch in another `catch` block.
if (e.Detail contains "zero-length")
{
catch (any e) {
// This is only tested on CF9. If you get an error on Railo or Lucee, see if there is an equivalent error to
// catch in another `catch` block.
if (e.Detail contains "zero-length") {
this.addError(property=arguments.property, message="Can't upload an empty file");
return false;
}
else
{
else {
$throw(argumentCollection=e);
}
}
Expand Down
5 changes: 3 additions & 2 deletions index.cfm
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<cfsetting enablecfoutputonly="true" />

<cfset attachments = {}>
<cfset attachments.version = "0.7">
<cfset attachments.version = "0.2">

<cfinclude template="stylesheets/doc_styles.cfm" />

Expand All @@ -10,7 +10,8 @@
<h1>Attachments v#attachments.version#</h1>

<p>
Add support for file uploads to your model with the <tt>hasAttachment()</tt> function. Also provides <tt>attachmentImageTag()</tt> and <tt>attachmentLinkTo()</tt> view helpers.
Add support for file uploads to your model with the <tt>hasAttachment()</tt> function. Also provides
<tt>attachmentImageTag()</tt> and <tt>attachmentLinkTo()</tt> view helpers.
</p>
<p>
Automatically resize uploaded images to a set of &quot;styles&quot; that you define. (For example, you could automatically
Expand Down

0 comments on commit ab25d00

Please sign in to comment.