Coldfusion validate list of emails - validation

I am trying to validate a list of emails that have been pulled from the database.
<cfquery name="AdminEmail" datasource="#blah#">
Select email from users where role = "admin"
<cfquery>
<cfset variable.mailto = #adminemail.Email#>
The query would return multiple emails which is fine for cfmail, but IsValid only validates a single variable. Any advice. This is needed to get to the security standards asked of me.

Loop through the query of your emails and then add them to a new variable if they're valid.
<cfset validEmails = []>
<cfloop query="adminemail">
<cfif isValid('email', adminemail.email)>
<cfset arrayAppend(validEmails, adminemail.email)>
</cfif>
</cfloop>
<cfset mailTo = arrayToList(validEmails)>
Note: I used an array to store the emails because appending to a list is a more costly process and an array will be slightly faster. Probably nothing you'll notice unless you have hundreds of emails but still a good practice.

Related

CFWheels - updateByKey() - The key argument contains an invalid value

<cfset result = model("user").updateByKey(
key=authUser.user_id
, encryption_key=local.encryptionKey
)>
The code above returns the following error in cfwheels:
The key argument contains an invalid value.
Suggested action
The key argument contains a list, however this table doesn't have a
composite key. A list of values is allowed for the key argument, but
this only applies in the case when the table contains a composite key.
Now I have resolved this by using the update all method like this:
<cfset recordsReturned = model("user").updateAll(
encryption_key=local.encryptionKey
, where="user_id=#authUser.user_id#"
)>
I've checked the database and cannot find duplicate primary keys. I've also tried setting the instantiated=false argument in the updateByKey method but that did not work either. Any explanation as to why this might happen would be appreciated.
ps: the closest thing i have to a primary key in the table apart from the user_id is the email_address which is unique so as not to allow duplicates.

Coldfusion and session variable not setting

I have a survey form with 5 ques, there is one question on each page and user clicks through them with next button on the page. Now, the user is not logged in, I want to set a session variable only when the user takes the first ques on form and clicks next. But I am getting userid not defined in session for the line 2. I am not really sure what I am doing wrong here. Can anyone suggest if they see what is going on. I don't want to be creating multiple userids every time he hits next button. Thanks
<cfif structKeyExists(FORM, "user_mode") and form.user_mode EQ "next">
<cfif NOT ( StructKeyExists(session,userid) )>
<cfquery name="insertuser" datasource="#application.datasource#">
INSERT INTO survey_user(ip_address)
VALUES (<cfqueryparam cfsqltype="cf_sql_varchar" value="#CGI.REMOTE_ADDR#" />)
</cfquery>
</cfif>
</cfif>
StructKeyExists(session,userid)
should be:
structKeyExists( session, 'userid' )
Note the quotes. Without them it's looking for the variable "userid" rather than the key name "userid".

Where to put queries (especially long ones) in a CFWheels project

(wheels novice here)
I'm trying to figure out the best place to put a number of large and/or complex queries that are used in the controllers function for the view.
I have a view calendar.cfm, and a controller with the function:
<cffunction name="calendar">
<cfset formData = getValidatedFormData()>
<cfset fromDate = formData.fromDate>
<cfset toDate = formData.toDate>
<cfset dbLocation = formData.dbLocation>
<cfset dateList = getDateList()>
<cfset selectLists = getSelectLists()>
<cfset companySelectList = selectLists.companySelectList>
<cfset activitySelectList = selectLists.activitySelectList>
<cfset instructorSelectList = selectLists.instructorSelectList>
<cfset statusSelectList = selectLists.statusSelectList>
<cfset courseNumberLists = getCourseNumberLists()>
<cfset girsCourseNumberList = courseNumberLists.girsCourseNumberList>
<cfset activityCourseNumberList = courseNumberLists.activityCourseNumberList>
<cfset activityCourseNumberList = courseNumberLists>
<cfset ELMActivityList = getELMActivityList()>
<cfset activityList = getActivityList()>
<cfif len(elmActivityList.LM_ACT_CD) gt 0>
<cfset elmActIDList = Replace(QuotedValueList(ELMActivityList.LM_ACT_CD, ","), "'',", "", "all")>
<cfelse>
<cfset elmActIDList = "'String1','String2'">
</cfif>
<cfif len(activityList.girs_act_cd) gt 0>
<cfset girsActIDList = Replace(QuotedValueList(activityList.GIRS_ACT_CD, ","), "'',", "", "all")>
<cfelse>
<cfset girsActIDList = "'String1','String2'">
</cfif>
<cfset combinedList = getCombinedList( elmActIDLIst , girsActIDList )>
<cfset needUnion = false>
<cfset programList = getProgramList()>
</cffunction>
Each of the functions, such as getDateList(), contains long and/or complex queries. The controller is already almost 700 lines long, and I've only implemented one of the 5 or 6 views in the project -- which will require additional queries.
I have the sense that I'm doing this wrong. I tried putting all the query functions in a cfc file in the models folder
<cfcomponent extends="Model">
functions...
but I can't figure out how to call them from the calendar function in the controller. I tried, for instance,
<cfset dateList= model("model_file_name").getDateList()>
but that isn't it.
Where should I put the queries and how should I call them?
EDIT
When I try to call the function in the model, I get "The data source could not be reached." However, I explicitly specify the datasource in the query. For example I have the following function in both the model and controller:
<cffunction name="getDateList" returntype="any">
<cfquery name="dateList" dataSource="ELM_Prod">
SELECT DATES FROM
(SELECT dateadd(dd,DAYS, <cfqueryparam cfsqltype="cf_sql_date" value="#fromDate#">) DATES
FROM
(SELECT TOP 365 colorder - 1 AS DAYS from master..syscolumns
WHERE id = -519536829 order by colorder) a
WHERE datediff(
dd,
dateadd(
dd, DAYS, <cfqueryparam cfsqltype="cf_sql_date" value="#fromDate#">
),
<cfqueryparam cfsqltype="cf_sql_date" value="#toDate#">
) >= 0
AND dateadd(
dd,
DAYS,
<cfqueryparam cfsqltype="cf_sql_date" value="#fromDate#">
) <= <cfqueryparam cfsqltype="cf_sql_date" value="#toDate#">
) a order by DATES
</cfquery>
<cfreturn dateList>
</cffunction>
When I call the function in the controller with <cfset dateList = getDateList()>, everything is fine, and I don't get the datasource error. However if I call it from the model with <cfset dateList = model("wheels_girs_model").getDateList()/>, I get the error. Because I am using more than one datasource, I'm not setting the datasources in the config file. I have set them both up in the admin panel and refer to them directly in the cfqeury. What would prevent the model from finding the datasource?
There are different ways to do this:
First of all, 700 lines per controller is not too long.
You can put all queries in the controller it self. You can create different functions for different queries (i guess you are doing this).
If you still think this is too long. You can group functions in different cfc's. Then you can create object of these cfc's using createObject to access methods or you can invoke cfc using cfinvoke to access your function.
Secondly, You can put your queries in the model file. You need to create a function in the your model cfc, then add your query in this function and you need to return the query or particular value, whatever you want using cfreturn.
You can call that function using the format
<cfset yourVariableName = model("yourModelName").yourCustomFunctionName(arguments if required) />
After adding a new function to your cfc, you need to reload application using your_site_url/?reload=true&password=password_you_set
Third, as Dan Bracuk suggested, you can use stored procedures and call stored procedures using cfstoredProc
Edit Answer to the problem i understood from comment
You should have put error in the question itself as this changes everything. This error has nothing to do with your code. This error means you haven't set the correct datasource or you haven't created datasource but you are using it or it means there is something wrong in your datasource configuration.
Do as the following:
Check whether you have defined correct datasource in the
config/settings.cfm.
If not, please define it. You can define the datasource by <cfset
set(dataSourceName="your_desired_datasource_name.") />
If yes, then go to your cfadministrator control and datasource tab.
Check whether that datasource exists or not.
If not, create datasource. If yes, check whether it is correctly
configured or not, also check for spelling differnece between the
datasource name from cfadministrator and the one defined in the
config/settings.cfm.
Your problem should go if you do one of the above. Remember, whatever you do, you have to reload application using yourappurl/?reload=1&password=password_you_set
Second Edit:
Your question still doesn't give us clear info like How do you set datasource in admin panel and then how do you access in the query? This should have been different question as this question is totally different from the original question. Anyway, You should always use default datasource (the one defined in the config/settings.cfm). You can override this datasource in the model cfc. You can override default datasource for particular model by <cfset dataSource("your datasource name for that particular table")>. Please check the link for more info. And if you have more queries, you should as separate question (you will probably get more responses).

Adding a 'fake' field to grocerycrud add/edit form

On my users table I have a 128 char 'hashed_password' field. In my User_model I have functions to encrypt and decrypt the password. When encrypting I randomly generate a salt and it gets stored in the first 64 chars of hashed_password field. The hashed pw result gets stored in the last 64 chars. When decrypting I do the reverse.
As I guess is almost universal, there is never a plaintext password to display.
So, when my users (through grocery_CRUD) are adding/editing a user I thought it was possible to include fake fields: "password" and "passconf" to the add & edit forms with the following:
$crud->fields('username', ... <other fields> ... 'password', 'passconf');
Just to be crystal clear - the "password" and "passconf" fields DO NOT exist on my users table. I just want my users to input the new password there then deal with it in my own way.
But it doesn't work. By that I mean the add/edit form renders with the two fake fields correctly (validation below works correctly) but if I try to update any other user information then 'Update Changes', that action fails with "Loading" graphic spinning briefly but not updating the database.
I have tried replicating this on a VERY simply grocery_CRUD form with no other complexity and get the same behaviour: the form renders correctly but will not update the db.
Is it even possible to use fake fields? Am I missing something?
Is grocery_CRUD trying to do something with these fields behind the scenes that is causing the db update to fail?
I had then hoped to do the following:
$crud->set_rules('password', 'Password', 'callback_valid_password');
$crud->set_rules('passconf', 'Password Confirmation', 'matches[password]');
$crud->callback_before_insert(array($this,'encrypt_password_callback'));
$crud->callback_before_update(array($this,'encrypt_password_callback'));
function encrypt_password_callback($post_array, $primary_key = null){
if ($post_array['password'] <> '') {
$this->User_model->set_password($post_array['username'], $post_array['password']);
}
}
function valid_password($str) {
//do some pw validation
return TRUE;
}
I have solved this problem using insert and update callbacks then encrypting the password then unset(ing) the offending 'password' & 'passconf' fields before the insert or update db call.

Access TreeMap entries by string key in JSTL

This is pretty similar to some other questions, but nobody else is working with string keys. So here we go.
I've got a TreeMap with a set of category names, keyed by category ID. The ID is a number (as a String).
I build up the TreeMap with values, then expose it to the page, like so:
<%
Map categories = new TreeMap();
...
String categoryId = ...;
String categoryName = ...;
categories.put(categoryId, categoryName);
...
pageContext.setAttribute("categories", categories);
%>
Later, I iterate through a series of items which have been assigned to categories. Each item has a .categories collection which contains the IDs of the categories to which it has been assigned. I want to display the names, so I do something like this:
<c:forEach items="${item.categories}" var="catId">
${categories[“${catId}”}
</c:forEach>
Unfortunately, this doesn't emit anything. Nor does ${categories["${catId}"].value}.
However, this does:
${categories["2"]}
Of course, that line isn't actually driven by item data.
I've checked, and the IDs attached to each item do in fact correspond to category IDs; this isn't a data mismatch problem.
So, how do I get my hands on category names when the data attached to items has only IDs?
P.S. I should mention that I'm not a Java programmer -- at all. LAMP is more my style. So modifying classes isn't really an option.
EDIT: Sorry, I misread the question.
Unwrap your catId variable:
${categories[“${catId}”}
should be
${categories[catId]}
That should fix it.

Resources