SharePoint Custom Lists – Living with Living the Dream


Creating lists programmatically can be useful in many scenarios.  The scenario we run into most often are lists for waterfall projects that aren’t well thought out.  Need to define 30 e-mail templates?  Forgot a column?  Want to easily reset content to a base state?  Dealing with these scenarios by deploying list definitions/instances in a package rather than content restores can restore sanity, but does offer some drawbacks.  Namely – custom security and content query web parts.

Custom Security

If you have lists that require anonymous access, different contributor / approver permissions than the web provides by default, this can become a pain.  As every time you delete a list, you lose its permissions.  Updating permissions can be fairly simple, and I have created a utility for doing so:

        public static void SetCustomPermission(UserSecurityGroup secuirtyGroup, SPRoleType permissionRoleType, IEnumerable lists)
        {
            SPSecurity.RunWithElevatedPrivileges(delegate
            {
                using (var elevatedSite = new SPSite(SPContext.Current.Site.ID))
                {
                    var elevatedRootWeb = elevatedSite.RootWeb;

                    var group = elevatedRootWeb.SiteGroups[secuirtyGroup.GetStringValue()];
                    var roleDefination = elevatedRootWeb.RoleDefinitions.GetByType(permissionRoleType);
                    var roleAssignment = new SPRoleAssignment(group);
                    roleAssignment.RoleDefinitionBindings.Add(roleDefination);

                    foreach (var listName in lists)
                    {
                        var list = elevatedRootWeb.Lists[listName.GetStringValue()];
                        list.BreakRoleInheritance(true);
                        list.RoleAssignments.Add(roleAssignment);
                        list.Update();
                    }

                    elevatedRootWeb.Update();
                }
            });
        }

The UserSecurityGroup enumeration simply contains the SharePoint group names you are assigning permissions for:

 public enum UserSecurityGroup
    {
        User,   
     
        Contributor,   
     
        [StringValue("Portal Owners")]
        PortalOwners,
    }

This, of course, isn’t necessary, but does provide a bit of sanity.  I typically use this on feature activating:

        private readonly ListNames[] portalOwner_ContentContribution = new[]
                                        {
                                            ListNames.SystemTooltipsAndMessages,
                                            ListNames.SystemErrorMessages,
                                            ListNames.GlobalEmailTemplates,
                                            ListNames.SidebarNavigationLinks,
                                            ListNames.SystemPageContent
                                        };
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
SharePointContentPermissionsUtility.SetCustomPermission(UserSecurityGroup.PortalOwners, SPRoleType.Contributor, this.portalOwner_ContentContribution);
        }

If you need to provide anonymous access to lists, I’ve created the following function:

        public static void ProvideAnonymousAccess(IEnumerable lists)
        {
            SPSecurity.RunWithElevatedPrivileges(delegate
            {
                using (var elevatedSite = new SPSite(SPContext.Current.Site.ID))
                {
                    var elevatedRootWeb = elevatedSite.RootWeb;
                    foreach (var listName in lists)
                    {
                        var list = elevatedRootWeb.Lists[listName.GetStringValue()];
                        list.BreakRoleInheritance(true);
                        list.AllowEveryoneViewItems = true;
                        if ((list.AnonymousPermMask64 & SPBasePermissions.ViewListItems) != SPBasePermissions.ViewListItems)
                        {
                            list.AnonymousPermMask64 = list.AnonymousPermMask64 | SPBasePermissions.ViewListItems;
                        }

                        list.Update();
                    }

                    elevatedRootWeb.Update();
                }
            });
        }

And then use it as such (once again, on FeatureActivating).

        private readonly ListNames[] anonymousAccess_lists = new[]
                                        {
                                            ListNames.HomePageRotatorContent,
                                            ListNames.SystemPageContent
                                        };

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
             SharePointContentPermissionsUtility.ProvideAnonymousAccess(this.anonymousAccess_lists);
        }

If more fine-grain permission updates are necessary, these functions can be updated to act on specific ListItems as well.  I, fortunately, have not had to go that far yet.

Content Query Web Parts

Content Query Web Parts (CQWP) wreck the party in a funny way.  Opening a page with a CQWP referencing one of your newly refreshed lists will display nothing.  Editing the page will reveal the CQWP couldn’t run successfully.  Open the CQWP and save the page?  Everything works. Ugh.

Even though when configuring a CQWP a user only selects a source List by name, the List GUID is stored and used.  Deleting and recreating the list changes the GUID.  Try hardcoding a GUID, and SharePoint will laugh at your efforts and greet you with a failed deployment.  So what to do?  The best medicine I’ve found is to traverse your publishing website, and update the GUIDs: 

        public static void UpdateContentQueryWebParts(SPSite site)
        {
            SPSecurity.RunWithElevatedPrivileges(
                delegate
                    {
                        using (var elevatedSite = new SPSite(site.ID))
                        {
                            foreach (SPWeb web in elevatedSite.AllWebs)
                            {
                                if (PublishingWeb.IsPublishingWeb(web))
                                {
                                    var pubWeb = PublishingWeb.GetPublishingWeb(web);
                                    var pages = pubWeb.PagesList;
                                    foreach (SPListItem item in pages.Items)
                                    {
                                        var changesMade = false;
                                        var manager = item.File.GetLimitedWebPartManager(PersonalizationScope.Shared);
                                        var enumerator = manager.WebParts.GetEnumerator();

                                        var webFile = manager.Web.GetFile(item.File.UniqueId);

                                        while (enumerator.MoveNext())
                                        {
                                            var webPart = enumerator.Current as ContentByQueryWebPart;
                                            if (webPart == null)
                                            {
                                                continue;
                                            }

                                            var list = web.Lists.TryGetList(webPart.ListName);
                                            if (list == null)
                                            {
                                                list = elevatedSite.RootWeb.Lists.TryGetList(webPart.ListName);
                                                if (list == null)
                                                {
                                                    continue;
                                                }
                                            }

                                            if (webPart.ListGuid == list.ID.ToString())
                                            {
                                                continue;
                                            }


                                            if (!changesMade && webPart.ListGuid != list.ID.ToString())
                                            {
                                                try
                                                {
                                                    if (webFile.Level == SPFileLevel.Checkout)
                                                    {
                                                        webFile.UndoCheckOut();
                                                    }

                                                    webFile.CheckOut();
                                                    changesMade = true;
                                                }
                                                catch (Exception)
                                                {
                                                    continue;
                                                }
                                            }

                                            webPart.ListGuid = list.ID.ToString();
                                            manager.SaveChanges(webPart);
                                        }

                                        if (changesMade)
                                        {
                                            webFile.CheckIn("Updated ContentQuery WebPart");
                                            webFile.Publish("Updated ContentQuery WebPart");
                                            webFile.Approve("Updated ContentQuery WebPart");
                                        }

                                        manager.Web.Dispose();
                                    }
                                }
                            }
                        }
                    });
        }

A note of caution with the above code:  Any jokes that are checked in and  not published will suddenly be published with running this code.  Any unchecked in work will be discarded.

Happy Coding!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s