protected void Page_Load(object sender, EventArgs e) { PageTitle.TitleText = GetString("newsletter_issue_subscribersclicks.title"); linkId = QueryHelper.GetInteger("linkid", 0); if (linkId == 0) { RequestHelper.EndResponse(); } LinkInfo link = LinkInfoProvider.GetLinkInfo(linkId); EditedObject = link; IssueInfo issue = IssueInfoProvider.GetIssueInfo(link.LinkIssueID); EditedObject = issue; // Prevent accessing issues from sites other than current site if (issue.IssueSiteID != SiteContext.CurrentSiteID) { RedirectToResourceNotAvailableOnSite("Issue with ID " + link.LinkIssueID); } var where = new WhereCondition().Where("LinkID", QueryOperator.Equals, linkId); // Link's issue is the main A/B test issue if (issue.IssueIsABTest && !issue.IssueIsVariant) { // Get A/B test and its winner issue ID ABTestInfo test = ABTestInfoProvider.GetABTestInfoForIssue(issue.IssueID); if (test != null) { // Get ID of the same link from winner issue var winnerLink = LinkInfoProvider.GetLinks() .WhereEquals("LinkIssueID", test.TestWinnerIssueID) .WhereEquals("LinkTarget", link.LinkTarget) .WhereEquals("LinkDescription", link.LinkDescription) .TopN(1) .Column("LinkID") .FirstOrDefault(); if (winnerLink != null) { if (winnerLink.LinkID > 0) { // Add link ID of winner issue link where.Or(new WhereCondition().Where("LinkID", QueryOperator.Equals, winnerLink.LinkID)); } } } } where.And(new WhereCondition(fltOpenedBy.WhereCondition)); UniGrid.WhereCondition = where.WhereCondition; UniGrid.QueryParameters = where.Parameters; UniGrid.Pager.DefaultPageSize = PAGESIZE; UniGrid.Pager.ShowPageSize = false; UniGrid.FilterLimit = 1; UniGrid.OnExternalDataBound += UniGrid_OnExternalDataBound; }
protected void btnSend_Click(object sender, EventArgs e) { // Validate date/time if (dtpMailout.SelectedDateTime == DateTimeHelper.ZERO_TIME) { ShowError(GetString("newsletterissue_send.invaliddatetime")); return; } IssueInfo winner = (IssueInfo)EditedObject; int parentIssueId = winner.IssueVariantOfIssueID; // Get A/B test info ABTestInfo abi = ABTestInfoProvider.GetABTestInfoForIssue(parentIssueId); if (abi != null) { IssueInfo issue = IssueInfoProvider.GetIssueInfo(parentIssueId); // Check if winner was selected and sent if (abi.TestWinnerIssueID != 0) { if ((issue.IssueStatus == IssueStatusEnum.Finished) || (issue.IssueStatus == IssueStatusEnum.Sending)) { // Winner was already sent CloseDialogAndRefreshParent(); return; } } // Update A/B test info and winner selection task (if exist) abi.TestWinnerOption = ABTestWinnerSelectionEnum.Manual; NewsletterTasksManager.EnsureWinnerSelectionTask(abi, issue, false, DateTime.Now); abi.TestSelectWinnerAfter = 0; abi.TestWinnerSelected = DateTime.Now; abi.TestWinnerIssueID = winner.IssueID; ABTestInfoProvider.SetABTestInfo(abi); if ((issue != null) && (winner != null)) { var parentIssue = IssueInfoProvider.GetIssueInfo(parentIssueId); NewsletterSendingStatusModifier.ResetAllEmailsInQueueForIssue(parentIssue.IssueID); // Copy data from winner to parent IssueHelper.CopyWinningVariantIssueProperties(winner, issue); IssueInfoProvider.SetIssueInfo(issue); // Remove previous scheduled task of this issue NewsletterTasksManager.DeleteMailoutTask(issue.IssueGUID, issue.IssueSiteID); DateTime mailoutTime = dtpMailout.SelectedDateTime; Service.Resolve <IIssueScheduler>().ScheduleIssue(parentIssue, mailoutTime); } } // Close dialog and refresh parent page CloseDialogAndRefreshParent(); }
private void SetABTestWinnerManually(ABTestInfo abTest, IssueInfo parentIssue, IssueInfo winnerVariant) { // Update A/B test info and winner selection task (if exist) abTest.TestWinnerOption = ABTestWinnerSelectionEnum.Manual; NewsletterTasksManager.EnsureWinnerSelectionTask(abTest, parentIssue, false, DateTime.Now); abTest.TestSelectWinnerAfter = 0; abTest.TestWinnerSelected = DateTime.Now; abTest.TestWinnerIssueID = winnerVariant.IssueID; ABTestInfo.Provider.Set(abTest); }
/// <summary> /// Creates new AB variant if AB test filled in. /// </summary> /// <param name="newDocument">Newly created document</param> /// <returns>True if new variant is successfully created or if AB test is not defined.</returns> private bool CreateABVariant(TreeNode newDocument) { // If ABTest selected - create new variant int abTestID = ValidationHelper.GetInteger(ucABTestSelector.Value, 0); if (abTestID <= 0) { return(true); } // If no test found, handle it as no test was specified ABTestInfo abTest = ABTestInfoProvider.GetABTestInfo(abTestID); if (abTest == null) { return(true); } string defaultCodeName = TextHelper.LimitLength(ValidationHelper.GetCodeName(newDocument.NodeAlias), 45, String.Empty); string codeName = defaultCodeName; ABVariantInfo info = ABVariantInfoProvider.GetABVariantInfo(codeName, abTest.ABTestName, SiteContext.CurrentSiteName); // Find non existing variant code name int index = 0; while (info != null) { index++; codeName = defaultCodeName + "-" + index; info = ABVariantInfoProvider.GetABVariantInfo(codeName, abTest.ABTestName, SiteContext.CurrentSiteName); } // Save AB Variant ABVariantInfo variantInfo = new ABVariantInfo(); variantInfo.ABVariantTestID = abTestID; variantInfo.ABVariantPath = newDocument.NodeAliasPath; variantInfo.ABVariantName = codeName; variantInfo.ABVariantDisplayName = newDocument.NodeAlias; variantInfo.ABVariantSiteID = SiteContext.CurrentSiteID; try { ABVariantInfoProvider.SetABVariantInfo(variantInfo); } catch (InfoObjectException ex) { newDocument.Delete(true, true); ShowError(ex.Message); return(false); } return(true); }
private void InitTestGroupSlider(IssueInfo parentIssue, ABTestInfo abTest, bool forceReload) { var variants = IssueHelper.GetIssueVariants(parentIssue, null); ucGroupSlider.Variants = variants; ucGroupSlider.NumberOfSubscribers = GetNumberOfSubscribers(parentIssue, variants); if (forceReload || !ucGroupSlider.Enabled) { ucGroupSlider.CurrentSize = abTest?.TestSizePercentage ?? DEFAULT_TEST_GROUP_SIZE_PERCENTAGE; } ucGroupSlider.ReloadData(forceReload); }
protected void Page_Load(object sender, EventArgs e) { if (PostbackOnChange) { ucUniSelector.DropDownSingleSelect.AutoPostBack = true; ScriptManager scr = ScriptManager.GetCurrent(Page); scr.RegisterPostBackControl(ucUniSelector.DropDownSingleSelect); } if (!URLHelper.IsPostback()) { // If some test belongs to node give by NodeID - preselect it in ABTest selector if (NodeID != 0) { TreeProvider tree = new TreeProvider(CMSContext.CurrentUser); TreeNode node = tree.SelectSingleNode(NodeID, CMSContext.PreferredCultureCode, tree.CombineWithDefaultCulture); if (node != null) { DataSet ds = ABTestInfoProvider.GetABTests("ABTestSiteID = " + CMSContext.CurrentSiteID + " AND ABTestOriginalPage = '" + SqlHelperClass.GetSafeQueryString(node.NodeAliasPath, false) + "'", "ABTestName", -1, null, null); if (!DataHelper.DataSourceIsEmpty(ds)) { // Preselect running test bool runningTestFound = false; foreach (DataRow row in ds.Tables[0].Rows) { ABTestInfo abTestObj = new ABTestInfo(row); if (ABTestInfoProvider.ABTestIsRunning(abTestObj)) { runningTestFound = true; ucUniSelector.Value = abTestObj.ABTestID; } } // If no running test found for the page, preselect the first test (alphabetically) if (!runningTestFound) { int abTestID = ValidationHelper.GetInteger(ds.Tables[0].Rows[0]["ABTestID"], 0); if (abTestID != 0) { ucUniSelector.Value = abTestID; } } } } } } ReloadData(false); }
/// <summary> /// Handles Unigrid's OnExternalDataBound event. /// </summary> protected object gridElem_OnExternalDataBound(object sender, string sourceName, object parameter) { switch (sourceName.ToLower()) { case "abteststatus": int testID = ValidationHelper.GetInteger(parameter, 0); ABTestInfo testInfo = ABTestInfoProvider.GetABTestInfo(testID); if (testInfo != null) { if (!testInfo.ABTestEnabled) { return("<span class=\"StatusDisabled\">" + GetString("general.disabled") + "</span>"); } else { string status = string.Empty; if (ABTestInfoProvider.ABTestIsRunning(testInfo)) { // Display disabled information if (!webAnalyticsEnabled) { return(GetString("abtesting.statusNone")); } if (!ABTestInfoProvider.ContainsVariants(testInfo)) { // Display warning when the test does not contain any variant return("<img src=\"" + GetImageUrl("Design/Controls/UniGrid/Actions/Warning.png") + "\" alt=\"" + GetString("abtest.novariants") + "\" title=\"" + GetString("abtest.novariants") + "\" /> " + GetString("abtesting.status" + ABTestStatusEnum.None)); } status += "<span class=\"StatusEnabled\">" + GetString("abtesting.status" + ABTestInfoProvider.GetABTestStatus(testInfo)) + "</span>"; } else { status += GetString("abtesting.status" + ABTestInfoProvider.GetABTestStatus(testInfo)); } return(status); } } return(string.Empty); } return(parameter); }
/// <summary> /// Creates a new AB variant that should be created by default to given AB test /// </summary> private void CreateDefaultVariant(ABTestInfo info) { // Create instance of AB variant ABVariantInfo variant = new ABVariantInfo(); // Set properties variant.ABVariantPath = info.ABTestOriginalPage; variant.ABVariantTestID = info.ABTestID; variant.ABVariantDisplayName = GetString("abtesting.originalvariantdisplayname"); variant.ABVariantName = "Original"; variant.ABVariantSiteID = info.ABTestSiteID; // Save to the storage ABVariantInfoProvider.SetABVariantInfo(variant); }
/// <summary> /// Initialize winner option control. /// </summary> /// <param name="enable">Control state (enabled/disabled)</param> /// <param name="abi">A-B test info to load to control</param> /// <param name="forceReload">TRUE if force load should be performed</param> private void InitWinnerOption(bool enable, ABTestInfo abi, bool forceReload) { if (abi == null) { return; } ucWO.Visible = true; ucWO.Enabled = enable; if (forceReload) { ucWO.WinnerSelection = abi.TestWinnerOption; ucWO.TimeInterval = abi.TestSelectWinnerAfter; } }
/// <summary> /// Collects data from controls and fills A/B test info. /// </summary> /// <param name="abi">A/B test info</param> private bool SaveABTestInfo(ABTestInfo abi) { if (abi == null) { return(false); } var selectionChanged = (abi.TestWinnerOption != ucWO.WinnerSelection) || (abi.TestSelectWinnerAfter != ucWO.TimeInterval) || (abi.TestSizePercentage != ucGroupSlider.CurrentSize); abi.TestWinnerOption = ucWO.WinnerSelection; abi.TestSelectWinnerAfter = ucWO.TimeInterval; abi.TestSizePercentage = ucGroupSlider.CurrentSize; return(selectionChanged); }
protected object UniGrid_OnExternalDataBound(object sender, string sourceName, object parameter) { switch (sourceName) { case "variantname": if (!isMainABTestIssue) { return(null); } IssueInfo issue = IssueInfoProvider.GetIssueInfo(ValidationHelper.GetInteger(parameter, 0)); string variantName = null; if (issue != null) { if (!issue.IssueIsVariant) { // Get variant name from the winner issue if (winnerIssue == null) { ABTestInfo test = ABTestInfoProvider.GetABTestInfoForIssue(issue.IssueID); if (test != null) { // Get A/B test winner variant winnerIssue = IssueInfoProvider.GetIssueInfo(test.TestWinnerIssueID); } } if (winnerIssue != null) { // Get variant name variantName = winnerIssue.IssueVariantName; } } else { // Get variant name variantName = issue.IssueVariantName; } } return(HTMLHelper.HTMLEncode(variantName)); default: return(parameter); } }
/// <summary> /// Reloads control data. /// </summary> /// <param name="forceReload">Indicates if force reload should be used</param> public override void ReloadData(bool forceReload) { if (StopProcessing && !forceReload) { return; } var parentIssueId = 0; mParentIssue = IssueInfoProvider.GetOriginalIssue(IssueID); if (mParentIssue != null) { parentIssueId = mParentIssue.IssueID; } // Get A/B test configuration mABTest = ABTestInfoProvider.GetABTestInfoForIssue(parentIssueId); if (mABTest == null) { // Ensure A/B test object with default settings mABTest = new ABTestInfo { TestIssueID = parentIssueId, TestSizePercentage = 50, TestWinnerOption = ABTestWinnerSelectionEnum.Manual }; ABTestInfo.Provider.Set(mABTest); } CurrentState = GetCurrentState(mParentIssue); if (mParentIssue.IssueForAutomation) { InitControlsForIssueUsedInAutomation(CurrentState, forceReload); } else { InitControls(CurrentState, forceReload); } ucMailout.ParentIssueID = parentIssueId; ucMailout.ReloadData(forceReload); InfoMessage = GetInfoMessage(CurrentState, mParentIssue, mABTest?.TestWinnerOption ?? ABTestWinnerSelectionEnum.Manual); // Init test group slider InitTestGroupSlider(mParentIssue, mABTest, forceReload); }
/// <summary> /// Reloads control data. /// </summary> /// <param name="forceReload">Indicates if force reload should be used</param> public override void ReloadData(bool forceReload) { if (StopProcessing && !forceReload) { return; } if (ForceReloadNeeded) { forceReload = true; ForceReloadNeeded = false; } int parentIssueId = 0; mParentIssue = IssueInfoProvider.GetOriginalIssue(IssueID); if (mParentIssue != null) { parentIssueId = mParentIssue.IssueID; } // Get A/B test configuration mABTest = ABTestInfoProvider.GetABTestInfoForIssue(parentIssueId); if (mABTest == null) { // Ensure A/B test object with default settings mABTest = new ABTestInfo() { TestIssueID = parentIssueId, TestSizePercentage = 50, TestWinnerOption = ABTestWinnerSelectionEnum.OpenRate, TestSelectWinnerAfter = 60 }; ABTestInfoProvider.SetABTestInfo(mABTest); } CurrentState = GetCurrentState(mParentIssue); InitControls(CurrentState, forceReload); ucMailout.ParentIssueID = parentIssueId; ucMailout.ReloadData(forceReload); InfoMessage = GetInfoMessage(CurrentState, mParentIssue, (mABTest != null ? mABTest.TestWinnerOption : ABTestWinnerSelectionEnum.OpenRate), GetPlannedMailoutTime(ucMailout.HighestMailoutTime)); // Init test group slider InitTestGroupSlider(mParentIssue, mABTest, forceReload); ucWO_OnChange(this, EventArgs.Empty); }
protected void StartABTest() { if (ABTest == null) { ShowWarning(GetString("abtesting.invalidtest")); return; } if (!CurrentUser.IsAuthorizedPerResource("CMS.ABTest", "Manage", ABTestSiteName)) { RedirectToAccessDenied("cms.abtest", "Manage"); } DateTime start = (radNow.Checked) ? DateTime.Now : calendarControl.SelectedDateTime; // Validate input if (radLater.Checked && !ABTestValidator.IsValidStart(start)) { ShowError(GetString("abtesting.scheduled.invaliddate")); return; } // Create clone of the test to circumvent caching issues ABTestInfo testClone = ABTest.Clone(); testClone.ABTestOpenFrom = start; // Check for collisions string collidingTestName = ABTestValidator.GetCollidingTestName(testClone); if (!String.IsNullOrEmpty(collidingTestName)) { ShowError(String.Format(GetString("om.twotestsonepageerror"), HTMLHelper.HTMLEncode(ResHelper.LocalizeString(collidingTestName)), ABTest.ABTestOriginalPage)); return; } // Save the test with the new start date ABTest.ABTestOpenFrom = start; ABTestInfoProvider.SetABTestInfo(ABTest); ScriptHelper.RegisterWOpenerScript(this); // Refresh the window opener with parameter indicating that the refresh was caused by this modal window ScriptHelper.RegisterStartupScript(this, typeof(string), "RefreshPage", ScriptHelper.GetScript("wopener.RefreshPage(false); CloseDialog();")); }
/// <summary> /// Initialize winner option control. /// </summary> /// <param name="enable">Control state (enabled/disabled)</param> /// <param name="abi">A-B test info to load to control</param> /// <param name="forceReload">TRUE if force load should be performed</param> private void InitWinnerOption(bool enable, ABTestInfo abi, bool forceReload) { // Register handlers ucWO.OnChange -= new EventHandler(ucWO_OnChange); ucWO.OnChange += new EventHandler(ucWO_OnChange); if (abi == null) { return; } ucWO.Visible = true; ucWO.Enabled = enable; if (forceReload) { ucWO.WinnerSelection = abi.TestWinnerOption; ucWO.TimeInterval = abi.TestSelectWinnerAfter; } }
public override void ReloadData(bool forceReload) { if (StopProcessing && !forceReload) { return; } InitControls(forceReload); // Javascript for handling winner mailout time string scriptBlock = string.Format(@"function SelWinner(id) {{ modalDialog('{0}?issueid=' + id, 'NewsletterWinnerMailout', '400px', '300px'); return false; }} function ShowOpenedBy(id) {{ modalDialog('{1}?issueid=' + id, 'NewsletterIssueOpenedBy', '900px', '700px'); return false; }} function ViewClickedLinks(id) {{ modalDialog('{2}?issueid=' + id, 'NewsletterTrackedLinks', '900px', '700px'); return false; }}", ResolveUrl(@"~\CMSModules\Newsletters\Tools\Newsletters\Newsletter_Issue_WinnerMailout.aspx"), ResolveUrl(@"~\CMSModules\Newsletters\Tools\Newsletters\Newsletter_Issue_OpenedBy.aspx"), ResolveUrl(@"~\CMSModules\Newsletters\Tools\Newsletters\Newsletter_Issue_TrackedLinks.aspx")); ScriptHelper.RegisterDialogScript(Page); ScriptHelper.RegisterClientScriptBlock(this, GetType(), "Actions", scriptBlock, true); // Register handlers grdElem.OnExternalDataBound -= new OnExternalDataBoundEventHandler(grdElem_OnExternalDataBound); grdElem.OnExternalDataBound += new OnExternalDataBoundEventHandler(grdElem_OnExternalDataBound); grdElem.GridView.RowDataBound -= new GridViewRowEventHandler(GridView_RowDataBound); grdElem.GridView.RowDataBound += new GridViewRowEventHandler(GridView_RowDataBound); // Get winner ID if any ABTestInfo abi = ABTestInfoProvider.GetABTestInfoForIssue(ParentIssueID); if (abi != null) { WinnerIssueID = abi.TestWinnerIssueID; } grdElem.WhereCondition = GetWhereCondition(ParentIssueID, false); grdElem.ShowActionsMenu = false; grdElem.ShowObjectMenu = false; if (!ShowSelectWinnerAction) { grdElem.GridActions = null; } grdElem.ReloadData(); }
protected void Page_Load(object sender, EventArgs e) { int abTestId = QueryHelper.GetInteger("abTestId", 0); int nodeID = QueryHelper.GetInteger("nodeid", 0); ABTestInfo abTest = ABTestInfoProvider.GetABTestInfo(abTestId); if (abTest != null) { // Prepare the tabs string[,] tabs = new string[3, 4]; tabs[0, 0] = GetString("general.general"); tabs[0, 1] = "SetHelpTopic('helpTopic', 'abtest_general');"; tabs[0, 2] = "Tab_General.aspx?abTestId=" + abTestId + "&nodeid=" + nodeID; tabs[1, 0] = GetString("abtesting.variant.list"); tabs[1, 1] = "SetHelpTopic('helpTopic', 'abtest_variants');"; tabs[1, 2] = ResolveUrl("~/CMSModules/OnlineMarketing/Pages/Content/ABTesting/ABVariant/List.aspx?abTestId=" + abTestId + "&nodeid=" + nodeID); tabs[2, 0] = GetString("general.reports"); tabs[2, 1] = "SetHelpTopic('helpTopic', 'abtest_reports');"; tabs[2, 2] = "abtestreports.aspx?abtestid=" + abTestId; // Prepare the breadcrumbs string[,] breadcrumbs = new string[2, 3]; breadcrumbs[0, 0] = GetString("abtesting.abtest.list"); breadcrumbs[0, 1] = "~/CMSModules/OnlineMarketing/Pages/Content/ABTesting/ABTest/List.aspx?nodeid=" + nodeID; breadcrumbs[0, 2] = "_parent"; breadcrumbs[1, 0] = HTMLHelper.HTMLEncode(abTest.ABTestDisplayName.ToString()); // Set the tabs ICMSMasterPage master = CurrentMaster; master.Tabs.Tabs = tabs; master.Tabs.UrlTarget = "content"; // Set the title PageTitle title = CurrentMaster.Title; title.Breadcrumbs = breadcrumbs; title.HelpTopicName = "abtest_general"; title.HelpName = "helpTopic"; } }
/// <summary> /// Handles Unigrid's OnExternalDataBound event. /// </summary> protected object gridElem_OnExternalDataBound(object sender, string sourceName, object parameter) { string param = parameter.ToString(); switch (sourceName.ToLowerCSafe()) { case "status": { ABTestStatusEnum status; if (Enum.TryParse(param, out status)) { return(ABTestStatusEvaluator.GetFormattedStatus(status)); } break; } case "page": return(new HyperLink { NavigateUrl = DocumentURLProvider.GetUrl(param), Text = HTMLHelper.HTMLEncode(param), Target = "_blank" }); case "visitors": case "conversions": { string statisticsCodeName = (sourceName.ToLowerCSafe() == "visitors" ? "abvisitfirst" : "absessionconversionfirst"); ABTestInfo abTestInfo = ABTestInfoProvider.GetABTestInfo(param, SiteContext.CurrentSiteName); if (abTestInfo != null) { return(ValidationHelper.GetInteger(HitsInfoProvider.GetAllHitsInfo(SiteContext.CurrentSiteID, HitsIntervalEnum.Year, statisticsCodeName + ";" + abTestInfo.ABTestName + ";%", "SUM(HitsCount)", abTestInfo.ABTestCulture).Tables[0].Rows[0][0], 0)); } return(0); } } return(null); }
/// <summary> /// Validates the form. If validation succeeds returns true, otherwise returns false. /// </summary> private bool Validate() { // Validate required fields string errorMessage = new Validator() .NotEmpty(txtABVariantDisplayName.Text.Trim(), rfvABVariantDisplayName.ErrorMessage) .NotEmpty(txtABVariantName.Text.Trim(), rfvABVariantName.ErrorMessage) .IsCodeName(txtABVariantName.Text.Trim(), GetString("general.invalidcodename")).Result; string abTestName = string.Empty; string siteName = CMSContext.CurrentSiteName; // Get AB test info object ABTestInfo abti = ABTestInfoProvider.GetABTestInfo(TestID); if (abti != null) { abTestName = abti.ABTestName; } // Test unique codename ABVariantInfo info = ABVariantInfoProvider.GetABVariantInfo(txtABVariantName.Text.Trim(), abTestName, siteName); if ((info != null) && ((VariantObj == null) || (info.ABVariantID != VariantObj.ABVariantID))) { errorMessage = GetString("general.codenameexists"); } if (String.IsNullOrEmpty(ucPath.Value.ToString())) { errorMessage = GetString("abtesting.entertestpage"); } // Set the error message if (!String.IsNullOrEmpty(errorMessage)) { ShowError(errorMessage); return(false); } return(true); }
/// <summary> /// Collects data from controls and fills A/B test info. /// </summary> /// <param name="abi">A/B test info</param> private bool SaveABTestInfo(ABTestInfo abi) { if (abi == null) { return(false); } bool result = (abi.TestWinnerOption != ucWO.WinnerSelection) || (abi.TestSelectWinnerAfter != ucWO.TimeInterval) || (abi.TestSizePercentage != ucGroupSlider.CurrentSize); switch (Mode) { case SendControlMode.Wizard: case SendControlMode.Send: abi.TestWinnerOption = ucWO.WinnerSelection; abi.TestSelectWinnerAfter = ucWO.TimeInterval; break; } abi.TestSizePercentage = ucGroupSlider.CurrentSize; return(result); }
/// <summary> /// Gets number of opened e-mails of winner variant issue. /// </summary> /// <param name="issueId">ID of parent issue</param> private int GetWinnerVariantOpenes(int issueId) { int openedEmails = 0; ABTestInfo test = ABTestInfoProvider.GetABTestInfoForIssue(issueId); if ((test != null) && (test.TestWinnerIssueID > 0)) { IssueInfo winner = IssueInfoProvider.GetIssueInfo(test.TestWinnerIssueID); if (winner != null) { // Get opened emails count from winner issue openedEmails += winner.IssueOpenedEmails; if (mOnlineMarketingEnabled) { // Get number of emails opened by contact group and persona members openedEmails += OpenedEmailInfoProvider.GetMultiSubscriberOpenedIssueActivityCount(winner.IssueID); } } } return(openedEmails); }
/// <summary> /// Checks whether the form is valid. /// </summary> private bool IsValid() { // If the test is finished, no validation is needed if (TestStatus == ABTestStatusEnum.Finished) { return true; } // Get page of the test so we can check for collisions string page = QueryHelper.GetString("AliasPath", null); if (String.IsNullOrEmpty(page)) { page = form.GetFieldValue("ABTestOriginalPage").ToString(); } // Validate original page of the test if (!PageExists(page)) { ShowError(GetString("abtesting.testpath.pagenotfound")); return false; } // Create temporary test used for validation of the new values ABTestInfo updatedTest = new ABTestInfo { ABTestID = ABTest.ABTestID, ABTestOriginalPage = page, ABTestCulture = form.GetFieldValue("ABTestCulture").ToString(), ABTestSiteID = SiteContext.CurrentSiteID, }; updatedTest.ABTestOpenFrom = ValidationHelper.GetDateTime(form.GetFieldValue("ABTestOpenFrom"), DateTimeHelper.ZERO_TIME); // Validate start time if the test is not already running if (TestStatus != ABTestStatusEnum.Running) { if (!ABTestValidator.IsValidStart(updatedTest.ABTestOpenFrom)) { ShowError(GetString("om.wrongtimeinterval")); return false; } } updatedTest.ABTestOpenTo = ValidationHelper.GetDateTime(form.GetFieldValue("ABTestOpenTo"), DateTimeHelper.ZERO_TIME); // Validate finish time of the test if (!ABTestValidator.IsValidFinish(updatedTest.ABTestOpenFrom, updatedTest.ABTestOpenTo)) { ShowError(GetString("om.wrongtimeinterval")); return false; } // Find out possible collision - another test running on the same page, culture and at the same time string collidingTestName = ABTestValidator.GetCollidingTestName(updatedTest); if (!String.IsNullOrEmpty(collidingTestName)) { ShowError(String.Format(GetString("om.twotestsonepageerror"), HTMLHelper.HTMLEncode(ResHelper.LocalizeString(collidingTestName)), updatedTest.ABTestOriginalPage)); return false; } // If we get here, all fields are valid return true; }
/// <summary> /// Creates new variant and raises "Add" event if specified. /// </summary> /// <param name="name">Name of new variant</param> /// <param name="issueId">ID of source issue on which the new variant will be based</param> private void RaiseOnAddEvent(string name, int issueId) { // Get main issue (original) int currentIssuedId = IssueID; IssueInfo parentIssue = IssueInfoProvider.GetOriginalIssue(currentIssuedId); // Allow modifying issues in idle state only if ((parentIssue == null) || (parentIssue.IssueStatus != IssueStatusEnum.Idle)) { return; } // Get issue content specified by ID (if not found use original) IssueInfo contentIssue = null; if (issueId > 0) { if (issueId == parentIssue.IssueID) { contentIssue = parentIssue; } else { contentIssue = IssueInfoProvider.GetIssueInfo(issueId); } } NewsletterInfo newsletter = NewsletterInfoProvider.GetNewsletterInfo(parentIssue.IssueNewsletterID); IssueInfo issueVariant = null; // ID of the first child (if new A/B test is being created (i.e. parent and 2 children) int origVariantId = 0; // Check if current issue is variant issue if (!parentIssue.IssueIsABTest) { // Variant issue has not been created yet => create original and 2 child variants parentIssue.IssueIsABTest = true; // Create 1st variant based on parent issue, the 2nd variant will be created as ordinary variant below IssueInfo issueOrigVariant = parentIssue.Clone(true); issueOrigVariant.IssueVariantOfIssueID = parentIssue.IssueID; issueOrigVariant.IssueVariantName = GetString("newsletter.abvariantoriginal"); issueOrigVariant.IssueScheduledTaskID = 0; IssueInfoProvider.SetIssueInfo(issueOrigVariant); // Create scheduled task for variant mail-out and update issue variant issueOrigVariant.IssueScheduledTaskID = CreateScheduledTask(issueOrigVariant, newsletter); IssueInfoProvider.SetIssueInfo(issueOrigVariant); // Update parent issue IssueInfoProvider.SetIssueInfo(parentIssue); try { ObjectVersionManager.DestroyObjectHistory(parentIssue.ObjectType, parentIssue.IssueID); } catch (Exception ex) { EventLogProvider.LogException("Newsletter-AddVariant", "EXCEPTION", ex); } origVariantId = issueOrigVariant.IssueID; } // Variant issue has been created => create new variant only issueVariant = (contentIssue != null ? contentIssue.Clone(true) : parentIssue.Clone(true)); issueVariant.IssueVariantName = name; issueVariant.IssueVariantOfIssueID = parentIssue.IssueID; // Prepare content with empty regions if empty content will be used string[] regions = null; if ((contentIssue == null) && (newsletter != null)) { EmailTemplateInfo template = EmailTemplateInfoProvider.GetEmailTemplateInfo(newsletter.NewsletterTemplateID); if (template != null) { bool isValidRegionName = false; List<string> regionNames = new List<string>(); EmailTemplateHelper.ValidateEditableRegions(template.TemplateBody, out isValidRegionName, out isValidRegionName, regionNames); for (int i = regionNames.Count - 1; i >= 0; i--) { regionNames[i] = regionNames[i] + "::"; } regions = regionNames.ToArray(); // Set template ID (i.e. this template with these regions is used for current issue) issueVariant.IssueTemplateID = template.TemplateID; } } issueVariant.IssueText = (contentIssue != null ? contentIssue.IssueText : IssueHelper.GetContentXML(regions)); issueVariant.IssueScheduledTaskID = 0; IssueInfoProvider.SetIssueInfo(issueVariant); // Duplicate attachments and replace old guids with new guids in issue text if current variant issue is based on content of another if (contentIssue != null) { List<Guid> guids = new List<Guid>(); MetaFileInfoProvider.CopyMetaFiles(contentIssue.IssueID, issueVariant.IssueID, (contentIssue.IssueIsVariant ? NewsletterObjectType.NEWSLETTERISSUEVARIANT : NewsletterObjectType.NEWSLETTERISSUE), MetaFileInfoProvider.OBJECT_CATEGORY_ISSUE, NewsletterObjectType.NEWSLETTERISSUEVARIANT, MetaFileInfoProvider.OBJECT_CATEGORY_ISSUE, guids); if (guids.Count > 0) { for (int i = 0; i < guids.Count; i += 2) { issueVariant.IssueText = LinkConverter.ReplaceInLink(issueVariant.IssueText, guids[i].ToString(), guids[i + 1].ToString()); } } } // Create scheduled task for variant mail-out issueVariant.IssueScheduledTaskID = CreateScheduledTask(issueVariant, newsletter); // Update issue variant IssueInfoProvider.SetIssueInfo(issueVariant); if (origVariantId > 0) { // New A/B test issue created => create new A/B test info ABTestInfo abi = new ABTestInfo() { TestIssueID = parentIssue.IssueID, TestSizePercentage = 50, TestWinnerOption = ABTestWinnerSelectionEnum.OpenRate, TestSelectWinnerAfter = 60 }; ABTestInfoProvider.SetABTestInfo(abi); // Move attachments (meta files) from parent issue to first variant MetaFileInfoProvider.MoveMetaFiles(parentIssue.IssueID, origVariantId, NewsletterObjectType.NEWSLETTERISSUE, MetaFileInfoProvider.OBJECT_CATEGORY_ISSUE, NewsletterObjectType.NEWSLETTERISSUEVARIANT, MetaFileInfoProvider.OBJECT_CATEGORY_ISSUE); MetaFileInfoProvider.MoveMetaFiles(parentIssue.IssueID, origVariantId, NewsletterObjectType.NEWSLETTERISSUEVARIANT, MetaFileInfoProvider.OBJECT_CATEGORY_ISSUE, NewsletterObjectType.NEWSLETTERISSUEVARIANT, MetaFileInfoProvider.OBJECT_CATEGORY_ISSUE); } if (OnAddVariant != null) { VariantEventArgs args = new VariantEventArgs(name, issueVariant.IssueID); OnAddVariant(this, args); } }
/// <summary> /// Reloads control data. /// </summary> /// <param name="forceReload">Indicates if force reload should be used</param> public override void ReloadData(bool forceReload) { if (StopProcessing && !forceReload) { return; } if (ForceReloadNeeded) { forceReload = true; ForceReloadNeeded = false; } int parentIssueId = 0; parentIssue = IssueInfoProvider.GetOriginalIssue(IssueID); if (parentIssue != null) { parentIssueId = parentIssue.IssueID; } // Get A/B test configuration abTest = ABTestInfoProvider.GetABTestInfoForIssue(parentIssueId); if (abTest == null) { // Ensure A/B test object with default settings abTest = new ABTestInfo() { TestIssueID = parentIssueId, TestSizePercentage = 50, TestWinnerOption = ABTestWinnerSelectionEnum.OpenRate, TestSelectWinnerAfter = 60 }; ABTestInfoProvider.SetABTestInfo(abTest); } CurrentState = GetCurrentState(parentIssue); InitControls(CurrentState, forceReload); ucMailout.ParentIssueID = parentIssueId; ucMailout.ReloadData(forceReload); InfoMessage = GetInfoMessage(CurrentState, parentIssue, (abTest != null ? abTest.TestWinnerOption : ABTestWinnerSelectionEnum.OpenRate), GetPlannedMailoutTime(ucMailout.HighestMailoutTime)); // Init test group slider List<IssueABVariantItem> variants = IssueHelper.GetIssueVariants(parentIssue, null); ucGroupSlider.Variants = variants; bool allVariantsSent = true; if (variants != null) { allVariantsSent = variants.TrueForAll(delegate(IssueABVariantItem item) { return item.IssueStatus == IssueStatusEnum.Finished; }); } if ((parentIssue.IssueStatus == IssueStatusEnum.Finished) || allVariantsSent) { // Issue was sent long time ago => get number of subscribers from issue properties instead of current number of subscribers int perVariantEmails = 1; if (abTest != null) { perVariantEmails = abTest.TestNumberPerVariantEmails; } ucGroupSlider.NumberOfTestSubscribers = ucGroupSlider.Variants.Count * perVariantEmails; if (parentIssue.IssueStatus == IssueStatusEnum.Finished) { // Issue was sent => get number of subscribers from number of sent issues ucGroupSlider.NumberOfSubscribers = parentIssue.IssueSentEmails; } else { // Only variants was sent => get current number of subscribers ucGroupSlider.NumberOfSubscribers = GetEmailAddressCount(parentIssue.IssueNewsletterID, parentIssue.IssueSiteID); } } else { ucGroupSlider.NumberOfSubscribers = GetEmailAddressCount(parentIssue.IssueNewsletterID, parentIssue.IssueSiteID); } if (forceReload || !ucGroupSlider.Enabled) { ucGroupSlider.CurrentSize = (abTest != null ? abTest.TestSizePercentage : 10); } ucGroupSlider.ReloadData(forceReload); ucWO_OnChange(this, EventArgs.Empty); }
/// <summary> /// Saves current newsletter settings. /// </summary> public bool SaveIssue() { try { switch (CurrentState) { case STATE_WAITING_TO_SEND_PAGE: case STATE_WAITING_TO_SEND_WIZARD: case STATE_TEST_READY_FOR_SENDING: case STATE_TEST_WAITING_TO_SEL_WINNER: if (abTest == null) { abTest = ABTestInfoProvider.GetABTestInfoForIssue(parentIssue.IssueID); } // Get A/B test settings from controls bool abTestChanged = SaveABTestInfo(abTest); if (abTest == null) { return(false); } if (abTest.TestWinnerOption != ABTestWinnerSelectionEnum.Manual) { // Check minimal time interval if (abTest.TestSelectWinnerAfter < 5) { ErrorMessage = GetString("newsletterissue_send.saveissuewrongwinnerselectioninterval"); return(false); } } // Check if test options has changed if (abTestChanged) { if (abTest.TestWinnerIssueID > 0) { // Options has been changed => reset previously selected winner IssueInfoProvider.DeleteMailoutTask(parentIssue.IssueGUID, parentIssue.IssueSiteID); abTest.TestWinnerIssueID = 0; abTest.TestWinnerSelected = DateTimeHelper.ZERO_TIME; // Hide/reload winner selection in issue mail-out grid ucMailout.ReloadData(false); } IssueInfoProvider.SetIssueInfo(parentIssue); } ABTestInfoProvider.SetABTestInfo(abTest); IssueHelper.EnsureWinnerSelectionTask(abTest, parentIssue, (CurrentState == STATE_TEST_WAITING_TO_SEL_WINNER), ucMailout.HighestMailoutTime); // Update info message for parent control int currentState = GetCurrentState(parentIssue); InfoMessage = GetInfoMessage(currentState, parentIssue, abTest.TestWinnerOption, GetPlannedMailoutTime(ucMailout.HighestMailoutTime)); return(true); case STATE_TEST_FINISHED: ErrorMessage = GetString("newsletterissue_send.saveissuehasbeensent"); break; } } catch (Exception e) { ErrorMessage = e.Message; return(false); } return(true); }
protected object UniGrid_OnExternalDataBound(object sender, string sourceName, object parameter) { DataRowView row = null; if (parameter is DataRowView) { row = (DataRowView)parameter; } int subscriberId = 0; switch (sourceName) { case "name": subscriberId = ValidationHelper.GetInteger(DataHelper.GetDataRowValue(row.Row, "SubscriberID"), 0); string name = null; if (subscriberId == 0) { // Get full name for contact group member (contact) name = ValidationHelper.GetString(DataHelper.GetDataRowValue(row.Row, "SubscriberFullName"), string.Empty); // Return encoded name return(HTMLHelper.HTMLEncode(name)); } else { // Add the field transformation control that handles the translation var tr = new ObjectTransformation("newsletter.subscriber", subscriberId); tr.Transformation = "SubscriberFullName"; return(tr); } case "email": subscriberId = ValidationHelper.GetInteger(DataHelper.GetDataRowValue(row.Row, "SubscriberID"), 0); string email = null; if (subscriberId == 0) { // Get email for contact group member (contact) email = ValidationHelper.GetString(DataHelper.GetDataRowValue(row.Row, "SubscriberEmail"), string.Empty); } else { SubscriberInfo subscriber = SubscriberInfoProvider.GetSubscriberInfo(subscriberId); if (subscriber != null) { if (subscriber.SubscriberType == null) { // Get email for classic subscriber email = subscriber.SubscriberEmail; } else { switch (subscriber.SubscriberType) { case UserInfo.OBJECT_TYPE: UserInfo user = UserInfoProvider.GetUserInfo(subscriber.SubscriberRelatedID); if (user != null) { // Get email for user subscriber email = user.Email; } break; case PredefinedObjectType.CONTACT: DataSet ds = ModuleCommands.OnlineMarketingGetContactForNewsletters(subscriber.SubscriberRelatedID, "ContactEmail"); if (!DataHelper.DataSourceIsEmpty(ds)) { // Get email from contact subscriber email = ValidationHelper.GetString(ds.Tables[0].Rows[0]["ContactEmail"], string.Empty); } break; } } } } if (!string.IsNullOrEmpty(email)) { // Return encoded email email = HTMLHelper.HTMLEncode(email); } return(email); case "variantname": if (!isMainABTestIssue) { return(null); } IssueInfo issue = IssueInfoProvider.GetIssueInfo(ValidationHelper.GetInteger(parameter, 0)); string variantName = null; if (issue != null) { if (!issue.IssueIsVariant) { // Get varinat name from the winner issue if (winnerIssue == null) { ABTestInfo test = ABTestInfoProvider.GetABTestInfoForIssue(issue.IssueID); if (test != null) { // Get A/B test winner variant winnerIssue = IssueInfoProvider.GetIssueInfo(test.TestWinnerIssueID); } } if (winnerIssue != null) { // Get variant name variantName = winnerIssue.IssueVariantName; } } else { // Get variant name variantName = issue.IssueVariantName; } } return(variantName); default: return(parameter); } }
/// <summary> /// Saves current newsletter settings. /// </summary> public bool SaveIssue() { try { switch (CurrentState) { case VariantStatusEnum.WaitingToSend: case VariantStatusEnum.ReadyForSending: case VariantStatusEnum.ReadyForTesting: case VariantStatusEnum.WaitingToSelectWinner: if (mABTest == null) { mABTest = ABTestInfoProvider.GetABTestInfoForIssue(mParentIssue.IssueID); } // Get A/B test settings from controls var abTestChanged = SaveABTestInfo(mABTest); if (mABTest == null) { return(false); } if (mABTest.TestWinnerOption != ABTestWinnerSelectionEnum.Manual) { // Check minimal time interval if (mABTest.TestSelectWinnerAfter < 5) { ErrorMessage = GetString("newsletterissue_send.saveissuewrongwinnerselectioninterval"); return(false); } } // Check if test options has changed if (abTestChanged && mABTest.TestWinnerIssueID > 0) { // Options has been changed => reset previously selected winner NewsletterTasksManager.DeleteMailoutTask(mParentIssue.IssueGUID, mParentIssue.IssueSiteID); mABTest.TestWinnerIssueID = 0; mABTest.TestWinnerSelected = DateTimeHelper.ZERO_TIME; // Hide/reload winner selection in issue mail-out grid ucMailout.ReloadData(false); } ABTestInfo.Provider.Set(mABTest); if (CurrentState == VariantStatusEnum.WaitingToSelectWinner) { NewsletterTasksManager.EnsureWinnerSelectionTask(mABTest, mParentIssue, true, ucMailout.HighestMailoutTime); } // Update info message for parent control var currentState = GetCurrentState(mParentIssue); InfoMessage = GetInfoMessage(currentState, mParentIssue, mABTest.TestWinnerOption); return(true); case VariantStatusEnum.Finished: ErrorMessage = GetString("newsletterissue_send.saveissuehasbeensent"); break; } } catch (Exception e) { ErrorMessage = e.Message; return(false); } return(true); }
/// <summary> // Processes the form - saves the data. /// </summary> private void Process() { // Check manage permissions if (!CheckPermissions("CMS.ABTest", PERMISSION_MANAGE)) { return; } // Validate the form if (Validate()) { bool isNew = false; // Ensure the info object if (AbTestObj == null) { AbTestObj = new ABTestInfo(); if (AliasPath != String.Empty) { AbTestObj.ABTestOriginalPage = AliasPath; } isNew = true; } String dName = txtABTestDisplayName.Text.Trim(); if (AbTestObj.ABTestDisplayName != dName) { ScriptHelper.RefreshTabHeader(Page, null); } // Initialize object String newName = txtABTestName.Text.Trim(); AbTestObj.ABTestDisplayName = dName; AbTestObj.ABTestDescription = txtABTestDescription.Text.Trim(); AbTestObj.ABTestMaxConversions = ValidationHelper.GetInteger(txtABTestMaxConversions.Text.Trim(), 0); AbTestObj.ABTestOpenFrom = dtpABTestOpenFrom.SelectedDateTime; AbTestObj.ABTestOpenTo = dtpABTestOpenTo.SelectedDateTime; AbTestObj.ABTestCulture = ucCultureSelector.Value.ToString(); AbTestObj.ABTestEnabled = chkABTestEnabled.Checked; AbTestObj.ABTestSiteID = CMSContext.CurrentSiteID; // Name has changed. Change analytics statistics data for existing object if ((AbTestObj.ABTestID != 0) && (AbTestObj.ABTestName != newName)) { ABTestInfoProvider.RenameABTestStatistics(AbTestObj.ABTestName, newName, CMSContext.CurrentSiteID); } AbTestObj.ABTestName = newName; // Store conversion type TargetConversionType conversionType = TargetConversionType.Total; if (radAnyVariant.Checked) { conversionType = TargetConversionType.AnyVariant; } AbTestObj.ABTestTargetConversionType = conversionType; if (ShowAliasPath) { AbTestObj.ABTestOriginalPage = ucPath.Value.ToString().Trim(); } // Save object data to database ABTestInfoProvider.SetABTestInfo(AbTestObj); ItemID = AbTestObj.ABTestID; // For new A/B test create default variant if (isNew) { // Create instance of ab variant ABVariantInfo variant = new ABVariantInfo(); // Set properties variant.ABVariantPath = AbTestObj.ABTestOriginalPage; variant.ABVariantTestID = AbTestObj.ABTestID; variant.ABVariantDisplayName = AbTestObj.ABTestDisplayName + " " + GetString("om.variant"); variant.ABVariantName = AbTestObj.ABTestName; variant.ABVariantSiteID = AbTestObj.ABTestSiteID; // Save to the storage ABVariantInfoProvider.SetABVariantInfo(variant); } RaiseOnSaved(); // Set the info message ShowChangesSaved(); } }
protected void Page_Load(object sender, EventArgs e) { PageTitle.TitleText = GetString("newsletter_issue_subscribersclicks.title"); linkId = QueryHelper.GetInteger("linkid", 0); if (linkId == 0) { RequestHelper.EndResponse(); } LinkInfo link = LinkInfoProvider.GetLinkInfo(linkId); EditedObject = link; IssueInfo issue = IssueInfoProvider.GetIssueInfo(link.LinkIssueID); EditedObject = issue; // Prevent accessing issues from sites other than current site if (issue.IssueSiteID != SiteContext.CurrentSiteID) { RedirectToResourceNotAvailableOnSite("Issue with ID " + link.LinkIssueID); } var listingWhereCondition = new WhereCondition().WhereEquals("ClickedLinkNewsletterLinkID", linkId); // Link's issue is the main A/B test issue if (issue.IssueIsABTest && !issue.IssueIsVariant) { // Get A/B test and its winner issue ID ABTestInfo test = ABTestInfoProvider.GetABTestInfoForIssue(issue.IssueID); if (test != null) { // Get ID of the same link from winner issue var winnerLink = LinkInfoProvider.GetLinks() .WhereEquals("LinkIssueID", test.TestWinnerIssueID) .WhereEquals("LinkTarget", link.LinkTarget) .WhereEquals("LinkDescription", link.LinkDescription) .TopN(1) .Column("LinkID") .FirstOrDefault(); if (winnerLink != null) { if (winnerLink.LinkID > 0) { // Add link ID of winner issue link listingWhereCondition.Or(new WhereCondition().WhereEquals("ClickedLinkNewsletterLinkID", winnerLink.LinkID)); } } } } UniGrid.Pager.DefaultPageSize = PAGESIZE; UniGrid.Pager.ShowPageSize = false; UniGrid.FilterLimit = 1; fltOpenedBy.EmailColumn = "ClickedLinkEmail"; // Get click count by email UniGrid.DataSource = ClickedLinkInfoProvider.GetClickedLinks() .Columns( new QueryColumn("ClickedLinkEmail"), new AggregatedColumn(AggregationType.Count, null).As("ClickCount") ) .GroupBy("ClickedLinkEmail") .Where(listingWhereCondition) .And() .Where(fltOpenedBy.WhereCondition) .OrderByDescending("ClickCount") .Result; }
/// <summary> /// Collects data from controls and fills A/B test info. /// </summary> /// <param name="abi">A/B test info</param> private bool SaveABTestInfo(ABTestInfo abi) { if (abi == null) { return false; } bool result = (abi.TestWinnerOption != ucWO.WinnerSelection) || (abi.TestSelectWinnerAfter != ucWO.TimeInterval) || (abi.TestSizePercentage != ucGroupSlider.CurrentSize); switch (Mode) { case SendControlMode.Wizard: case SendControlMode.Send: abi.TestWinnerOption = ucWO.WinnerSelection; abi.TestSelectWinnerAfter = ucWO.TimeInterval; break; } abi.TestSizePercentage = ucGroupSlider.CurrentSize; return result; }
/// <summary> /// Checks whether the form is valid. /// </summary> private bool IsValid() { // If the test is finished, no validation is needed if (TestStatus == ABTestStatusEnum.Finished) { return(true); } // Get page of the test so we can check for collisions string page = QueryHelper.GetString("AliasPath", null); if (String.IsNullOrEmpty(page)) { page = form.GetFieldValue("ABTestOriginalPage").ToString(); } // Validate original page of the test if (!PageExists(page)) { ShowError(GetString("abtesting.testpath.pagenotfound")); return(false); } // Create temporary test used for validation of the new values ABTestInfo updatedTest = new ABTestInfo { ABTestID = ABTest.ABTestID, ABTestOriginalPage = page, ABTestCulture = form.GetFieldValue("ABTestCulture").ToString(), ABTestSiteID = SiteContext.CurrentSiteID, }; updatedTest.ABTestOpenFrom = ValidationHelper.GetDateTime(form.GetFieldValue("ABTestOpenFrom"), DateTimeHelper.ZERO_TIME); // Validate start time if the test is not already running if (TestStatus != ABTestStatusEnum.Running) { if (!ABTestValidator.IsValidStart(updatedTest.ABTestOpenFrom)) { ShowError(GetString("om.wrongtimeinterval")); return(false); } } updatedTest.ABTestOpenTo = ValidationHelper.GetDateTime(form.GetFieldValue("ABTestOpenTo"), DateTimeHelper.ZERO_TIME); // Validate finish time of the test if (!ABTestValidator.IsValidFinish(updatedTest.ABTestOpenFrom, updatedTest.ABTestOpenTo)) { ShowError(GetString("om.wrongtimeinterval")); return(false); } // Find out possible collision - another test running on the same page, culture and at the same time string collidingTestName = ABTestValidator.GetCollidingTestName(updatedTest); if (!String.IsNullOrEmpty(collidingTestName)) { ShowError(String.Format(GetString("om.twotestsonepageerror"), HTMLHelper.HTMLEncode(ResHelper.LocalizeString(collidingTestName)), updatedTest.ABTestOriginalPage)); return(false); } // If we get here, all fields are valid return(true); }
/// <summary> /// Reloads control data. /// </summary> /// <param name="forceReload">Indicates if force reload should be used</param> public override void ReloadData(bool forceReload) { if (StopProcessing && !forceReload) { return; } if (ForceReloadNeeded) { forceReload = true; ForceReloadNeeded = false; } int parentIssueId = 0; parentIssue = IssueInfoProvider.GetOriginalIssue(IssueID); if (parentIssue != null) { parentIssueId = parentIssue.IssueID; } // Get A/B test configuration abTest = ABTestInfoProvider.GetABTestInfoForIssue(parentIssueId); if (abTest == null) { // Ensure A/B test object with default settings abTest = new ABTestInfo() { TestIssueID = parentIssueId, TestSizePercentage = 50, TestWinnerOption = ABTestWinnerSelectionEnum.OpenRate, TestSelectWinnerAfter = 60 }; ABTestInfoProvider.SetABTestInfo(abTest); } CurrentState = GetCurrentState(parentIssue); InitControls(CurrentState, forceReload); ucMailout.ParentIssueID = parentIssueId; ucMailout.ReloadData(forceReload); InfoMessage = GetInfoMessage(CurrentState, parentIssue, (abTest != null ? abTest.TestWinnerOption : ABTestWinnerSelectionEnum.OpenRate), GetPlannedMailoutTime(ucMailout.HighestMailoutTime)); // Init test group slider List <IssueABVariantItem> variants = IssueHelper.GetIssueVariants(parentIssue, null); ucGroupSlider.Variants = variants; bool allVariantsSent = true; if (variants != null) { allVariantsSent = variants.TrueForAll(delegate(IssueABVariantItem item) { return(item.IssueStatus == IssueStatusEnum.Finished); }); } if ((parentIssue.IssueStatus == IssueStatusEnum.Finished) || allVariantsSent) { // Issue was sent long time ago => get number of subscribers from issue properties instead of current number of subscribers int perVariantEmails = 1; if (abTest != null) { perVariantEmails = abTest.TestNumberPerVariantEmails; } ucGroupSlider.NumberOfTestSubscribers = ucGroupSlider.Variants.Count * perVariantEmails; if (parentIssue.IssueStatus == IssueStatusEnum.Finished) { // Issue was sent => get number of subscribers from number of sent issues ucGroupSlider.NumberOfSubscribers = parentIssue.IssueSentEmails; } else { // Only variants was sent => get current number of subscribers ucGroupSlider.NumberOfSubscribers = GetEmailAddressCount(parentIssue.IssueNewsletterID, parentIssue.IssueSiteID); } } else { ucGroupSlider.NumberOfSubscribers = GetEmailAddressCount(parentIssue.IssueNewsletterID, parentIssue.IssueSiteID); } if (forceReload || !ucGroupSlider.Enabled) { ucGroupSlider.CurrentSize = (abTest != null ? abTest.TestSizePercentage : 10); } ucGroupSlider.ReloadData(forceReload); ucWO_OnChange(this, EventArgs.Empty); }
/// <summary> /// Creates new variant and raises "Add" event if specified. /// </summary> /// <param name="name">Name of new variant</param> /// <param name="issueId">ID of source issue on which the new variant will be based</param> private void RaiseOnAddEvent(string name, int issueId) { // Get main issue (original) int currentIssuedId = IssueID; IssueInfo parentIssue = IssueInfoProvider.GetOriginalIssue(currentIssuedId); // Allow modifying issues in idle state only if ((parentIssue == null) || (parentIssue.IssueStatus != IssueStatusEnum.Idle)) { return; } // Get issue content specified by ID (if not found use original) IssueInfo contentIssue = null; if (issueId > 0) { if (issueId == parentIssue.IssueID) { contentIssue = parentIssue; } else { contentIssue = IssueInfoProvider.GetIssueInfo(issueId); } } NewsletterInfo newsletter = NewsletterInfoProvider.GetNewsletterInfo(parentIssue.IssueNewsletterID); // ID of the first child (if new A/B test is being created (i.e. parent and 2 children) int origVariantId = 0; // Check if current issue is variant issue if (!parentIssue.IssueIsABTest) { // Variant issue has not been created yet => create original and 2 child variants parentIssue.IssueIsABTest = true; // Create 1st variant based on parent issue, the 2nd variant will be created as ordinary variant below IssueInfo issueOrigVariant = parentIssue.Clone(true); issueOrigVariant.IssueVariantOfIssueID = parentIssue.IssueID; issueOrigVariant.IssueVariantName = GetString("newsletter.abvariantoriginal"); issueOrigVariant.IssueScheduledTaskID = 0; IssueInfoProvider.SetIssueInfo(issueOrigVariant); // Create scheduled task for variant mail-out and update issue variant issueOrigVariant.IssueScheduledTaskID = CreateScheduledTask(issueOrigVariant); IssueInfoProvider.SetIssueInfo(issueOrigVariant); // Update parent issue IssueInfoProvider.SetIssueInfo(parentIssue); try { ObjectVersionManager.DestroyObjectHistory(parentIssue.ObjectType, parentIssue.IssueID); } catch (Exception ex) { EventLogProvider.LogException("Newsletter-AddVariant", "EXCEPTION", ex); } origVariantId = issueOrigVariant.IssueID; } // Variant issue has been created => create new variant only IssueInfo issueVariant = (contentIssue != null ? contentIssue.Clone(true) : parentIssue.Clone(true)); issueVariant.IssueVariantName = name; issueVariant.IssueVariantOfIssueID = parentIssue.IssueID; // Prepare content with empty regions if empty content will be used string[] regions = null; if ((contentIssue == null) && (newsletter != null)) { EmailTemplateInfo template = EmailTemplateInfoProvider.GetEmailTemplateInfo(newsletter.NewsletterTemplateID); if (template != null) { bool isValidRegionName; List <string> regionNames = new List <string>(); EmailTemplateHelper.ValidateEditableRegions(template.TemplateBody, out isValidRegionName, out isValidRegionName, regionNames); for (int i = regionNames.Count - 1; i >= 0; i--) { regionNames[i] = regionNames[i] + "::"; } regions = regionNames.ToArray(); // Set template ID (i.e. this template with these regions is used for current issue) issueVariant.IssueTemplateID = template.TemplateID; } } issueVariant.IssueText = (contentIssue != null ? contentIssue.IssueText : IssueHelper.GetContentXML(regions)); issueVariant.IssueScheduledTaskID = 0; IssueInfoProvider.SetIssueInfo(issueVariant); // Duplicate attachments and replace old guids with new guids in issue text if current variant issue is based on content of another if (contentIssue != null) { List <Guid> guids = new List <Guid>(); MetaFileInfoProvider.CopyMetaFiles(contentIssue.IssueID, issueVariant.IssueID, (contentIssue.IssueIsVariant ? IssueInfo.OBJECT_TYPE_VARIANT : IssueInfo.OBJECT_TYPE), ObjectAttachmentsCategories.ISSUE, IssueInfo.OBJECT_TYPE_VARIANT, ObjectAttachmentsCategories.ISSUE, guids); if (guids.Count > 0) { for (int i = 0; i < guids.Count; i += 2) { issueVariant.IssueText = LinkConverter.ReplaceInLink(issueVariant.IssueText, guids[i].ToString(), guids[i + 1].ToString()); } } } // Create scheduled task for variant mail-out issueVariant.IssueScheduledTaskID = CreateScheduledTask(issueVariant); // Update issue variant IssueInfoProvider.SetIssueInfo(issueVariant); if (origVariantId > 0) { // New A/B test issue created => create new A/B test info ABTestInfo abi = new ABTestInfo { TestIssueID = parentIssue.IssueID, TestSizePercentage = 50, TestWinnerOption = ABTestWinnerSelectionEnum.OpenRate, TestSelectWinnerAfter = 60 }; ABTestInfoProvider.SetABTestInfo(abi); // Move attachments (meta files) from parent issue to first variant MetaFileInfoProvider.MoveMetaFiles(parentIssue.IssueID, origVariantId, IssueInfo.OBJECT_TYPE, ObjectAttachmentsCategories.ISSUE, IssueInfo.OBJECT_TYPE_VARIANT, ObjectAttachmentsCategories.ISSUE); MetaFileInfoProvider.MoveMetaFiles(parentIssue.IssueID, origVariantId, IssueInfo.OBJECT_TYPE_VARIANT, ObjectAttachmentsCategories.ISSUE, IssueInfo.OBJECT_TYPE_VARIANT, ObjectAttachmentsCategories.ISSUE); } if (OnAddVariant != null) { VariantEventArgs args = new VariantEventArgs(name, issueVariant.IssueID); OnAddVariant(this, args); } }
protected object UniGrid_OnExternalDataBound(object sender, string sourceName, object parameter) { switch (sourceName) { case "clickrate": case "uniqueclicks": case "totalclicks": { DataRowView row = (DataRowView)parameter; int value = 0; if (sourceName.EqualsCSafe("totalclicks", true)) { // Get total clicks value value = ValidationHelper.GetInteger(DataHelper.GetDataRowValue(row.Row, "TotalClicks"), 0); } else { // Get unique clicks value value = ValidationHelper.GetInteger(DataHelper.GetDataRowValue(row.Row, "UniqueClicks"), 0); } // If A/B test links are shown... if (isMainABTestIssue) { // Get selected issue (main or variant) IssueInfo issue = IssueInfoProvider.GetIssueInfo(issueId); if ((issue != null) && (!issue.IssueIsVariant)) { // Get current link target and description string linkTarget = ValidationHelper.GetString(DataHelper.GetDataRowValue(row.Row, "LinkTarget"), string.Empty); string linkDescription = ValidationHelper.GetString(DataHelper.GetDataRowValue(row.Row, "LinkDescription"), string.Empty); // If the issue is main issue add winner variant statistics if (DataHelper.DataSourceIsEmpty(winnerData) && (UniGrid.InfoObject != null)) { int winnerIssueId = 0; ABTestInfo test = ABTestInfoProvider.GetABTestInfoForIssue(issue.IssueID); if (test != null) { // Get winner variant issue ID winnerIssueId = test.TestWinnerIssueID; } winnerData = UniGrid.InfoObject.GetData(null, "IssueID=" + winnerIssueId, null, -1, "LinkTarget,LinkDescription,UniqueClicks,TotalClicks", false); } if (!DataHelper.DataSourceIsEmpty(winnerData)) { // Select data with matching link target and description DataRow[] selectedRows = winnerData.Tables[0].Select(string.Format("LinkTarget='{0}' AND LinkDescription='{1}'", linkTarget, linkDescription)); if ((selectedRows != null) && (selectedRows.Length > 0)) { if (sourceName.EqualsCSafe("totalclicks", true)) { // Get total clicks value value += ValidationHelper.GetInteger(DataHelper.GetDataRowValue(selectedRows[0], "TotalClicks"), 0); // Store if grid action should be visible (hide it if total clicks is lower than 0) showGridAction.Add(ValidationHelper.GetInteger(DataHelper.GetDataRowValue(row.Row, "LinkID"), 0), (value > 0)); } else { // Get unique clicks value value += ValidationHelper.GetInteger(DataHelper.GetDataRowValue(selectedRows[0], "UniqueClicks"), 0); } } } } } if (sourceName.EqualsCSafe("clickrate", true)) { // Return formated click rate return(string.Format("{0:F0}", (ValidationHelper.GetDouble(value, 0) / sentEmails) * 100)); } else { // Return unique or total clicks return(value); } } case "linktarget": return(string.Format(@"<a href=""#"" onclick=""OpenTarget('{0}')"">{1}</a>", parameter, HTMLHelper.HTMLEncode(TextHelper.LimitLength(parameter.ToString(), 50)))); case "linktargettooltip": return(HTMLHelper.HTMLEncode(parameter.ToString())); case "linkdescription": return(HTMLHelper.HTMLEncode(TextHelper.LimitLength(parameter.ToString(), 25))); case "linkdescriptiontooltip": return(HTMLHelper.HTMLEncode(parameter.ToString())); case "view": if (sender is ImageButton) { ImageButton imageButton = sender as ImageButton; // Register for prerender event to hide actions for links without any clicks imageButton.PreRender += ActionButton_PreRender; } return(sender); case "deleteoutdated": if (sender is ImageButton) { ImageButton imageButton = sender as ImageButton; GridViewRow gvr = parameter as GridViewRow; if (gvr != null) { DataRowView drv = gvr.DataItem as DataRowView; if (drv != null) { bool isOutdated = ValidationHelper.GetBoolean(drv["LinkOutdated"], false); if (!isOutdated) { // Hide delete button for links that are not outdated imageButton.Style.Add(HtmlTextWriterStyle.Display, "none"); } } } } return(sender); default: return(parameter); } }
/// <summary> /// Saves current newsletter settings. /// </summary> public bool SaveIssue() { try { switch (CurrentState) { case STATE_WAITING_TO_SEND_PAGE: case STATE_WAITING_TO_SEND_WIZARD: case STATE_TEST_READY_FOR_SENDING: case STATE_TEST_WAITING_TO_SEL_WINNER: if (abTest == null) { abTest = ABTestInfoProvider.GetABTestInfoForIssue(parentIssue.IssueID); } // Get A/B test settings from controls bool abTestChanged = SaveABTestInfo(abTest); if (abTest == null) { return false; } if (abTest.TestWinnerOption != ABTestWinnerSelectionEnum.Manual) { // Check minimal time interval if (abTest.TestSelectWinnerAfter < 5) { ErrorMessage = GetString("newsletterissue_send.saveissuewrongwinnerselectioninterval"); return false; } } // Check if test options has changed if (abTestChanged) { if (abTest.TestWinnerIssueID > 0) { // Options has been changed => reset previously selected winner IssueInfoProvider.DeleteMailoutTask(parentIssue.IssueGUID, parentIssue.IssueSiteID); abTest.TestWinnerIssueID = 0; abTest.TestWinnerSelected = DateTimeHelper.ZERO_TIME; // Hide/reload winner selection in issue mail-out grid ucMailout.ReloadData(false); } IssueInfoProvider.SetIssueInfo(parentIssue); } ABTestInfoProvider.SetABTestInfo(abTest); IssueHelper.EnsureWinnerSelectionTask(abTest, parentIssue, (CurrentState == STATE_TEST_WAITING_TO_SEL_WINNER), ucMailout.HighestMailoutTime); // Update info message for parent control int currentState = GetCurrentState(parentIssue); InfoMessage = GetInfoMessage(currentState, parentIssue, abTest.TestWinnerOption, GetPlannedMailoutTime(ucMailout.HighestMailoutTime)); return true; case STATE_TEST_FINISHED: ErrorMessage = GetString("newsletterissue_send.saveissuehasbeensent"); break; } } catch (Exception e) { ErrorMessage = e.Message; return false; } return true; }
/// <summary> /// Creates document. /// </summary> /// <param name="createAnother">If false user will be redirected to created document</param> public int Save(bool createAnother) { // Validate input data string message = new Validator().NotEmpty(txtDocumentName.Text.Trim(), GetString("om.enterdocumentname")).Result; if (message == String.Empty) { if (node != null) { // Select parent node TreeNode parent = tree.SelectSingleNode(CMSContext.CurrentSiteName, ucPath.Value.ToString(), TreeProvider.ALL_CULTURES, false, null, false); if (parent != null) { // Check security if (!CMSContext.CurrentUser.IsAuthorizedToCreateNewDocument(parent.NodeID, node.NodeClassName)) { RedirectToAccessDenied(GetString("cmsdesk.notauthorizedtocreatedocument")); return(0); } TreeNode newNode = ProcessAction(node, parent, "copynode", false, true, true); if (newNode != null) { newNode.SetValue("DocumentMenuItemHideInNavigation", !chkShowInNavigation.Checked); newNode.SetValue("DocumentShowInSiteMap", chkShowInSiteMap.Checked); newNode.SetValue("DocumentSearchExcluded", chkExcludeFromSearch.Checked); // Limit length to 100 characters string nodeAlias = TextHelper.LimitLength(txtDocumentName.Text.Trim(), 100, String.Empty); newNode.NodeAlias = nodeAlias; newNode.DocumentName = nodeAlias; // Update menu item name newNode.SetDocumentNameSource(nodeAlias); newNode.Update(); // If ABTest selected - create new variant int abTestID = ValidationHelper.GetInteger(ucABTestSelector.Value, 0); if (abTestID != 0) { ABTestInfo abTest = ABTestInfoProvider.GetABTestInfo(abTestID); if (abTest != null) { string defaultCodeName = TextHelper.LimitLength(ValidationHelper.GetCodeName(newNode.GetDocumentName()), 45, String.Empty); string codeName = defaultCodeName; ABVariantInfo info = ABVariantInfoProvider.GetABVariantInfo(codeName, abTest.ABTestName, CMSContext.CurrentSiteName); // Find non existing variant code name int index = 0; while (info != null) { index++; codeName = defaultCodeName + "-" + index; info = ABVariantInfoProvider.GetABVariantInfo(codeName, abTest.ABTestName, CMSContext.CurrentSiteName); } // Save AB Variant ABVariantInfo variantInfo = new ABVariantInfo(); variantInfo.ABVariantTestID = abTestID; variantInfo.ABVariantPath = newNode.NodeAliasPath; variantInfo.ABVariantName = codeName; variantInfo.ABVariantDisplayName = newNode.GetDocumentName(); variantInfo.ABVariantSiteID = CMSContext.CurrentSiteID; ABVariantInfoProvider.SetABVariantInfo(variantInfo); } } // Get the page mode if (CMSContext.ViewMode != ViewModeEnum.EditLive) { CMSContext.ViewMode = ViewModeEnum.EditForm; } txtDocumentName.Text = String.Empty; return(newNode.NodeID); } } else { message = GetString("om.pathdoesnotexists"); } } } if (message != String.Empty) { lblError.Visible = true; lblError.Text = message; } return(0); }