Monday, 14 March 2016

Get List of all users in WEB 8. A basic alchemy plugin


Basic Steps 
1.    Download the Developer pack from visual studio gallery Link.
2.    Alchemy version that I have used can be downloaded from Alchemy4Tridion Version: 0.8.0.0 link.
3.    Create a project selecting "Starter Plugin Project" template change the project name .
4.    Build the project and navigate to the generated .a4t file.
5.    Drag and drop the file in alchemy window.



You can read the basics of an Alchemy plugin in the documentation 

Lets update the files go to : PluginControllers.cs  go to action methods and using CoreService client we can get the list of all users created in CM.

public string GetUserList()
   {
      List<TridionUserDetails> AuthorList = new List<TridionUserDetails>();
      var filter = new UsersFilterData { IsPredefined = false };
      var users = Client.GetSystemWideList(filter);
       foreach (TrusteeData user in users)
            {
AuthorList.Add(new TridionUserDetails(user.Id, user.Description,user.Title, user.IsEditable));
            }
               
          }            
      var output = JsonConvert.SerializeObject(AuthorList);
           
      return output.ToString();
   }

public class TridionUserDetails
{
    private string tcmuri;
    private string name;
    private string title;
    private bool? isEditable;


    public TridionUserDetails(string tcmuri, string name, string title, bool? isEditable)
    {
        this.tcmuri = tcmuri;
        this.name = name;
        this.title = title;
        this.isEditable = isEditable;


    }

    public string Tcmuri
    {
        get { return tcmuri; }
        set { tcmuri = value; }
    }

    public string Name
    {
        get { return name; }
        set { name = value; }
    }
    public string UserId
    {
        get { return title; }
        set { title = value; }
    }

    public bool? IsEditable
    {
        get { return isEditable; }
        set { isEditable = value; }
    }



}
Here, i have converted the output into JSON :) .later on you can consume this JSON on the popup window using Javascript e:g angular.js.

Command.JS file 

/**
 * Creates an anguilla command using a wrapper shorthand.
 *
 * Note the ${PluginName} will get replaced by the actual plugin name.
 */
Alchemy.command("${PluginName}", "GetUserList", {

    /**
     * If an init function is created, this will be called from the command's constructor when a command instance
     * is created.
     */
    init: function () { 
    },

    /**
     * Whether or not the command is enabled for the user (will usually have extensions displayed but disabled).
     * @returns {boolean}
     */
    isEnabled: function () {
        return true;
    }, 
    /**
     * Whether or not the command is available to the user.
     * @returns {boolean}
     */
    isAvailable: function () {
        return true;
    }, 
    /**
     * Executes your command. You can use _execute or execute as the property name.
     */
    execute: function () { 
       var progress = $messages.registerProgress("Getting ready to GetUserList...", null); 
        // This is the Promise pattern that the webapi proxy js exposes. Look at another example to
        // see how the callback method can also be used. Your WebAPI controller's route and route prefix
        // attributes controls how the namespace is generated.
        Alchemy.Plugins["${PluginName}"].Api.Service.GetUserList()
            .success(function (message) {
                //first arg in success is what's returned by your controller's action
                $messages.registerGoal(message);
            })
            .error(function (type, error) {
                // first arg is string that shows the type of error ie (500 Internal), 2nd arg is object representing
                // the error.  For BadRequests and Exceptions, the error message will be in the error.message property.
                $messages.registerError("There was an error", error.message);
            })
            .complete(function () {
                // this is called regardless of success or failure.
               // progress.finish();
            });
    }
});

If you wants to open pop-up then you need to create .aspx page in the views folder 

var url = "${ViewsUrl}/ListOfUsers.aspx?uri=" + message;
popup = $popup.create(url, "menubar=no,location=no,resizable=no,scrollbars=yes,status=no,width=800,height=800", null);
popup.open();

PluginCommandSet.CS

public PluginCommandSet()
{
     // we only need to add the name of our command
     AddCommand("GetUserList");
}

PluginContextMenuExtension.CS

public PluginContextMenuExtension()
        {
            AssignId = ""; 
            // Use this property to specify where in the context menu your items will go
            InsertBefore = Constants.ContextMenuIds.MainContextMenu.SendItemLink; 
            // Use AddItem() or AddSubMenu() to add items for this context menu 
            //       element id      title        command name
            AddItem("Get_User_List_cm", "GetUsersList", "GetUsersList"); 
            // Add a dependency to the resource group that contains the files/commands that this toolbar extension will use.
            Dependencies.Add<PluginResourceGroup>(); 
            // apply the extension to a specific view.
            Apply.ToView(Constants.Views.DashboardView);
        }

PluginResourceGroup.CS 

public PluginResourceGroup()
        {
            // only the filename of our JS files are needed
            AddFile("Command.js");
            // only the filename of our CSS files are needed
            AddFile("Styles.css");
            // add genertic type param to reference our command set
            AddFile<PluginCommandSet>();

            // Adds the web api proxy JS to this resource group... this allows us to call
            // our webapi service without any 3rd party libs.
            AddWebApiProxy();

            // AddWebApiProxy() includes Alchemy.Core as a dependency already... if not using
            // the proxy you can remove the comment from below.

            // Dependencies.AddAlchemyCore();
        }

PluginRibbonToolbarButton.CS

  public PluginRibbonToolbarButton()
        {
            // The unique identifier used for the html element created.
            AssignId = "GetUsersListButton";

            // The name of the command to execute when clicked
            Command = "GetUsersList";

            // The label of the button.
            Name = "GetUsersList";

            // The page tab to assign this extension to. See Constants.PageIds.
            PageId = Constants.PageIds.HomePage;

            // Option GroupId, put this into an existing group (not capable if using a .ascx Control)
            GroupId = Constants.GroupIds.HomePage.ShareGroup;

            // The tooltip label that will get applied.
            Title = "GetUsersList";

            // Add a dependency to the resource group that contains the files/commands that this toolbar extension will use.
            Dependencies.Add<PluginResourceGroup>();

            // apply the extension to a specific view.
            Apply.ToView(Constants.Views.DashboardView, "DashboardToolbar");
        }


And Image files in the Images folder and update the Style.css.i have added two files user16.png and user32.png


/**
 * Style the context menu button... #Get_User_List_cm is defined in our Context Menu Extension class' AssignId property
 */
.contextmenu #Get_User_List_cm> .image {
    background-image: url('${ImgUrl}user16.png');
}

/**
 * Style the ribbon tool bar button... #GetUsersListButton is defined in our Ribbon Toolbar Button class' AssignId property
 */
/* main icon in full ribbon mode */
.ribbontoolbar #GetUsersListButton.button .image, .ribbontoolbar #GetUsersListButton.button .image
{
    background-image: url('${ImgUrl}user32.png');
}

/* main icon in minimized ribbon mode */
.ribbontoolbar.minimized #GetUsersListButton.button .image, .ribbontoolbar.minimized #GetUsersListButton.button .image
{
    background-image: url('${ImgUrl}user16.png');
}

After Updating all the files built your project and navigate to the generated .a4t file 




Open Alchemy In CM and  Drag and drop the .a4t  file in alchemy window.



    Refresh the CM session  and go to Content Explorer 




      Here you can see new option is added which is GetUserList click on it and you will get the list of users

      





Happy Coding and keep Sharing !!!!

Thursday, 10 March 2016

Forms in DD4T MVC and SDL Tridion

How to create forms in DD4T MVC and SDL Tridion using Schema and components

Here we have used only two different schema to create forms.

·         Form field Schema: - Is used to create the controls such as text box, radio button etc.

o   Here i have field type ,field name and label text
o   You can create field Type as category,Keywords to list down all the possible controls





·         Form Builder Schema: - Is used to give the title, Description and here we also linked all our components which was created using Schema Form Field.

o   In This component we will linked all are component created using Form Field  Schema which contains all the different types of fields type Components “First Name, Last Name”.
o   Insert this component as component presentation in your page .





In your DD4T application you can using following sample code lines to render the controls 

@if (FormBuilder.Fields.ContainsKey("title"))
  {
     @FormBuilder.Fields["title"].Value
   }
 @if (FormBuilder.Fields.ContainsKey("description"))
 {
   @FormBuilder.Fields["description"].Value

  }

First Read EmbeddedValues ["sections"] and then LinkedComponentValues

@foreach (var fieldComp in FormBuilder.Fields["fields"].LinkedComponentValues)

{

var fieldType = fieldComp.Fields.ContainsKey("type") ? fieldComp.Fields["type"].Keywords[0].Key : string.Empty;

//In our case it’s a text field

var fieldName = fieldComp.Fields.ContainsKey("name") ? fieldComp.Fields["name"].Value : string.Empty;



var fieldValue = (fieldComp.Fields.ContainsKey("label") && fieldComp.Fields["label"].EmbeddedValues[0].ContainsKey("text")) ? fieldComp.Fields["label"].EmbeddedValues[0][" text"].Values[0] : string.Empty;




<label for=\"{0}\">{1}</label> .FormatArgs(fieldname,fieldname)

//We are using Switch cases to check the field Type and generate control accordingly

switch (fieldType)
{
case "text":
<input type="text" name="@fieldName" />
Break;
case "button":
<button type="button">@fieldValue</button>
}
 }



Happy Coding and keep Sharing !!!!

Friday, 4 March 2016

Drop down on page (DD4T MVC)should be in sync with Custom database. Create Keywords update Component and publish page

Requirement :- All filter drop down on DD4T MVC page should be in sync real-time with custom database






All the above drop-down are populating based on category and keywords.So we need to read client database create  keyword update the component presentation of filter component and publish the page.


Here, I have created the C# console application which keep on running and making sure that the SQL database and tridion taxonomies are in sync.


I have escaped the code of SQL connectivity and loops to iterate the data :)  
  1. Create core service ISessionAwareCoreService Client
public static class CoreServiceConnectionScheme
    {
        public const String netTcp = "net.tcp";
        public const String wsHttp = "http";
        public const String undefined = "undefined";
    }

    public static class CoreServiceFactory
    {
        public static ICoreServiceFrameworkContext GetCoreServiceContext(Uri endpointUri, NetworkCredential windowsNetworkCredentials)
        {
            switch (endpointUri.Scheme.ToLower())
            {
                case CoreServiceConnectionScheme.wsHttp:
                    return GetWsHttpContext(endpointUri, windowsNetworkCredentials);
                case CoreServiceConnectionScheme.netTcp:
                    return GetNetTcpContext(endpointUri, windowsNetworkCredentials);
                default:
                    throw new ArgumentException("The uri connection scheme specified [{0}] is invalid; a valid scheme (ie. http for WsHttp, or net.tcp for NetTcp must be specified).");
            }
        }
public static ICoreServiceFrameworkContext GetWsHttpContext(Uri endpointUri, NetworkCredential windowsNetworkCredentials)
        {
return new CoreServiceFrameworkWsHttpContext(endpointUri, windowsNetworkCredentials);
        }
public static ICoreServiceFrameworkContext GetNetTcpContext(Uri endpointUri, NetworkCredential windowsNetworkCredentials)
        {
return new CoreServiceFrameworkNetTcpContext(endpointUri, windowsNetworkCredentials);
        }
    }


   2. Go to Main method 


static void Main(string[] args)
{
Logger.WriteLog(Logger.LogLevel.INFO, "Calling Keyword creation process");           
CreateKeywords.Process();
Logger.WriteLog(Logger.LogLevel.INFO, "Calling Keyword creation process End"); 
}

    3. Create a class

public class CreateKeywords

{   
public static ICoreServiceFrameworkContext coreService = null;
public static void Process()
{
XmlDocument doc = new XmlDocument();
coreService = CoreServiceFactory.GetCoreServiceContext(new Uri(ConfigurationManager.AppSettings["CoreServiceURL"].ToString()), new NetworkCredential(ConfigurationManager.AppSettings["UserName"].ToString(), ConfigurationManager.AppSettings["Password"].ToString(), ConfigurationManager.AppSettings["Domain"].ToString()));

#region Creating Keywords and updating component
Logger.WriteLog(Logger.LogLevel.INFO, "Checking keyword already exist in tridion or not");  
TridionObjectInfo obj = Helper.GetTridionObject(coreService, ItemType.Keyword, "tcm:1-440-512", "Test");
var tcmID = obj.ObjectCount == 0 ? TridionKeyword.GenerateKeyword(coreService, "3 Test", "Test", "tcm:1-440-512") : "";
Logger.WriteLog(Logger.LogLevel.INFO, "Returned Tcmuri of keyword " + tcmID);

ComponentData component = (ComponentData)coreService.Client.Read(ConfigurationManager.AppSettings["CompId"].ToString(), new ReadOptions());

4. Create new element in component.Content XML 

doc.LoadXml(component.Content);
XmlElement createchild = doc.CreateElement("Filter1");
createchild.InnerText = 3 Test;
doc.DocumentElement.AppendChild(createchild);
component.Content=doc.InnerXml;

component.Id = ConfigurationManager.AppSettings["CompId"].ToString();
Logger.WriteLog(Logger.LogLevel.INFO, "Updating Component " + component.Id);
component = (ComponentData)coreService.Client.Update(component, new ReadOptions());


 Logger.WriteLog(Logger.LogLevel.INFO, "Updating Component done " + component.Id + "Sending page for publishing " + ConfigurationManager.AppSettings["PageId"].ToString());

}

5.To Generate Keywords


public static string GenerateKeyword(ICoreServiceFrameworkContext coreService, string value, string key, string CategoryID)
        {
            try
            {
                KeywordData keyword = (KeywordData)coreService.Client.GetDefaultData(ItemType.Keyword, CategoryID);
                keyword.Id = "tcm:0-0-0";
                keyword.Title = value;
                keyword.Key = key;

                keyword = (KeywordData)coreService.Client.Create(keyword, new ReadOptions());
                Logger.WriteLog(Logger.LogLevel.INFO, "KeyWord TcmID :" + keyword.Id.ToString() + " Under category ID" + CategoryID);
                return keyword.Id.ToString();
            }
            catch(Exception ex)
            {               
                Logger.WriteLog(Logger.LogLevel.ERROR, "GenerateKeyword :" + ex.Message);             
                return "";
            }
           
6. To Publish Use

coreService.Client.Publish(new[] { PageId}, pubData, new[] { target.ToString() }, PublishPriority.High, null);


7. On your DD4T Mvc App you can bind dropdown with keywords

<select id="Filter1">                    
@if (Model.Fields.ContainsKey("Filter1"))
{
foreach (var value in Model.Fields["Filter1"].Keywords)
{
<option value="@value.Key">@value.Title</option>                       
}
}
</select>



Happy Coding and keep Sharing !!!!