Sitecore poll module sample code - sitecore

I installed and configured the Poll Module to work fine. The website I am working on will have a Poll instance on a page either as a left rail or a right rail item. The Polls would be setup in a separate folder. On the page item there will be a multilist field which will point to the Polls folder and the user can select whichever poll they choose to. The folder will also contain different sublayouts which will could be selected to be displayed on the rail. I have some custom code which will look at the above mentioned multilist field and show these rail items.
I don't know how to display a Poll programmatically. I haven't found any code samples and also not sure where to set the sublayout. Should I set it on the Poll template itself and then let use code to display it? How can I achieve this in code? Any code samples would be helpful.

Hoping that you will this time accept the answer, I wrote the following for you (based on the OMS Poll module:
Read out the field on your item:
Sitecore.Data.Fields.ReferenceField selectedPoll = (Sitecore.Data.Fields.ReferenceField)Sitecore.Context.Item.Fields["Poll"];
Get the pollItem:
if (selectedPoll.TargetItem != null)
{
Item pollItem = selectedPoll.TargetItem;
if (pollItem != null)
{
Check if the poll is opened or closed and place:
Sitecore.Data.Fields.CheckboxField pollClosed = (Sitecore.Data.Fields.CheckboxField)pollItem.Fields["Closed"];
if (pollClosed.Checked == false)
{
// Set the header of the snippetBlock
ltPollHeader.Text = pollItem.Name;
PollVotingSublayout pollSublayout = (PollVotingSublayout)LoadControl("/sitecore modules/Shell/Poll Module/Controls/PollVotingSublayout.ascx");
pollSublayout.Attributes.Add("sc_parameters", "PollPath=" + pollItem.Paths.FullPath);
pollSublayout.CurrentPoll = (PollItem)pollItem;
this.pollRegion.Controls.Add(pollSublayout);
phPollSnippet.Visible = true;
int blockPos = 0;
if (snippetField != null)
{
if (snippetField.GetItems().Any())
{
blockPos = 1;
}
}
string cssClass = String.Empty;
if (blockPos == 0)
{
cssClass = "snippetColHomeFirst";
}
this.SetClass("snippetColHome", cssClass);
}
Hope that you can make up something using this snippets. Good luck!

There should be a user account called "poll" on the sitecore domain. This account is normally used internal by the poll. In the comment of this account is stated: "Please do not remove this account". the account should have the Sitecore Minimal Page Editor role. I don't know the poll user credentials, but you might find that by either using reflector or opening cs files that you can get by downloading the source.

Related

How to tell if the user already rated my UWP app?

Windows 10 Store UWP apps can use StoreContext.RequestRateAndReviewAppAsync function, or simply a URL like this ms-windows-store://review/?ProductId=9WZDNCRFHVJL, to display a user rating window for the app:
I prefer the URL method since I can simply invoke it via ShellExecute method.
But my question is how do I find out if the user had already rated my app, so that I don't display that rating window again?
This is unfortunately not possible, but there is probably a good reason for it - if developers were able to check this programmatically, they could "cheat the system" by giving users who rated some bonuses/perks for reviewing the app.
Currently there is no such api can directly tell if the user already rated the UWP app, but you could use roaming data in your app which keeps your app's app data in sync across multiple devices.
If the user has rated your app, you can set "Yes" in the RoamingSettings, if the value from RoamingSettings is "No", you can display that rating window again. You could determine whether the rating is successful, e.g. in StoreContext.RequestRateAndReviewAppAsync method, the ExtendedJsonData property of the StoreRateAndReviewResult class contains a JSON-formatted string that indicates whether the rating request was successful. By ExtendedJsonData property, you can know if the rating is successful and then set the value to "Yes" in the RoamingSettings.
private async void Button_Click(object sender, RoutedEventArgs e)
{
ApplicationDataContainer RatingSettings = ApplicationData.Current.RoamingSettings;
//initialization
if (RatingSettings.Values["isRated"] == null)
{
RatingSettings.Values["isRated"] = "No";
}
var isRatedStr = RatingSettings.Values["isRated"].ToString();
if (isRatedStr == "No")
{
//display the rate windows
if (//if rated successfully)
{
RatingSettings.Values["isRated"] = "Yes";
}
}
}
Or you can use the Get app ratings and Get app reviews methods in the Store analytics API to programmatically retrieve the ratings and reviews from your customers in JSON format. For more details, you can refer to this document.

Enrolling Anonymous Users in Engagement Plans

I know that it is possible to enroll users in an engagement plan from with Sitecore by adding them to a specific state in the plan when they visit a campaign URL, adding them when they submit a Web Forms for Marketers Form, and manually adding them in the Supervisor interface.
Additionally, I know that you can use the API to add a user as described here:
http://briancaos.wordpress.com/2013/06/03/programming-for-sitecore-dms-engagement-plans/
However, that method requires a username.
I would like to enroll anonymous users in an engagement plan when they visit any page represented by a particular template in Sitecore (ie, page from the Product template). Is this possible using the API?
To expand on my above comment, and to supplement your own answer, here's a processor that you could add to the after the ItemResolver in the httpRequestBegin pipeline that would achieve the desired result. It is a very basic version that you could embellish as you see fit
class CampaignRedirect
{
public void Process(HttpRequestArgs args)
{
var request = HttpContext.Current.Request;
// must not already have the querystring in the URL
if(request.QueryString["sc_camp"] != null &&
request.QueryString["sc_camp"] != "XXXXXXXX")
return;
// must have a context item
if(Sitecore.Context.Item == null)
return;
var item = Sitecore.Context.Item;
// must be the right template
if(item.TemplateID.ToString() != "{XXXXXXXXX-XXXX-XXXXXX}")
return;
var basicUrl = LinkManager.GetItemUrl(item);
var response = HttpContext.Current.Response;
response.Redirect(basicUrl + "?sc_camp=XXXXXXX");
}
}
If you're not familiar with adding processors, take a look here.
Per Sitecore support, this is not currently possible. However, I was able to achieve what I wanted by adding a jQuery AJAX call to the campaign URL to the sublayout used by the page type in question. Naturally this only works for clients with JS enabled, but for my purposes, that is not an issue.
<script type="text/javascript">$(function() { $.get('/?sc_camp=[campaignid]'); });</script>
Edited 2014-05-19
I found a way to do this via the Sitecore API. This is rough and needs to check for null values, exceptions, etc., but it does work:
string cookieVal = Request.Cookies["SC_ANALYTICS_GLOBAL_COOKIE"].Value;
List<Guid> guids = new List<Guid>() {
new Guid(cookieVal)
};
Guid automationStateId = new Guid("{24963AE9-1C8C-4E18-8EEE-01BC249D1F1B}");
Guid automationId = Sitecore.Context.Database.GetItem(new Sitecore.Data.ID(automationStateId)).ParentID.ToGuid();
Sitecore.Analytics.Automation.Data.AutomationManager.Provider.CreateAutomationStatesFromBulk(guids, automationId, automationStateId);

Search Dialogs in Epicor

Hopefully someone here is familiar with creating customizations in Epicor 9. I've posted this to the Epicor forums as well, but unfortunately that forum seems pretty dead. Any help I can get would be much appreciated.
I've created a customization on the Order Entry form to display and store some extra information about our orders. One such field is the architect on the job. We store the architects in the customer table using a GroupCode of AR to distinguish them from regular customers. I have successfully added a button that launches a customer search dialog and filters the results to only display the architects (those with GroupCode AR). Here's where the problems come in. I have two questions:
1: On the customer search, there is a customer type field that defaults to a value of Customer. Other choices are < all>, Suspect, or Prospect. How can I make the search form default to < all>?
2: How do I take the architect (customer) I select through the search dialog and populate its CustID into the ShortChar01 field on my Order Entry customization? Here's the code I have:
private void SearchOnCustomerAdapterShowDialog()
{
// Wizard Generated Search Method
// You will need to call this method from another method in custom code
// For example, [Form]_Load or [Button]_Click
bool recSelected;
//string whereClause = string.Empty;
string whereClause = "GroupCode = 'AR'";
System.Data.DataSet dsCustomerAdapter = Epicor.Mfg.UI.FormFunctions.SearchFunctions.listLookup(this.oTrans, "CustomerAdapter", out recSelected, true, whereClause);
if (recSelected)
{
System.Data.DataRow adapterRow = dsCustomerAdapter.Tables[0].Rows[0];
// Map Search Fields to Application Fields
EpiDataView edvOrderHed = ((EpiDataView)(this.oTrans.EpiDataViews["OrderHed"]));
System.Data.DataRow edvOrderHedRow = edvOrderHed.CurrentDataRow;
if ((edvOrderHedRow != null))
{
edvOrderHedRow.BeginEdit();
edvOrderHedRow["ShortChar01"] = adapterRow["CustID"];
edvOrderHedRow.EndEdit();
}
}
}
When I select a record and click OK, I get an unhandled exception.
I think the problem you are/were having is that you aren't adding the CustNum to the Sales Order first. In my mind I would do it this way first, but there is might be ChangeCustomer BO method in oTrans that you could call to make sure everything defaults correct.
EpiDataView edvOrderHed = ((EpiDataView)(this.oTrans.EpiDataViews["OrderHed"]));
if (edvOrderHed.HasRow)
{
edvOrderHed[edvOrderHed.Row].BeginEdit();
edvOrderHed[edvOrderHed.Row]["CustNum"] = adapterRow["CustNum"];
edvOrderHed[edvOrderHed.Row]["ShortChar01"] = adapterRow["CustID"];
edvOrderHed[edvOrderHed.Row].EndEdit();
}
Hope that is helpful, even if late.

Avoiding 100 item limit in the Media Library

We have a project for which we are storing user profile photos in Sitecore. Our user base is going to be integrated with LDAP (meaning that we will have tens of thousands of users, if not more), and profiles will be created the first time a user logs in. Users will be able to change their profile photos later, and we have a customized Sitecore Profile, which has a property to store the ID of the profile photo media item.
What I am trying to do is figure out a way to avoid breaking the 100 item limit and store the photos in the Sitecore Media Library. We do not want to use item buckets, and we want to leverage Sitecore caching, so storing the images externally is out. I was thinking about a ten-level deep folder structure based on the username, but that is a bit dirty.
Does anyone have any suggestions that might help?
Thank you, in advance.
Sitecore 6.6
Avoiding breaking the 100 children limit is a very good practice and you should follow this for sure.
To achieve this in your scenario you definitely need some kind of folder structure. Creating such a kind of structure is not fun. You can automate it by adding you event handler to item:created event and move the newly created item automatically.
I've written quick code that should check if the current folder contains max 50 items and if not it tries to create additional folders with a single char as a name recursively and move the item to the folder.
You wrote that you're storing reference as ID so moving the item will not break reference.
Please have in my that I haven't tested the code so it might need tweaking.
<event name="item:created">
<handler type="My.Assembly.Namespace.ProfilePhotoHandler, My.Assembly" method="OnItemCreated" />
</event>
protected void OnItemCreated(object sender, EventArgs args)
{
ItemCreatedEventArgs eventArgs = Event.ExtractParameter(args, 0) as ItemCreatedEventArgs;
if (eventArgs == null || eventArgs.Item == null)
return;
Item item = eventArgs.Item;
if (item == null
|| !item.Paths.IsMediaItem
|| !item.Paths.FullPath.Contains("/profile-images/")
|| item.TemplateID.ToString() == "{FE5DD826-48C6-436D-B87A-7C4210C7413B}")
// we want to move only media items in profile-images and not media folders
return;
string guid = item.ID.ToShortID().ToString();
MoveItemToProperDirectory(guid, item, item.Parent, 0);
}
private void MoveItemToProperDirectory(string guid, Item item, Item folder, int level)
{
if (folder.Children.Count < 1)
{
if (item.Parent.ID != folder.ID)
{
item.MoveTo(folder);
}
return;
}
using (new SecurityDisabler())
{
// take next letter from the hash or random char if the hash is too short
string newSubfolderName = (level < guid.Length)
? guid[level].ToString()
: ('a' + new Random((int)DateTime.Now.Ticks).Next(24)).ToString();
Item subfolder = folder.Children.FirstOrDefault(c => c.Name == newSubfolderName);
if (subfolder == null)
{
// create new Media Folder and move the item there
subfolder = folder.Add(newSubfolderName, new TemplateID(ID.Parse("{FE5DD826-48C6-436D-B87A-7C4210C7413B}")));
}
MoveItemToProperDirectory(guid, item, subfolder, level + 1);
}
}
If somehow an update is not an option, you could consider the following:
The images are not used by content editors, thus from the content editor, the items are not used.
This makes it possible to hide the node that contains the images, just like the buckets do.
Combining this with a folder structure (created during import, or in the handles) makes a good solution.

EventReceiver not Firing on SharePoint List

I am trying to create an EventReceiver for a blog site (for the Posts list) and am having some trouble getting it working. I want to change the Created By column to Anonymous. Basically I have this whole thing working in a console application, however, that will only change the Created By column names when the console application is executed.
I need it to change the Created By whenever a new item is added to the list. My code is below....how do I modify this to use in an EventReceiver project??? Since I already tell the EventReceiver project the URL I want the EventReceiver attached to, I'm not sure what I can remove from this code, right now it just doesn't do anything, no error and no changing of the Created By column when I debug.
using (SPSite site = new SPSite("http://test-sharepoint/subsite/"))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["Posts"];
SPListItemCollection listItemCollection = list.Items;
foreach (SPListItem listItem in listItemCollection)
{
SPFieldUserValue userName = new SPFieldUserValue(web, 22, "Anonymous");
listItem["Author"] = userName;
listItem["Editor"] = userName;
listItem.Update();
}
web.Update();
}
}
EDIT: Code is in ItemAdded method
EDIT #2: This is trying the same code except without the loop and using properties.ListItem, this was my attempt in a Event Recevier project but no luck. It just doesn't change the Created By field, or any field for that matter (I tried the Title as well)
SPSite site = new SPSite("http://test-sharepoint/subsite/");
SPWeb web = site.OpenWeb();
SPFieldUserValue userName = new SPFieldUserValue(web, 22, "Anonymous");
properties.ListItem["Author"] = userName;
properties.ListItem["Editor"] = userName;
properties.ListItem.Update();
*Also from my understanding the SPFieldUserValue will grab either a User or a SharePoint User Group (Permissions) so in my code, the 22 grabs the SharePoint User Group that I want and "Anonymous" is the user from that group...
EDIT #3: More progress, this code works without issues for a list, however, not for the Posts or Comments lists, for those it does not change the Created By field. Could it be because of the approve/reject for all items??? Whether approved orpending it still does not show annonymous, BUT like I mentioned, it works fine in a different list.
public override void ItemAdded(SPItemEventProperties properties)
{
base.ItemAdded(properties);
SPSite site = new SPSite("http://test-sharepoint/hr/blog/"); //SPContext.Current.Site;
SPWeb web = site.OpenWeb();
SPFieldUserValue userName = new SPFieldUserValue(web,22,"Anonymous");
SPListItem currentItem = properties.ListItem;
//currentItem["Title"] = userName; //DateTime.Now.ToString();
currentItem["Author"] = userName;
currentItem["Editor"] = userName;
currentItem.SystemUpdate();
}
**EDIT #4: Alright I found my issue, when creating the project I chose Custom List as my list to attach to but I needed to choose Posts or Comments and now the above code works!!!
But now I have another problem, all posts on the blog are first submitted for approval...and due to this the event receiver doesn't seem to work for users other than the admin. It works fine for the admin account where I can just directly publish a post or comment but for a user with Contribute permissions whose posts are submitted for approval still shows their name on the Manage Posts page...what could I do about this? Any ideas?**
The code that works:
public override void ItemAdded(SPItemEventProperties properties)
{
base.ItemAdded(properties);
SPSite site = new SPSite("http://test-sharepoint/hr/blog/"); //SPContext.Current.Site;
SPWeb web = site.OpenWeb();
SPFieldUserValue userName = new SPFieldUserValue(web, 23, "Anonymous");
SPListItem currentItem = properties.ListItem;
currentItem["Author"] = userName;
currentItem["Editor"] = userName;
currentItem.SystemUpdate();
}
In response to edit #4, when working with SharePoint, if code works when executed by the administrator account, but does not work when executed by a "normal" account, permissions are likely to blame.
See the answer to the question SharePoint/WSS: Modify “created by” field? for an example of an SPItemEventReceiver that modifies the Author field.
Note: Many SharePoint developers recommend against the use of RunWithElevatedPrivileges and suggest using impersonation instead. See my answer to the question In which situation use SPSecurity.RunWithElevatedPrivileges with superusertoken? for more details.