Tuesday 13 May 2008

Adding a custom disclaimer page to a Moss 2007 site

I had a task for a client of adding a compulsary terms and conditions page to a portal site. The requirement was for each user to be presented with this aspx page when they first log on to the portal, and then they have to either accept of reject the disclaimer. It they reject it the browser is closed. If they accept the value was to be saved somewhere so the data could be accessed in case of a query. This is especially needed when dealing with financial or legally regulated clients. There needed to be some way of catching every call to the portal and a check to see whether the user trying to log on has accepted the disclaimer or not then they would be redirected correctly.

My plan was first to use a list to store the accepted information but this would need to be more secure and uneditable so I opted for adding a custom attribute to the user profile for each user.
I would incorporate the disclaimer aspx page into the site by making it a site collection feature. I used visual studio to create my solution.

I used a codeplex template and modofied it to install the disclaimer page to my portal.

http://www.codeplex.com/stsdev

STSDEV is a proof-of-concept utility application which demonstrates how to generate Visual Studio project files and solution files to facilitate the development and deployment of templates and components for the SharePoint 2007 platform including Windows SharePoint Services 3.0 (WSS) and Microsoft Office SharePoint Server 2007 (MOSS). Note that the current version of the stsdev utility only supports creating projects with the C# programming language.

I realised I needed an http handler to intercept every request for every url in the portal, this would perform the functionality of checking for the required value in the user profile. I wrote a class which intercepts the HTTP request pipeline before the default landing page loads,and this class performs a check on a custom profile attribute of our sharepoint user session. I used a Boolean flag to indicate if the user has accepted terms and conditions for site usage. If not, the user is redirected to a custom aspx page from th Http module code, which presents the disclaimer text and a couple of buttons to handle whether the user accepts it or not.

If the user clicks ok, I simply made the call to the user profile properties store and it updates the Boolean field accordingly, and then redirect the browser to the default landing page. The next time a user session is launched for accessing the intranet, the Http module will again intercept the request, the flag will be true, and we do nothing (the request continues on to the default landing page).

To accomplish this required some familiarity with Http modules in ASP.net in general, and also usage of the SharePoint object model to access the user properties. I would recommend starting out with a simple asp.net application with a couple of pages, and write a small class for the Http module which performs a redirect based on a Boolean flag held in a custom user profile attribute, created in the SharedServices admin console, and call the userprofile object to check for the property value in code. I used the UserProfileManager class, which references the Microsoft.Office.Server dll in the project, you can then get user profile info along the following lines...

using Microsoft.Office.Server.UserProfiles

//Get the current user
SPWeb litwareWeb = SPControl.GetContextWeb(Context);SPUser currentUser = litwareWeb.CurrentUser;//Create a new UserProfileManagerUserProfileManager pManager = new UserProfileManager();//Get the User Profile for the current userUserProfile uProfile = pManager.GetUserProfile(currentUser.LoginName);
And then access the properties within the UserProfile class using the collection reference (uProfile[‘CustomAttribute’].value or something like that...)

Using the template you will need to modify the ProjectFolder variable in the .targets file before you build the project –
E.G. "C:\Documents and Settings\tenille\My Documents\Visual Studio 2005\Projects\DisclaimerPage"

Code Examples:

The User Profile Check Class :

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using Microsoft.SharePoint;
using Microsoft.Office.Server.UserProfiles;
using System.Web.UI;
using System.Configuration;
namespace GLGCustomPages
{
public class UserProfileCheck : IHttpModule
{
public UserProfileCheck()
{ }
#region IHttpModule Members
public void Dispose()
{ }
public void Init(HttpApplication app)
{
// Hook into Release Request
app.ReleaseRequestState += new EventHandler(ReleaseRequest_Handler);
}
///
///

///
///
void ReleaseRequest_Handler(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
//HttpContext context = app.Context;
//context.User.Identity.Name;
if (!app.Request.RawUrl.Contains("Disclaimer.aspx"))
{
string originatingUrl = app.Request.Url.ToString();
using (SPSite site = new SPSite(SPContext.Current.Web.Url))
{
SPWeb currentWeb = site.RootWeb;
SPUser currentUser = currentWeb.CurrentUser;
//Create a new UserProfileManager
UserProfileManager pManager = new UserProfileManager();
//Get the User Profile for the current user
try
{
UserProfile uProfile = pManager.GetUserProfile(currentUser.LoginName);
if (uProfile["DisclaimerAcceptance"].Value.Equals(false))
{
app.Response.StatusCode = 301;
app.Response.AddHeader("Location", "http://" + app.Request.ServerVariables["HTTP_HOST"].ToString() + "/Pages/Disclaimer.aspx?Source="+ app.Server.UrlEncode(originatingUrl));
app.Response.End();
}
}
catch (Exception ex)
{
}
}
}
}
#endregion
}
}

The Disclaimer Page Class File:


using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.Office.Server;
using Microsoft.Office.Server.UserProfiles;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Administration;
namespace GLGCustomPages
{
public class DisclaimerPage : Page
{
//add in any page control references here
protected Button AcceptDisclaimer;
protected Button DeclineDisclaimer;
protected UserProfileManager pManager;
protected override void OnInit(EventArgs e)
{
AcceptDisclaimer.Click += new EventHandler(AcceptDisclaimer_Click);
DeclineDisclaimer.Click += new EventHandler(DeclineDisclaimer_Click);
base.OnInit(e);
}
protected void AcceptDisclaimer_Click(object sender, EventArgs e)
{
using (SPSite site = new SPSite(SPContext.Current.Web.Url))
{
SPWeb currentWeb = site.RootWeb;
SPUser currentUser = currentWeb.CurrentUser;
//Create a new UserProfileManager
UserProfileManager pManager = new UserProfileManager();
//Get the User Profile for the current user
UserProfile uProfile = pManager.GetUserProfile(currentUser.LoginName);
uProfile["DisclaimerAcceptance"].Value = true;
uProfile.Commit();
Response.Redirect(Request.QueryString["Source"].ToString());
}
//update the user profile attribute and then redirect to the default page
}
protected void DeclineDisclaimer_Click(object sender, EventArgs e)
{
//Response.Write("");
//close the browser event initiated from the client
}
}
}

Note: A snk file must be created in order for it to work.

The elements.xml and feature.xml files must be modofied correctly to build the project.

When deploying the feature, it must be activated in site collection settings and the user profile attribute must be made editable for users who are logging in for the first time. There was a lot of work involved and many errors later I managed to get it working. Any comments or modifications are most welcome.

No comments:

Zootmastaflex

Zootmastaflex
The Queen of RockStars!