Confusion on when to use cfoutput in cfmail - coldfusion

I am not 100% on when to use cfoutput and how cfoutput can be used in the following example. Should the whole cfmail be wrapped in a cfoutput?
Background: I have a function that sends an email based on an if statement. The message of the email has variables that come from a cfquery.
<cffunction name="emailUpdate" access="public" returntype="string">
<cfargument name="usr_email" required="yes">
<cfargument name="status_update" required="yes">
<cfargument name="form_id" required="yes">
<cfquery name="emailformData" datasource="RC">
SELECT *
FROM Basic_Info
WHERE ID = <cfqueryparam value="#ARGUMENTS.form_id#">
</cfquery>
<cfoutput query="emailformData">
<cfmail
from="forms#email.us"
to="#usr_email#"
subject="Status Update">
<cfif status_update EQ 'Submitted'>
Form Submitted: The following quote request ID: #emailformData.ID# has been submitted on
#emailformData.Submission_Date# for the following party #emailformData.Sold_to_Party#. You will receive automated
updates via email when your submission changes status. <b>- Admin Team</b>
<cfelseif status_update EQ 'Assigned'>
Form Assigned by Admin Request ID: #emailformData.ID# for the following party #emailformData.Sold_to_Party# was
assigned to Admin ID #emailformData.Admin_ID# on #DateFormat(Now())#, #TimeFormat(Now())#.
Below is their direct contact information for any change requests or status updates. <b>- Admin Team</b>
<cfelseif status_update EQ 'Returned'>
Returned by Admin Form ID: #emailformData.ID# for the following party #emailformData.Sold_to_Party# was
returned by Admin ID #emailformData.Admin_ID# on #DateFormat(Now())#, #TimeFormat(Now())#
for the following reasons. Admin Notes: #emailformData.Admin_Notes#.
<b>- Admin Team</b>
<cfelseif status_update EQ 'Completed'>
Form Completed Form ID: #emailformData.ID# for the following party #emailformData.Sold_to_Party# has been
marked as COMPLETED on #DateFormat(Now())#, #TimeFormat(Now())#. The following Quote Number has been
assigned to this form #emailformData.Quote_Num#. The quote will be emailed to you. If the Admin added any closing notes to the form they will appear below:
#emailformData.Admin_Notes#
<b>- RFQ Admin Team</b>
</cfif>
</cfmail>
</cfoutput>
</cffunction>

You don't need it, unless perhaps you're doing looped output of a cfquery. e.g. if your emailformData query returned multiple rows (and it obviously doesn't), you might do:
<cfmail ...>
Here's the email data #form.name# asked for:
<cfoutput query="emailformData">
#emailformData.Sold_to_Party#
</cfoutput>
Sent on #dateFormat(now())#
</cfmail>
See Sample uses of the cfmail tag on the Adobe site, and this discussion on Ray Camden's site

Related

How to check if user is logged in?

I want to implement lock feature in my app. Once a user selects the Customer in my App, that record should not be available to other users. I have created Lock table that contains User ID and Record ID. So in situation when someone else tries to select the same record I will check the Lock table. If a Record ID exists, in the Lock table, I should check if the user is still logged in. I'm wondering if there is a way to check that in ColdFusion 9?
Here is example of my session variable and function that should update Lock table:
userdata
APPFNAME John
APPJOBTITLE Manager
APPLNAME Miller
APPUSERID G890H32
APPUSER jmiller
<cffunction name="onSessionEnd" returnType="void" output="true">
<cfargument name="SessionScope" type="struct" required="true">
<cfargument name="AppScope" type="struct" required="true">
<cfif StructKeyExists(session,"userdata")>
<cfset currentDate = DateFormat(Now(),'mm/dd/yyyy')>
<cfset currentTime = TimeFormat(Now(),'hh:mm tt')>
<cfquery name="updateLock" datasource="Test">
UPDATE Locked
SET l_active = '0',
l_udt = <cfqueryparam value="#currentDate#" cfsqltype="cf_sql_date" maxlength="10" />,
l_utime = <cfqueryparam value="#currentTime#" cfsqltype="cf_sql_char" maxlength="8" />
WHERE l_userID = <cfqueryparam value="#trim(request.userdata.APPUSERID)#" cfsqltype="cf_sql_char" maxlength="10" />
</cfquery>
</cfif>
</cffunction>
The system that I'm working on doesn't have any temporary table that stores currently logged in users. What would be the other option to check if user is logged in? I saw few posts that are related to cflogin but none of them explained this specific scenario. If anyone can help please let me know.
I suggest adding a query to the onSessionEnd() method of your Application.cfc that updates the lock table to indicate that the user is no longer logged in. Whether this update deletes records or updates a field is up to you.

Assign one error log file per application

We have multiple applications running on the same server and default log files end up being a mess of everything, especially the Exception log for which the admin panel does not offer search capacities.
Is it at all possible to have Coldfusion log things pertaining to a given application (as defined by Application.cfm or .cfc) to a separate log?
If not, any alternative solutions to this issue?
I'd recommend application.cfc onError method to log uncaught errors in separate log file. Also this doc could be helpful: Handling errors in Application.cfc
Here's a basic example of using the onError function in application.cfc to log errors to an application-specific log file.
<cfcomponent output="false">
<cfset this.name = "myApp">
<cffunction name="onError">
<cfargument name="exception" required="true">
<cfargument name="eventName" type="string" required="true">
<cfset var myAppName = this.name>
<cfset var details = "">
<!--- You need to specify and check for the exception details you want to include in your log text --->
<cfif IsDefined( "exception.type" )>
<cfset details = "Type: #exception.type#. ">
</cfif>
<cfif IsDefined( "exception.message" )>
<cfset details = details & "Details: #exception.message#">
</cfif>
<cflog type="error" file="#myAppName#" text="#details#">
<!--- Specify how you want the error to be handled once it's been logged --->
<cfdump var="#exception#">
</cffunction>
</cfcomponent>
You need to specify which parts of the exception details you want to include in your log entry, bearing in mind that the keys of the exception struct will vary according to the type of error thrown. It's therefore best to check for their existence before adding them to the log text.
Official onError docs for ColdFusion MX7 (since your question's tagged with that version - which is also why I've used tags rather than cfscript in my example to be on the safe side).

ColdFusion cfautosuggestvalue content is blank, even though a good array is returned from the cfc

I'm working with ColdFusion Server version 8,0,0,176276.
I'm trying to add an autosuggested form field, with asynchronous population through a cfc. I'm using http://www.forta.com/blog/index.cfm/2007/5/31/coldfusion-ajax-tutorial-1-autosuggest for inspiration and syntax.
The autosuggest field works fine if I use a static query (as in Forta's first example). The cfc is successfully returning an array when not used in the form field.
But when I use the cfc for autosuggest, there are no suggestions provided.
I can't see the contents of the input field with "view source," but if I do "inspect element" on the field in Chrome, I can see a div with class="yui-ac-bd" and a ul under it. The list items in the ul are empty when using the cfc, whereas when I use a static query, the list items contain the array members.
Here's the code on my page:
<cfform>
<cfinput type="text" name="JobP"
autosuggest="cfc:autosuggest.AutoSuggest({cfautosuggestvalue})">
</cfform>
And here's autosuggest.cfc:
<cfcomponent output="false" >
<cffunction name="AutoSuggest" access="remote" returntype="array">
<cfargument name="ObjectType" required="false" default="JOBP">
<cfset var result=ArrayNew(1)>
<cfquery name="Objects" datasource="UC4MP">
SELECT oh_name
FROM uc4.oh
WHERE oh_otype = '#ObjectType#'
AND oh_deleteflag = 0
AND oh_lastdate > sysdate - 90
AND oh_client = 1000
and oh_name like 'A%'
ORDER BY oh_name
</cfquery>
<cfloop query="Objects">
<cfset ArrayAppend(result,oh_name)>
</cfloop>
<cfreturn result>
If I put the following code on my page, it outputs the array with the desired contents:
<cfinvoke component="autosuggest" method="AutoSuggest" returnVariable="result">
cfdump var="#result#">
I don't use jQuery yet; most of my Google results for CF autosuggest have involved jQuery and I haven't been able to wade through them for relevance to my problem. Just in case that was going to be your suggestion.
Thank you all for your advice! I had not known there was a separate ajax debugger, the output of which immediately made the problem clear:
info:http: Invoking CFC: /rd/autosuggest.cfc , function: AutoSuggest ,
arguments: {"ObjectType":"A"}
My cfc arguments didn't include the autosuggest itself, so the string passed to the input field was being interpreted as "ObjectType" (the first argument) and used in the query. Since there are no records where oh_otype = 'A', the result was always empty.
I updated my cfc's arguments to
<cfargument name="ObjectType" required="yes" default="JOBP">
<cfargument name="autosuggest" required="yes">
and the invocation to
<cfinput type="text" name="JobP"
autosuggest="cfc:autosuggest.AutoSuggest('JOBP',{cfautosuggestvalue})">
...works perfectly now.
If i remember correctly when I did this some years ago, I had to create a virtual directory in Apacahe and set permisions using the following directives. You can apply the same to IIS if you are working in that environment. That should get it going for you.
Alias /CFIDE "/opt/coldfusion9/wwwroot/CFIDE"
<Directory "/opt/coldfusion9/wwwroot/CFIDE">
allow from all
Options FollowSymLinks
Since then I have been using the typehead javascript from bootstrap 2. Much cleaner and easier to style. You can still use your cfc to call the data and I am including the code to clean it up for typehead.
<cfinvoke component="autosuggest" method="AutoSuggest" returnVariable="result">
<cfset mylist = ArrayToList(result, ",")>
<cfset mylist=ValueList(ShowKey.keyword)>
<cfset mylist = jSStringFormat(#mylist#)>
<input name="keyword" id="keyword" type="text" data-provide="typeahead" data-items="10" data-source='["<cfoutput>#replace(mylist,',','","','ALL')#</cfoutput>"]'/>

Using Onclick on an HREF tag in Coldfusion

I was wondering if someone can tell me what is wrong with this code because it doesn't work and it does not give me any errors either.
With this code I am trying to access a component that updates a DB table each time someone press on the link.
<cfajaxproxy bind="url:http://www.example.com/admin/CRM/linktracking.cfc" />
<cfscript>
SSLtype = (CGI.HTTPS EQ 'off')?'http://':'https://';
</cfscript>
<cfset domainname = CGI.SERVER_NAME>
<cfset domainURL = SSLtype&CGI.SERVER_NAME&CGI.SCRIPT_NAME&'?'&CGI.QUERY_STRING>
<script>
function insertTracking(href) {
var instance = new ajaxjsclass();
instance.setCallbackHandler();
<cfoutput>
instance.insertTrack(href,'#surveymain.contactid#','#domainname#','#domainURL#');
</cfoutput>
}
</script>
This is the component I am trying to access.
<cfcomponent>
<cffunction name="insertTrack" access="remote" returntype="void" >
<cfargument name="clickedURL" required="yes">
<cfargument name="contactid" required="yes">
<cfargument name="domainName" required="yes">
<cfargument name="domainURL" required="yes">
<cfquery name="q_inserttrack" datasource="dpsigweb">
update survey_tracking
set surveystarted = <cfqueryparam value="#now()#" cfsqltype="CF_SQL_TIMESTAMP">
where contactid= '#contactid#'
</cfquery>
<cfif ARGUMENTS.contactid NEQ ''>
<cfscript>
additionalInfo = '<b>Clicked URL</b> - <i>#ARGUMENTS.clickedURL#</i><br><br><b>From Site</b> - <i>#ARGUMENTS.domainURL#</i>';
gaCFC = CreateObject("component","mod_sigweb.components.guestaccount");
gaCFC.AddCorrespondenceCurDoctorProcedureRemote(
functionPassword = 'password',
contactid = '#ARGUMENTS.contactid#',
theMessage = additionalInfo,
statustype = 'Survey Started',
contactresult ='Survey Started'
);
</cfscript>
</cfif>
</cffunction>
</cfcomponent>
This is where I am trying to access the function from:
<a href="http://dev.example.com/surveys/survey.cfm?id=#id#&contactid=#contactid#&doctorid=#doctorid#" onClick="insertTracking(this.href)" >
I am suspecting that my <cfajaxproxy> tag may have a syntax error but when I am pressing the link I am not getting any errors.
I change my cfajaxproxy to this
<cfajaxproxy cfc="linktracking" jsclassname="ajaxjsclass" />
but still the function does not seem to work. I even moved the component and the cfm file in the same folder but it still doesn't work.
Edit:
I forgot to mention that i am sending this code in an email template. i don't know if that matters in any way. I created a test page that I am testing locally and my code works just fine. If there is something that I need to change because of that please let me know
Solution Found. I put the update query code directly on the page so when the user presses on the link and opens the page the query runs from there instead from the link.
The above code is working fine I just had issues with it because I was sending the page via email to the user. At least this is what I suspect.

Is there a way to (per request) set a non-persistent Database Bean in Coldbox

I am looking to migrate from a custom framework to Coldbox.
The application has 3 datasources
Core
Common
Site
The Core datasource stores information about the sites, the common datasource stores shared information, like the states table, and the Site datasource stores the data relevant to the website.
The Site datasource is changed per request based on the URL of the request, allowing each site to be sandboxed into its own database.
From my testing it seems that the DatasourceBeans generated by Coldbox and used in it's autowiring are stored/cached in the application scope. This is what I'm thinking to do, but the change to the datasource is persisted across requests.
In Coldbox.cfc
datasources = {
Core = {name="DSNCore", dbType="mssql", username="", password=""},
Common = {name="DSNCommon", dbType="mssql", username="", password=""},
Site = {name="", dbType="mssql", username="", password=""}
};
and
interceptors = [{
class="interceptors.Website",
properties={}
}];
Interceptor named Website.cfc
<cfcomponent name="Website" output="false" autowire="true">
<cfproperty name="dsncore" inject="coldbox:datasource:Core">
<cfproperty name="dsn" inject="coldbox:datasource:Site">
<cffunction name="Configure" access="public" returntype="void" output="false" >
</cffunction>
<cffunction name="preProcess" access="public" returntype="void" output="false" >
<cfargument name="event" required="true" type="coldbox.system.web.context.RequestContext">
<cfargument name="interceptData" required="true" type="struct">
<cfset var q="" />
<cfdump var="#dsn.getMemento()#" label="DSN before change" />
<cfquery name="q" datasource="#dsncore.getName()#">
SELECT
Datasource
FROM
Websites
WHERE
Domain = <cfqueryparam cfsqltype="cf_sql_idstamp" value="#cgi.http_host#" />
</cfquery>
<cfscript>
dsn.setName(q.Datasource);
</cfscript>
<cfdump var="#dsn.getMemento()#" label="DSN after change" />
<cfdump var="#q#" label="Results of query" /><cfabort />
</cffunction>
</cfcomponent>
Is there any way to do this in a way that I can use the Coldbox autowire datasource beans?
Honestly, this is just the way I thought I would do it, if anyone has any other ideas on how to get my model to use NON-hardcoded different datasource per request, I would love to understand the framework better.
This question also extends to ORMs. Is there a way for, say, Transfer to use a different datasource per request? What if the databases can have potentially different schemas? Lets say that one database has been updated to a newer version, but another still uses an older version and I essentially have some if statements in the code to provide enhanced functionality to the updated database.
You may be reading these questions and thinking to yourself "You shouldn't do that." Well i am, so please no answers saying not to do it. If you have ideas on better ways to have single codebase attached to different databases then I'm all ears though.
Another way you could do it is by using the requestStartHandler in Coldbox.cfc
<!---config/Coldbox.cfc--->
requestStartHandler = "Main.onRequestStart"
<!---handlers/Main.cfc--->
<cffunction name="onRequestStart" returntype="void" output="false">
<cfargument name="event" required="true">
<cfquery name="q" datasource="#dsncore.getName()#">
SELECT
Datasource
FROM
Websites
WHERE
Domain = <cfqueryparam cfsqltype="cf_sql_idstamp" value="#cgi.http_host#" />
</cfquery>
<cfset rc.dataSource = q.Datasource />
</cffunction>
Then you just have your dataSource stored in the Request Collection becuase onRequestStart will fire on every Request.