Thursday, October 30, 2014

SharePoint 2013 Blog template custom web part

Hi all.
Today I want to continue my previous post (http://sharepointandaspnet.blogspot.com/2014/07/how-to-expand-sharepoint-2013-blog.html)  about SharePoint 2013 Blog site template.

As we as everybody knows, SharePoint 2013 has a site template Blog. The site template has OOTB web parts that extends the template and adds additional functionality as all usual web blogs have. This web parts you can find when you edit the page of the blog template. There are such web part as Category, Comments and Blog tools, but there is no such part as blog authors to show the last authors that wrote an post. To close the luck of this we will create a custom web part.
1.       Create a farm solution (this will need to read user profiles)
2.       Add web part and name it BlogAuthors



Blog web part will do the following:
1.       It creates a DataSet and DataTable called AuthorsTable
2.       AuthorsTable will store all temporary info from list called „Posts”
3.       It reads all item on by one and takes an author from the list
4.       Temporary array uniqueBlogPostUserAcc stores only unique authors objects, because list Posts can contain any author as many post he or she wrote
5.       After that we read array uniqueBlogPostUserAcc to get user property such as picture from author profile
6.  If user has a picture in profile we fill a table AuthorsTable with author name, picture and article url that we created in a previous post (http://sharepointandaspnet.blogspot.com/2014/07/how-to-expand-sharepoint-2013-blog.html)
7.       Fill in a web contol repeater datasource that is located on VisualWebPart1.ascx with authorsTable

Note. I wrote a custom class InfoAndErrorLogger with method LogEvent to log an error in SharePoint ULS logs in case of catching exceptions.
InfoAndErrorLogger.LogEvent(TraceSeverity.Monitorable, "Blog webpart exception" + ex);

using System;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
//The following two namespaces are required to work with user profiles
using Microsoft.Office.Server;
using Microsoft.Office.Server.UserProfiles;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Data;
using System.Collections.Generic;
using BlogAuthorsWebPartProject.Logger;
using Microsoft.SharePoint.Administration;

namespace BlogAuthorsWebPartProject.VisualWebPart1
{
    [ToolboxItemAttribute(false)]
    public partial class VisualWebPart1 : WebPart
    {
        // Uncomment the following SecurityPermission attribute only when doing Performance Profiling using
        // the Instrumentation method, and then remove the SecurityPermission attribute when the code is ready
        // for production. Because the SecurityPermission attribute bypasses the security check for callers of
        // your constructor, it's not recommended for production purposes.
        // [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Assert, UnmanagedCode = true)]
        public VisualWebPart1()
        {
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            InitializeControl();
        }

   

        protected void Page_Load(object sender, EventArgs e)
        {
           try
              {

            List<SPUser> uniqueBlogPostUserAcc = new List<SPUser>();
            List<int> uniqueBlogPostUserId = new List<int>();
            string authorArticlePage = "PostsByAuthor.aspx";
            string authorParam = "AuthorId";
            string articleUrl;
            DataSet authors = new DataSet();
            DataTable authorsTable = authors.Tables.Add("AuthorsTable");
            authorsTable.Columns.Add("Author");
            authorsTable.Columns.Add("Picture");
            authorsTable.Columns.Add("ArticleUrl");

            /*----------Get Posts list unique users------------*/
                SPWeb spweb = SPContext.Current.Web;
           
                SPList postsList = spweb.Lists["Posts"];
                SPQuery query = new SPQuery();
                query.Query = "<OrderBy><FieldRef Ascending='FALSE' Name='Created' /></OrderBy>";
                query.RowLimit = 12;
                var items = postsList.GetItems(query);
                articleUrl = postsList.ParentWebUrl + "/" + postsList.RootFolder.Url + "/" + authorArticlePage + "?" + authorParam + "=";
                foreach (SPListItem item in items)
                {

                    SPField authorField = (SPField)item.Fields.GetFieldByInternalName("Author");
                    String strAuthor = authorField.GetFieldValueAsText(item["Author"]);

                    SPFieldUser authorFieldUser = (SPFieldUser)item.Fields.GetFieldByInternalName("Author");
                    SPUser blogAuthorUser = GetSPUser(item, "Author");
                    //Get unique blog authors account and push it to List
                    if (!uniqueBlogPostUserId.Contains(blogAuthorUser.ID))
                    {
                       uniqueBlogPostUserId.Add(blogAuthorUser.ID);
                      
                       uniqueBlogPostUserAcc.Add(blogAuthorUser);
               
                    }
                }
           
            /*----------------------*/

                SPSite sitesCollection = SPContext.Current.Site;
           
               
                //Get the user profile manager
                UserProfile profile = null;
                SPServiceContext context = SPServiceContext.GetContext(sitesCollection);
                UserProfileManager profileManager = new UserProfileManager(context);
  
                //Loop through all the user profiles
                foreach (SPUser userAccName in uniqueBlogPostUserAcc)
                {
                    string[] accName = userAccName.LoginName.Split('|');
                    int userAcccountId = userAccName.ID;
                    string userAcccountName = accName[1];
                    string articlePostUrl;
                    profile = profileManager.GetUserProfile(userAcccountName);
                    articlePostUrl = articleUrl + userAcccountId.ToString();
               
                    ProfileValueCollectionBase profileValueCollection = profile.GetProfileValueCollection("PictureURL");
                    ProfileValueCollectionBase profileValueId = profile.GetProfileValueCollection("UserProfile_GUID");
                    //display if the user has set their picture.
                    if ((profileValueCollection != null) && (profileValueCollection.Value != null))
                    {

                
                        authorsTable.Rows.Add(profile.DisplayName, profileValueCollection.Value.ToString(), articlePostUrl);
                    }
                   //display if the user has not set their picture
                    else
                    {
                        authorsTable.Rows.Add(profile.DisplayName, "/_layouts/15/images/person.gif?rev=23", articlePostUrl);
                    }
                }


                BlogAuthorsRepeater.DataSource = authorsTable;
                BlogAuthorsRepeater.DataBind();
           

           }
           catch (Exception ex)
           {
               InfoAndErrorLogger.LogEvent(TraceSeverity.Monitorable, "Blog webpart exception" + ex);
           }
        }
        //Get the user form user field
        public static SPUser GetSPUser(SPListItem item, string key)
        {
            SPFieldUser field = (SPFieldUser)item.Fields.GetFieldByInternalName(key);
            if (field != null)
            {
                SPFieldUserValue fieldValue =
                 field.GetFieldValue(item[key].ToString()) as SPFieldUserValue;
                if (fieldValue != null)
                    return fieldValue.User;
            }
            return null;
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Administration;

namespace BlogAuthorsWebPartProject.Logger
{
    public class InfoAndErrorLogger
    {
        public static void LogEvent(TraceSeverity Level, string OutStr)
        {
            SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("BlogAuthors", Level, EventSeverity.Error), TraceSeverity.Unexpected, OutStr, null);
        }
    }
}

I use PowerShell script to install a wsp package


Install
  # Adding the PowerShell Snapin
cls
if((Get-PSSnapin | Where {$_.Name -eq "Microsoft.SharePoint.PowerShell"}) -eq $null) {
    Add-PSSnapin Microsoft.SharePoint.PowerShell;
}
$webApplication = "http://server"
$webUrl = "http://server/sites/devsite/"

$invocation = (Get-Variable MyInvocation).Value
$currDir = Split-Path $invocation.MyCommand.Path

$solutionName = "BlogAuthorsWebPartProject.wsp"
$solutionPath = $currDir + "\wsp\" + $solutionName
$blogAuthorFeaturePath = "BlogAuthorsWebPartProject_BlogAuthorsFeature"


 Write-Host -ForegroundColor Green "Add Blog authors webpart solution ..."
 #Add Timer Job notification solution
 Add-SPSolution $solutionPath
 Start-Sleep -Seconds 30
  Write-Host -ForegroundColor Green "Installing solution ..."
 #Install Timer Job notification solution
 Install-SPSolution –Identity $solutionName -WebApplication $webApplication -GACDeployment -Force -Confirm:$false
 Start-Sleep -Seconds 30
 Write-Host -ForegroundColor Green "Installing feature ..."
 Install-SPFeature $blogAuthorFeaturePath
 Start-Sleep -Seconds 30
 Write-Host -ForegroundColor Green "Activating feature ..."
 Enable-SPFeature -identity $blogAuthorFeaturePath -URL $webUrl
 Start-Sleep -Seconds 30
 Write-Host -ForegroundColor Green "Done"

Uninstall

cls
if((Get-PSSnapin | Where {$_.Name -eq "Microsoft.SharePoint.PowerShell"}) -eq $null) {
    Add-PSSnapin Microsoft.SharePoint.PowerShell;
}
$webApplication = "http://server"
$webUrl = "http://server/sites/devsite/"

$invocation = (Get-Variable MyInvocation).Value
$currDir = Split-Path $invocation.MyCommand.Path

$solutionName = "BlogAuthorsWebPartProject.wsp"
$solutionPath = $currDir + "\wsp\" + $solutionName
$blogAuthorFeaturePath = "BlogAuthorsWebPartProject_BlogAuthorsFeature"

 Write-Host -ForegroundColor Green "Disabling feature ..."
Disable-SPFeature -identity $blogAuthorFeaturePath -URL $webUrl
 Start-Sleep -Seconds 30
 Write-Host -ForegroundColor Green "Un-Installing feature ..."
 Uninstall-SPFeature $blogAuthorFeaturePath
 Start-Sleep -Seconds 30
 Write-Host -ForegroundColor Green "Un-Installing solution ..."
 Uninstall-SPSolution –Identity $solutionName -WebApplication $webApplication
 Start-Sleep -Seconds 30

 Write-Host -ForegroundColor Green "Remove Blog authors webpart solution ..."
 #Add Timer Job notification solution
 Remove-SPSolution $solutionName
 Start-Sleep -Seconds 30

 Write-Host -ForegroundColor Green "Done"

That’s all.
Have a good day,

Aleks