I'm trying to run a very quick update query to record that a user's email address is confirmed (setting the confirmed [bit] column in my users table to 1 after they click a link sent via email). Here's the action that should do it:
<cffunction name="confirmEmail">
<cfscript>
user = model("user").findOne(where="id=#params.userid# AND uuid='#params.uuid#'", returnAs="query");
if(user.recordCount) {
pageTitle = "E-mail Confirmation Success";
user.update(confirmed=1);
} else {
redirectTo(route="authenticationDenied", alert="Something was wrong with your confirmation string. Please contact site administrators.");
}
</cfscript>
</cffunction>
But when I submit the appropriate URL (I've dumped and can see the model call finds one valid record), I get the following error in Railo 3.3.x:
No matching Method/Function [update] for call with named arguments found
...highlighting the user.update(confirmed=1); line in my code. So what am I doing wrong? Previously I have always used save/update(params.user) or thereabouts for these queries, but that seems like overkill here; I just want to pass a 1-bit update.
Okay, my CTO who is new to CFML and Wheels figured this out in like 5 seconds. Hence the "C" I guess.
By returning the user model as a query instead of an object, I didn't have access to the update/save() methods. (Duh, MVC n00b.) The reason I was returning it as a query was simply that I've been doing that a fair bit in order to have easy manipulation of output, and in this case so that I can test for the existence of a record the way I always have (if recordCount). But this works...
<cffunction name="confirmEmail">
<cfscript>
user = model("user").findOne(where="id=#params.userid# AND uuid='#params.uuid#'");
if(isObject(user)) {
user.update(confirmed="1");
} else {
flashInsert(error="Something was wrong with your confirmation string. Please contact site administrators.");
redirectTo(route="authenticationDenied");
}
</cfscript>
</cffunction>
Related
Sitecore return field "Fields" with zero count in SocialProfiles, but this fields in social network really exist. How I can get need fields?
var socialProfileManager = new SocialProfileManager();
var twitterNetwork = allProfiles.FirstOrDefault(x => x.NetworkName == "Twitter");
if (twitterNetwork.Fields.Count != 0) //Dicitionary "Fields" is empty here
{
...
}
I had a similar situation where I was trying to retrieve the fields and dealing with the zero field count. Take a look at this post: https://stackoverflow.com/a/30519345/4897782
Specifically, my issue was resolved when I passed false as the second parameter in the base login method. The default true parameter attempts to update the profile asynchronously, making it unavailable during my attempts to do what you are doing.
To be able to override the parameter though, I had to deviate from the standard out of the box login controls and implement my own version of what happens when you click login. It's pretty simple though. Take a look at the post and hopefully that resolves your issue.
We are using CF MX7 for one of our applications.
When we enter a set of characters to search for through the application CF throws out an error stating the below:
Element USER_NAME is undefined in URL.
The error occurred in D:\Inetpub\wwwroot\MISWEB\lci\userNavigator.cfm: line 2
1 : <CFSET login_id = #url.user_login#>
2 : <CFSET user_name = #url.user_name#>
3 : <CFSET user_id = #url.user_id#>
This is occurring when we enter a login ID to search for that has an # character in it 0952#2. so basically, i understood that the problem is with the login ID that we are entering, but we cannot ask the user to change his login ID. is there an alternate way to change the code in such a way that it accepts these values?
<CFSET login_id = #0952#2#>
hence the error is being thrown out at the second line where it is not accepting the username as it is not correct. Is there any way we can include the # present in the login ID provided inside the declaring #..# open and close # function?
Because the search form is performing a GET request, the form fields are added to the URL. The problems is the hashes (#) are being interpreted by the browser as an on-page location, so nothing after the first hash in the URL is even being sent to the server, which is why ColdFusion says it doesn't exist.
To overcome this, you'll need to encode the hashes before submitting the form. You can do this with JavaScript and the form's onsubmit handler.
escape(document.formName.user_name.value);
This will send the user_name in the URL in an encoded format (%230952%232%23), which you can then decode when you set it to user_name.
<cfset user_name = urlDecode(url.user_name)>
I am trying to filter Google Analytics data for my company site based on a cookie. I don't want to track internal traffic, but I can't just filter based on an IP address range because there are some internal users who we want to still track. I have some pretty simple code for adding a cookie, but I am just not sure where to add the code. I am really new to cookies, and couldn't find anything online that was clear on how to actually add or use the cookie.
<html>
<head>
<title>Remove My Internal Traffic from Google Analytics</title>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXX-YY']);
_gaq.push(['_setVar','employee']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
So my question is, where does this code actually go? Thanks for helping out my novice skills with cookies.
Do not use setVar (this is deprecated), use _setCustomVar:
_setCustomVar(index, name, value, opt_scope)
The call goes before the _trackPageview Call.
There are five custom vars in standard GA (50 in premium), that's "index". 'Name' and 'value' should be clear.
CustomVars are either valid for the current page, for the session or for the visitor (in the last case they are valid until the visitors clears the cookies in his browsers unless he waits six months before he visits you site again).
Like every instruction with the asynonchronous GA code this is "pushed" on the gaq-Array, so the correct call would be:
_gaq.push(['_setCustomVar',
1, // This custom var is set to slot #1. Required parameter.
'Items Removed', // The name acts as a kind of category for the user activity. Required parameter.
'Yes', // This value of the custom variable. Required parameter.
2 // Sets the scope to session-level. Optional parameter.
]);
which is taken from the Google documentation here:
https://developers.google.com/analytics/devguides/collection/gajs/gaTrackingCustomVariables#setup.
I still maintain that for your use case the opt-out plugin is the better solution.
UPDATE: Thinking about it I don't think you need setCustomVar or custom cookies at all. Have your employees go to your website via a link like:
mywebsite.com?utm_source=allyourbasearebelongtous
Then go to the profile settings and create a custom filter, set to exclude, filter field "campaign source" , filter pattern "allyourbasearebelongtous" (or whatever name you gave to your campaign parameter).
This uses also a cookie (the standard google cookie) but does not need any custom code at all. The campaign source parameter is valid until they visit another campaign geared towards your site, so if somebody wants to test the GA code they need to delete their cookies or use incognito mode (but that't not different from setting a custom cookie or setCustomVar-methods).
I'm trying to get a better setup working for updating a model with nested properties.
Right now in my edit view I define the textFieldTag manually to create the params struct by setting up the name as "myModel[myNestedProperty][#modelID#,#key2id#][name]"
in update action...
if I just use myModel.update(params.myModel) I can't get the update to work if there are any elements that require deletion
so I destroy all the models of the nested property that have the same id as myModel, in which case it works.
The downside is that if the update fails, the nested properties are all gone.
I've tried grabbing all of the models first before deleting them and .saveing them, but for some reason that's not working.
Looks like cfwheel is setup for this kind of relation with the checkboxes, but I need it to work with textfield and select items in my form.
Update
I realized I have another issue. Essentially I would like to expand on this to be able to use it across multiple nested properties and relationships.
the issue is in the way I setup the name especially for select dropdowns:
name="myModel[myNestedProperty][#modelID#, ][nestedID]"
the issue is that the second id cannot be declared, because it will be assigned as the id rather than using the value that I select.
To be honest, this is the one issue I've been battling with my whole time. I'm dealing with it by regenerating the models in the controller, I just forgot I haven't solved that issue yet.
Is there a way I can have these values not be used at all, and have them populated from the structure dynamically?
let's say I have (truncated) a name tcat[34,0][catID] or tcat[34,][catID], (where the catID should be the 2nd ID).
the params' tcat structure that gets generated is
[34,0]{catID = 12,14,18}
or
[34,]{catID = 12,14,18}
I'd like the params' tcat structure to have multiple structs like:
[34,12]{tID = 34; catID = 12}
[34,14]{tID = 34; catID = 14}
[34,18]{tID = 34; catID = 18}
Is there a way around this?
I'm working with a lot of composite key nested properties, and if I could have this part alone working it would make it a lot easier. I know one way is to update the name with javascript, but I think that would be the (very,very) last resort.
Can you give this a try?
Set up a callback in the parent model that checks to see if name is blank and flags for deletion if it's blank.
<cffunction name="init">
...
<!--- This could also be `beforeValidation` if you want to make `name` required for the child model --->
<cfset beforeSave("$provisionMyNestedProperty")>
</cffunction>
<cffunction name="$provisionMyNestedProperty">
<cfscript>
if (StructKeyExists(this, "myNestedProperty") && IsArray(this.myNestedProperty))
{
for (local.i = 1; local.i <= ArrayLen(this.myNestedProperty); local.i++)
{
if (!StructKeyExists(this.myNestedProperty[local.i], "name") || !Len(Trim(this.myNestedProperty[local.i].name)))
this.myNestedProperty[local.i]._delete = true;
}
}
</cfscript>
</cffunction>
I'll keep editing my answer until we can bang out a solution. Hopefully that gives you a good start though.
In WFFM there is an option so that, when someone abandons the form, any data that was entered in the form itself is recorded and should be accessible via the Dropout Report.
I have a WFFM for which I have turned on Analytics and turned on the dropout feature. Unfortunately I don't see any data being recorded in the DB and the Dropout Report is visible, but empty.
I see from the javascript code included in the WFFM folder that a series of AJAX calls are supposed to save the fields on blur events -- with calls to /sitecore modules/web/Web Forms for Marketers/Tracking.aspx
I tried debugging the Javascript code, but the method supposed to post the info to /sitecore modules/web/Web Forms for Marketers/Tracking.aspx is never being called. Can you think of any reasons for this code not to work? Also, does anyone know which table this information is supposed to be recorded? Is it the fields table in the WFFM DB?
Finally, even though I have turned on analytics on this particular WFFM form and I have associated a campaign and a goal to the submission of the form, none of these is being recorded. I see that the data entered in the form is stored successfully and is displaying in the Data Report, but no info about the Campaign nor the Goal are recorded in the DB.
I even checked manually directly in the DMS DB running:
select top 10
p.DateTime, p.UrlText, cp.CampaignName
,i.Url, vi.VisitId
from pages p
inner join ItemUrls i on p.ItemId = i.ItemId
inner join Visits vi on vi.VisitId = p.VisitId
inner join GeoIps g on vi.Ip = g.Ip
left join Campaigns cp on cp.CampaignId = vi.CampaignId
order by p.DateTime desc
This one shows that the page where the form is rendered is being hit, but no campaign is associated to the visit.
Then I tried the following:
select pe.datetime, ped.Name, pg.UrlText from PageEvents pe
inner join PageEventDefinitions ped on ped.PageEventDefinitionId = pe.PageEventDefinitionId
inner join Pages pg on pg.PageId = pe.PageId
order by pe.DateTime desc
But I don't see any entry for this particular campaign nor for the goal (while I see entries for other campaigns and goals associated to non-WFFM Sitecore items)
Any advice would be greatly appreciated!
Thanks,
Francesco
EDIT
The sc.webform.js file contains this method:
_create: function () {
var self = this,
options = this.options;
if (options.tracking) {
this.element.find("input[type!='submit'], select, textarea")
.bind('focus', function (e) { self.onFocusField(e, this) })
.bind('blur change', function (e) { self.onBlurField(e, this) });
this.element.find("select")
.change(function () { $scw.webform.controls.updateAnalyticsListValue(this) });
this.element.find("input[type='checkbox'], input[type='radio']")
.click(function () { $scw.webform.controls.updateAnalyticsListValue(this) });
}
this.element.find(".scfDatePickerTextBox").each(function () { $scw.webform.controls.datePicker(this) });
},
This is supposed to be called by the form on sc.webform widget initialization. It should bind the focus and blur change events for all input fields, drop downs and text areas. Unfortunately, when I tried to put a break point inside this method, it never gets called.
SECOND EDIT
Interesting. I figured out that the whole thing should start from this line of Javascript code embedded in the page that contains the WFFM form:
<script type="text/javascript">
$scwhead.ready(function() {
$scw('#form_A8BF483419174F97A2830E12CBCF7E4F').webform({formId: "{A8BF4834-1917-4F97-A283-0E12CBCF7E4F}",pageId: "{21C24144-B964-4FBA-8388-D9B90EBBC17C}",eventCountId: "pagecolumns_0_columncontent_0_bottomrow_0_form_A8BF483419174F97A2830E12CBCF7E4F_form_A8BF483419174F97A2830E12CBCF7E4F_eventcount",tracking: true})
});
</script>
Once I put a break point here, I was finally able to trace into the _create method of the jQuery.UI widget defined in sc.webform.js. The code that calls _create is actually inside the jQuery.UI library. Kinda makes sense, right?
Finally, the code inside _create is executed, the blur events are bound to the TrackEvents method, also defined within the widget:
_trackEvents: function(events) {
$scw.ajax({
type: 'POST',
url: "/sitecore modules/web/Web Forms for Marketers/Tracking.aspx" + location.search,
data: {track: JSON.stringify(events)},
dataType: 'json'
});
What doesn't make sense is that now, even though I can finally see trackEvents being called whenever I tab from field to field in the WFFM form (why wasn't working before it's a mistery to me), I don't see any data recorded in the WFFM DB. I even tried a quick query in the DB:
select f.Timestamp, f.StorageName, fi.Value, fi.FieldName
from Form f
inner join Field fi on f.Id = fi.FormId
order by f.Timestamp desc, FieldName
Does anybody know where is Tracking.aspx supposed to save the captured field informations?
This may be silly to ask, but did you configure the data source correctly for your WFFM? I mean, obviously, you're using WFFM..but is it set to use SQL or is it using the "file" that WFFM uses by default as it's database.
like this to use SQL:
<!-- MSSQL-->
<formsDataProvider type="Sitecore.Forms.Data.DataProviders.WFMDataProvider,Sitecore.Forms.Core">
<param desc="connection string">Database=Sitecore_WebForms;Data Source=xxx;user id=xxx;password=xxx;Connect Timeout=30</param>
</formsDataProvider>
<!-- SQLite -->
<!--<formsDataProvider type="Sitecore.Forms.Data.DataProviders.SQLite.SQLiteWFMDataProvider,Sitecore.Forms.Core">
<param desc="connection string">Data Source=/data/sitecore_webforms.db;version=3;BinaryGUID=true</param>
</formsDataProvider>-->
If you don't configure that correctly, I'm wondering if somehow data is being recorded in one place but not another? Also, another question I have is to ask if this is a dev environment, are you running webforms in live mode? It just seems to me like this is a configuration issue.
We are experiencing the exact same problem on 6.5 update 6 and WFFM 2.3.3 rev. 111209. We can see the asynchronous calls to the server including the probably well formed json object containing the correct event.
Example:
track:[{"fieldId":"{E0A0BCDD-85E1-4D8D-9E76-5ABD240423C9}","type":"Field Completed","value":"test","formId":"{0F3B57C1-1B6A-43B9-A5A6-2E958C168B31}","pageId":"{025AFF68-62B9-42CE-B49F-0C36311E1976}","ticks":16}]
We don't see any of the dropouts arrive in the database, though...
Have you made sure your campaigns and goals have been deployed? If you have switched databases they may not be. To redeploy do this:
For each Goal in System -> Marketing Center -> Goals
Change the workflow state to draft
Save
Then in the review ribbon click deploy.
This will create an entry in the pageeventdefinition table and allow
you to query.
Don't forget to do the same for campaigns.