Created
March 5, 2019 21:45
-
-
Save AThraen/d5acf1f59bb486d82889eb6107283de0 to your computer and use it in GitHub Desktop.
Contentful Content Provider for Episerver
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.ComponentModel.DataAnnotations; | |
| using EPiServer.Core; | |
| using EPiServer.DataAbstraction; | |
| using EPiServer.DataAnnotations; | |
| using EPiServer.Web; | |
| namespace ContentfulDemo.Models.Blocks | |
| { | |
| [ContentType(DisplayName = "Contentful Blog Block", GUID = "f28b3914-509d-41e4-bc8c-da0f63065fd7", Description = "")] | |
| public class CFBlogBlock : BlockData | |
| { | |
| [Editable(false)] | |
| public virtual string Name { get; set; } | |
| [Editable(false)] | |
| public virtual string HeroImage { get; set; } | |
| [Editable(false)] | |
| [UIHint(UIHint.Textarea)] | |
| public virtual string Description { get; set; } | |
| [Editable(false)] | |
| [UIHint(UIHint.Textarea)] | |
| public virtual string Body { get; set; } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @using EPiServer.Core | |
| @using EPiServer.Web.Mvc.Html | |
| @model ContentfulDemo.Models.Blocks.CFBlogBlock | |
| <div class="row"> | |
| <div class="span4 hidden-tablet hidden-phone"> | |
| <img src="@Model.HeroImage"/> | |
| </div> | |
| <div class="span8"> | |
| <h1 class="jumbotron">@Model.Name</h1> | |
| <p class="subHeader">@Model.Description</p> | |
| <p>@Html.Raw(Markdig.Markdown.ToHtml(Model.Body))</p> | |
| </div> | |
| </div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using Contentful.Core; | |
| using ContentfulDemo.Contentful; | |
| using ContentfulDemo.Models.Blocks; | |
| using EPiServer; | |
| using EPiServer.Construction; | |
| using EPiServer.Core; | |
| using EPiServer.Data.Entity; | |
| using EPiServer.DataAbstraction; | |
| using EPiServer.ServiceLocation; | |
| using EPiServer.Web; | |
| using System; | |
| using System.Collections.Generic; | |
| using System.Collections.Specialized; | |
| using System.Globalization; | |
| using System.Linq; | |
| using System.Net.Http; | |
| using System.Web; | |
| using System.Web.Configuration; | |
| namespace ContentfulDemo.ContentfulTools | |
| { | |
| public class ContentfulContentProvider : ContentProvider | |
| { | |
| protected IdentityMappingService IdentityMappingService { get; set; } | |
| protected ExternalTypeMapper TypeMapper { get; set; } | |
| protected IContentTypeRepository TypeRepo { get; set; } | |
| protected IContentFactory _ContentFactory { get; set; } | |
| protected IContentRepository ContentRepo { get; set; } | |
| public const string KEY = "CF"; | |
| private const string BASEURI = "CF://"+KEY+"/"; | |
| private ContentfulClient _Client { get; set; } | |
| public ContentfulContentProvider(IdentityMappingService mappingService,ExternalTypeMapper mapper, IContentTypeRepository typerepo, IContentFactory contentfactory, IContentRepository contentrepo) : base() | |
| { | |
| IdentityMappingService = mappingService; | |
| TypeMapper = mapper; | |
| TypeRepo = typerepo; | |
| _ContentFactory = contentfactory; | |
| ContentRepo = contentrepo; | |
| } | |
| protected override IList<GetChildrenReferenceResult> LoadChildrenReferencesAndTypes(ContentReference contentLink, string languageID, out bool languageSpecific) | |
| { | |
| languageSpecific = false; | |
| if (contentLink.CompareToIgnoreWorkID(EntryPoint)) | |
| { | |
| //Root, list mapped types | |
| //Get list of all mapped items | |
| var results=_Client.GetEntries<dynamic>().Result; | |
| List<GetChildrenReferenceResult> rt = new List<GetChildrenReferenceResult>(); | |
| foreach(var itm in results.Items) | |
| { | |
| string ctid = itm.sys.contentType.sys.id; | |
| if (TypeMapper.TypeMappings.ContainsKey(ctid)) | |
| { | |
| string entryid = itm.sys.id; | |
| var id=IdentityMappingService.Get(new Uri(new Uri(BASEURI), entryid), true); | |
| rt.Add(new GetChildrenReferenceResult() { ContentLink = id.ContentLink, IsLeafNode = true, ModelType = TypeMapper.TypeMappings[ctid].ContentType }); | |
| } | |
| } | |
| //Return those that we can map | |
| return rt; | |
| } | |
| return base.LoadChildrenReferencesAndTypes(contentLink, languageID, out languageSpecific); | |
| } | |
| /// <summary> | |
| /// Loads content items | |
| /// </summary> | |
| /// <param name="contentLink"></param> | |
| /// <param name="languageSelector"></param> | |
| /// <returns></returns> | |
| protected override IContent LoadContent(ContentReference contentLink, ILanguageSelector languageSelector) | |
| { | |
| var lnk = IdentityMappingService.Get(contentLink); | |
| string entryid = lnk.ExternalIdentifier.AbsolutePath.TrimStart('/'); | |
| //Future improvement: Handle languages, load linked content and assets as well | |
| var entry=_Client.GetEntry<dynamic>(entryid).Result; | |
| return GenerateContentFromEntry(entry); | |
| } | |
| /// <summary> | |
| /// Generates the IContent entries | |
| /// </summary> | |
| /// <param name="entry"></param> | |
| /// <returns></returns> | |
| protected IContent GenerateContentFromEntry(dynamic entry) | |
| { | |
| string ctid = entry.sys.contentType.sys.id; | |
| var map = TypeMapper.TypeMappings[ctid]; | |
| string entryid = entry.sys.id; | |
| var id = IdentityMappingService.Get(new Uri(new Uri(BASEURI), entryid), true); | |
| ContentType type = TypeRepo.Load(map.ContentType); //Update | |
| var fc = _ContentFactory.CreateContent(type, new EPiServer.Construction.BuildingContext(type) | |
| { | |
| Parent = ContentRepo.Get<ContentFolder>(EntryPoint), ContentLink=id.ContentLink | |
| }) as IContent; | |
| fc.ContentGuid = id.ContentGuid; | |
| map.MapAllProperties(fc, entry); | |
| (fc as IVersionable).Status = VersionStatus.Published; | |
| (fc as IVersionable).IsPendingPublish = false; | |
| (fc as ILocalizable).Language = CultureInfo.GetCultureInfo("en"); | |
| (fc as ILocalizable).MasterLanguage = CultureInfo.InvariantCulture; | |
| (fc as ILocalizable).ExistingLanguages = new List<CultureInfo>(); | |
| (fc as IReadOnly).MakeReadOnly(); | |
| return fc as IContent; | |
| } | |
| //Avoid caching for now. Future: Cache, but cancel caching based on webhooks | |
| protected override void SetCacheSettings(IContent content, CacheSettings cacheSettings) | |
| { | |
| base.SetCacheSettings(content, cacheSettings); | |
| cacheSettings.CancelCaching = true; | |
| } | |
| protected override void SetCacheSettings(ContentReference contentReference, IEnumerable<GetChildrenReferenceResult> children, CacheSettings cacheSettings) | |
| { | |
| base.SetCacheSettings(contentReference, children, cacheSettings); | |
| cacheSettings.CancelCaching = true; | |
| } | |
| protected override void SetCacheSettings(ContentReference parentLink, string urlSegment, IEnumerable<MatchingSegmentResult> childrenMatches, CacheSettings cacheSettings) | |
| { | |
| base.SetCacheSettings(parentLink, urlSegment, childrenMatches, cacheSettings); | |
| cacheSettings.CancelCaching = true; | |
| } | |
| protected override ContentResolveResult ResolveContent(ContentReference contentLink) | |
| { | |
| ContentResolveResult crr = new ContentResolveResult(); | |
| crr.ContentLink = contentLink; | |
| var id=IdentityMappingService.Get(contentLink); | |
| if (id == null) return null; | |
| crr.UniqueID = id.ContentGuid; | |
| return crr; | |
| } | |
| protected override ContentResolveResult ResolveContent(Guid contentGuid) | |
| { | |
| ContentResolveResult crr = new ContentResolveResult(); | |
| crr.UniqueID = contentGuid; | |
| var id = IdentityMappingService.Get(contentGuid); | |
| if (id == null) return null; | |
| crr.ContentLink = id.ContentLink; | |
| return crr; | |
| } | |
| public override void Initialize(string name, NameValueCollection config) | |
| { | |
| base.Initialize(name, config); | |
| var httpClient = new HttpClient(); | |
| _Client = new ContentfulClient(httpClient, WebConfigurationManager.AppSettings["Contentful:ApiKey"], WebConfigurationManager.AppSettings["Contentful:PreviewKey"], WebConfigurationManager.AppSettings["Contentful:SpaceId"]); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Collections.Specialized; | |
| using System.Linq; | |
| using ContentfulDemo.Contentful; | |
| using ContentfulDemo.Models.Blocks; | |
| using EPiServer; | |
| using EPiServer.Configuration; | |
| using EPiServer.Core; | |
| using EPiServer.DataAccess; | |
| using EPiServer.Framework; | |
| using EPiServer.Framework.Initialization; | |
| using EPiServer.Security; | |
| using EPiServer.ServiceLocation; | |
| namespace ContentfulDemo.ContentfulTools | |
| { | |
| [InitializableModule] | |
| [ModuleDependency(typeof(EPiServer.Web.InitializationModule))] | |
| public class ContentfulInit : IInitializableModule | |
| { | |
| public void Initialize(InitializationEngine context) | |
| { | |
| //Setup mapping | |
| var mapper = ServiceLocator.Current.GetInstance<ExternalTypeMapper>(); | |
| mapper.MapType<CFBlogBlock>("blogPost").Map((a, b) => | |
| { | |
| a.Name = Convert.ToString(b.title); | |
| (a as CFBlogBlock).Description = Convert.ToString(b.description); | |
| (a as CFBlogBlock).Body = Convert.ToString(b.body); | |
| } ); | |
| } | |
| public void Uninitialize(InitializationEngine context) | |
| { | |
| //Add uninitialization logic | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using Contentful.Core.Models; | |
| using EPiServer.Core; | |
| using EPiServer.ServiceLocation; | |
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Linq.Expressions; | |
| using System.Reflection; | |
| using System.Web; | |
| namespace ContentfulDemo.Contentful | |
| { | |
| [ServiceConfiguration(Lifecycle = ServiceInstanceScope.Singleton, ServiceType = typeof(ExternalTypeMapper))] | |
| public class ExternalTypeMapper | |
| { | |
| public Dictionary<string, ExternalTypeMapping> TypeMappings { get; set; } | |
| public ExternalTypeMapping MapType<G>(string Identifier) | |
| { | |
| //Return a type mapping object? | |
| var rt = new ExternalTypeMapping(); | |
| rt.Identifier = Identifier; | |
| rt.ContentType = typeof(G); | |
| TypeMappings.Add(Identifier, rt); | |
| return rt; | |
| } | |
| public ExternalTypeMapper() | |
| { | |
| TypeMappings = new Dictionary<string, ExternalTypeMapping>(); | |
| } | |
| } | |
| public class ExternalTypeMapping | |
| { | |
| public Action<EPiServer.Core.IContent, dynamic> MapAllProperties { get; set; } | |
| public ExternalTypeMapping Map(Action<EPiServer.Core.IContent, dynamic> map) | |
| { | |
| this.MapAllProperties = map; | |
| return this; | |
| } | |
| public string Identifier { get; set; } | |
| public Type ContentType { get; set; } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment