Friday, 9 February 2018

Unique ticket number generation in SharePoint Lists

There are multiple requirements for Unique ticket number generation in SharePoint Lists.
It can be achieved by below JavaScript code and calling it content editor/Script Editor in NewForm.aspx


It generates Random ticket number along with Year and month value extracted from client machine's Year and Month parameter.
Replace "COLUMN_NAME" with the Display Value of the column name which needs to be written with the Unique ticket number generation. e.g. your Column field is Ticket Number then


var columnName = "Ticket Number";


Using little modification same can be utilized in jsLink of the New Item section of the List as well.


This ticket number gives user easy interpretation of ticket detail.
Prefix :- This is specify source of ticket generation e.g. for SharePoint online
Year-Month :- This is give the detail when the ticket was created
Ticket Number :- Unique ticket number for tracking of tickets.




 
<!-- Sricpt for Random ticket generation method Starts-->

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js">

</script>
<script type="text/javascript">

var columnName = "COLUMN_NAME";
var prefixVal = "TicketNo";
$(document).ready(function () {
var listName = _spPageContextInfo.listTitle;
// SP.PageContextInfo.get_pageListId();
var eleReq = $("input[title='" + columnName+"']"); // Get Element to update the
var dateTime = new Date();

getLastItemId();

function getLastItemId() {

var caml = "<View><Query><Where>"

+ "<Geq><FieldRef Name='ID' /><Value Type='Integer'>"

+ 0 + "</Value></Geq></Where>"

+ "<OrderBy><FieldRef Name='ID' Ascending='False' /></OrderBy>"

+ "</Query><RowLimit>1</RowLimit></View>";
var ctx = SP.ClientContext.get_current();
var web = ctx.get_web();
var list = web.get_lists().getByTitle(listName);
var query = new SP.CamlQuery();
query.set_viewXml(caml);

var items = list.getItems(query);
ctx.load(items); ctx.executeQueryAsync(function () {

// success actions
var id = "00000";
var enumerator = items.getEnumerator();
enumerator.moveNext(); var item = enumerator.get_current();

try {
id = item.get_id(); }
catch (exception)

{ // For first item it will return nothing.. thus it is set to 00000
id = "00000";
}

var fiveDigitId = "00000";
fiveDigitId = fiveDigitId.substring(id.toString().length) + id;
var strRedId = prefixVal + dateTime.toISOString().slice(0, 8).replace(/-/g, "") + fiveDigitId;//



eleReq.val(strRedId);


}, function () {


var strRedId = prefixVal + dateTime.toISOString().slice(0, 8).replace(/-/g, "") + Math.floor((Math.random() * 10000) + 1);
eleReq.val(strRedId); });
}
});


</script>

<!-- Sricpt for Random ticket generation method ENDS-->

Thursday, 17 March 2016

Rich Text Editor validator (using HTML Parser) in SharePoint 2013

Requirement:
Contents in SharePoint in rich text column was getting consumed in iOS app.
There was some issues in WebView consuming some of the data which it find was not well formatted. Although such contents were rendered perfectly alright in SharePoint.

Solution:
Using JSlink rich text were validated on Blur of the rich text div element.

(function () {
    var zPlaceholder = "Default";
    var overrideCtx = {};
})();

jQuery(document).ready(function () {
   
  
    jQuery.getScript(_spPageContextInfo.siteAbsoluteUrl + '/Style%20Library/scripts/htmlparser.js', GetRTEandFixHtml());
});

function GetRTEandFixHtml() {
    // Get the rich text edit field by id starts with e.g. [id^='ProfileInformation'] ...
   // along with class and role
    var ProfileInformation = $("div[id^='ProfileInformation'][class='ms-rtestate-write ms-rteflags-0 ms-rtestate-field'][role='textbox']");
    if (ProfileInformation !== "undefined" || ProfileInformation !== null) {
        ProfileInformation.blur(function () {
            fixHTML(ProfileInformation, ProfileInformation.html());
        });
    }

    function fixHTML(element, html) {
        // Check if there is value or not before validating HTML...
        if (html.indexOf("div class=") > 0 && html.indexOf("ExternalClass") > 0) {
            try {
                var d = document.createElement('div');
                d.innerHTML = html;
                element.html(d.innerHTML); // Strips off script tags, which was major issue;
                var modifiedHTML = HTMLtoXML(d.innerHTML);// Can implement htmlparser.js call .. there are few available in JS;
                element.html(modifiedHTML);
            }
            catch (e) {
                element.html(html);
                element.unbind('blur');
            }
        }
    }

}

Tuesday, 29 September 2015

Delete Multiple sites ECMA script -

DeleteSite: function () {

var count=siteUrlArray.length;

var i = 0;

for (i = 0; i < siteUrlArray.length; i++) {

var url = siteUrlArray[i];

var clientContext = new SP.ClientContext(url);

var oweb = clientContext.get_web();

oweb.deleteObject();
         
}
clientContext.executeQueryAsync(function () { alert("Total site deleted= "+count); }, function () { });


}
-------------
Above functions shows how to delete multiple sites using ECMA Script. If any one is aware of bulk delete by JSOM using REST API plz do share.



Wednesday, 5 August 2015

Send Email using ecma script/JSOM / REST API - SharePoint

Below is the send email functionality based on SP.js As we can see below we have TO field commented out. Call 1: Sending to single user
var msg="html message to send";
buildContent.sendEmail("admin@test.com", "user@test.com" , msg, "Alert Notification!!");
in that case uncomment the line
// 'To': { 'results': [to] },
and comment the next line.

If we want to send to multiple users and SharePoint user Groups.

Call 2:
var to = [];
to.push("testUser1@test.com");
to.push("testUser2@test.com");
to.push("Site Owners");
var msg="html message to send";
buildContent.sendEmail("admin@test.com", to, msg, "Alert Notification!!");

sendEmail: function (from, to, body, subject) {
var siteurl = _spPageContextInfo.webServerRelativeUrl;
var urlTemplate = siteurl + "/_api/SP.Utilities.Utility.SendEmail";
        $.ajax({
            contentType: 'application/json',
            url: urlTemplate,
type: "POST",
            data: JSON.stringify({
'properties': { '__metadata': { 'type': 'SP.Utilities.EmailProperties' },
'From': from,
// 'To': { 'results': [to] },
'To': { 'results': to }, //
'Body': body, 'Subject': subject
                } } ),
            headers: { "Accept": "application/json;odata=verbose", "content-type": "application/json;odata=verbose", "X-RequestDigest": $("#__REQUESTDIGEST").val() }, success: function (data) { alert("Email send"); }, error: function (err) { alert(err.responseText);
// debugger;
} }); },

reference : http://blogs.msdn.com/b/spses/archive/2014/10/24/you-can-t-specify-the-from-address-for-email-messages-when-you-use-the-quot-send-an-email-quot-option-from-a-sharepoint-designer-2013-workflow-action.aspx 

Monday, 21 July 2014

"Active Profile" & Profiles missing from Import

As the title suggests we have two types of users under Manage Users section.

We were experiencing some issue with user repotee in custom organization chart.
A user who has left the company long back was reflecting in user profile:- Org Chart data.

From central admin this user was not available in "Active Profile" , but under Profile Import missing.

What seems to happen is subsequent User Profile Sync.. not has deleted the relationship as well as (Manager /Reportee ) and not deleted the stale data for users already not in the company / AD. This has to be fixed by running the "My Site Cleanup Job"

Thursday, 19 June 2014

Alerts update fixes post SharePoint Migration

Based on the contributions from Kirk Stark & skelley. There were few queries for Q & A section of getting the siteUrl property to be updated by Site Collection against the Web Application URL.

First query your site collections DB migrated based on DB Attach Upgrade against the following tables immedsubscriptions & schedsubscriptions
That's what I modified the above codes from powershell  & console app to take inputs from a text file as 3 set of values.
It reads a Alerts.csv placed at C:\ drive which has parameters as
SiteUrl,OldUrl,NewUrl

values can be
SiteCollection1Url,OldUrl,NewUrl
SiteCollection1Url,Old1Url,New1Url
SiteCollection2Url,OldUrl,NewUrl
SiteCollection2Url,Old1Url,New1Url
based on the results retuned against the above table in your case. (based on different zones values default, Intranet or Internet)

Note that the SiteUrl in the properties section has to be Web Application url while Mobile url may not the same. Please note the mobileurl section has been commented out. To cater to that scenario, u can pass 5 set of parameters in Alerts.csv and update accordingly.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using System.IO;

namespace AlertUpdates
{
   class Program
{
static int countsiteurlprop = 0;
static int countmobileurlprop = 0;

static string strSiteCollection =string.Empty;// Site collection url to open new context

static string strOldString =string.Empty; //old url or portion of string which needs to be replaced.// http://novahome

static string strNewString = string.Empty; //new url which will be replaced by the old Url

static void Main(string[] args)
{
try
{
using (StreamReader reader = new StreamReader(File.OpenRead(@"C:\Alerts.csv")))


{
while (!reader.EndOfStream)


{
string line = reader.ReadLine();

var values = line.Split(',');


strSiteCollection = values[0];

strOldString = values[1];

strNewString = values[2];
// GetFileOutput();


IterateSites();

}

}

}
catch (Exception ex)
{
 
Console.WriteLine("Error:"+ex.Message);

}
 Console.ReadLine();

}
        
           
static void IterateSites()


{
           

try


{
using (SPSite spsitecol = new SPSite(strSiteCollection))


{
using (SPWeb sprootweb = spsitecol.RootWeb)


{

ListAndFixAlerts(sprootweb);
} // using sprootweb

} // using spsitecol


}
catch (System.IO.FileNotFoundException ioex)


{
Console.WriteLine("Could not access Site Collection: {0}", ioex.Message);


}
catch (Exception ex)


{
Console.WriteLine("An unexpected error occurred: {0}", ex.Message);

} // try

//}

//else

Console.WriteLine(" Modified count for siteUrlCount : {0} & mobileUrlCount: {1}", countsiteurlprop, countmobileurlprop);

Console.WriteLine(Environment.NewLine + "Update done! Click to exit.");

Console.ReadLine();


}
//Enumerates all Alerts present on a Site Collection and modifies them

//so that wrong information (for example, in the SiteUrl column) is corrected.

static void ListAndFixAlerts(SPWeb spweb)


{
Console.WriteLine("\n{0} Alert(s) for site: {1} ({2})", spweb.Alerts.Count, spweb.Title, spweb.Url);

string oldurl = strOldString;

string newurl = strNewString;// spweb.Site.Url;

foreach (SPAlert alert in spweb.Alerts)


{
try


{


SPPropertyBag spprop = alert.Properties;

Console.WriteLine(" {2} Alert \"{0}\" for user \"{1}\" \n (Id: {3})\n", alert.Title, (alert.User != null ? alert.User.Name : "<unknown>"), alert.AlertFrequency.ToString(), alert.ID.ToString());

//Preserve the initial Alert frequency (Immed., Daily, Weekly).

SPAlertFrequency afPrevious = alert.AlertFrequency;

//Change the Alert frequency so the datarow inside

//is touched by SharePoint API.

if (afPrevious == SPAlertFrequency.Immediate)

alert.AlertFrequency = SPAlertFrequency.Weekly;

else

alert.AlertFrequency = SPAlertFrequency.Immediate;

try


{
if (spprop["siteurl"] != null) //fix hard coded properties


{
//Console.WriteLine("pre alert site url: " + spprop["siteurl"].ToString());

if (spprop["siteurl"].Contains(oldurl)) //found old link reference/


{
spprop["siteurl"] = spprop["siteurl"].Replace(oldurl, newurl);

//Console.WriteLine("post alert site url: " + spprop["siteurl"].ToString());

Console.WriteLine("Updated siteurl in properties");


countsiteurlprop++;

spprop.Update();

}

}

/*
if (spprop["mobileurl"] != null){

//Console.WriteLine("alert mobile url: " + spprop["mobileurl"].ToString());

if (spprop["mobileurl"].Contains(oldurl)) //found old link reference/


{
spprop["mobileurl"] = spprop["mobileurl"].Replace(oldurl, newurl);

Console.WriteLine("Updated mobileurl in properties");


countmobileurlprop++;

spprop.Update(); }}
*/



alert.Update();
//Change the Alert frequency back to the initial state.


alert.AlertFrequency = afPrevious;

alert.Update();

}
catch (Exception ex)


{
Console.WriteLine(" -> Error changing Alert. {0}", ex.Message);

} // inner try


}
catch (Exception ex)


{
Console.WriteLine(" An unexpected error occurred while accessing the Alert object: {0}", ex.Message);

} // outer try

} // foreach alert



//Handle all Sub-Webs recursively.

if (spweb.Webs.Count > 0)


{
for (int i = spweb.Webs.Count - 1; i >= 0; i--)


{
using (SPWeb spsubweb = spweb.Webs[i])


{

ListAndFixAlerts(spsubweb);
} // using spsubweb

} //for subwebs

} //if has subweb


}

}

}