DCSIMG
November 2008 - Posts - justguy's

November 2008 - Posts

Base Content Type Hierarchy

 

Hi,

As you may know, Content Types are hierarchical and uniquely identified with an ID.
Read about it here: Base Content Type Hierarchy, Content Type IDs.

 

 

 

 

If you actually read the articles above, you know that inherited content types always start with the ID of the part and add a suffix.

I wrote this small class to help identify the type of a Content Type. Use it with String.StartsWith() :)

public static class ContentTypePrefix
{
    public static readonly string Item            = "0x01";

    // document
    public static readonly string Document        = "0x0101";
    public static readonly string XMLDocument     = "0x010101";
    public static readonly string Picture         = "0x010102";
    public static readonly string UntypesDocument = "0x010104";
    public static readonly string MasterPage      = "0x010105";
    public static readonly string WikiDocument    = "0x010108";
    public static readonly string BasicPage       = "0x010109";
    public static readonly string WebPartPage     = "0x01010901";
    public static readonly string LinkToDocument  = "0x01010A";
    public static readonly string DublinCoreName  = "0x01010B";

    public static readonly string Event           = "0x0102";
    public static readonly string Issue           = "0x0103";
    public static readonly string Announcement    = "0x0104";
    public static readonly string Link            = "0x0105";
    public static readonly string Contact         = "0x0106";
    public static readonly string Message         = "0x0107";
    
    // task
    public static readonly string Task            = "0x0108";
    public static readonly string WorkflowTask    = "0x010801";
    public static readonly string AdminTask       = "0x010802";

    public static readonly string WorkflowHistory = "0x0109";
    public static readonly string BlogPost        = "0x0110";
    public static readonly string BlogComment     = "0x0111";
    public static readonly string FarEastContact  = "0x0116";
    
    // folder
    public static readonly string Folder          = "0x0120";
    public static readonly string RootOfList      = "0x012001";
    public static readonly string Discussion      = "0x012002";
}
Saved you some work, huh?

 

 

 

 

Updated (same day)

Here’s an example of using some Linq to get the best matching base content type:

private static string GetBaseType(string id)
{
    string baseTypeName = string.Empty;
    List<FieldInfo> fields = new List<FieldInfo>(typeof(ContentTypePrefix).GetFields());

    // get the values of the static fields
    var fieldValues = from field in fields
                      select new { Name = field.Name, Value = (string)field.GetValue(null) };

    var baseTypes = from fieldValue in fieldValues
                    where id.StartsWith(fieldValue.Value)
                    orderby fieldValue.Value.Length descending
                    select fieldValue.Name;

    baseTypeName = baseTypes.First<string>();

    return baseTypeName;
}
Posted by justguy | 1 comment(s)

SharePoint list templates and base types

Hi!

I come across another strange request from the same client…
I had something to do with displaying all items from all document libraries in the site.

Trying to think caught me off guard, and I decided to go ahead and work with the CQWP (Content Query Web Part).
I found it too complicated and uncustomizable (the client has fantasies about web development).

Scratching my head a bit got me thinking about a nice web part I put together once:
Get a list, use the GetDataTable() mehod, use WriteXml() and parse the whole thing with XSL…

 

 

 

 

 

 

 

 

OK!

What about *all* the lists in the web site?
First, the user must select the list template to base the query on (localized):

SPListTemplateCollection listTemplates = SPContext.Current.Site.RootWeb.ListTemplates;
SortedList list = new SortedList();
List<int> templatesToIgnore = new List<int>() { 110, 0x75, 0x76, 0x2776 };
ListItem item = null;

listTypeDropDown = new DropDownList();

#region populate the list template drop down
foreach (SPListTemplate template in listTemplates)
{
    int type = (int)template.Type;
    
    if (templatesToIgnore.Contains(type))
    {
        continue;
    }

    item = new ListItem(template.Name, Convert.ToString(type, CultureInfo.InvariantCulture));
    list[item.Text] = item;
    item.Attributes.Add("BaseType", template.BaseType.ToString("D"));
    
    ListItem item2 = new ListItem(SPUtility.GetLocalizedString("$Resources:core,posts_schema_blg_title;",
        null, (uint)CultureInfo.CurrentUICulture.LCID), SPListTemplateType.Posts.ToString("d"));

    list[item2.Text] = item2;
    item2.Attributes.Add("BaseType", "0");
    ListItem[] array = new ListItem[list.Count];
    list.Values.CopyTo(array, 0);
    listTypeDropDown.Items.Clear();
    listTypeDropDown.Items.AddRange(array);

    //if (string.IsNullOrEmpty(baseType))
    //{
    //    baseType = this.contentByQueryWebPart.ServerTemplate;
    //}
}

Second, get all the lists based on that type:

/// <summary>
/// Retrieves all lists based of the specified template type in the provided web
/// </summary>
/// <param name="parentWeb"></param>
/// <param name="listTemplateType"></param>
/// <returns></returns>
/// <exception cref="ArgumentException" />
public static List<SPList> GetListsByType(SPWeb parentWeb, int listTemplateType)
{
    List<SPList> lists = new List<SPList>();

    if (parentWeb == null)
    {
        throw new ArgumentException("parentWeb cannot be null");
    }

    // look for lists based of the requrested template type
    foreach (SPList list in parentWeb.Lists)
    {
        if ((int)list.BaseTemplate == listTemplateType)
        {
            lists.Add(list);
        }
    }

    return lists;
}

Cheers!

Posted by justguy | with no comments
תגים:,

What happens when your client requires list item aggregation from sub sites…

Hi,

As you all know, client have an annoying tendency of getting annoying.
Yes, I am talking about the money-makers!

I came across this request:

  1. Aggregate list items (news, tasks) from sub sites to the root site.
    The condition for aggregation will be a site column named “Copy to Homepage”.
  2. Aggregated items will require content approval.
  3. The client should be able to implement the same behavior himself (on programmers on board).

1st thing’s 1st… damn!

Now let’s get to work…

 

Step 1 - Aggregate the items – SPItemEventReceiver

If you’re not familiar with the SPItemEventReceiver, Google it.

The event will check if the “Copy to Homepage” column is checked. If so, the following method will copy it:

public static void CopyMoveListItem(
            SPListItem sourceItem,
            SPFolder destinationFolder,
            bool deleteSourceItem)
        {

            // create a new item
            SPListItem targetItem = GetListById(destinationFolder.ParentWeb, destinationFolder.ParentListId).Items.Add(
                destinationFolder.ServerRelativeUrl,
                sourceItem.FileSystemObjectType
                );

            // loop over the soureitem, restore it
            for (int i = sourceItem.Versions.Count - 1; i >= 0; i--)
            {
                SPListItemVersion version = sourceItem.Versions[i];

                //set the values into the archive
                foreach (SPField sourceField in sourceItem.Fields)
                {
// add the field to the new item make sure the field exists in the target list if ((!sourceField.ReadOnlyField) && (sourceField.Type != SPFieldType.Attachments) &&
targetItem.Fields.ContainsField(sourceField.Title))
                    {
                        targetItem[sourceField.Title] = version[sourceField.Title];
                    }
                    else if (sourceField.Title == "Created" && sourceField.Title == "Created By" &&
                        sourceField.Title == "Modified" && sourceField.Title == "Modified By")
                    {
                        targetItem[sourceField.Title] = version[sourceField.Title];
                    }
                }
                
                // update the new item
                targetItem.Update();
            }

            // copy the attachments (they are not versioned)
            foreach (string attachmentName in sourceItem.Attachments)
            {
                SPFile file = sourceItem.ParentList.ParentWeb.GetFile(
                    sourceItem.Attachments.UrlPrefix + attachmentName);
                
                targetItem.Attachments.Add(attachmentName, file.OpenBinary());
            }
            
            targetItem.Update();

            // delete the source item if needed
            if (deleteSourceItem)
            {
                sourceItem.Delete();
            }
        }

Notes:

  • This code is based on something I found once. If you recognize your code, let me know. I’ll give you the credit :)
  • GetListById returns the parent list of the item. It’s too simple for blog posts.
  • When adding the code to the SPItemEventReceiver, I’d cosider using DisableEventFiring Method and EnableEventFiring Method.
    If you modify an item, you might cause the event to fire again for the update.


That got me thinking about letting the ItemAdded method where the target list is located…
I used the web.config

 

Step 2 – Content Approval

This is a simple step that you can Google up…
Here’s an example.

 

Step 3 – User Friendly GUI for Event Receivers

The biggest issue in this entire escapade is allowing non-programming users to attach event receivers to new lists.

Then I came across Gaetan Bouveret’s SharePoint Events Manager.

 

 

Enough with the writing!

Adi.

Posted by justguy | 1 comment(s)
תגים:,