Dynamic Export of SharePoint Documents as Zip folder via Model Driven Apps selecive Views

Downloading SharePoint Documents in Bulk as a ZIP folder for (Printing / Maling purpose etc.) via Model Driven based on your selective filter is a highly demand featured now a days. Our Team has able to develop a Solution which was eventually a game changer as part of our G-Banking Product, so decided to share it with community.

Objective:
To Download multiple documents directly to your PC from SharePoint from Model Driven Apps based on your Views criteria.

Solution:
Solution comprises of 4 main components.
  1. Custom Button with Library
  2. JavaScript
  3. Action
  4. Plugin
Below will be the Final Results you will See on Your Screen.





Plugin Code:

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace CustomerPlugin
{
    public class AccessTokenCallPlugin : IPlugin
    {
        void IPlugin.Execute(IServiceProvider serviceProvider)
        {
            var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            if (context.Depth > 1) // return for infinite loop
                return;
            var factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            var service = factory.CreateOrganizationService(context.UserId);
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            tracingService.Trace("AccesTokenCall Plugin Starts");
            try
            {
                //Initial Tracking Service Message
                tracingService.Trace("Plugin Starts");
                string fetchXMLBodyData = @"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
                <entity name='gits_configurationparameter'>
                <attribute name='gits_configurationparameterid' />
                <attribute name='gits_name' />
                <attribute name='gits_value' />
                <attribute name='createdon' />
                <order attribute='gits_name' descending='false' />
                <filter type='and'>
                <filter type='or'>
                <condition attribute='gits_name' operator='eq' value='SharePoint Access Token Client Id' />
                <condition attribute='gits_name' operator='eq' value='SharePoint Access Token Tenant Id' />
                <condition attribute='gits_name' operator='eq' value='SharePoint Access Token Client Secret' />
                <condition attribute='gits_name' operator='eq' value='SharePoint Access Token Resource' />
                </filter>
                </filter>
                </entity>
                </fetch>"; 
                string ClientId = "";
                string TenantId = "";
                string ClientSecret = "";
                string Resource = "";
                EntityCollection BodyDetails = service.RetrieveMultiple(new FetchExpression(fetchXMLBodyData));
                if (BodyDetails.Entities.Count > 0)
                {
                    for (int i = 0; i < BodyDetails.Entities.Count; i++)
                    {
                        if (BodyDetails[i].Attributes["gits_name"].ToString() == "SharePoint Access Token Client Id")
                        {
                            ClientId = BodyDetails[i].Attributes["gits_value"].ToString();
                            tracingService.Trace("1");
                        }
                        if (BodyDetails[i].Attributes["gits_name"].ToString() == "SharePoint Access Token Tenant Id")
                        {
                            TenantId = BodyDetails[i].Attributes["gits_value"].ToString();
                            tracingService.Trace("2");
                        }
                        if (BodyDetails[i].Attributes["gits_name"].ToString() == "SharePoint Access Token Client Secret")
                        {
                            ClientSecret = BodyDetails[i].Attributes["gits_value"].ToString();
                            tracingService.Trace("3");
                        }
                        if (BodyDetails[i].Attributes["gits_name"].ToString() == "SharePoint Access Token Resource")
                        {
                            Resource = BodyDetails[i].Attributes["gits_value"].ToString();
                            tracingService.Trace("4");
                        }
                    }
                }
                tracingService.Trace("Plugin Continued");
                tracingService.Trace(ClientId);
                tracingService.Trace(TenantId);
                tracingService.Trace(ClientSecret);
                tracingService.Trace(Resource);
                Body token = new Body
                {
                    grant_type = "client_credentials",
                    client_id = ClientId + "@" + TenantId,
                    client_secret = ClientSecret,
                    resource = Resource + "@" + TenantId
                };


                var client = new RestClient(@"https://accounts.accesscontrol.windows.net/b3180c2a-402f-440f-852e-3c8eb5c51931/tokens/OAuth/2") { Timeout = int.MaxValue };
                var request = new RestRequest(Method.POST);
                request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
                //request.AddParameter("application/x-www-form-urlencoded", $"grant_type={token.grant_type}&client_id={token.client_id}&client_secret={token.client_secret}&resource={token.resource}", ParameterType.RequestBody);
                request.AddObject(token);
                //request.AddParameter("application/json", json, ParameterType.RequestBody);
                IRestResponse response = client.Execute(request);
                tracingService.Trace($"GBP API StatusCode: {response.StatusCode}");
                //tracingService.Trace($"GBP API Response: {response.Content}");
                if (response.IsSuccessful && response.StatusCode == HttpStatusCode.OK)
                {
                    var data = (JObject)JsonConvert.DeserializeObject(response.Content);
                    if (data != null)
                    {
                        tracingService.Trace("Data is not Null Condition");
                        string accessToken = data["access_token"].ToString();
                        tracingService.Trace($"GBP API Response: {accessToken}");
                        context.OutputParameters["TokenOutput"] = accessToken;

                    }
                }

                //End Tracking Service Message
                tracingService.Trace("CreateDefendantonPoliceCaseCreate Plugin End");
            }
            catch (Exception ex)
            {
                tracingService.Trace("Exception: " + ex.Message);
                throw new InvalidPluginExecutionException(ex.Message);
            }
        }
        public class Body
        {
            public string grant_type { get; set; }
            public string client_id { get; set; }
            public string client_secret { get; set; }
            public string resource { get; set; }
        }
    }
}


Action:


JavaScript Code:

function DownloadAllLetterWithMailSentNo(selectedControl){
var Filter = selectedControl.getFetchXml().substr(selectedControl.getFetchXml().indexOf("<filter"));
Filter = Filter.split("<attribute")[0]
        var FetchForData = "<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false' >" +
"<entity name='gits_collectionletters'>" +
"<attribute name='gits_sharepointlink'/>" +
"<order attribute='gits_dayspastdue' descending='false'/>" + Filter
+
"</entity>" +
"</fetch>";
FetchForData =FetchForData.replace(/"/g, "'");
var Data = XrmServiceToolkit.Soap.Fetch(FetchForData); 
console.log(Data);
var sharepointUrl;
var reqs = new XMLHttpRequest();
reqs.open("GET", window.parent.Xrm.Page.context.getClientUrl() + "/api/data/v9.1/gits_configurationparameters?$select=gits_value&$filter=gits_name eq 'SharePoint Access URL'", false);
reqs.setRequestHeader("OData-MaxVersion", "4.0");
reqs.setRequestHeader("OData-Version", "4.0");
reqs.setRequestHeader("Accept", "application/json");
reqs.setRequestHeader("Content-Type", "application/json; charset=utf-8");
reqs.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
reqs.onreadystatechange = function() {
if (this.readyState === 4) {
    reqs.onreadystatechange = null;
    if (this.status === 200) {
        var results = JSON.parse(this.response);
        for (var i = 0; i < results.value.length; i++) {
            debugger;
           sharepointUrl = results.value[i]["gits_value"];
        var count = 0;
        var zip = new JSZip();
        var Token = _SynCallActionAPI('Your_Action_Name_To_Get_Sharepoint_AccessToken');
        for (var i = 0; i < Data.length; i++) {
            debugger;
            var gits_sharepointlink = Data[i].attributes["gits_sharepointlink"].value;
            var filepath = gits_sharepointlink;
            var access_token = "Bearer " + Token;
            var url = sharepointUrl + "_api/Web/GetFileByServerRelativePath(decodedurl='"+filepath+"')/$Value";
            var XHR = new XMLHttpRequest();
XHR.open("GET",url, true); 
XHR.setRequestHeader("Authorization",access_token);
XHR.responseType= "blob";
var filename;
XHR.onload = function(e) {
    var url = e.srcElement.responseURL.substring(0,e.srcElement.responseURL.length-9);
    url = url.substring(url.lastIndexOf('/')+1);
    filename = url.replace(/%20/g, " ");
    debugger;
    if (this.status == 200) {
     debugger;
        var zipFilename = "Collection Letters.zip";
    var myBlob = this.response;
// then trigger the download link:        
     zip.file(filename, myBlob, {binary:true});
      count++;
      if(count == Data.length){
    zip.generateAsync({type:"blob", compression: "DEFLATE" })
.then(function(content) {
    saveAs(content, zipFilename);
}, function(err){
    console.log(err)
});
}
          }
        };   
XHR.send();
        }
        }
    } else {
        Xrm.Utility.alertDialog(this.statusText);
    }
}
};
reqs.send();
}
function _SynCallActionAPI(actionName, parameters) {
debugger;
var results = null;
var setName = actionName;
var API_ENDPOINT = this._APIPath();
var APIData = API_ENDPOINT + setName;
query = APIData;
var req = new XMLHttpRequest();
req.open("POST", query, false);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.onreadystatechange = function () {
if (this.readyState == 4) {
req.onreadystatechange = null;
if (this.status == 200) {
results = JSON.parse(this.response);
results=results.TokenOutput;
}
else {
Xrm.Utility.alertDialog(this.statusText);
}
}
};
req.send();


return results;
}

function _APIPath() {
    if(this._UCIClient){
    return parent.Xrm.Page.context.getClientUrl() + "/api/data/v9.0/";
    }
    return Xrm.Page.context.getClientUrl() + "/api/data/v9.0/";
    
    }
function _UCIClient() {
        return Xrm.Internal.isUci();
        }

Custom Ribbon Button Library:

You will need 3 Libraries to add on your form.













Comments