How can I include mappings into Application.cfc from external property file? - properties

I have trouble with setting mappings in Application.cfc
We have diverent Server (dev,QS,prod)
Each with a little different Pathes.
I want to set serverspecific pathes and variables via configuration file.
On ApplicationStart you read the ini file and setup your system.
http://www.raymondcamden.com/index.cfm/2005/8/26/ColdFusion-101-Config-Files-AGoGo
This works fine.
Normaly you set mappings in Applcation.cfc like this:
<!--- in Application.cfc --->
<cfset this.mappings['/components'] = "D:\Inetpub\wwwroot\myApp\components">
Somewhere in a normal cfm File I instatiate a cfc named test via:
<cfset t = createObject("component", "components.test")>
I want to set the mappings only once at onApplicationsStart
<cffunction
name="OnApplicationStart"
access="public"
returntype="boolean"
output="false"
hint="Fires when the application is first created.">
<!---create structure to hold configuration settings--->
<cfset ini = structNew()>
<cfset ini.iniFile = expandPath("./ApplicationProperties.ini")>
<cfset application.ini = ini>
<!--- read ini file --->
<cfset sections = getProfileSections(application.ini.iniFile)>
<cfloop index="key" list="#sections.mappings#">
<cfset this.mappings[key] = getProfileString(application.ini.iniFile, "mappings", key)>
</cfloop>
But this don't work because this.mappings is empty and next request. :(
Putting this to OnRequestStart
<!--- read ini file --->
<cfset sections = getProfileSections(application.ini.iniFile)>
<cfloop index="key" list="#sections.mappings#">
<cfset this.mappings[key] = getProfileString(application.ini.iniFile, "mappings", key)>
</cfloop>
I get an error that the component can't be found.
This is strange.
Putting the struct into Application scope
<cfloop index="key" list="#sections.mappings#">
<cfset APPLICATION.mappings[key] = getProfileString(application.ini.iniFile, "mappings", key)>
</cfloop>
How to call my Component?
<cfset t = createObject("component", "application.components.test")>
Doesn't work.
So I have 3 targets.
reading all pathes and mappings from ini file
reading them once at ApplicationStart
easy usage in sourcecode.

Mappings can't be set in onApplicationStart(), they must be set in the pseudo constructor of Application.cfc, and they must be set on every request.
It's also important to note that the application scope is not available at this point, therefore if you need to cache anything you'll need to use the server scope. You can cache your mapping struct to the server scope and just set it into this.mappings each request.
<cfcomponent>
<cfset this.name = "myapp" />
<!--- not cached so create mappings --->
<cfif NOT structKeyExists(server, "#this.name#_mappings")>
<cfset iniFile = getDirectoryFromPath(getCurrentTemplatePath()) & "/ApplicationProperties.ini" />
<cfset sections = getProfileSections(iniFile) />
<cfset mappings = structnew() />
<cfloop index="key" list="#sections.mappings#">
<cfset mappings[key] = getProfileString(iniFile, "mappings", key)>
</cfloop>
<cfset server["#this.name#_mappings"] = mappings />
</cfif>
<!--- assign mappings from cached struct in server scope --->
<cfset this.mappings = server["#this.name#_mappings"] />
<cffunction name="onApplicationStart">
<!--- other stuff here --->
</cffunction>
</cfcomponent>
If you intend to keep you ini file in the webroot, you should make it a .cfm template and start it with a <cfabort>. It will work just the same but will not be readable
ApplicationProperties.ini.cfm
<cfabort>
[mappings]
/foo=c:/bar/foo

Related

cfthread object empty inside of a cfthread tag in Lucee 5.2

In Lucee v5.2.9.31, the following code throws an error inside of the checkTest thread when I request the status of the test_thread thread from the cfthread object. The error I get is key [test_thread] doesn't exist.
<cfthread action="run" name="test_thread">
<cfloop index='i' from='1' to='50'>
<cffile action="append" file="./test_thread.txt" addNewLine="yes" output="Index: #i#" />
<cfset sleep(500) />
</cfloop>
</cfthread>
<cfthread action="run" name="checkTest">
<cfset test_thread_complete = false />
<cfloop condition="test_thread_complete eq false">
<cfset test_thread_status = cfthread['test_thread'].status />
<cffile action="append" file="./checkTestThread.txt" addNewLine="yes" output="#test_thread_status#" />
<cfif test_thread_status eq 'COMPLETED'>
<cfset test_thread_complete = true />
</cfif>
<cfset sleep(1000) />
</cfloop>
</cfthread>
<cfdump var="#cfthread#" />
<cfdump var="#cfthread['test_thread']#" />
However in an older version of Lucee (v4.5.5.015), the code works as expected and generated 2 files: test_thread.txt with the incrementing index, and checkTestThread.txt which contains the status of test_thread.
In both versions, the cfdumps return the cfthread object. The first dump contains both threads and the 2nd dump contains just the test_thread object as expected.
Is this a bug in Lucee 5 or was the code exploiting a bug in earlier versions of Lucee/Railo?
This was caused by an update that was made to Lucee.
According to Michael Offner (The maintainer of Lucee):
The reason is this no longer works in Lucee, because we added support
of having threads inside threads, since then "cfthread" only shows the
children of the current thread, in a tree (see key "childThreads"
inside "cfthread"). We cannot show all threads on one level that would
create a mess, because we would show the tree of threads at the same
time.
Issue is fixed in v5.3.4.37, however the code will need to be updated as their solution adds a threadData function which returns the root cfthread object.
In my code changing the following: <cfset test_thread_status = cfthread['test_thread'].status /> to <cfset test_thread_status = threadData()['test_thread'].status /> fixes the error and properly returns the status of a sibling thread.
More Information:
Git commit of the fix: https://github.com/lucee/Lucee/commit/576ff5f7e2556c1cc8298154d40006a158da9270
Jira Issue: https://luceeserver.atlassian.net/browse/LDEV-2150

cf9 cffileupload - uploads file but progress par shows error

I am having issues with the cffileupload function in ColdFusion9. I when I select upload, it uploads the first files to the correct location, but the progress bar shows in red and says error. If I hit upload again, it does the exact same thing with the next file. In the browse console it shows Status: 500. I have googled this issue and have not found a answer. Has anyone been able to get this to work correctly?
submission.cfm:
<cfset session.myuploadroot = "\\coldfusion\devl\uploads\cfeis_redbook\">
<form action="submission.cfm" method="post">
<cffileupload extensionfilter="xls,xlsx,doc,docx,pdf" name="bfiles" maxfileselect="3" title="Portfolio Images" url="fileupload.cfm?#urlEncodedFormat(session.urltoken)#" oncomplete="handleComplete">
</form>
fileupload.cfm
<cfif structKeyExists(form, "filedata")>
<cffile action="upload" filefield="filedata" destination="#session.myuploadroot#" nameconflict="overwrite" result="result">
</cfif>
<cfset str.STATUS = 200>
<cfset str.MESSAGE = "passed">
<cfoutput>#serializeJSON(str)#</cfoutput>

Dynamically add text into body as I click <Select> indexes in coldfusion

On my cold fusion page what I want to do is click one of the options from my <Select> statement. After doing so I want to see a richtextbox be dynamically filled with a matching record in my database from the value of the item I clicked. I also want it to do the same for a checkbox, and authors object.
Each object already has a column in my database, what is left is to add this dynamic feature to fill in my data for editing a post.
My code looks like this:
<!--- Query --->
<cfquery name="Posts" datasource="Postings">
Select *
from BlogPosts
</cfquery>
<!--- Fill Listbox --->
<cfselect name="LoopPosts" size="12">
<cfoutput query="Posts"><option value="#PostID#">
#PostTitle#</option></cfoutput>
</cfselect>
<!--- Secondary Query --->
<cfquery name="PostsQuery" datasource="Postings">
Select *
from BlogPosts
</cfquery>
<!--- Fill --->
<cftextarea style="width: 1000px; height: 600px;" name="PostBody" id="blog"><cfoutput query="Postquery">#PostBody#</cfoutput></cftextarea>
<input name="ActivePost" type="checkbox" value="<cfoutput query="Postquery">#Active#</cfoutput>">
Let me try to redeem myself with a modified answer:
You can dynamically reapply options to elements using ajax calls to your cfc file (since cfc bind is apparently a no-no) by adding an event listener to the first select field and calling the method in the cfc file via an AJAX get request. In the success function, you can then update the response to the textarea field.
Every time a selection is made from the select box, the text box will refresh the data with the appropriate query result.
The HTML page could look something like this:
<script type="text/javascript">
document.forms['yourformname'].elements['LoopPosts'].addEventListener('click', function(){
$.ajax({
type:"GET",
url: "yourcfcfilename.cfc?method=GetSelectedPost",
data: {selectedPost : this.value},
success: function(response) {
document.forms['yourformname'].elements['PostBody'].innerHTML = response;
},
error : function(XMLHttpRequest, textStatus, errorThrown) {
alert("Status: " + textStatus); alert("Error: " + errorThrown);
}
});
});
</script>
And the cfc page could look something like this:
<cfcomponent displayname="Post Functions" output="true">
<!--- Secondary Query --->
<cffunction name="GetSelectedPost" access="remote" returntype="String">
<cfargument name="selectedPost" type="string" required="true">
<cfquery name="PostsQuery" datasource="Postings">
SELECT PostBody
FROM BlogPosts
WHERE PostID = <cfqueryparam value="ARGUMENTS.selectedPost">
</cfquery>
<cfreturn PostsQuery.PostBody>
</cffunction>
</cfcomponent>
Every time a selection is made from the select box, the text box will refresh the data with the appropriate query result.

Can I use Coldfusions cffile action="upload" with an image destination url?

I need to loop over a list of pathnames and image names and verify that the file exists and is a jpg/png, before changing it's size and storing it to the server.
I want to use this:
<cffile result="upload" action="upload" accept="image/jpeg, image/png" destination="#tempDirectory#" nameconflict="overwrite" />
<cfset testFilePath = tempDirectory & upload.serverFile>
<cfimage name="tempFile" action="read" source="#testFilePath#" />
<cfif NOT isImageFile( testFilePath ) >
<cfset fileDelete( testFilePath ) />
<cfthrow type="FileNotFound" message="#tx_settings_icons_error_img#" />
<cfelseif NOT listfindnocase(allow, upload.serverfileext) >
<cfset fileDelete( testFilePath ) />
<cfthrow type="FileNotFound" message="#tx_settings_icons_error_file#" />
</cfif>
But my problem is, I don't know how to upload a file from a path like
http://www.some.com/folder/image.jpg
Question:
Can I just read the image, perform my validation and then store to disk or do I need to upload the image first. I will have to loop through a list of 500 images and am reading cffile action="read" shouldn't be used with large files. What would be an alternative to check image files for correct type, isImageand file extension?
I generally use cfhttp to read the image and verify that I have it, then convert to a valid cfimage object and do my manipulations then. You can see my process in the answer to this question.
Use cfimage to read the file from a URL. Set the source to be that URL. Then, you can write that to disk locally.
Code example:
<cfset imageData = ImageRead("http://tutorial28.learncf.com/img/bgHead.png") />
<cfimage action="write" source="#imageData#" destination="#expandPath('test.png')#" />

ColdFusion Component to Variable

I have a coldfusion component that is uneditable, only echos strings, and does not return a variable(and there is no return * statement). How can I grab this echoed string and place it in a variable before it is displayed directly on screen?
So :
<cfcomponent displayname="Helpz">
<cffunction name="OutputString" returnType="void" output="yes">
I love Stack overflow
</cffunction>
The outputted string needs to be stored into a variable.
CFSavecontent is what you need.
<cfsavecontent variable="myString"><cfset object.outputString() /></cfsavecontent>
Then you can do anything you want with #myString#.
<cfsavecontent variable="foo">
<cfset myComponent.outputString()>
</cfsavecontent>
It's probably a better practice to avoid that kind of output from within a function. An alternative solution would be:
<cfcomponent displayname="Helpz">
<cffunction name="getString" returnType="string" output="no">
<cfset var myString = "">
<cfsavecontent variable="myString">I love Stack overflow</cfsavecontent>
<cfreturn myString>
</cffunction>
</cfcomponent>
and then in you're template or wherever:
<cfoutput>#myCfc.getString()#</cfoutput>