May 23, 2007

MOSS: Populating User fields programmatically

Problem:
On a Content Type you have People Picker fields and you wish to set values to them programmatically. Trying to put user Active Directory account name or anything in the field may results in error: Invalid data has been used to update the list item. The field you are trying to update may be read only.

Thoughts:
User name string must be in form User Id + ";#" + User name. How to get the user id?

If the user doesn't exist on the site collection, you will get an error. What MOSS does when you add user to a User field using a browser is that it adds the user to the Site Collection level (All Users list), as described here. Apparently there is some sort of issue related to this, but it is unclear what _should_ be done in this case.

Solution:
In order to do it, as far as I know, is to do it like MOSS does it, even though it's possible that MS will change the functionality slightly as they repair the "problem".

So what you must do is to add the user to the site collection and after that you can query the user ID using the UserGroup.GetUserInfo web service or just directly from the All Users List.

siteCollection.RootWeb.AllowUnsafeUpdates = true;
siteCollection.RootWeb.AllUsers.Add(userLoginName, string.Empty, string.Empty, string.Empty);
siteCollection.RootWeb.AllowUnsafeUpdates = false;

int id = siteCollection.RootWeb.AllUsers[userLoginName].ID.ToString();

string userNameIdString = id + ";#" + userLoginName;

May 16, 2007

MOSS: How to disable "Require Check Out" programmatically

Problem:
Require Check Out for a list is set to Yes by default. How can it be changed in code using API?

Thoughts:
Versioning can be changed by setting the EnableVersioning property.

Solution:
Set ForceCheckout property of the list to false. This works in code and items can be modified programmatically without checking out, but still the UI shows that Require Check Out is Yes.

MOSS: This page is not using a valid page layout.

Problem:
When creating a custom Site Definition containing Publishing features, the site creation succeeds, but when entering the site you receive error: "This page is not using a valid page layout. To correct the problem, edit page settings and select a valid page layout.""

Solution:
See that you have Type set in the File element under Modules -> Module in the ONET.XML of the Site Definition.
<File Url="default.aspx" NavBarHome="True" Type="GhostableInLibrary" Level="Draft">

May 2, 2007

MOSS: How to hide UI elements according to user's Audience

Problem:
I need to hide different UI elements from the master page depending on the current user's audience. SPSecurityTrimmedControl apparently knows nothing about audiences so it cannot be used.

Solution:
Changing master pages on the fly is possible, as described here, but if you'd just want to hide some specific things without making whole lotta master pages this custom control might come handy.

Create Web Custom Control with VS 2005 and add this code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint;
using Microsoft.Office.Server.Audience;
using Microsoft.Office.Server;
using System.Collections;
 
namespace HamarData.WebControls
{
    [DefaultProperty("Text")]
    public class AudienceControl : SPSecurityTrimmedControl
    {
        private List<string> _audiences = new List<string>();
 
        [DefaultValue(""), Category("Behavior")]
        public string AudiencesString
        {
            get
            {
                return string.Join(",", _audiences.ToArray());
            }
            set
            {
                _audiences.AddRange(value.Split(new char[] { ',' }, System.StringSplitOptions.RemoveEmptyEntries));
            }
        }
 
        protected override void Render(HtmlTextWriter output)
        {
            if (!string.IsNullOrEmpty(AudiencesString) && CheckAudience())
            {
                base.Render(output);
            }
        }
 
        /// 
        /// Checks if the user belongs to an audience that is allowed to view the content.
        /// 
        /// True if user is allowed to see the content, otherwise false.
        private bool CheckAudience()
        {
            bool retVal = false;
 
            try
            {
                SPSite site = SPControl.GetContextSite(HttpContext.Current);
 
                ServerContext context = ServerContext.GetContext(site);
                AudienceManager AudMgr = new AudienceManager(context);
 
                SPWeb web = SPControl.GetContextWeb(HttpContext.Current);
 
                try
                {
                    ArrayList audienceIDNames = AudMgr.GetUserAudienceIDs(HttpContext.Current.User.Identity.Name, true, web);
 
                    for(int i = 0; i < audienceIDNames.Count; i++)
{
                        if(_audiences.Contains(((AudienceNameID)audienceIDNames[i]).AudienceName))
                        {
                            retVal = true;
                            break;
                        }
                    }
                }
                catch(AudienceException)
                {
                    //Your exception handling code here
                }
            }
            catch(Exception)
            {
            }
 
            return retVal;
        }
    }
}

Then register the custom control on your chosen master page:
<%@ Register TagPrefix="HamarData" Namespace="HamarData.WebControls" 
Assembly="AudienceControl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=90342589787ab5be" %>

And finally just surround the control(s) you wish to control with the tags like below. This shows the search functionality only for users in the audience "External users":

<HamarData:AudienceControl AudiencesString="External users" runat="server">
    <asp:ContentPlaceHolder id="PlaceHolderSearchArea" runat="server">
        <SharePoint:DelegateControl runat="server" ControlId="SmallSearchInputBox"/>
    </asp:ContentPlaceHolder>
</HamarData:AudienceControl>

The custom control inherits from SPSecurityTrimmedControl so you could possibly (haven't tested) use some functionality of that control too. It's not necessary to inherit it from SPSecurityTrimmedControl, of course, you could just inherit from WebControl if you're only interested in the Audience functionality.