Thứ Hai, 25 tháng 10, 2010

SharePoint PermissionMask

I found the values in C:\Program Files (x86)\Microsoft Office\Office14\CAML2XSL.XSL

<!-- keep in sync with global.cs!!!
EmptyMask =0x0000000000000000,

// list/document perms =0x000000000000XXXX,
ViewListItems =0x0000000000000001,
AddListItems =0x0000000000000002,
EditListItems =0x0000000000000004,
DeleteListItems =0x0000000000000008,
ApproveItems =0x0000000000000010,
OpenItems =0x0000000000000020,
ViewVersions =0x0000000000000040,
DeleteVersions =0x0000000000000080,
CancelCheckout =0x0000000000000100,
ManagePersonalViews =0x0000000000000200,
// UnusedList10 =0x0000000000000400, /* obsolete ManageListPermission */
ManageLists =0x0000000000000800,
ViewFormPages =0x0000000000001000,
// UnusedList20 =0x0000000000002000,
// UnusedList40 =0x0000000000004000,
// UnusedList80 =0x0000000000008000,

// web level perms =0x0000XXXXXXXX0000,
Open =0x0000000000010000,
ViewPages =0x0000000000020000,
AddAndCustomizePages =0x0000000000040000,
ApplyThemeAndBorder =0x0000000000080000,
ApplyStyleSheets =0x0000000000100000,
ViewUsageData =0x0000000000200000,
CreateSSCSite =0x0000000000400000,
ManageSubwebs =0x0000000000800000,
CreateGroups =0x0000000001000000,
ManagePermissions =0x0000000002000000,
BrowseDirectories =0x0000000004000000,
BrowseUserInfo =0x0000000008000000,
AddDelPrivateWebParts =0x0000000010000000,
UpdatePersonalWebParts =0x0000000020000000,
ManageWeb =0x0000000040000000,
UseRemoteAPIs =0x0000002000000000,
ManageAlerts =0x0000004000000000,
CreateAlerts =0x0000008000000000,
EditMyUserInfo =0x0000010000000000,

// special perms =0xXXXX000000000000,
EnumeratePermissions =0x4000000000000000,

// end of list
FullMask =0x7FFFFFFFFFFFFFFF,
-->

GetPermissionMask

<xsl:template name="GetPermissionMask">

<xsl:variable name="Permission" select="name(@*[1])"/>

<xsl:choose>
<xsl:when test="$Permission='PermEmptyMask'">0</xsl:when>
<xsl:when test="$Permission='PermViewListItems'">1</xsl:when>
<xsl:when test="$Permission='PermAddListItems'">2</xsl:when>
<xsl:when test="$Permission='PermEditListItems'">4</xsl:when>
<xsl:when test="$Permission='PermDeleteListItems'">8</xsl:when>
<xsl:when test="$Permission='PermApproveItems'">16</xsl:when>
<xsl:when test="$Permission='PermOpenItems'">32</xsl:when>
<xsl:when test="$Permission='PermViewVersions'">64</xsl:when>
<xsl:when test="$Permission='PermDeleteVersions'">128</xsl:when>
<xsl:when test="$Permission='PermCancelCheckout'">256</xsl:when>
<xsl:when test="$Permission='PermManagePersonalViews'">512</xsl:when>
<xsl:when test="$Permission='PermManageLists'">2048</xsl:when>
<xsl:when test="$Permission='PermViewFormPages'">4096</xsl:when>
<xsl:when test="$Permission='PermOpen'">65536</xsl:when>
<xsl:when test="$Permission='PermViewPages'">131072</xsl:when>
<xsl:when test="$Permission='PermAddAndCustomizePages'">262144</xsl:when>
<xsl:when test="$Permission='PermApplyThemeAndBorder'">524288</xsl:when>
<xsl:when test="$Permission='PermApplyStyleSheets'">1048576</xsl:when>
<xsl:when test="$Permission='PermViewUsageData'">2097152</xsl:when>
<xsl:when test="$Permission='PermCreateSSCSite'">4194314</xsl:when>
<xsl:when test="$Permission='PermManageSubwebs'">8388608</xsl:when>
<xsl:when test="$Permission='PermCreateGroups'">16777216</xsl:when>
<xsl:when test="$Permission='PermManagePermissions'">33554432</xsl:when>
<xsl:when test="$Permission='PermBrowseDirectories'">67108864</xsl:when>
<xsl:when test="$Permission='PermBrowseUserInfo'">134217728</xsl:when>
<xsl:when test="$Permission='PermAddDelPrivateWebParts'">268435456</xsl:when>
<xsl:when test="$Permission='PermUpdatePersonalWebParts'">536870912</xsl:when>
<xsl:when test="$Permission='PermManageWeb'">1073741824</xsl:when>
<xsl:when test="$Permission='PermUseRemoteAPIs'">137438953472</xsl:when>
<xsl:when test="$Permission='PermManageAlerts'">274877906944</xsl:when>
<xsl:when test="$Permission='PermCreateAlerts'">549755813888</xsl:when>
<xsl:when test="$Permission='PermEditMyUserInfo'">1099511627776</xsl:when>
<xsl:when test="$Permission='PermEnumeratePermissions'">4611686018427387904</xsl:when>
<xsl:when test="$Permission='PermFullMask'">9223372036854775807</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:template>

Thứ Sáu, 15 tháng 10, 2010

Building batch approval ribbon in SharePoint 2010

In SharePoint 2010, We can delete multiple items but cannot with approve/reject items. So, how can user approve/reject multiple items in one time? For example TimeSheet application in SharePoint. We can create custom Ribbon then using Application page as dialog and SharePoint Server-Side object model to solve that problem. To complete your function, you have to resolve following things:

1. How we pass the selected items and list to dialog page? We use ECMAScript as following script in CommanAction funtion of the ribbon button

// Shows custom dialog using SharePoint Client JS OM
function RibbonButtonHandler() {
var ctx = SP.ClientContext.get_current();
var items = SP.ListOperation.Selection.getSelectedItems(ctx);
var myItems = '';
var k;

for (k in items) {
myItems += '|' + items[k].id;
}
var options = {
url: "/_layouts/BatchApprovalRibbon/UI/ApproveRejectPage.aspx?items=" + myItems + "&list=" + SP.ListOperation.Selection.getSelectedList(),
width: 600,
height: 400,
dialogReturnValueCallback: demoCallback
};

SP.UI.ModalDialog.showModalDialog(options);
}

By passing selected items and list as text in url parameter, we can easy to get those in application page by Request.QueryString


2. In Application Page dialog, how can We approve/reject item programmatically? We cannot use item[“Approval Status”] = “approved”, we must use following scripts instead.

SPListItem item = currentList.GetItemById(Int32.Parse(id));               SPModerationInformation approvalStatus = item.ModerationInformation; approvalStatus.Status = status;                        
approvalStatus.Comment = comments;
item.Update();

with status is SPModerationStatusType.


3. After approve/reject Items, how can we close dialog page and refresh parent page?


First we must close  the dialog page in server-side code:

protected void CloseDialogPage()
{
Context.Response.Write("<script type='text/javascript'>window.frameElement.commitPopup();</script>");
Context.Response.Flush();
Context.Response.End();
}

Then we call SP.UI.ModalDialog.RefreshPage(SP.UI.DialogResult.OK) in dialogReturnValueCallback function as following

function demoCallback(dialogResult, returnValue) {
SP.UI.Notify.addNotification('Operation Successful!');
SP.UI.ModalDialog.RefreshPage(SP.UI.DialogResult.OK);
}

Now You can use your ribbon to process batch approve/reject items.


clip_image002


4. But I think we should consider how to enable/disable your ribbon by condition or context. To Enable/Disable ribbon button, we use EnabledScript attribute in CommandUIHandler element in you ribbon custom action

<CommandUIHandler
Command="Ribbon.Approval.Batch Approval.Button_CMD"
EnabledScript="javascript:EnableRibbonButton();"
CommandAction="javascript:RibbonButtonHandler();" />

And in javascript funtion, in my scenario, we want to disable the button when there isn’t any items has selected and will enable for special list only. We use following script

function EnableRibbonButton() {
var items = SP.ListOperation.Selection.getSelectedItems();
var ci = CountDictionary(items);
var listId = SP.ListOperation.Selection.getSelectedList();
if (ci > 0 && listId == '{A32BC151-5396-4377-AFB3-B769668C3A83}') {
return true;
}
return false;
}

Finally: NOTE


Keep in mind that we pass url: "/_layouts/BatchApprovalRibbon/UI/ApproveRejectPage.aspx…. It mean dialog page will called under top level sie context. So SPContext.Current always return top level site. So if You use this ribbon in subsite, You should get error message “the list does not exist”. To resolve it, We can


- change the url to: url: "/[your subsite]/_layouts/…


- In Code behind, does not use SPContext.Current.Web directly, we must find the exactly the web of the list instead. We was use

SPSite site = SPContext.Current.Site;           
foreach (SPWeb web in site.AllWebs)
{
currentList = SearchListById(web, listGuid);
.................
}
SPList SearchListById(SPWeb web, Guid listId)
{
foreach (SPList list in web.Lists)
{
if (list.ID.Equals(listGuid))
{
return list;
}
}
return null;
}

Hope this help!

Thứ Năm, 14 tháng 10, 2010

ECMAScript: SP.ClientContext is undefined or null

Sometime We cannot use SP.ClientContext in Site pages, Web part pages or Application pages. Although We was following this guide from msdn

Setting Up an Application Page for ECMAScript

If so, please replace the below lines

<script type="text/ecmascript" src="/_layouts/SP.Core.js" />
<script type="text/ecmascript" src="/_layouts/SP.Debug.js" />
<script type="text/ecmascript" src="/_layouts/SP.Runtime.Debug.js" />

With

<SharePoint:ScriptLink ID="ScriptLink1" Name="sp.debug.js" LoadAfterUI="true" Localizable="false" runat="server" />

Reference MSDN

SharePoint 2010 Woes: Avoid comments in your CustomAction-XML for Ribbon customizations

For a customer project I had to add a custom tab to the Ribbon of SharePoint 2010 for a specific library. In this tab I wanted to have several groups of controls. In one group I needed to have a button that triggers the standard upload functionality of SharePoint (Command="UploadDocument"). So far this is a pretty straight forward process.

If you've ever created a CustomAction to add a tab to the Ribbon, you'll agree that you've to write a looot of XML. I personally believe it's a best practice to comment the code one creates. If you have a XML-document with hundreds of lines of mark-up, usually it makes sense to add a comment here and there. In my case my CustomAction-XML was commented like this:


<Groups
Id="Test.Ribbon.Tab.Groups">
  <!--
    Group "New" with Button "Upload"
-->
  <Group
Id="Test.Ribbon.Tab.NewGroup"

>
    <Controls
Id="Test.Ribbon.Tab.NewGroup.Controls">
  <Button
Id="Test.Ribbon.Tab.NewGroup.Controls.Upload"
Command="UploadDocument"

/>
    </Controls>
  </Group>

</Groups>

As you can see I've added a comment above the group "Test.Ribbon.Tab.NewGroup" and with this I've entered a world of pain. The Ribbon and the tab including all groups and controls were rendered without any issues. I also was able to click on the button "Test.Ribbon.Tab.NewGroup.Controls.Upload" and the "Upload Document"-dialog was displayed as expected, but after clicking on the "OK"-button in the dialog, I ran into this well-known error:

clip_image001[7]

In the SharePoint log you can find the following entry related to this error:

System.NullReferenceException: Object reference not set to an instance of an object. at Microsoft.Web.CommandUI.Ribbon.CreateRenderContext(CUIDataSource uiproc) at Microsoft.Web.CommandUI.Ribbon.Render(HtmlTextWriter writer) at Microsoft.SharePoint.WebControls.SPRibbon.Render(HtmlTextWriter writer) at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) at System.Web.UI.HtmlControls.HtmlForm.RenderChildren(HtmlTextWriter writer) at System.Web.UI.HtmlControls.HtmlForm.Render(HtmlTextWriter output) at System.Web.UI.HtmlControls.HtmlForm.RenderControl(HtmlTextWriter writer) at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) at System.Web.UI.HtmlControls.HtmlContainerControl.Render(HtmlTextWriter writer) at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) at System.Web.UI.Page.Render(HtmlTextWriter writer) at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

The method "Microsoft.Web.CommandUI.Ribbon.CreateRenderContext" throws a "System.NullReferenceException". Whoa! To make a long story short, after digging around for several hours I found the reason for this issue: the comment above the group in the CustomAction-XML. Here is what Reflector tells you about the implementation of "Microsoft.Web.CommandUI.Ribbon.CreateRenderContext":

DataNode node4 = uiproc.GetResultDocument().SelectSingleNode("/spui:CommandUI/spui:Ribbon/spui:Tabs/spui:Tab[@Id='" + this.InitialTabId + "']/spui:Groups");

if (node4 == null)

{

node4 = uiproc.GetResultDocument().SelectSingleNode("/spui:CommandUI/spui:Ribbon/spui:ContextualTabs/spui:ContextualGroup/spui:Tab[@Id='" + this.InitialTabId + "']/spui:Groups");

}

Hashtable hashtable = new Hashtable();

if (node4 != null)

{

foreach (DataNode node5 in node4.ChildNodes)

{

XmlAttribute attribute2 = node5.Attributes["Id"];

if (attribute2 != null)

{

hashtable[attribute2.Value] = node5;

} } }

I will not comment on the quality of this implementation, but if you look at XmlAttribute attribute2 = node5.Attributes["Id"]; it becomes clear: the Attributes-property is the reason why I get the NullReferenceException, because for a System.Xml.XmlNode-Object that is a System.Xml.XmlComment this property is null (http://msdn.microsoft.com/en-us/library/system.xml.xmlnode.attributes.aspx). So if you put a comment above your group in your CustomAction-XML you're doomed. Do yourself a favor and don't do it.

I hope this blog-post will save you save some time and headaches. It took me quite some time to figure out the reason why my button in my custom Ribbon-tab wasn't working.

Reference

Created by Sven Häfker

Thứ Bảy, 9 tháng 10, 2010

Update current user info using SPServices and ECMAScript

Here is the source code:

1. Get user info then auto fill to controls

var displayName = "";
function GetUser()
{
displayName = $().SPServices.SPGetCurrentUser({
fieldName: "Title"
});
var ctx = new SP.ClientContext.get_current();
this.currentUser = ctx.get_web().get_currentUser();
ctx.load(this.currentUser);
ctx.executeQueryAsync(Function.createDelegate(this, this.onSucceededGetUser),
Function.createDelegate(this, this.onQueryFailed));
}

function onSucceededGetUser(sender, args)
{
//alert("The users " + this.currentUser.get_loginName());
$("input[Title='Title']").val(displayName);
$("input[Title='Account']").val(this.currentUser.get_loginName());
$("input[Title='Email']").val(this.currentUser.get_email());
}
function onQueryFailed(sender, args)
{
alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}

2. Update user email info

function UpdateUserEmail() 
{
var ctx = new SP.ClientContext.get_current();
this.currentUser = ctx.get_web().get_currentUser();
var email = $("input[Title='Email']").val();
this.currentUser.set_email(email);
this.currentUser.update();
ctx.executeQueryAsync(Function.createDelegate(this, this.onSucceededUpdateUserEmail),
Function.createDelegate(this, this.onQueryFailed));
}
function onSucceededUpdateUserEmail(sender, args)
{
alert("Updated! " + this.currentUser.get_email());
}

I’d like SPServices and ECMAScripts.

Thứ Năm, 7 tháng 10, 2010

Complete Install SharePoint 2010 on Windows 7

Following these guide:

Setting Up the Development Environment for SharePoint 2010 on Windows Vista, Windows 7, and Windows Server 2008

Single Server Complete Install of SharePoint 2010 using local accounts

Notice:

- In SharePoint 2010 Management Shell: don’t use localhost, (local) or (.) for DatabaseServer parameter. Use machine name or IP address instead. Otherwise you may get “localhost is an invalid or loopback address.  Specify a valid server address” error message.

- In login page: use full user name like “machinename\account name” instead only account name. For example: “basquang\Nguyen Ba Quang” is correct.

- imageimage

Hope this help!