How to check if user is logged in? - coldfusion

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.

Related

Confusion on when to use cfoutput in cfmail

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

How to run a cfquery within the onRequestStart() function?

I want to run a query on every page that a user requests. This query is needed to get back preferences set by the user's organisation for the application. This is what I have tried:
<cffunction name="onRequestStart" access="public" returntype="boolean">
<cfargument type="String" name="TargetPage" required="true"/>
<cfquery name="rsSettings">
SELECT *
FROM
dbo.Settings
</cfquery>
<cfreturn true>
</cffunction>
</component>
However each pages that looks for the rsSettings recordset says that its not defined. If I put the same query within each page that needs it then it works fine.
Does onRequestStart() not handle cfquery?
<cfquery name="request.rsSettings">
SELECT *
FROM
dbo.Settings
</cfquery>
Then in the page use:
request.rsSettings.columName

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.

Coldfusion 8 doing both CFIf and the CFElse statement

I am making a user signup app for an ecomerce site, but I have run into a very odd problem. When I run this code:
<cfif isValid("email", form.email)>
<cfquery name="check_user" datasource="#request.dsn#">
SELECT var_username, var_password
FROM tbl_users
WHERE var_username = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#FORM.EMAIL#">
AND var_password = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#FORM.PASSWORD#">
</cfquery>
<cfif check_user.recordcount LT 1>
<cfquery datasource="#request.dsn#" name="insertuser">
INSERT INTO tbl_users (var_username, var_password)
VALUES
(<cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#FORM.EMAIL#">,
<cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#FORM.PASSWORD#">)
</cfquery>
<cflogin idletimeout="1800">
<cfloginuser
name = "#FORM.email#"
password ="#FORM.password#"
roles = "0">
</cflogin>
<cflocation addtoken="No" url="#request.secure_url#checkout.cfm">
<cfelse>
<cfset client.error_message = "Your Email Address is already registered.">
<cflocation addtoken="No" url="#request.site_url#New-Account.html">
</cfif>
<cfelse>
<cfset client.error_message = "Your Email Address is not Valid.">
<cflocation addtoken="No" url="#request.site_url#New-Account.html">
</cfif>
What this code is supposed to do, is check to see if the email is already in the database, if its not, it then adds the email/password into the database then logs them in and moves them to the secure checkout site.
What the code is actually doing, is quite different though. It is checking to see if they are in the database, and then adding them, however, after it adds them to the database it skips the login and the cflocation and goes to the cfelse, going back to the original page "New-Account" and displaying the client.error_message.
How is it possible for the code to run the cfif check_user.recordcount and then part way through it skip to the cfelse?
Things I have done to try and narrow down whats happening-
It is getting pass the check_user statement and adding a user, because I have direct access to the database and after trying to signup a user, I delete it and try again (and notice that when I try to create it, it does create it), so I know its getting past the insertuser cfquery. I have changed the cflocation to redirect to google, but it doesnt, and I also have it show on the page whether or not I am logged in, so I know that it is skipping to the cfelse before the cflogin.
I would suggest commenting out all of your cflocations temporarily and seeing if your behaviour is the same. It could be that your login process doesn't finish before your cflocation starts.
Or, it could be that your page submits to itself correctly the first time, and then the second time hits the else clause.
There is nothing in your code that is obviously wrong to me.

CFGRID, CFGRIDUPDATE and extra values

I'm using CFGRID and CFGRIDUPDATE to insert values into a database. The problem is, each record needs to get an additional field that isn't in the grid. Is there any way to save that additional field to the record, or do I have to whip up an alternative to CFGRID?
Basically, I have a bunch of users I'm entering into a grid. The page is getting a category id. I want all of the users to be saved with that category id.
Another thing that would work is if I could get a list of all primary keys, including those for the just-created records, and update all of them with the category id. But it looks like CFGRIDUPDATE doesn't return any information about the rows that were created.
-- original answer removed --
Based on your comment to my original answer, there is now an implied assumption that Category_ID is a foreign key, possibly on a join table, that cannot (for whatever reason) be included in the initial display query--or, that you simply wish to include a dynamic variable into the grid which will be included during inline inserts, without the user intervening (ie. physically preventing them from selecting the Category_ID themselves, but that it will still be dynamic in some capacity, say...by being fed from a URL var).
If correct, I believe the true question leans closer to:
Can a CFGRID update multiple tables/dynamic columns via CFGRIDUPDATE?
Short answer: No
Long answer: Yes, but not via CFGRIDUPDATE--rather, via CFQUERY and a little more work on the CFGRID, via CFC binds and the CFAJAXPROXY.
Solution:
1) You'll need two files for this solution. File #1 is your Component which wraps the query functionality; we'll call it cfgrid.cfc
<cfcomponent>
<cfset this.dsn = "gridexample" />
<cffunction name="getUsers" returntype="any" access="remote" output="false">
<cfargument name="page" />
<cfargument name="pageSize" />
<cfargument name="gridsortcolumn" />
<cfargument name="gridsortdirection" />
<cfset var getUsers = 0 />
<cfquery name="getUsers" datasource="#this.dsn#">
SELECT Users.UserID, Users.FirstName, UserCategories.Category_ID
FROM Users
INNER JOIN UserCategories ON (Users.User_ID = UserCategories.UserID)
<cfif arguments.gridsortcolumn neq "" or arguments.gridsortdirection neq "">
order by #arguments.gridsortcolumn# #arguments.gridsortdirection#
</cfif>
</cfquery>
<cfreturn QueryConvertForGrid(getUsers, page, pageSize) />
</cffunction>
<cffunction name="addNewUser" returntype="string" access="remote" output="false">
<cfargument name="fullname" type="string" required="true" />
<cfargument name="category_id" type="numeric" required="true" />
<cfquery datasource="#this.dsn#">
INSERT INTO Users
(
fullname
)
VALUES
(
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.fullname#">
)
</cfquery>
<cfquery name="getPkey" datasource="#this.dsn#">
SELECT Max(User_ID) as PKey
FROM Users
</cfquery>
<cfquery datasource="#this.dsn#">
INSERT INTO UserCategories
(
User_ID,
Category_ID
)
VALUES
(
<cfqueryparam cfsqltype="cf_sql_integer" value="#getPKey.PKey#" />
<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.category_id#" />
)
</cfquery>
<cfreturn "User Added" />
</cffunction>
<cffunction name="editUser" access="remote">
<cfargument name="gridaction">
<cfargument name="gridrow">
<cfargument name="gridchanged">
</cffunction>
</cfcomponent>
Pay attention to these key pieces of the CFC:
a) getUsers() returns the current user data along with their CategoryID. You'll have to re-write this query to match your schema, but the key takeaway is that this is a data population query, so all the data that's necessary for creating a user should also be present for updating the user as well. This also assumes you only have 1 CategoryID per User (which many developers de-normalize by leaving the CategoryID on the Users table--I'll leave that to your discretion).
b) addNewUser() takes expects the form/grid submission to pass along the new name--as well as the category_id--but we know ahead of time we're not going to be asking that the Category_ID be filled out by the person entering the form/grid data--we'll do that programmatically. The end result is still the same, however--the query is going to need to know both values. For brevity, I've left off <CFTRANSACTION> calls, but bear it in mind--you're about to execute three queries in succession, one of which (the 3rd) depends on dynamic data from the other (the 1st and 2nd)--so you'll need to keep concurrency in mind when you move forward with this type of design.
c) Disregard editUser() for now--you will need to populate it at some point--it simply needs to exist for this demonstration to work.
2) The second file you'll need is the front end--the grid itself, we'll call it cfgrid.cfm.
We'll go through this one, top to bottom, as its quite large, and each chunk of code will need explanation:
<cfparam name="URL.Category_ID" default=4 />
The first line of the template parameterizes a URL variable, which we want to use to programmatically provide behind-the-scenes assignment to new users. Use your own mechanism to supply a dynamic Category_ID as needed.
<cfajaxproxy cfc="cfgrid" jsclassname="dataproxy">
This line causes ColdFusion to create a javascript object named 'dataproxy' and wrap it in a container necessary to provide access the core functions that exist in the CFC you point it to...and in this case, you are pointing it to 'cfgrid', which is our first file mentioned above (cfgrid.cfc). Therefore, you can now comfortably expect that you have a javascript object with getUsers() and addNewUser() methods.
<html>
<head>
<script type="text/javascript" src="/CFIDE/scripts/ajax/ext/package/toolbar/toolbar.js"></script>
Here, you begin your HTML document tags, and include a reference to one of the Ajax libraries included in ColdFusion, the toolbar.js file.
<script type="text/javascript">
var dataproxy = new dataproxy();
dataproxy.setCallbackHandler(handleResult);
function handleResult(response)
{
alert(response);
}
Here, you create a local instance of the dataproxy object (remember above, from the <CFAJAXPROXY> call) and assign a callback handler, which points to another javascript function 'handleResult'. This is the process you employ when dealing with asynchronous communication--a fundamental part of working in Ajax.
function init()
{
grid = ColdFusion.Grid.getGridObject("UserGrid");
var gridHead = grid.getView().getHeaderPanel(true);
var tbar = new Ext.Toolbar(gridHead);
tbar.addButton({text:"Add User", handler:onAdd });
}
This init() function creates the javascript objects necessary to drive communication to the cfgrid. You obtain a reference to the cfgrid via ColdFusion.Grid.getGridObject, and from there, access the grid's header, which allows you to target to toolbar, and add a button "Add User", which you then programmatically decide to call a new function when it is clicked...that function is named "onAdd"...
function onAdd(button,event)
{
ColdFusion.Window.show('addUserWin');
}
Unsurprisingly, here is that onAdd() function, which displays a new window to add a user (its the window that contains the input field for the user's fullname).
Finally, the new AddUserWin Window above is going to need its own function to add a user, since we will need to provide the Category_ID dynamically--as opposed to letting the user supply it. So, addUser() will do just that:
function addUser()
{
var f = document.frmUser;
dataproxy.addNewUser(
f.txtFullname.value,
f.txtCategory_ID.value
);
ColdFusion.Window.hide('addUserWin');
grid.refresh();
}
</script>
</head>
In addUser(), we refer to the <FORM> below by its name (frmUser), and call our javascript proxy object's addNewUser() method--which maps to the CFC. As expected, it'll need to know the values of the new user, so we'll pass it the value of txtFullname and txtCategory_ID. We finish by hiding the window and refreshing the grid.
Remember, we're asynchronous now, so we don't need to read a result and display it--that result will fire via the callback handler assigned above in the handleResult() method.
Now, build the arguments that will feed the population of the CFGRID:
<cfset args = StructNew() />
<cfset args.name = "UserGrid" />
<cfset args.format = "html" />
<cfset args.bindOnLoad = "true" />
<cfset args.bind = "cfc:cfgrid.getUsers({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection})" />
<cfset args.selectmode = "edit" />
<cfset args.onchange = "cfc:cfgrid.editUser({cfgridaction},{cfgridrow},{cfgridchanged})" />
Here we:
1. Name the grid "UserGrid" (as we have referred to it by that name in javascript above),
2. Make it render using html,
3. Tell it to bind its data when the page loads,
4. Bind that data via the cfgrid.cfc, calling the getUsers() method (and passing in the current parameters of the cfgrid via its page, pagesize, sortcolumn, and sortdirection values),
5. Make it editable, and
6. Assign an onChange handler, in case we also want to allow the users to be edited. This last part (unfortunately) is necessary, so I was unable to strip it out for this example.
Now, build the <CFFORM> and <CFGRID>:
<cfform>
<cfgrid attributeCollection="#args#">
<cfgridcolumn name="User_ID" display="false">
<cfgridcolumn name="Category_ID" display="false">
<cfgridcolumn name="FullName" header="Full Name">
</cfgrid>
</cfform>
Here, we populate the grid with our arguments specified above, and you'll note we display only the "FullName" field on the grid, yet User_ID and Category_ID are still present, and a part of the dataset; they simply aren't displayed to the front-end.
Last but not least, the window that will pop-up when a user clicks the "Add New User" button, which provides the interface we need to allow user entry, while at the same time, control (behind the scenes) what Category_ID is dynamically supplied:
<cfwindow name="addUserWin" modal="true" resizable="false" title="Add New User">
<form name="frmUser">
<input type="hidden" name="txtCategory_ID" value="<cfoutput>#URL.Category_ID#</cfoutput>" />
<table width="100%">
<tr>
<td>Fullname</td>
<td><input type="text" name="txtFullname" value=""></td>
</tr>
<tr>
<td colspan="2"><input type="button" value="Add User" onclick="javascript:addUser();"></td>
</tr>
</form>
</cfwindow>
This call to CFWINDOW provides the necessary "pop-up" to encapsulate the form. Note that the form name is frmUser, as we have referred to it above in code. Also, note that the name of the fields match (including their case) what are referred to in javascript. This form displays the Fullname field to the user to fill out, while the Category_ID stays hidden, but is still programmatically driven by you--via your URL parameter at the top of this code example. Finally, the button, when clicked, fires the addUser() method, which you'll recall is the one that talks to the javascript object--which in turn--talks to the CFC--and commits your data to the database.
Finally, just before you complete this template, don't forget to fire your init() javascript function!
<cfset ajaxOnLoad("init")>
</html>
Hope this helps.
Adapted from CRUD with cfgrid html format (Source: Anuj Gakhar)
There is another way. It involves handling directly the form variables which are posted by CFGRID. Here's some example code:
form.cfm:
<cfform method="post" action="post.cfm">
<cfoutput><input type="hidden" name="ParentID" value="#ParentID#"></cfoutput>
<cfgrid format="html" name="GridData" query="Records" insert="yes" delete="yes" selectmode="edit">
<cfgridcolumn name="RecordID" display="no">
<cfgridcolumn name="RecordName" width="150" header="Name" headeralign="left" dataalign="left" select="Yes" display="Yes">
<cfgridcolumn name="RecordColor" width="150" header="Color" headeralign="left" dataalign="left" select="Yes" display="Yes">
</cfgrid>
<br />
<input type="submit" value="Save Records" />
</cfoutput>
</cfform>
then in post.cfm
<cfif isDefined("GridData.RowStatus.Action") and isArray(GridData.RowStatus.Action)>
<cfloop from="1" to="#ArrayLen(GridData.RowStatus.Action)#" index="i">
<cfswitch expression="#GridData.RowStatus.Action[i]#">
<cfcase value="I">
<cfquery name="Records_INSERT" datasource="#request.maindatasource#" blockfactor="100">
INSERT INTO Records (RecordName, RecordColor, RecordParent)
VALUES (
<cfqueryparam cfsqltype="cf_sql_varchar" value="#Trim(GridData.RecordName[i])#">,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#Trim(GridData.RecordColor[i])#">,
<cfqueryparam cfsqltype="cf_sql_integer" value="#Val(ParentID)#">
)
</cfquery>
</cfcase>
<cfcase value="U">
<cfquery name="Records_UPDATE" datasource="#request.maindatasource#" blockfactor="100">
UPDATE Records
SET
RecordName = <cfqueryparam cfsqltype="cf_sql_varchar" value="#Trim(GridData.RecordName[i])#">,
RecordColor = <cfqueryparam cfsqltype="cf_sql_varchar" value="#Trim(GridData.RecordColor[i])#">
WHERE
RecordID=<cfqueryparam cfsqltype="cf_sql_integer" value="#GridData.original.RecordID[i]#">
</cfquery>
</cfcase>
<cfcase value="D">
<cfquery name="Records_DELETE" datasource="#request.maindatasource#" blockfactor="100">
DELETE
FROM Records
WHERE
RecordID=<cfqueryparam cfsqltype="cf_sql_integer" value="#GridData.original.RecordID[i]#">
</cfquery>
</cfcase>
</cfswitch>
</cfloop>
</cfif>