SaguiItay

My blog has moved!

You should be automatically redirected in 4 seconds. If not, visit:
http://itaysagui.wordpress.com
and update your bookmarks.

Monday, November 19, 2007

Don't name the URL for a sub-site 'CON' in MOSS 2007 - mindykelly's blog

Now, I'm not the best person to speak about documentation and openness is code and products, but every now and then I find myself raising an eyebrow about someone else's behavior: Don't name the URL for a sub-site 'CON' in MOSS 2007 - mindykelly's blog I don't complain that Microsoft don't allow the "CON" as the URL of a WSS/MOSS site. But people, how about making this a public knowledge. How about putting up a one-stop repository for all SharePoint limitation and restrictions? Among the many sites that Microsoft pops-up every other week, I'd love to see a site that centralize all the information about naming convention and limitations in SharePoint. Starting from the list of invalid characters for any type of items, list of "illegal" endings (_files, -files, etc), invalid names and so on...

Labels: , ,

Tuesday, October 2, 2007

SharePoint Associated groups

When you create a new sub-site in SharePoint, and choose the "Use Unique Permissions" option, three groups are created at the site-collection level: Owners, Members & Visitors. These groups are "associated" to the sub-site that you've just created.

But what does "associated" actually mean?

First, I misled you a bit - the names of the groups are actually SiteName Owners, SiteName Members & SiteName Visitors (where SiteName is the name of the sub-site you're creating).

Next they all have a nice link in their description, directing you to the sub-site.

More interesting, those three groups get some permissions on the sub-site.

The less obvious "associations" are the fact that those groups will appear in the Quick Launch area when you go to the "People and Groups" section of the site. Also, if you delete the sub-site, the groups will be removed from the site-collection.

Lastly, when you add a user to the site, you can either assign the user an explicit permission level, or you can add her to onw of the associated groups of the site.

That's quite a lot of meaning for a single word. Let look a bit deeper into each meaning:

Title & Description: This is just some basic naming policy used by SharePoint. The SiteName is validated, the group type is appended, the description is generated with a link. Nothing fancy here.

Permissions: The permissions are obtained by assigning permission levels to each group. Again, nothing too interesting.

Quick Launch: The list of groups that appear in the Quick Launch is retained in the AssociatedGroups property of the SPWeb. This list can also be updated by modifying the vti_associategroups key in the AllProperties property of SPWeb. Setting a group as the AssociatedMemberGroup, AssociatedVisitorGroup or AssociatedOwnerGroup automatically adds the group to the list of AssociatedGroups. These properties can be also updated by modifying the vti_associatemembergroup, vti_associatevisitorgroup & vti_associateownergroup keys in the AllProperties property of SPWeb. These three properties are also reflected in the "Set up Groups" page of the sub-site.

Auto deletion: This issue is a bit more complex. When using the SharePoint UI, or when calling CreateDefaultSharePointGroups methods of SPWeb, this behavior is implemented automatically. However, creating a group, and even associating it with a site, doesn't reproduce it. Only after using Lutz Roeder's .Net Reflector, and examining the CreateDefaultSharePointGroups method, I've found that you need to add the group's ID to the vti_createdassociategroups key in AllProperties.

Adding Users: When adding a user to a sub-site, only the groups listed in AssociatedGroups are listed as possible groups for the new user.

Labels: , ,

Friday, September 14, 2007

Connecting to Documentum using .Net

I've spoke in an earlier post about working with Documentum in .Net. In this post, I'll show you how to connect to a DocBase, and get the list of cabinets. The following code will connect to a DocBase. It assumes that you have a Username, Password and DocBase variables declared that contain valid information:

// Get a client object 
DfClientX _clientx = new DfClientX(); 
IDfClient _client = _clientx.getLocalClient(); 

if (_client == null) 
    throw new Exception("Failed creating Documentum client"); 

// Retrieve the client's version 
Console.WriteLine("Using DFC version '{0}'", _clientx.getDFCVersion()); 

// Create an object with the credentials of the user
IDfLoginInfo _loginInfoObj = _clientx.getLoginInfo(); 
_loginInfoObj.setUser(Username); 
_loginInfoObj.setPassword(Password); 

// Create a new session to the requested DocBase 
IDfSession _session = _client.newSession(DocBase, _loginInfoObj); 
if (_session == null && !_session.isConnected()) 
{ 
    Console.WriteLine("Failed conecting to Documentum"); 
    if (_session != null) 
    { 
        Console.WriteLine("DFC Messages:\r\n{0}", _session.getMessage(1)); 
    } 
    return; 
} 
Console.WriteLine("Using server version '{0}'", _session.getServerVersion()); 

Now, once we're connected to the Documentum DocBase, we'll list all the cabinets:

IDfQuery query = _clientx.getQuery();
// Quering the "dm_cabinet" table returns only items of dm_cabinet type
query.setDQL("SELECT r_object_id, object_name, title FROM dm_cabinet");

// Query the session for the cabinets
IDfCollection col = query.execute(_session, (int)DFCLib.tagDfQueryTypes.IDfQuery_DF_READ_QUERY);

// Loop through all the items in the collection
while (col.next())
{
    // Get the current item from the collection
    IDfTypedObject typedObj = col.getTypedObject();
    // Print the item's name
    Console.WriteLine("Cabinet name: {0}", typedObj.getString("object_name"))
}
col.Close();

One of the most important thing to remember, is that you have to close the IDfCollection. Each session has a very limited number of collections it can have open at the same time. If you need more collections, I would suggest just caching the items inside a .Net collection for later use.

Labels: , , ,

Wednesday, September 12, 2007

Retrieving extended permissions in Documentum with .Net

Following version 5 of the Documentum Content Server, security entities can have extended permissions on items. Those extended permissions include: Execute Procedure, Change Location, Change State, Change Permission and Change Ownership In order to retrieve those permissions by code, it is required to manually check for those permissions. Assuming that you have the object ID of an item, here's the .Net code in order to know if the user has those extended permissions:
IDfId itemIdObj = null;
IDfSysObject itemSysObj = null;
IDfACL aclObj = null;
string itemId = null;
try
{
    // Get the Id object of the item
    itemIdObj = _clientx.getId(itemId);
    // Get the item itself
    itemSysObj = (IDfSysObject)_session.getObject(itemIdObj);
    // Get the ACL of the item
    aclObj = itemSysObj.getACL();
    // Get extended permissions for entity i. This code should be run for each entity
    int xperms = aclObj.getAccessorXPermit(i);
    if ((xperms & 1) == 1)
    {
        // User has the "Execute Procedure"
    }
    if ((xperms & 2) == 2)
    {
        // User has the "ChangeLocation"
    }
    if ((xperms & 32768) == 32768)
    {
        // User has the "Change State"
    }
    if ((xperms & 65536) == 65536)
    {
        // User has the "Change Permission"
    }
    if ((xperms & 131072) == 131072)
    {
        // User has the "Change Ownership"
    }
}
catch (Exception ex)
{
    // Log exception
}

Labels: , , ,

Monday, September 10, 2007

Retrieving a list of available Documentum DocBases

While adding support for EMC Documentum to the Tzunami Deployer, our SharePoint migration tool, I needed to allow the user to enter the name of a DocBase to connect to. I wanted a interface that is a bit more that just a TextBox where the user can enter the DocBase name. I ended up using a ComboBox, and added a "Refresh" button, similar to the one used in the Server Explorer of Visual Studio. When the user press the "Refresh" button, the ComboBox gets populated by the list of known DocBases. Bellow is the code in the event handler of the button:

comboBoxDocBase.Items.Clear();
try
{
    IDfClientX clientx = new DfClientX();
    IDfClient client = clientx.getLocalClient();
    IDfDocbaseMap docbaseMap = client.getDocbaseMap();

    int docbaseCount = myMap.getDocbaseCount();
    for (int i = 0; i < docbaseCount; i++)
    {
        comboBoxDocBase.Items.Add(docbaseMap.getDocbaseName(i));
    }
}
catch (Exception ex)
{
    // Log the exception and show the user a warning
}

This allowed me to easily allow average users to just select from a list of available servers, and advanced users can just enter the name of the DocBase.

Labels: , , ,

Thursday, September 6, 2007

Populating a TreeView with Outlook folders

In this post I will demonstrate how to populate a TreeView with the different Outlook folders. We’ll be using the Outlook Object Model (OOM) to retrieve the folder and some basic information about them. The code itself is well documented, so I’ll not explain it.
private void GetFolders(MAPIFolder currentFolder)
{
    TreeNodeCollection nodes = null;
    if (currentFolder == null)
    {
        // If current folder is null, we’ll be adding the root folders to
        // the TreeView itself
        nodes = treeView1.Nodes;
    }
    else
    {
        // otherwise, find th node that represent the MAPIFolder we’re about
        // to expand
        TreeNode parentNode = folderToNode[currentFolder] as TreeNode;
        if (parentNode == null)
            throw new ArgumentException("currentFolder");
        nodes = parentNode.Nodes;
    }

    // If this folder was already expanded, there’s nothing left for us to do
    if (currentFolder != null && folderExpanded[currentFolder] != null)
        return;
    else if (currentFolder != null)
    {
        // Otherwise, clear the children nodes of the node we’re about to expand
        // This is done since we might have placed a Dummy node there - see later
        if (nodes.Count > 0)
            nodes.Clear();
        // Mark folder as expanded
        folderExpanded[currentFolder] = true;
    }
    
    // Retrieve the root/sub folders
    Folders folders = (currentFolder == null ? nameSpace.Folders : currentFolder.Folders);
    foreach (MAPIFolder folder in folders)
    {
        // If this folder already has a node, we’re done with it
        if (folderToNode[folder] != null)
            continue;
        // Generate a node for the current subfolder
        TreeNode newNode = GenerateNode(folder);
        // Add folder to hashes and to it’s parent node
        nodeToFolder[newNode] = folder;
        folderToNode[folder] = newNode;
        nodes.Add(newNode);
    }
}

private TreeNode GenerateNode(MAPIFolder folder)
{
    // Create a new node with the correct name
    TreeNode newNode = new TreeNode(folder.Name);
    // Check if and how the number of items should be displayed
    switch (folder.ShowItemCount)
    {
        case OlShowItemCount.olNoItemCount:
            // Don’t display the number of items
            break;
        case OlShowItemCount.olShowTotalItemCount:
            // Display the total number of items
            if (folder.Items.Count > 0)
                newNode.Text += " (" + folder.Items.Count + ")";
            break ;
        case OlShowItemCount.olShowUnreadItemCount:
            // Display only the number of unread items
            if (folder.UnReadItemCount > 0)
                newNode.Text += " (" + folder.UnReadItemCount + ")";
            break;
    }

    // If folder has any subfolders, create a dummy node beneath it. This is
    // used so that the node will have the nice plus (+) sign next to it
    // so the user will know there are subfolders. This Dummy node will be
    // removed once the folder is actually expanded
    if (folder.Folders.Count > 0)
        newNode.Nodes.Add(new TreeNode(DummyNode));

    return newNode;
}

private const string DummyNode = "{1194595F-CAF7-474b-8972-CF143F097243}";
private Hashtable nodeToFolder = new Hashtable();
private Hashtable folderToNode = new Hashtable();
private Hashtable folderExpanded = new Hashtable();

Labels: , , , , , ,

Wednesday, August 8, 2007

MOSS Documents Libraries naming policy

When you create a new Documents Library in MOSS, you are asked to provide a title for that Library. The provided title will be later used to define the internal name of the Library, as well as its URL. This is where the problems start. It only makes sense that MOSS allows the user to enter any value for the Library's title. However, there are a lot of limitations on internal names, and even more on URLs. This result in MOSS doing some kind of encoding/validation on the title. The result might range from having the name exactly the same as the title, to the name being completely different and unrelated. After some digging, I came up with the following logic:
For each char:
  if char is valid
    add it to URL
  if char is invalid
    if URL already ends with '_' (underscore)
      don't do anything
    else
      add '_' (underscore)

Strip '_' from beginning and end of URL
If URL is empty
replace URL with a legal DocLibXXX value where XXX is a number
Invalid characters are the following:
  1. Any character bellow 0x20
  2. Any of the following characters: ~!@#$%^&*{}[]-=+\:"'<>,?/.
  3. Any character that takes more than 1 byte (Unicode and such)

Labels: , ,

Thursday, August 2, 2007

Creating a user in Documentum

Here's 2 ways to create a user in Documentum: Using the DQL:

    create dm_cabinet object
    set object_name = '%USERNAME%'
    go

    create dm_user object
    set user_name = '%USER DISPLAY NAME%,
    set default_folder = '/%USERNAME%',
    set user_os_name = '%USERNAME%',
    set user_privileges = %PRIVILEGES%',
    set user_address = '%USER EMAIL%
    go

Using the IAPI:

    create,c,dm_user
    set,c,l,user_name
    set,c,l,user_os_name
    set,c,l,user_address
    save,c,l

Labels: ,

Wednesday, April 25, 2007

Comparison between the Deployer and another migration product

Jingmei Li, a Microsoft employee, did a comparison on her blog between the Tzunami Deployer 2.01, and DocAve 4.1 Migrator.

Labels: , , , ,

Thursday, February 15, 2007

Scot Hillier's "Microsoft SharePoint: Building Office 2007 Solutions in C# 2005"

Scot Hillier, on of the gurus of Microsoft SharePoint, just shipped his new book about Sharepoint solutions, entitles "Microsoft SharePoint: Building Office 2007 Solutions in C# 2005". As with the rest of Scot's book, this is definetly a must-read for all SharePoint administrators and developers. Scot is an independent consultant focused on SharePoint, the Microsoft Office System, and .NET technologies. Scot has authored eight books on Microsoft technologies over the last ten years, as well as numerous articles appearing in magazines and online.

Labels: , , , , ,