I’m writing some custom application pages that run from the _Layouts directory. They’re triggered by items on the Edit Control Block menu.. (See the previous post from the other day on this option..)
One of the things that has really come up with this is the question of authorisation, and confirming that the user does have the rights for what you’re attempting to do. For the work that I’m doing, this means checking those rights in two places.
The first place is the Edit Control Block that we’re placing the menu option into. This is defined in your elements.xml as a CustomAction. One of the useful features about custom actions, is that you have two elements available to hide them from inappropriate users.
The first is the RequireSiteAdministrator element. This does exactly what it says on the tin, If the current context user is a Site Admin, they get the menu option, if not, they don’t.
RequireSiteAdministrator = "TRUE"
The second option is based on the SPBasePermissions enumeration and is a comma separated list of ALL the permissions that a user must have on a list item before the menu option is shown.
Rights="EditListItems,ApproveItems"
Click here for more information on SPBasePermissions
BUT.. And there is always a but… if your user knows the URL and the format of the query string, they can always type that in directly, so you must include a security wrapper in your application page.
E.g.
try
{
if (sourceItem.DoesUserHavePermissions(SPBasePermissions.ApproveItems) && sourceItem.DoesUserHavePermissions(SPBasePermissions.EditListItems))
{
//Do stuff
}
else
{
throw new SecurityException("You do not have the required rights for that operation.");
}
}
catch (SecurityException ex)
{
SPUtility.HandleAccessDenied(ex);
}
As you can see, we can place the authorisation failure into the try/catch block, and just throw a SecurityException to call the redirect functionality from the SPUtility model. This presents the user with the familiar Access Denied page.
Cheers
Reg.
There’s plenty of articles on the net that tell you how to add items onto the Edit Control Block for a given list type, But I found articles on Content Types to be in short supply..
So, for the benefit of Mr google bot… (Edit Control Block Entries for Custom Content Types)
How do we do it, well it’s quite simple. Go to Site Settings, Site Content types and click on the content type you want to affect. In the URL that opens you’ll see something similar to “ctype=0×0100140835253A1B6F4E8B40A833287BB367”
Grab that sortof GUID and add the following entries into your ECB declaration in the Elements.Xml file of your feature..
1
2
3
4
5
6
7
8
9
10
11
12
| <CustomAction Id="UpdateDeliveryState"
RegistrationType="ContentType"
RegistrationId="0x0100140835253A1B6F4E8B40A833287BB367"
ImageUrl="/_layouts/images/customimage.jpg"
Location="EditControlBlock"
Sequence="242"
Rights="EditListItems"
Title="Update Delivery State" >
<UrlAction Url="~site/_layouts/UpdateDeliveryState.aspx?ItemId={ItemId}&ListId={ListId}&Source=http%3A%2F%2Fdemosite"/>
</CustomAction>
Reg. |
On a clients Intranet/Extranet recently, I was asked to provide a static Google map for both staff and visitors to find the Head Office location.
The main problem with this is that Google want you to use a static API key for each URL that will refer a connection. Obviously if you’re using alternate access mapping then this will be a problem as internal staff may be connecting to http://intranet whilst your customers may be using http://extranet.myhouse.com
The simplest way that i could see of fixing this problem is to use Javascript in a content editor webpart to look at the Document.URL and output the correct IMG tag accordingly. I also wanted to ensure that it wouldn’t matter if we had a port in the URL, so I’ve stripped that as well.
Here’s the code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| <script type="text/javascript" language="javascript">
var myRequest = document.URL.toUpperCase();
var firstBound = myRequest.indexOf("HTTP://")+ 7;
var secondBound = myRequest.indexOf('/',firstBound);
var serverUrl = myRequest.substring(firstBound,secondBound);
//Now check for a port entry.
if (serverUrl.indexOf(':') == -1)
{
//There isn't a port so we're ok.
}
else
{
//We've got a port entry to remove.
serverUrl = serverUrl.substring(0,serverUrl.indexOf(':'));
}
if (serverUrl == "{INTERNALURL HERE in UPPERCASE")
{
document.writeln("<div class="bs-BoxBorder" style="text-align: center;">");
document.writeln("<img src="http://maps.google.com/staticmap?center=51.504235,-0.081904&zoom=15&size=400x400&markers=51.504035,-0.081890,blueb&key={Your Google API Key goes Here}"></div>");
}
else if (serverUrl == "{EXTERNALURL HERE in UPPERCASE}")
{
document.writeln("<div class="bs-BoxBorder" style="text-align: center;">");
document.writeln("<img src="http://maps.google.com/staticmap?center=51.504235,-0.081904&zoom=15&size=400x400&markers=51.504035,-0.081890,blueb&key={Your Google API Key goes Here}"></div>");
}
</script> |
EDIT: Ok, I’m really not happy with the way this code plugin is formatting pasted scripts.. they look fine in the editor but awful on the site. I’ll leave this one as is for now and hopefully sort out a better code display block asap. EDITEDIT Much better.. I changed to the WP-Syntax plugin which seems to work.
Reg.
I’ll be one of the first to admit, Javascript is NOT my strong point.. or my favorite.. C# however is, so I amended the ASCX page to use C# throughout.
2 ASP controls for the Image and text box both of which have a click event “cmdRunSearch_Click”
This calls:-
protected void cmdRunSearch_Click(object sender, EventArgs e)
{
string strEncodedUrl
= SPEncode.UrlEncodeAsUrl("http://demosearch/results.aspx",false);
string targetUrl = strEncodedUrl + "?k=" + txtSearchText.Text;
Response.Redirect(targetUrl);
}
A little bit of styling on the asp objects and the new control adapter looks the part and performs well.
The only downside to this approach is that the ascx page has to be edited manually after the feature is installed to ensure the correct URL is used for the SSE implementation.
To take this further, I’m tempted to restore the scope activities that I took out of the original MS page, however this time we need to pull the scope options from the search centre, so this may need some thought.
Reg.
Just recently we installed Search Server Express for a client on their WSS infrastructure. It’s working quite nicely having a much more granular control than the standard WSS search functions, but my main gripe is the lack of SmallSearchServer control to replace the existing WSS one.
Most users would rather click into a text box at the top of the page, and enter their search query than click off to another search url and perform the action there. So, we need to remove the WSS search input and replace it with our own.
Now, thanks to Microsoft using Delgate controls on the master page, this is nice and simple. All we need is a feature consisting of the standard Feature.Xml and Elements.Xml and the new controltemplate, in this case BSSearchArea.ascx.
So far so good. I’ve customized the existing SearchArea.ascx taken from 12/TEMPLATES/CONTROLTEMPLATES and i’ve removed all mention of the scope. My elements file has been configured to override the existing control using:-
<Control
Id="SmallSearchInputBox"
ControlSrc="~/_controltemplates/new.search/BSSearchArea.ascx"
Sequence="10"
/>
And my control is appearing as expected. but my problem now is the error that appears when I enter a search term and click search. I receive:- “This Page has been modified since you opened it. You must open the page again.”
Well I know that the submit button is calling a SharePoint javascript function, so I decided to pull a copy of that out of core.js and put it inline with my ascx after removing anything i don’t want.
So now I’m left with the function called by my form button onClick() event.
function bsSubmitSearchRedirect(strUrl)
{
var frm=document.forms["frmSiteSearch"];
if (frm==null)
{
if (typeof(MSOWebpartPageFormName) !="undefined")
frm=document.forms[MSOWebPartPageFormName];
}
if (frm !=null)
{
var searchText=frm.elements["SearchString"].value;
strUrl=strUrl+"?k=" + escapeProperly(searchText);
frm.action=strUrl;
frm.submit();
}
}
But I’m still having this errpr when searching.. the weirdest thing about it though, if you click the refresh page link in the error.. it works perfectly..
Watch this space..
I just picked up the news on Eric Shupps blog that well known SharePoint MVP Patrick Tisseghem passed away whilst travelling in Sweden to teach a course.
This is a sad loss for the SharePoint community as Patrick’s articles have helped more than a few of us other last few years.
My thoughts go out to Patrick’s family and friends at this time.
Eric has posted a nice memorial on the ISPA website here..
Reg.