Feeds:
Posts
Comments

Archive for January, 2014


With my earlier post users(Thanks to Das) reported issue while parsing a date format that it wouldn’t properly validate / compare the  dates for eg. if you use the script posted in my previous blog, and use Date e.g. start date – 10-Jan-2014 and finish date as 6-Feb-2014, it would alert that finish date should not be less than start date, however on investigating the issue, it seemed to be working fine in my environment, with trial and error trying it out in different environments it was narrowed down to the IE locale issue, in scenario where date format is different eg works where date format is dd/mm/yyyy but fails where date format is mm/dd/yyyy and the reason for it is we are extracting the date in an array and comparing them hence the problem, try swapping the array index for date & month as below and it should work, verify it by adding an alert statement that you are comparing the correct values


var smallDt = smallDateArr[1]; var smallMt = smallDateArr[0]; var smallYr = smallDateArr[2];

alert(“StDt-”+smallDt+” StMt-”+smallMt+” StYr-”+smallYr);

var largeDt = largeDateArr[1];var largeMt = largeDateArr[0]; var largeYr = largeDateArr[2];

alert(“FiDt-”+largeDt+” FiMt-”+largeMt+” FiYr-”+largeYr);

Advertisements

Read Full Post »


With reference to our earlier post  Date Validation on PDP and similar kind of example in the post secure PDP pages, quite a few people have been trying to use the logic for disabling the controls on PDP pages now, while you can disable all the fields on the PDP, however it doesn’t do it for multi line text fields, the reason for it is while it initially disables it, but being a context sensistive control while you click in the box it loads the rich text ribbon and enables the text box for editing, however this can be overcome by disabling the entire div tag instead of just the text box, however also be aware the OOB description text box behaves slightly different than other textarea controls, to disable the text area control use the procedure as below


var arrtxtArea = document.getElementsByTagName('textarea');
for (var k = 0; k < arrtxtArea.length; k++)
{
if(arrtxtArea[k].title == 'Description')
{
arrtxtArea[k].disabled='disabled';
arrtxtArea[k].readonly='readonly';
}
else
{
<span style="color: #003366;">var divID=arrtxtArea[k].id+'_div';</span>
<span style="color: #003366;"> var txtAreaDiv =document.getElementById(divID);</span>
if(txtAreaDiv!=null)
{
txtAreaDiv.disabled = true;
}
}

As you notice in this case i am disabling the entire div tag for the text area and that works

RichTextBoxDisabled

Read Full Post »


As we all know project server security is not very granular when it comes to PDP pages or enterprise custom fields, So project server security is more or less at project level for eg. If a user has rights to edit the project, hen can edit anything in the project, but at times we have seen this is not the case wherein multiple departments are working on project and you wouldn’t want a share PDP to be edited by a contractor, wherein he just needs to edit other few pages but not the one containing the secured details, have been thinking over it and finally came up with a solution which restricts PDP page based on project server group, if a person is present in a group then he should be able to edit the page else he shouldn’t be

We have seen a lots of methods wherein adding a javascript to CEW disables but with that we have a lack of control on how dynamically we can use it so

As usual to make this happen i had to perform a bit of customization, which i did through having a custom webpart on the page which loads a javascript on runtime comparing the users presence in the project server group, challenge was not just injecting a javascript on the page rather managing the AJAX postbacks which overrides the script as well 😉

so here it goes, have a look at the snapshots before we proceed towards the code
You would notice that even though i have edit rights, project is checked out to me but all the fields on the specific PDP pages are disabled, also notice the save button is no more available on the ribbon(i will explain why we needed this)
SecuredPDPInAction2

SecuredPDPInAction1

Now lets take a look at the configuration >> Added the secure custom webpart on the page >> edit webpart properties
note: currently i am in Administrator group, but the security group is set to Executive hence i am not restricted from editing the page

SecuredWebpartConfig

Now lets go over the logic on how i did it, this custom web part gets the current logged in user, grabs the resourceUID property and run it against the security group all PSI calls, if current logged in user is found in the security group it doesn’t injects the javascript, however if not found injects the javascript to disable all fields on PDP and trims the Save button on the ribbon and the code behind looks like this


//find the current resource name
string resourceName = string.Empty;
var currentUserUId = psUtil.resourceClient.GetCurrentUserUid();
SPSecurity.RunWithElevatedPrivileges(delegate
{
ResourceDataSet resDs = psUtil.resourceClient.ReadResource(currentUserUId);

if (resDs != null &amp;&amp; resDs.Resources.Count &gt; 0)
{
resourceName = resDs.Resources[0].RES_NAME;
}
});

// Check for User in security Group
if (this.SecurityGroupUid.HasValue) // Security group taken from web part properties
{
ResourceAuthorizationDataSet authDS = null;

SPSecurity.RunWithElevatedPrivileges(delegate
{
authDS = psUtil.resourceClient.ReadResourceAuthorization(currentUserUId);
});

if (authDS != null &amp;&amp; authDS.GroupMemberships.Any(p =&gt; p.WSEC_GRP_UID == this.SecurityGroupUid.Value))
{
displayinReadonlyMode = false;
}
}

if (displayinReadonlyMode)
{
MakeControlsReadonly(); // this is the actual javascript which is injected to disable the PDP
}
else
{
RegisterCloseOutReadonlyScript();
CloseOutStageReadonly();
}

///
/// Makes all children Webcontrols and HTMLControls readonly
///

///
private void MakeControlsReadonly()
{

//ScriptManager.RegisterStartupScript(this, GetType(), &quot;DisableControl&quot;, &quot;MakeReadOnly();&quot;, true);
SPRibbon ribbon = SPRibbon.GetCurrent(this.Page);
if (ribbon != null)
{
ribbon.TrimById(&quot;Ribbon.Tabs.PDP.Home.Project.Save&quot;);
}
ScriptManager.RegisterStartupScript(this, GetType(), &quot;DisableControl&quot;, &quot;_spBodyOnLoadFunctionNames.push('MakeReadOnly()');&quot;, true);
}

///////////////////////////Script////////////////


/*This script makes all input, button, textarea, and select elements readonly*/
function MakeReadOnly()
{
try {
var arrInput = document.getElementsByTagName('input');
for (var i = 0; i &lt; arrInput.length; i++)
{
__MakeReadOnly(arrInput[i]);
}
var arrbtn = document.getElementsByTagName('button');
for (var j = 0; j &lt; arrbtn.length; j++) {
__MakeReadOnly(arrbtn[j]);
}
var arrtxtArea = document.getElementsByTagName('textarea');
for (var k = 0; k &lt; arrtxtArea.length; k++)
{
if(arrtxtArea[k].title == 'Description')
{
arrtxtArea[k].disabled='disabled';
arrtxtArea[k].readonly='readonly';
}
else
{
var divID=arrtxtArea[k].id+'_div';
var txtAreaDiv =document.getElementById(divID);
if(txtAreaDiv!=null)
{
txtAreaDiv.disabled = true;
}
}
}

with regular javascript you would notice the description / multiline text boxed wouldn’t get disabled even though you have looped through all of the controls on the page, hence there are specific things added to the script

>> also note you will need to make these fields workflow controlled so that they are not editable in MSP

Now i did it for the entire page to be disabled, however this same logic can be extended and applied in order to secure specific fields for different project server security group on the same page 🙂

WebPart Download available at – https://1drv.ms/f/s!Asm_5CUps3HRbXXiIbWpp6E4nTI

Read Full Post »


This is with reference to an earlier post wherein we explained on how you can have a custom webpart which would in turn generate unique ID each time a project is created and saved, This should be considered as an enhancement to my previous post wherein i have enabled a few options within the webpart properties to make it easier to configure as a requirement you would need to perform the following steps as outlined below, try this webpart, even though the codebase remains more or less the same, however there are few enhancements, which i will be outlining in my future posts

1. use the script to create a table in database, i have used reporting DB to house my custom table, change DB names as required


USE
GO

/****** Object: Table [dbo].[tbl_ProjUniqueID] Script Date: 01/20/2014 08:49:33 ******/
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tbl_ProjUniqueID]') AND type in (N'U'))
DROP TABLE [dbo].[tbl_ProjUniqueID]
GO

USE
GO

/****** Object: Table [dbo].[tbl_ProjUniqueID] Script Date: 01/20/2014 08:49:33 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[tbl_ProjUniqueID](
[ProjectID] [bigint] IDENTITY(100000,1) NOT NULL,
[ProjectUID] [uniqueidentifier] NULL,
[ProjectCustomUniqueID] [nvarchar](100) NULL,
CONSTRAINT [PK_tbl_ProjUniqueID] PRIMARY KEY CLUSTERED
(
[ProjectID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

2. Make sure your webapp pool account has read write permissions to the database where you created the table in above steps

3. Deploy the WSP File by using powershell command line or Central Admin
Add-SPSolution -LiteralPath
Install-SPSolution -Identity ProjectUniqueID.wsp -WebApplication http://Servername -GACDeployment -Force

Once installed verify the feature in site collection and activate it

ProjectUniqueIDFeatureActive1

Add the webpart to desired PDP page as shown in the image below, note it will display error message, unless configured
ProjectUniqueIDAddWebPart

Once added configure the webpart as described in the image below
ProjectUniqueIDConfigureWebPart

And finally you would see webpart in action
ProjectUniqueIDWebPartInAction

Finally the link – WSP can be downloaded from here

Read Full Post »


I have had quite a few requests from users, wherein they wanted to bulk add Risks/Issues onto project site from other systems, while working on it there are several ways to do it, i chose one to use the powershell as it seemed easiest to implement and use, even within powershell you can either use web service to do the same or you can use the SharePoint object model to add/update, i have chosen object model as that suits my need but for reference i am also posting the web service method in case you want to use it

Generally have seen users having problem with updating DateTime type and person type columns, hence emphasizing on that in notes below

As usual before we make it to the actual powershell, few snapshots

Note::

Make Sure your URL is properly formatted i.e. without any special characters

ExcelPowershellUpdateURLFormat

Make sure Date Format is like yyyy-mm-dd hh:mm:ss

I used a text type column and formatted the date time type as above

ExcelPowershellUpdateDateFormat

ExcelPowershellUpdateSharepointUpdate

If your excel is properly formatted, launch SharePoint powershell prompt, or if its native powershell add sharepoint snapin


<span style="color: #000080;"><strong>#Adding list item using Object Model</strong> </span>

$xl = New-Object -COM "Excel.Application"
#$xl.Visible = $true
$wb = $xl.Workbooks.Open("C:\Users\Administrator\Desktop\IssuesandRisks.xls")
$ws = $wb.Sheets.Item(1)
for ($i = 2; $i -le 5; $i++) #Change row no highlighted here
{
$ProjectHref = $ws.Cells.Item($i, 2).value2 #Adjust Column no here
$SPWeb = Get-SPWeb $ProjectHref
$List = $SPWeb.Lists["Risks"]
$Item = $List.Items.add()
$Item["Title"] = $ws.Cells.Item($i, 4).value2
$Item["Status"] = $ws.Cells.Item($i, 7).value2
$Item["Category"] = $ws.Cells.Item($i, 8).value2
$Item["Description"] = $ws.Cells.Item($i, 10).value2
$Item["Due Date"] = $ws.Cells.Item($i, 9).value2
[Microsoft.SharePoint.SPUser]$spuser = $SPWeb.EnsureUser($ws.Cells.Item($i, 5).value2)
$Item["Assigned To"] =$spuser
[Microsoft.SharePoint.SPUser]$spuser = $SPWeb.EnsureUser($ws.Cells.Item($i, 6).value2)
$Item["Owner"] =$spuser
$item.Update()
Write-Host "Updated row-" $i
$SPWeb.Dispose()
}
$wb.Close()
$xl.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)
Write-Host "Operation Complete"

<strong><span style="color: #000080;">#Adding list item using Web Service</span></strong>

$xl = New-Object -COM "Excel.Application"
#$xl.Visible = $true
$wb = $xl.Workbooks.Open("C:\Users\Administrator\Desktop\IssuesandRisks.xls")
$ws = $wb.Sheets.Item(1)
for ($i = 2; $i -le 5; $i++) #Change row no highlighted here
{
$ProjectHref = $ws.Cells.Item($i, 2).value2 #Adjust Column no here
$uri = "$ProjectHref/_vti_bin/lists.asmx?wsdl"
$listname = "Risks"
$SPService = New-WebServiceProxy -uri $uri -NameSpace SpWs -UseDefaultCredential
$ListInfo = $SPservice.GetListandView($listname,"")
$ListID  = $ListInfo.List.Name
$ViewID  = $ListInfo.View.Name
# build the XML 'batch' of entries that make up the Item
$doc = new-object "System.Xml.XmlDocument"
$batch = $doc.CreateElement("Batch")
$batch.SetAttribute("OnError", "Continue");
$batch.SetAttribute("ListVersion", "1");
$batch.SetAttribute("ViewName", $ViewID);

$batch.InnerXml = "<Method ID='1' Cmd='New'>" +
""+$ws.Cells.Item($i, 4).value2+"" +
""+$ws.Cells.Item($i, 7).value2+"" +
""+$ws.Cells.Item($i, 8).value2+"" +
""+$ws.Cells.Item($i, 10).value2+"" + ""
$response = $SPservice.UpdateListItems($ListID, $batch)

}
$wb.Close()
$xl.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)

Read Full Post »