Monday, October 22, 2012

Finding site column used anywhere in your web application

Little powershell script to find out where your fields are currently being used in the web app

$solutionWebApplication = "http://yourSPurl/"
$fieldTitle = "ActiveConfig"    #DisplayName
$fieldGroup = "Custom Columns"
$spAssigment = Start-SPAssignment    #Use to dispose SPWeb safely
$spWeb = Get-SPWeb $solutionWebApplication -AssignmentCollection $spAssignment     #Get SPWeb Instance
foreach ($field in $web.AvailableFields)
{
 if($field.Group -eq $fieldGroup -and $field.Title -eq $fieldTitle)
 {
  $field.ListsFieldUsedIn() | ForEach-Object {
   $web = $site.AllWebs[$_.WebID]
   $list = $web.Lists[$_.ListID]
   Write-Host "Web:" $web.Title " | List:" $list.Title " | ListUrl:" $list.RootFolder.Url " | StaticName:" $field.StaticName " | FieldID:" $field.ID
  }
 }
}

Tuesday, October 16, 2012

Finding site column used in content type by querying content db

Exception calling "Delete" with "0" argument(s): "Site columns which are included in content types or on lists cannot be deleted. Please remove all instances of this site column pri
or to deleting it."


ughh..

there are myriad approaches to hunt down that damn column, for example by using powershell. here is an alternative, directly querying the content db


SELECT
     ct.ContentTypeId            [ContentType ID]
,    Definition                  [ContentType Definition]    
,    ct.DeleteTransactionId      [ContentType DeleteTransaction]
,    ctu.ListId                  [List GUID using CT]
,    l.tp_Created                [List Creation Date]
,    tp_DeleteTransactionId      [List DeleteTransaction]
,    tp_FeatureId                [Feature GUID]
FROM
     ContentTypeUsage             ctu
     INNER JOIN dbo.Webs          w  ON ctu.WebId         = w.Id
     INNER JOIN dbo.AllLists      l  ON ctu.ListId        = l.tp_ID
     INNER JOIN dbo.ContentTypes  ct ON ct.ContentTypeId  = ctu.ContentTypeId
WHERE
     ct.Definition LIKE '%your column%'     

Friday, August 17, 2012

Splitting key-value string using LINQ

Time has come to get down-and-dirty with LINQ! For an app i'm building, i need to store an array of key/value pairs in a single string. It consists of an ID and a folder path, which are separated by use of a semicolon delimiter. The actual pairs are then separated using a pipe. Here is an example:



string folders = @"32;c:\|48;c:\code|52;c:\program files|";

I created the following method that returns a Dictionary object:



        public static Dictionary<int, string> GetFolders(string folders)
        {
            string[] x = folders.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); // first retrieve a string array of all the pairs

            return x.ToDictionary(y => Convert.ToInt32(y.Split(';')[0]), y => y.Split(';')[1]); // second stage of splitting
        }

Here's a full working console example:



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string folders = @"30;c:\|48;c:\code|99;c:\Program Files";
            Dictionary<int, string> KeyValuePairs = GetFolders(folders);
            foreach (KeyValuePair<int, string> pair in KeyValuePairs)
            {
                Console.WriteLine("Key: '" + pair.Key + "', Value: '" + pair.Value + "'");
            }
            Console.ReadKey();

            /* Results:
             * 
             * Key: '30', Value: 'c:\'
             * Key: '48', Value: 'c:\code'
             * Key: '99', Value: 'c:\Program Files'
            */
        }

        public static Dictionary<int, string> GetFolders(string folders)
        {
            string[] x = folders.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); // first retrieve a string array of all the pairs

            return x.ToDictionary(y => Convert.ToInt32(y.Split(';')[0]), y => y.Split(';')[1]); // second stage of splitting
        }
    }
}

Wednesday, August 8, 2012

Convert enum to string and vice versa



            Vehicle myPreference = Vehicle.Bicycle;
            string vehicle = myPreference.ToString(); // returns string with value: "Bicycle"

            Vehicle secondChoice = (Vehicle)Enum.Parse(typeof(Vehicle), "Spaceship", true); // returns enum: Vehicle.Spaceship

Wednesday, June 20, 2012

Securing SharePoint lists by code

Rather than stuffing configuration keys into *.CONFIG files, it's more convenient to use SharePoint lists instead. This makes it easier to alter configuration settings, as for each change we would need to deploy a new .CONFIG file and involve SysAdmins, get approval from the management, et cetera.

But obviously, you do not want all users to have access to these, if you will, configuration lists. Manually setting all permissions per list and user group would be a nag. Therefore, I'm doing this by code, using the feature event receiver. I basically fetch the SPLists required, break the inheritance and re-set the permissions. The 'userGroup' variable holds the name of the user group associated with the feature. Same goes for the 'prefixList' variable.



public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            const string userGroup = "TeamGary";
            const string prefixList = "config.";

            using (SPSite site = (SPSite)properties.Feature.Parent)
            {
                using (SPWeb web = site.OpenWeb())
                {
                    List<string> fdtListTitles = new List<string>();

                    // get all feature-related SPList titles
                    foreach (SPList list in web.Lists)
                    {
                        if (list.Title.Substring(0, 7) == prefixList)
                        {
                            web.AllowUnsafeUpdates = true;

                            // break inheritance from parent
                            list.BreakRoleInheritance(false);

                            // remove all permissions from list, except for userGroup
                            SPGroupCollection groupCollection = list.ParentWeb.SiteGroups;
                            SPGroup group = groupCollection[userGroup];
                            SPRoleDefinitionCollection roleDefCollection = list.ParentWeb.RoleDefinitions;
                            SPRoleDefinition roleDefinition = roleDefCollection["Read"]; // set access level here
                            SPRoleAssignment roleAssignment = new SPRoleAssignment((SPPrincipal)group);

                            roleAssignment.RoleDefinitionBindings.Add(roleDefinition);

                            list.RoleAssignments.Add(roleAssignment);

                            list.Update();
                        }
                    }
                }
            }
        }

Friday, May 11, 2012

How to block the execution thread using RadConfirm

Finally found a way to use the RadConfirm popup, which is invoked from client side, in combination with server side events. Following example will display the confirmation window and only continues to call the button click event IF the OK button is clicked by the user.


ASPX:


<telerik:RadWindowManager ID="RadWindowManager1" runat="server" EnableShadow="true">
</telerik:RadWindowManager>

<telerik:RadCodeBlock ID="RadCodeBlock1" runat="server">
    <script type="text/javascript">

        var lastClickedItem = null;
        var clickCalledAfterRadprompt = false;
        var clickCalledAfterRadconfirm = false;

        function onClientButtonClicking(sender, args) {
            if (args.get_item().get_text() == "Order another beer") {
                if (!clickCalledAfterRadconfirm) {
                    args.set_cancel(true);
                    lastClickedItem = args.get_item();
                    radconfirm("Are you sure? You order it, you finish it!", confirmCallbackFunction);
                }
            }
        }

        function confirmCallbackFunction(args) {
            if (args) {
                clickCalledAfterRadconfirm = true;
                lastClickedItem.click();
            }
            else
            clickCalledAfterRadconfirm = false;
            lastClickedItem = null;
        }  

    </script>
</telerik:RadCodeBlock>

<CommandItemTemplate>
    <telerik:RadToolBar ID="RadToolBar1" runat="server" OnClientButtonClicking="onClientButtonClicking" OnButtonClick="RadToolBar1_ButtonClick" Width="100%">
        <CollapseAnimation Duration="200" Type="OutQuint" /> 
            <Items> 
                <telerik:RadToolBarButton CommandName="OrderBeer" runat="server" Text="Order another beer"></telerik:RadToolBarButton> 
            </Items> 
    </telerik:RadToolBar>
</CommandItemTemplate>

The CommandItemTemplate part you obviously need to add to your MasterTableView element..



CS:



protected void RadToolBar1_ButtonClick(object sender, RadToolBarEventArgs e)
    {
        RadToolBarButton button = e.Item as RadToolBarButton;
        if (button.CommandName == "OrderBeer")
        {
            \\Do stuff, drink the beer
            \\DrinkBeer();
        }
    }

Have a nice weekend folks!!!


Tuesday, April 10, 2012

Serverside RowClick event handling for RadGrid

Here are a few steps to handle an event on the server side for Telerik's RadGrid

1. Add attribute OnItemCommand to <Telerik:RadGrid>, for example "OnItemCommand="radGrid1_ItemCommand" if your grid name is radGrad1
2. Add attribute EnablePostBackOnRowClick="true" to <ClientSettings>
3. To your code behind, add the following, which will assign a specific cell value to a string:

protected void radGrid1_ItemCommand
{
    // this block will take the value of the column "ContactName" from the grid and assign it to a string
    if (e.CommandName == "RowClick")
    {
        int index = e.Item.ItemIndex;
        GridDataItem item = (GridDataItem)radGrid1.Items[index];
        string contactName = item["ContactName"].Text;
    }
}