Problem
There is an issue with OOTB SharePoint logic.Scenario
- 2 types of Users
- User1 is Site Administrator
- User2 is a simple user with Read, Limited Access.
- Issue comes under blog site.
How to reproduce? Follow the below given test case.
- Create a site collection. In my case I have created it on "http://pc92".
- I create a blog site with name "TestBlog" using User1. In my case it is "http://pc92/TestBlog/".
- Navigate to default blog created on site and add 11 comments. Right now the URL will be "http://pc92/TestBlog/Lists/Posts/Post.aspx?ID=1". This will enable the paging at the comments webpart.
- Now login with User2(Read, Limited Access User) and navigate to the URL "http://pc92/TestBlog/Lists/Posts/Post.aspx?ID=1". The page will show normal. The only difference here is you won't see the "Add Comment" box at the bottom of the screen.
- Click the next button. You will see the error.
Cause
The cause of the whole act is when you login as a User2(Read, Limited Access) the Comment Box(ListFormWebPart) is not available for this users. On page load everything is fine. But when you do a postback like paging event it bombs out. This might have got out of the site of MicroSoft Team.Solution
I created 2 features, one is a site based feature(BlogFixSite) and another one web based feature(BlogFixWeb). On the BlogFixSite activation we check all the web which doesnot have BlogFixWeb activated and the template is a Blog template. So if the feature is activated I assume that the site is already having a fix. In the BlogFixWeb I go to the "Posts" folder and copy "Post.aspx" content and create "Post1.aspx". In the "Post1.aspx" i will remove the "ListFormWebPart" programatically. In "Post.aspx" at the bottom i will place a jquery which will check if the "Add Comment" box is missing than take the user to "Post1.aspx". Repeat the above given test cases and you should be all good.BlogFixSite - C#
#region System using System; using System.Runtime.InteropServices; using System.Security.Permissions; using Microsoft.SharePoint; using Microsoft.SharePoint.Security; using Microsoft.SharePoint.Administration; using System.Collections.Generic; using System.Linq; #endregion namespace BlogFix.Features.BlogFixSite { [Guid("63c859cc-77ff-436e-a79e-b4619a67c7c3")] public class BlogFixSiteEventReceiver : SPFeatureReceiver { #region Events /// <summary> /// Activating /// </summary> /// <param name="properties"></param> public override void FeatureActivated(SPFeatureReceiverProperties properties) { base.FeatureActivated(properties); try { //Site object SPSite _site = (SPSite)properties.Feature.Parent; if (_site != null) { //Feature ID - BlogFixWeb Guid _featureWeGuid = new Guid("c7178a85-ed45-4f27-bd4a-db2ec3eed95b"); //Web List IList<SPWeb> _webList = (from _web in _site.AllWebs.Cast<SPWeb>() where string.Compare(_web.WebTemplate, "Blog", true) == 0 && _web.Features[_featureWeGuid] == null select _web).ToList(); //Change the post page foreach (SPWeb _web in _webList) { //Enables the feature - BlogFixWeb if (_web.Features[_featureWeGuid] == null) { _web.Features.Add(_featureWeGuid); } } } } catch (Exception Exc) { SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("BlogFixSiteEventReceiver - Activated", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, Exc.Message, Exc.StackTrace); } } #endregion } }
BlogFixWeb - C#
#region System using System; using System.Runtime.InteropServices; using System.Security.Permissions; using Microsoft.SharePoint; using Microsoft.SharePoint.Security; using Microsoft.SharePoint.Administration; using System.Collections.Generic; using System.Linq; #endregion namespace BlogFix.Features.BlogFixWeb { [Guid("564b0ad9-90a0-45fc-a672-901ec1fd111b")] public class BlogFixWebEventReceiver : SPFeatureReceiver { #region Events /// <summary> /// Activate the web based feautre /// </summary> /// <param name="properties"></param> public override void FeatureActivated(SPFeatureReceiverProperties properties) { base.FeatureActivated(properties); try { SPWeb _web = (SPWeb)properties.Feature.Parent; //All the subfolders SPFolderCollection _folderCollection = _web.Folders["Lists"].SubFolders; //Finds the folder containing Post.aspx IList<SPFolder> _folderPostList = (from _folderX in _folderCollection.Cast<SPFolder>() let _fName = _folderX.Name let _fCount = (from _fileX in _folderX.Files.Cast<SPFile>() where string.Compare(_fileX.Name, "post.aspx", true) == 0 select _fileX).Count() where _fCount > 0 select _folderX).ToList(); //Loop it if there are more than one if (_folderPostList != null) { foreach (SPFolder _folderPost in _folderPostList) { //Get the Post file SPFile _filePost = (from _fileX in _folderPost.Files.Cast<SPFile>() where string.Compare(_fileX.Name, "post.aspx", true) == 0 select _fileX).FirstOrDefault(); //The file post to be copied if (_filePost != null) { //New Post1.aspx URL string _newPostUrl = string.Format("{0}/{1}/{2}", _web.Url, _folderPost.Url, "Post1.aspx"); //Copy the file _filePost.CopyTo(_newPostUrl, true); //Update the folder _folderPost.Update(); //Remove the control once the page is copied Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager _webPartCollection = _web.GetLimitedWebPartManager(_newPostUrl, System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared); //Retrive the webpart and remove Microsoft.SharePoint.WebPartPages.WebPart _listFormWebPart = (from _wp in _webPartCollection.WebParts.Cast<Microsoft.SharePoint.WebPartPages.WebPart>() where _wp.GetType().UnderlyingSystemType.Name == "ListFormWebPart" select _wp).FirstOrDefault(); //Microsoft.SharePoint.WebPartPages.ListFormWebPart _XlistFormWebPart = (Microsoft.SharePoint.WebPartPages.ListFormWebPart)_listFormWebPart; //string _webPartTitle = _XlistFormWebPart.Title //return; if (_listFormWebPart != null) { //Remove the webpart _webPartCollection.DeleteWebPart(_listFormWebPart); //Update _web.Update(); } //Modify Post1.aspx and add the javascript tag if (_filePost.RequiresCheckout) { _filePost.CheckOut(); } //Edit the file byte[] _htmlByte = _filePost.OpenBinary(); string _html = System.Text.Encoding.ASCII.GetString(_htmlByte); string _topHtml = _html.Substring(0, _html.LastIndexOf("</asp:Content>")); string _stript = "\n<script language=\"javascript\" type=\"text/javascript\">!window.jQuery && document.write('<script src=\"http://code.jquery.com/jquery-1.4.2.min.js\"><\\/script>');</script>\n<script language='javascript'>\n\r$(document).ready(function(){\n\r\rif($(\"h3[class='ms-CommentHeader']\").length == 1){\n\r\r\r\rwindow.location.href = window.location.href.replace(\".aspx?\" , \"1.aspx?\");\n\r\r}\n\r});</script>"; _html = string.Format("{0}{1}</asp:Content>", _topHtml, _stript); _filePost.SaveBinary(System.Text.Encoding.ASCII.GetBytes(_html)); //Check In if (_filePost.RequiresCheckout) { _filePost.CheckIn(string.Empty); } } } } } catch (Exception Exc) { SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("BlogFixWebEventReceiver - Activated", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, Exc.Message, Exc.StackTrace); } } #endregion } }
JavaScript added on Post.aspx
There are 2 "<h3></h3>" tags on the post.aspx page. (1) is "Comments" and (2) is "Add Comments". So if a user dont have access he/she wont see "Add Comment" box. If that box doesnot exists on the page I simply send the user to Post1.aspx.<script> !window.jQuery && document.write('<script src="http://code.jquery.com/jquery-1.4.2.min.js"><\/script>');</script> <script language='javascript'> $(document).ready(function () { if ($("h3[class='ms-CommentHeader']").length == 1) { window.location.href = window.location.href.replace(".aspx?", "1.aspx?"); } });</script>
Final Comments
To make this feature available for all the webs just create a feature stapler which activates the web based feature just like its done in "BlogFixSite".I know many people wont agree with my solution but right now it is what it is. Happy Coding. Do let me know if this helped you.
No comments:
Post a Comment