2017년 8월 31일 목요일

사이트코어 크롬 익스텐션 (Chrome Extension)

사이트코어 CMS를 사용하다보면 UI 디자인부분 또는 자바스크립 기능에서 불편함 점이있다.

예를 들면, 데스크탑 모드에서 작업을하다보면 Maser 또는 Web DB를 이동해야하는 경우가 간혹(?) 발생하며, 또는 Content Editor에서 아이템 정보를 일괄적으로 늘려야 하는경우도 생긴다.

추가적으로 많은 기능을 필요로화 하지만, Siteocre에서는 모든것은 추가할수가 없다. 이것을 보완하기 위하여, 필자는 크롬 익스텐션에서 Sitecore Extension 이라는 플러그인을 사용한다.

플러그인에는 아주 많은 기능이 있어 모두 다 나열하지는 못하지만, 필자가 생각하는 가장 좋은 기능은 Ctrl+Space key를 사용하여 Shortcut 기능을 수행할수가 있다.

Install at Chrome: Sitecore Extension





 

2017년 8월 30일 수요일

Placeholder 컨트롤 수 제한하기

xEditor를 사용하다보면, 사이트코어 사용자의 권한 설정에 따라 특정한 Placeholder에 하나 이상의 컴포넌트를 제한해야하는 경우가 있다.

또한, 특정한 필드가 각각의 페이지가 아닌, 템플릿 __Standard Values에서 일괄적으로 변경을 해야하는 경우가 있는데, 이럴경우 사이트코어의 GetChromeDataArgs 클래스 파이프라인을 통하여 제한설정을 할수가 있다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
using System;
using System.Collections.Generic;
using System.Linq;
using Sitecore.Pipelines.GetChromeData;
using System.Text.RegularExpressions;
using Sitecore.Diagnostics;
using Sitecore.Data.Items;
using Sitecore.Security.Accounts;
using Sitecore.Layouts;
using Sitecore.Data;
using Sitecore.Data.Fields;

namespace Sitecore.Placeholder.Restriction
{
    public class RemoveDeleteButton : GetPlaceholderChromeData
    {
        public override void Process(GetChromeDataArgs args)
        {
            Assert.ArgumentNotNull(args, "args");
            Assert.IsNotNull(args.ChromeData, "Chrome Data");
            if ("placeholder".Equals(args.ChromeType, StringComparison.OrdinalIgnoreCase))
            {
                string placeholderKey = args.CustomData["placeHolderKey"] as string;

                Sitecore.Data.Fields.LayoutField layoutField = new Sitecore.Data.Fields.LayoutField(Context.Item.Fields[Sitecore.FieldIDs.FinalLayoutField]);
                LayoutDefinition layoutDefinition = LayoutDefinition.Parse(layoutField.Value);
                DeviceDefinition deviceDefinition = layoutDefinition.GetDevice(Context.Device.ID.ToString());

                // Initial setting path is "/sitecore/system/Modules/Placeholder Restriction Manager/Remove Delete Button"
                Item removeDeleteButtonItem = Context.Item.Database.GetItem("/sitecore/system/Modules/Placeholder Restriction/Remove Delete Button");

                if (removeDeleteButtonItem == null)
                {
                    Assert.IsNull(removeDeleteButtonItem, "Item is null");
                    return;
                }

                MultilistField listOfRenderingItemsDelete = removeDeleteButtonItem.Fields["List of Rendering Items"];
                string listOfUserRolesDelete = removeDeleteButtonItem.Fields["List of Users and Roles"].Value.Trim();
                List<string> eachListOfUserRolesDelete = !String.IsNullOrEmpty(listOfUserRolesDelete) ? listOfUserRolesDelete.Split(';').ToList() : null;

                // Remove "Delete" button in placeholder
                if (eachListOfUserRolesDelete != null && eachListOfUserRolesDelete.Select(e => User.Current.IsInRole(e) || User.Current.LocalName.Equals(e)).Any())
                {
                    args.ChromeData.Custom["removeAddHereButton"] = true;
                    foreach (ID renderingItemId in listOfRenderingItemsDelete.TargetIDs)
                    {
                        RenderingItem r = RenderingItem.GetItem(renderingItemId, Context.Data.Database, true);
                        string renderingName = Regex.Replace(r.Name.ToLower(), @"\s+", "");
                        string displayName = Regex.Replace(args.ChromeData.DisplayName.ToLower(), @"\s+", "");

                        // Only when rendering name matches to its display name
                        // Only when rendering item's display name contains rendering name
                        if (renderingName == displayName || displayName.Contains(renderingName))
                        {
                            args.ChromeData.Custom["editable"] = false;
                        }
                    }
                }
            }
        }
    }
}


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <getChromeData>
        <processor
          type="Sitecore.Placeholder.Restriction.RemoveDeleteButton, Sitecore.Placeholder.Restriction"
          patch:after="processor[@type='Sitecore.Pipelines.GetChromeData.GetPlaceholderChromeData, Sitecore.Kernel']"/>
      </getChromeData>
    </pipelines>
  </sitecore>
</configuration>

2017년 8월 8일 화요일

사이트코어와 Slack (슬랙) API 연동하기

이번에는 사이트코어와 Slack API 연동에 대하여 알아보도록 하겠다.

Slack API은 메신저와 같은 커뮤니케이션 공간으로써, 많은 유저들이 하나의 커뮤니티 공간에서 많은 채널 (채팅방)을 서로 공유하며, 정보를 주고 받을 수가 있다.

개발자들 및 IT 유저들 사이에는 이미 널리 알려진 웹어플리케이션으로써, 필자가 일하고 있는 회사에서도 역시 직원들의 커뮤니티 공간으로 잘 활용을 하고 있다.

이전에 포스트에서 올려놓았던 Workflow Related Item 업데이트 하기에서 Custom Workflow를 소개하였으며, Workflow가 업데이트 될때마다 관리자 및 검증자가 업데이트 되어진 정보를 이메일로 받는 동시에, Slack API를 통하여 Slack 채널에도 업데이트된 정보가 올려지도록 클래스를 많들었다.

우선, Real-Time message를 전송하기 위하여, Slack 플러그인 (Incoming WebHooks)을 추가적으로 설치한 후,  Webhook URL의 값을 WebClient의 UploadString 메쏘드 파라미터로 입력을 한다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
public static class PostSlackMessage
{
    public static void PostMessage(Item pageItem, User user, bool isPublished, string comment = null)
    {
        if (pageItem == null) {
            Sitecore.Diagnostics.Assert.IsNull(null, "Page Item can't be found!");
        }
        if (user == null) {
            Sitecore.Diagnostics.Assert.IsNull(null, "User can't be found!");
        }

        string pagePath = pageItem.Paths.Path.ToString().ToLower();
        pagePath = pagePath.Replace(Sitecore.Context.Data.Site.RootPath.ToLower(), "");
        pagePath = pagePath.Replace(Sitecore.Context.Data.Site.StartItem.ToLower(), "");

        string requestedByEmail = user.Profile.Email;
        string requestedByFullName = user.Profile.FullName;
        string updatedByEmail = User.FromName(pageItem.Statistics.UpdatedBy, true).Profile.Email;
        string updatedByFullName = User.FromName(pageItem.Statistics.UpdatedBy, true).Profile.FullName;
        string requestedDate = DateTime.Now.ToString("g");
        
        string pretextMsg = "Approval Request :file_cabinet:";
        string fallbackMsg = "ReferenceError - UI is not defined";
        string titleMsg = "<https://yoursitecms.com" + pagePath + "|" + pageItem.Fields["Page Title"].Value + "> - " + pagePath;
        string commentMsg = comment;
        string colorMsg = "#FF8000";
        
        if (isPublished)
        {
            pretextMsg = "Approved and Published :white_check_mark:";
            titleMsg = "<http://yoursitecds.com" + pagePath + "|" + pageItem.Fields["Page Title"].Value + ">";
            colorMsg = "#36a64f";
        }
        var field = new[]{
                new {
                    title = (isPublished) ? "Approved by" : "Requested by",
                    value = "<mailto:" + requestedByEmail + "|" + requestedByFullName + ">",
                    @short = true
                },
                new {
                    title = "Updated by",
                    value = "<mailto:" + updatedByEmail + "|" + updatedByFullName + ">",
                    @short = true
                },
                new {
                    title = (isPublished) ? "Approved Date" : "Requested Date",
                    value = requestedDate,
                    @short = true
                },
                new {
                    title = "Page Version",
                    value = pageItem.Version.Number.ToString(),
                    @short = true
                }
        };

        var message = new
        {
            username = "Mr. Sitecore",
            channel = "G690XEDK4", // Private Channel "Sitcore Publishing"
            icon_emoji = ":sitecore:",
            attachments = new[]{ 
                new {
                    pretext = pretextMsg,
                    fallback = fallbackMsg,
           title = titleMsg,
           text = commentMsg,
                    color = colorMsg,
                    fields = field
                }
            }
        };

        var json = JsonConvert.SerializeObject(message);

        var webClient = new WebClient();
        webClient.Headers[HttpRequestHeader.ContentType] = "application/json";
        webClient.UploadString("https://hooks.slack.com/services/your/code/here", json);
    }
}



1
2
// Post Slack Message
PostSlackMessage.PostMessage(args.DataItem, User.Current, true, args.CommentFields["Comments"].ToString());