Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanolsen committed Nov 22, 2017
1 parent 3b53e67 commit c6768a0
Show file tree
Hide file tree
Showing 37 changed files with 2,476 additions and 0 deletions.
31 changes: 31 additions & 0 deletions CatalogFeeds.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.15
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StefanOlsen.Commerce.CatalogFeed", "StefanOlsen.Commerce.CatalogFeed\StefanOlsen.Commerce.CatalogFeed.csproj", "{FD6E6A92-67A6-4B9B-B94F-03DE6CC237BB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StefanOlsen.Commerce.CatalogFeed.GoogleMerchant", "StefanOlsen.Commerce.CatalogFeed.GoogleMerchant\StefanOlsen.Commerce.CatalogFeed.GoogleMerchant.csproj", "{BDF8F4E3-1584-4625-90CF-15DFCF0E0C67}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FD6E6A92-67A6-4B9B-B94F-03DE6CC237BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FD6E6A92-67A6-4B9B-B94F-03DE6CC237BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FD6E6A92-67A6-4B9B-B94F-03DE6CC237BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FD6E6A92-67A6-4B9B-B94F-03DE6CC237BB}.Release|Any CPU.Build.0 = Release|Any CPU
{BDF8F4E3-1584-4625-90CF-15DFCF0E0C67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BDF8F4E3-1584-4625-90CF-15DFCF0E0C67}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BDF8F4E3-1584-4625-90CF-15DFCF0E0C67}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BDF8F4E3-1584-4625-90CF-15DFCF0E0C67}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5BB33DC0-8D30-4583-832B-A422BFD2B97B}
EndGlobalSection
EndGlobal
27 changes: 27 additions & 0 deletions Samples/GoogleFeedMapping.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<FieldMapping xmlns="http://stefanolsen.com/CatalogFeed.GoogleMerchant/MappingDocument.xsd">
<ContentType CommerceType="CatalogNode">
<Fields>
<MappedField MetaField="GoogleProductCategoryId" FeedField="google_product_category"/>
</Fields>
</ContentType>

<ContentType CommerceType="Product">
<Fields>
<MappedField MetaField="DisplayName" FeedField="title"/>
<MappedField MetaField="Description" FeedField="description"/>
<MappedField MetaField="Brand" FeedField="brand"/>
</Fields>
<ImageGroup AssetMetaField=""/>
</ContentType>

<ContentType CommerceType="Variation">
<Fields>
<MappedField MetaField="Code" FeedField="code"/>
<MappedField MetaField="StopPublish" FeedField="expiration_date"/>
<MappedField MetaField="Color" FeedField="color"/>
<MappedField MetaField="Size" FeedField="size"/>

<FixedField FeedField="condition" Value="new"/>
</Fields>
</ContentType>
</FieldMapping>
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System.Linq;
using System.Web.Mvc;
using EPiServer.Commerce.Security;
using EPiServer.PlugIn;
using Mediachase.Commerce.Markets;
using StefanOlsen.Commerce.CatalogFeed.GoogleMerchant.AdminPlugin.ViewModels;
using StefanOlsen.Commerce.CatalogFeed.Mapping;
using StefanOlsen.Commerce.CatalogFeed.Settings;

namespace StefanOlsen.Commerce.CatalogFeed.GoogleMerchant.AdminPlugin.Controllers
{
[GuiPlugIn(
Area = PlugInArea.AdminConfigMenu,
DisplayName = "Google Product Feed",
Url = "/googleproductfeedconfig")]
[Authorize(Roles = RoleNames.CommerceAdmins)]
public class GoogleProductFeedConfigController : Controller
{
private readonly CatalogService _catalogService;
private readonly IMarketService _marketService;
private readonly SettingsRepository _settingsRepository;

public GoogleProductFeedConfigController(
CatalogService catalogService,
IMarketService marketService,
SettingsRepository settingsRepository)
{
_catalogService = catalogService;
_marketService = marketService;
_settingsRepository = settingsRepository;
}

public ActionResult Index()
{
var viewModel = new AdministrationViewModel();
viewModel.AvailableCatalogs = _catalogService.GetCatalogs().ToArray();
viewModel.AvailableMarkets = _marketService.GetAllMarkets().ToArray();

FeedSettings feedSettings =
_settingsRepository.GetFeedSettings(Constants.ProviderNameGoogle) ?? new FeedSettings();

viewModel.CatalogIds = feedSettings.CatalogIdList;
viewModel.MarketIds = feedSettings.MarketIdList;
viewModel.Enabled = feedSettings.Enabled;
viewModel.Key = feedSettings.Key;
viewModel.FeedName = feedSettings.FeedName;
viewModel.FeedExpirationMinutes = feedSettings.FeedExpirationMinutes;
viewModel.MappingDocument = feedSettings.MappingDocument;

return View("Index", viewModel);
}

[HttpPost]
public ActionResult Index(AdministrationViewModel viewModel)
{
if (string.IsNullOrWhiteSpace(viewModel.MappingDocument))
{
bool valid = FieldMappingHelper.ValidateFieldMapping(viewModel.MappingDocument);
if (!valid)
{
ModelState.AddModelError("MappingDocument", "The entered data is not valid XML.");
}
}

if (!ModelState.IsValid)
{
return Index();
}

FeedSettings feedSettings =
_settingsRepository.GetFeedSettings(Constants.ProviderNameGoogle) ?? new FeedSettings();

feedSettings.CatalogIdList = viewModel.CatalogIds;
feedSettings.MarketIdList = viewModel.MarketIds;
feedSettings.ProviderName = Constants.ProviderNameGoogle;
feedSettings.Enabled = viewModel.Enabled;
feedSettings.Key = viewModel.Key;
feedSettings.FeedName = viewModel.FeedName;
feedSettings.FeedExpirationMinutes = viewModel.FeedExpirationMinutes;
feedSettings.MappingDocument = viewModel.MappingDocument;

_settingsRepository.Save(feedSettings);

return Index();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
using EPiServer.Commerce.Catalog.ContentTypes;
using Mediachase.Commerce;

namespace StefanOlsen.Commerce.CatalogFeed.GoogleMerchant.AdminPlugin.ViewModels
{
public class AdministrationViewModel
{
public CatalogContent[] AvailableCatalogs { get; set; }

public IMarket[] AvailableMarkets { get; set; }

public bool Enabled { get; set; }

[Required]
public string FeedName { get; set; }

[Required]
[StringLength(32, MinimumLength = 10)]
public string Key { get; set; }

public int[] CatalogIds { get; set; }

public string[] MarketIds { get; set; }

[Required]
[Range(10, short.MaxValue)]
public int FeedExpirationMinutes { get; set; }

[AllowHtml]
[Required]
public string MappingDocument { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web.Http;
using EPiServer.Framework.Blobs;
using StefanOlsen.Commerce.CatalogFeed.Data;
using StefanOlsen.Commerce.CatalogFeed.Settings;

namespace StefanOlsen.Commerce.CatalogFeed.GoogleMerchant
{
[RoutePrefix("catalogfeed/googlemerchant")]
public class GoogleMerchantCatalogFeedController : ApiController
{
private readonly IBlobFactory _blobFactory;
private readonly CatalogFeedDataService _catalogFeedDataService;
private readonly SettingsRepository _settingsRepository;


public GoogleMerchantCatalogFeedController(
IBlobFactory blobFactory,
CatalogFeedDataService catalogFeedDataService,
SettingsRepository settingsRepository)
{
_blobFactory = blobFactory;
_catalogFeedDataService = catalogFeedDataService;
_settingsRepository = settingsRepository;
}

[Route("")]
public HttpResponseMessage GetFeed(string key, string marketId)
{
FeedSettings feedSettings = _settingsRepository.GetFeedSettings(Constants.ProviderNameGoogle);
if (feedSettings == null ||
!feedSettings.Enabled)
{
return new HttpResponseMessage(HttpStatusCode.NotFound);
}
if (!string.Equals(key, feedSettings.Key, StringComparison.InvariantCulture))
{
return new HttpResponseMessage(HttpStatusCode.Forbidden);
}

CatalogFeedItem feedItem = _catalogFeedDataService.Get(Constants.ProviderNameGoogle, marketId);
if (feedItem == null)
{
return new HttpResponseMessage(HttpStatusCode.NotFound);
}

Blob blob = _blobFactory.GetBlob(feedItem.BlobId);
return new HttpResponseMessage
{
Content = new PushStreamContent(async (outputStream, httpContent, transportContext) =>
await WriteToStream(outputStream, blob),
new MediaTypeHeaderValue("aplication/xml"))
};
}

private static async Task WriteToStream(Stream outputStream, Blob blob)
{
Stream blobStream = blob.OpenRead();
try
{
await blobStream.CopyToAsync(outputStream);
}
finally
{
blobStream.Dispose();
outputStream.Dispose();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using EPiServer.ServiceLocation;
using StefanOlsen.Commerce.CatalogFeed.Data;

namespace StefanOlsen.Commerce.CatalogFeed.GoogleMerchant
{
[InitializableModule]
[ModuleDependency(typeof(ServiceContainerInitialization))]
public class CatalogFeedInitialization : IConfigurableModule
{
public void Initialize(InitializationEngine context)
{
}

public void Uninitialize(InitializationEngine context)
{
}

public void ConfigureContainer(ServiceConfigurationContext context)
{
IServiceConfigurationProvider services = context.Services;

services.AddTransient<ICatalogFeedDataService, CatalogFeedDataService>();
services.AddTransient<IProductDataService, ProductDataService>();
}
}
}
17 changes: 17 additions & 0 deletions StefanOlsen.Commerce.CatalogFeed.GoogleMerchant/Constants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace StefanOlsen.Commerce.CatalogFeed.GoogleMerchant
{
internal static class Constants
{
public const string NamespaceAtom = "http://www.w3.org/2005/Atom";
public const string NamespaceGoogleMerchant = "http://base.google.com/ns/1.0";

public const string BooleanValueNo = "no";
public const string BooleanValueYes = "yes";

public const string InventoryInStock = "in stock";
public const string InventoryOutOfStock = "out of stock";
public const string InventoryPreorder = "preorder";

public const string ProviderNameGoogle = "GoogleProductFeed";
}
}
Loading

0 comments on commit c6768a0

Please sign in to comment.