Microsoft MVP Community Camp 2015

 

Microsoft MVPs in the Asia region continues with various events in 2015.  The first event is the MVP Community Camp held at the start of the year. 

 

Melbourne's starts "today" on January 30.

Sydney's will be the next Friday on February 6.

https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032610278&Culture=en-AU&community=0

There are two tracks:

MS Technologies for Business

 

In-depth with Azure

Register for free here

https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032610278&Culture=en-AU&community=0

While I won't be presenting a session, I'll be hanging around with the other MVPs across the Microsoft stack answering questions. 

 

Ask me anything about:

  • Office 365
  • SharePoint
  • TypeScript
  • JavaScript
  • WindowsPhone
  • Microsoft Band
  • XBox One
  • Windows 10

Quick - TSQL select XPath from XML Data Type with namespace

 

Examples on MSDN shows the full TSQL syntax for XPath query in a TSQL statement, this has been supported since SQL Server 2008.

SELECT CatalogDescription.query(' declare namespace PD="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription"; <Product ProductModelID="{ /PD:ProductDescription[1]/@ProductModelID }" /> ') as Result FROM Production.ProductModel

This returns:

<Product ProductModelID="19"/>
<Product ProductModelID="23"/>

Wildcard in XPath Query

This is a much easier syntax with Wildcards that isn't well know.

SELECT CatalogDescription.query('/*:ProductDescription[1]/@ProductModelID') as Result
FROM Production.ProductModel

This returns:

19
23

Plenty of people will tell you using Wildcard matches in XPath is the worst thing in the world.  But I think if you just want to do a quick query, this is fine.

So, this is what can happen if you hack SP javascript files

 

SharePoint 2010's April 2014 CU introduced a bug with copy and paste. 

Bform.debug.js 381,869 11-Feb-2014 12:37
Bform.js 249,012 30-Jan-2014 16:39
Form.debug.js 211,134 11-Feb-2014 12:37
Form.js 126,783 30-Jan-2014 16:39

 

This was fixed and released in SharePoint 2010's August 2014 CU.
http://support.microsoft.com/kb/2760757

Bform.debug.js 381,888 15-Jul-2014 11:17
Bform.js 249,022 15-Jul-2014 11:17
Form.debug.js 211,153 15-Jul-2014 11:17
Form.js 126,793 15-Jul-2014 11:17

 

Story

On December 10, 2014, before we patched to the August 2014 CU level.  A certain very naughty person (me) couldn't wait and decided to offer a quick hack to the Javascript for the users over the holidays.  He even did a bak backup file of the original Form.js

 

image

 

We have now applied the August patch, but unfortunately, you can see:

bform.js, bform.debug.js, form.debug.js all updated.

Form.js is NOT updated.

Copy and paste still doesn't work in our environment.

 

Oops.

 

While a cheating way would be that we install the patch on another environment, and copy the correct Form.js file over. 

We'll be experimenting in this dev environment to see what is the best way to revert and go back to the supported path.  Stay tuned for a follow up article.

SPD2013 Workflow - how to check user is member of group

 

I want to describe a method that I use to check if a user is a member of a group.

 

Steps

  • Call a REST webservice
    • Reference MSDN for the correct API
    • Build a RequestURL and a basic RequestHeader
    • Figure out what the results mean
  • Wrap it up in a Workflow Custom Activity

 

API

MSDN (http://msdn.microsoft.com/en-us/library/office/dn268594(v=office.15).aspx - this needs to be a SharePoint Developer's home page) documents a few REST end points that I use for this.

http://msdn.microsoft.com/en-us/library/office/dn531432(v=office.15).aspx#bk_Group

Says you can get to a sharepoint group via:

  • http://<site url>/_api/web/sitegroups(<group id>)
  • http://<site url>/_api/web/sitegroups(<group name>)

The group also has a Users property that points to a Users Collection.

http://msdn.microsoft.com/en-us/library/office/dn531432(v=office.15).aspx#bk_UserCollection

This expands our example to:

  • http://<site url>/_api/web/sitegroups(<group id>)/users

For example:

 

The Users Collection does not have a method for testing if a user exists.  So I've taken the shortcut and basically brute force the service and just try to retrieve a user.  If you try to request a user that doesn't exist in the collection, it will just error, and I just catch that error.

 

SharePoint Designer workflow

 

image

 

Build Request Header

image

Both Accept and Content-Type needs to be "application/json;odata=verbose"

 

Build Request URL

image

Concatenate Current Site URL (which ends without a trailing /) and the earlier API.

Note my group name is 'john Members'

 

Call Web Service

image

 

Catch and process the result value.

image

 

The ResponseCode could be either OK or InternalServerError

Get a property from the returned Response variable "d/Title" would correspond to the Display Name of the user returned.  If the ResponseCode was Error, then there would be no value in the Response object.

 

 

Sandbox Custom Workflow Activity

 

In Visual Studio, these activities can be bundled into one single Activity that can be reused in SharePoint Designer.  I'll update this in a future blog post on Visual Studio.

 

 

Thoughts on checking nested group or AD group memberships

  • There are no way to check member with nested groups.  One possibility is to not think of it as membership, but think of it as whether the person has a certain permission.

    Does the current user have permission to do Contribute on the current Site. 
  • A more complicated thinking could be to create a list, kick out everyone except the group you are interested in, and check if the current user has permission to that list.

 

 

This Example in JavaScript

 

The more I work with SharePoint 2013 Workflows the closer parallels I see relating to a traditional programming language.  Here's the same function call in Javascript.

var promise = $.ajax({
        type: "GET",
        url: _spPageContextInfo.siteServerRelativeUrl + "/_api/web/sitegroups/getbyname('john Owners')/users/getbyid(" + _spPageContextInfo.userId + ")",
        headers: {
                "accept": "application/json;odata=verbose"
        },
        contentType: "application/json;odata=verbose",
        dataType: "json",
        cache: false,
        processData: true
});

promise.then(
        function (data, status) {

                if (status == "success" && data && data.d) {
                        var title = d.Title;

                }
                else {
                    // success, but no records - this can't really happen.
                }
        },
        function () {
                // not successful - usually not a member of that group
        }
);

TypeScript Definition file for SPServices v0.1

 

Here's something I have wanted to write for a long time, both as Thank-You to Marc Anderson's work on SPServices, as well as for personal learning of the TypeScript language.

 

Adding TypeScript Definition reference:

image

 

$().sp (intellisense)

image

 

$().SPServices.defaults.cacheXML

image

 

$().SPServices.Version()

image

 

$().SPServices.SPCascadeDropdowns({ ... })

image

 

And one more.

$().SPServices({ ... })

image

 

Syntax Error Detection that TypeScript does so well. 

Except for the error message.

Repeat after me in a ROBOT way.  "String is missing apply from type Function".

What it means is I was expecting a function why did I find a string. 

And because Javascript can be surprisingly retarded, TypeScript tries to accommodate and wonders: perhaps this string is a function in disguise - so let me look for the apply method on this object.  NOPE.  It is not a function.   /s

 

image

 

 

Bonus.  TypeScript understands SPServices returns a JQueryXHR promise object.

image

 

Wait.  Where's all the other methods?

 

This is v0.1...

 

Download

https://static1.squarespace.com/static/5527bff2e4b0b430660b0d10/5527c30de4b030eeeef09715/5527c30ee4b030eeeef09d1c/1418221412217/jquery.SPServices.d.ts

Also, how do I get this into Marc's repo?