Table of Contents


Document Library Folder Sharing

Programmatically control Document Library folder access and permissions to enable collaboration, content distribution, and secure file sharing. This guide covers how to configure folder sharing, manage permissions, and implement access control in code.


Overview

Folder sharing in the Document Library provides granular control over who can access folders and what actions they can perform. By default, all folders are private to the owner and administrators. Sharing must be explicitly configured to allow other users to view, upload, or manage folder content.

Key Characteristics:

  • Default private access (owner and administrators only)
  • Three sharing levels: private, all users, specific users/groups
  • Granular permissions: Full Control, Can Upload, Can View
  • Support for User Groups and Security Roles
  • Public access via Guest Security Role configuration
  • Programmatic sharing through ShareWithSpecificUsers() method

Access Control Layers:

  1. Entity Permissions - Security Role permissions on Folder (system) entity
  2. Folder Sharing - Specific folder access configuration
  3. File Publishing - Individual file public access settings

Sharing Levels

Level 1: Visible Only to Owner (Default)

The most restrictive level. Only the folder owner and administrators can access the folder.

// Default when folder is created - no additional code needed
var folder = new Folder
{
    Name = "Private Folder",
    ParentId = null,
    OwnerId = SystemInfo.UserId
};

Database.Insert(folder);
// Folder is automatically private to owner only

Level 2: Visible to All Users

All portal users can access the folder. Guest users (non-authenticated) can access if Guest Security Role has Read permission on Folder entity.

public ActionResponse ShareWithAllUsers(string folderId)
{
    var folder = Database.Retrieve<Folder>(folderId);
    
    if (folder == null)
    {
        return PageNotFound();
    }
    
    // Share with all portal users
    folder.ShareWithAllUsers();
    
    AspxPage.AddMessage("Folder shared with all users!");
    return RedirectToAction("FolderDetails", new { id = folderId });
}

Level 3: Visible to Specific Users/Groups

The most flexible option. Specify exactly which users, groups, or security roles can access the folder and their permission level.

public ActionResponse ShareWithSpecificUsers(string folderId)
{
    var folder = Database.Retrieve<Folder>(folderId);
    
    if (folder == null)
    {
        return PageNotFound();
    }
    
    // Define sharing permissions
    var permissions = new List<FolderSharingOption>
    {
        new FolderSharingOption
        {
            RecordId = "user-id-1",
            AccessLevel = "FullControl"
        },
        new FolderSharingOption
        {
            RecordId = "user-id-2",
            AccessLevel = "CanUpload"
        },
        new FolderSharingOption
        {
            RecordId = "user-group-id",
            AccessLevel = "CanView"
        }
    };
    
    // Apply sharing
    folder.ShareWithSpecificUsers(permissions);
    
    AspxPage.AddMessage("Folder shared successfully!");
    return RedirectToAction("FolderDetails", new { id = folderId });
}

Permission Levels

Full Control

Complete management access including editing, deleting, and managing folder permissions.

Users with Full Control can:

  • View all files in the folder
  • Upload new files
  • Edit file properties
  • Delete files
  • Move or copy files
  • Manage folder sharing settings
  • Delete the folder
new FolderSharingOption
{
    RecordId = userId,
    AccessLevel = "FullControl"
}

Can Upload

Users can view files and upload new content.

Users with Can Upload can:

  • View all files in the folder
  • Upload new files
  • Edit properties of files they uploaded
  • Download files

Users with Can Upload cannot:

  • Delete files uploaded by others
  • Modify folder sharing settings
  • Delete the folder
new FolderSharingOption
{
    RecordId = userId,
    AccessLevel = "CanUpload"
}

Can View

Read-only access to folder contents.

Users with Can View can:

  • View all files in the folder
  • Download files

Users with Can View cannot:

  • Upload new files
  • Edit any properties
  • Delete anything
  • Modify sharing settings
new FolderSharingOption
{
    RecordId = userId,
    AccessLevel = "CanView"
}

FolderSharingOption Class

The FolderSharingOption class defines sharing permissions for users, groups, or security roles.

Properties

PropertyTypeRequiredDescription
RecordIdstringYesID of User, UserGroup, or SecurityRole to grant access
AccessLevelstringYesPermission level: "FullControl", "CanUpload", or "CanView"

Usage

var sharingOption = new FolderSharingOption
{
    RecordId = "user-or-group-id",
    AccessLevel = "FullControl" // or "CanUpload" or "CanView"
};

Sharing Methods

ShareWithAllUsers()

Share folder with all portal users.

public ActionResponse SharePublicFolder(string folderId)
{
    try
    {
        var folder = Database.Retrieve<Folder>(folderId);
        
        if (folder == null)
        {
            return PageNotFound();
        }
        
        // Validate user has permission to share
        if (folder.OwnerId != SystemInfo.UserId && !SystemInfo.IsAdminUser)
        {
            AspxPage.AddError("You don't have permission to share this folder.");
            return RedirectToAction("Index");
        }
        
        folder.ShareWithAllUsers();
        
        AspxPage.AddMessage($"Folder '{folder.Name}' is now visible to all users!");
        return RedirectToAction("FolderDetails", new { id = folderId });
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"Share error: {ex.Message}");
        AspxPage.AddError("Failed to share folder.");
        return RedirectToAction("Index");
    }
}

ShareWithSpecificUsers()

Share folder with specific users, groups, or security roles.

public ActionResponse ShareFolder(string folderId, List<FolderSharingOption> permissions)
{
    try
    {
        var folder = Database.Retrieve<Folder>(folderId);
        
        if (folder == null)
        {
            return PageNotFound();
        }
        
        // Validate ownership or admin
        if (folder.OwnerId != SystemInfo.UserId && !SystemInfo.IsAdminUser)
        {
            AspxPage.AddError("Only the folder owner or administrator can share this folder.");
            return RedirectToAction("Index");
        }
        
        // Apply sharing
        folder.ShareWithSpecificUsers(permissions);
        
        AspxPage.AddMessage("Folder sharing configured successfully!");
        return RedirectToAction("FolderDetails", new { id = folderId });
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"Share error: {ex.Message}");
        AspxPage.AddError("Failed to configure folder sharing.");
        return RedirectToAction("Index");
    }
}

Common Sharing Scenarios

Scenario 1: Share with Team Members

public ActionResponse ShareWithTeam(string folderId, List<string> teamMemberIds)
{
    var folder = Database.Retrieve<Folder>(folderId);
    
    if (folder == null)
    {
        return PageNotFound();
    }
    
    // Create permissions for team members
    var permissions = teamMemberIds.Select(userId => new FolderSharingOption
    {
        RecordId = userId,
        AccessLevel = "CanUpload"
    }).ToList();
    
    // Apply sharing
    folder.ShareWithSpecificUsers(permissions);
    
    AspxPage.AddMessage($"Folder shared with {teamMemberIds.Count} team members!");
    return RedirectToAction("FolderDetails", new { id = folderId });
}

Scenario 2: Share with Department (User Group)

public ActionResponse ShareWithDepartment(string folderId, string userGroupId, string accessLevel)
{
    var folder = Database.Retrieve<Folder>(folderId);
    
    if (folder == null)
    {
        return PageNotFound();
    }
    
    // Share with User Group
    var permissions = new List<FolderSharingOption>
    {
        new FolderSharingOption
        {
            RecordId = userGroupId,
            AccessLevel = accessLevel
        }
    };
    
    folder.ShareWithSpecificUsers(permissions);
    
    AspxPage.AddMessage("Folder shared with department!");
    return RedirectToAction("FolderDetails", new { id = folderId });
}

Scenario 3: Share with Security Role

public ActionResponse ShareWithRole(string folderId, string securityRoleId)
{
    var folder = Database.Retrieve<Folder>(folderId);
    
    if (folder == null)
    {
        return PageNotFound();
    }
    
    // Share with all users in a security role
    var permissions = new List<FolderSharingOption>
    {
        new FolderSharingOption
        {
            RecordId = securityRoleId,
            AccessLevel = "CanView"
        }
    };
    
    folder.ShareWithSpecificUsers(permissions);
    
    AspxPage.AddMessage("Folder shared with security role!");
    return RedirectToAction("FolderDetails", new { id = folderId });
}

Scenario 4: Mixed Permission Levels

public ActionResponse ShareProjectFolder(string folderId, string managerId, string teamGroupId, string viewerRoleId)
{
    var folder = Database.Retrieve<Folder>(folderId);
    
    if (folder == null)
    {
        return PageNotFound();
    }
    
    // Define different permission levels
    var permissions = new List<FolderSharingOption>
    {
        // Project manager gets full control
        new FolderSharingOption
        {
            RecordId = managerId,
            AccessLevel = "FullControl"
        },
        // Team members can upload
        new FolderSharingOption
        {
            RecordId = teamGroupId,
            AccessLevel = "CanUpload"
        },
        // Stakeholders can only view
        new FolderSharingOption
        {
            RecordId = viewerRoleId,
            AccessLevel = "CanView"
        }
    };
    
    folder.ShareWithSpecificUsers(permissions);
    
    AspxPage.AddMessage("Project folder shared with appropriate permissions!");
    return RedirectToAction("FolderDetails", new { id = folderId });
}

Public Access Configuration

Enable public access for non-authenticated users (Guest users).

Step 1: Configure Guest Security Role

// This is typically done through Setup UI, not code
// Guest Security Role must have Read permission on Folder (system) entity

Step 2: Share Folder Publicly

public ActionResponse MakeFolderPublic(string folderId)
{
    try
    {
        var folder = Database.Retrieve<Folder>(folderId);
        
        if (folder == null)
        {
            return PageNotFound();
        }
        
        // Share with all users (includes guest users if configured)
        folder.ShareWithAllUsers();
        
        AspxPage.AddMessage("Folder is now publicly accessible!");
        
        // Note: Individual files must also be marked as "Published Publicly"
        return RedirectToAction("FolderDetails", new { id = folderId });
    }
    catch (Exception ex)
    {
        SystemInfo.Debug($"Public share error: {ex.Message}");
        AspxPage.AddError("Failed to make folder public.");
        return RedirectToAction("Index");
    }
}

Step 3: Publish Individual Files

public ActionResponse PublishFilesPublicly(string folderId)
{
    var folder = Database.Retrieve<Folder>(folderId);
    
    if (folder == null)
    {
        return PageNotFound();
    }
    
    // Get all files in folder
    var documents = Database.Query<Document>()
        .Where(d => d.FolderId == folderId)
        .ToList();
    
    // Mark each file as published publicly
    foreach (var doc in documents)
    {
        doc.Published = true;
        Database.Update(doc);
    }
    
    AspxPage.AddMessage($"{documents.Count} files published publicly!");
    return RedirectToAction("FolderDetails", new { id = folderId });
}

Best Practices

Security

Always validate ownership or admin rights

if (folder.OwnerId != SystemInfo.UserId && !SystemInfo.IsAdminUser)
{
    AspxPage.AddError("You don't have permission to share this folder.");
    return RedirectToAction("Index");
}

Use least privilege principle

// Start with most restrictive access
new FolderSharingOption
{
    RecordId = userId,
    AccessLevel = "CanView" // Start restrictive, expand as needed
}

Validate access levels

string[] validLevels = { "FullControl", "CanUpload", "CanView" };
if (!validLevels.Contains(accessLevel))
{
    AspxPage.AddError("Invalid access level.");
    return View();
}

Performance

Use User Groups for team sharing

// Good: One permission for entire group
new FolderSharingOption
{
    RecordId = userGroupId,
    AccessLevel = "CanUpload"
}

// Avoid: Individual permissions for each user
// (though sometimes necessary)

Maintenance

Document sharing decisions

// Create audit note when sharing
var note = new NoteAndAttachment
{
    Name = "Folder Shared",
    Body = $"Folder shared with {permissions.Count} users/groups by {SystemInfo.UserName}",
    ReferenceId = folderId,
    Type = 0
};
Database.Insert(note);

Common Pitfalls

Pitfall 1: Forgetting to check ownership

// Bad: No validation
folder.ShareWithAllUsers();

// Good: Validate ownership
if (folder.OwnerId != SystemInfo.UserId && !SystemInfo.IsAdminUser)
{
    return UnauthorizedAccessResponse();
}

Pitfall 2: Public sharing without file publishing

// Bad: Folder shared but files not published
folder.ShareWithAllUsers();
// Files are not publicly accessible yet

// Good: Share folder AND publish files
folder.ShareWithAllUsers();
foreach (var doc in documents)
{
    doc.Published = true;
    Database.Update(doc);
}

Pitfall 3: Invalid RecordId

// Bad: No validation
new FolderSharingOption
{
    RecordId = userId, // Could be null or invalid
    AccessLevel = "CanView"
}

// Good: Validate before sharing
if (string.IsNullOrEmpty(userId))
{
    AspxPage.AddError("Invalid user ID.");
    return View();
}

Related Topics