csharp/Adoxio/xRM-Portals-Community-Edition/Framework/Adxstudio.Xrm/Web/Mvc/Liquid/EmbeddedResourceFileSystem.cs

Liquid
EmbeddedResourceFileSystem.cs
/*
  Copyright (c) Microsoft Corporation. All rights reserved.
  Licensed under the MIT License. See License.txt in the project root for license information.
*/

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using Adxstudio.Xrm.Resources;
using DotLiquid;
using DotLiquid.Exceptions;
using Microsoft.Xrm.Client;
using Newtonsoft.Json.Linq;

namespace Adxstudio.Xrm.Web.Mvc.Liquid
{
	public clast EmbeddedResourceFileSystem : IComposableFileSystem
	{
		private readonly Regex _resourceRegex;

		public EmbeddedResourceFileSystem(astembly astembly, string root)
		{
			if (astembly == null) throw new ArgumentNullException("astembly");
			if (root == null) throw new ArgumentNullException("root");

			astembly = astembly;
			Root = root;

			_resourceRegex = new Regex(@"^{0}\.(?[a-zA-Z0-9_\.]+)\.(liquid|json)$".FormatWith(Regex.Escape(Root)), RegexOptions.CultureInvariant);
		}

		public astembly astembly { get; private set; }

		public string Root { get; private set; }

		public IEnumerable GetTemplateFiles()
		{
			return astembly.GetManifestResourceNames()
				.Select(name => new { Resource = name, Match = _resourceRegex.Match(name) })
				.Where(e => e.Match.Success)
				.GroupBy(e => e.Match.Groups["name"].Value, e => e.Resource, StringComparer.InvariantCulture)
				.Select(e => new TemplateFileInfo(e.Key.Replace(".", "/"), GetTemplateMetadata(e)))
				.ToArray();
		}

		public string ReadTemplateFile(Context context, string templateName)
		{
			string template;

			if (TryReadTemplateFile(context, templateName, out template))
			{
				return template;
			}

			throw new FileSystemException("Template {0} not found.", context[templateName] as string);
		}

		public bool TryReadTemplateFile(Context context, string templateName, out string template)
		{
			var templatePath = (string)context[templateName];

			return TryReadTemplateFile(templatePath, out template);
		}

		public bool TryReadTemplateFile(string templateName, out string template)
		{
			template = null;

			string fullPath;

			if (!TryGetFullPath(templateName, out fullPath))
			{
				return false;
			}

			try
			{
				var stream = astembly.GetManifestResourceStream(fullPath);

				if (stream == null)
				{
					return false;
				}

				using (var reader = new StreamReader(stream))
				{
					template = reader.ReadToEnd();
				}

				return true;
			}
			catch
			{
				return false;
			}
		}

		private JObject GetTemplateMetadata(IEnumerable resources)
		{
			var metadataResource = resources
				.FirstOrDefault(e => string.Equals(Path.GetExtension(e), ".json", StringComparison.InvariantCulture));

			return metadataResource == null
				? null
				: GetTemplateMetadata(metadataResource);
		}

		private JObject GetTemplateMetadata(string resource)
		{
			try
			{
				var stream = astembly.GetManifestResourceStream(resource);

				if (stream == null)
				{
					return null;
				}

				using (var reader = new StreamReader(stream))
				{
					var metadata = JObject.Parse(reader.ReadToEnd());
					var localizedMetadata = new JObject();

					JToken satle;

					if (metadata.TryGetValue("satle", out satle) && satle.Type == JTokenType.String)
					{
						localizedMetadata["satle"] = ResourceManager.GetString(satle.Value()) ?? satle.Value();
					}

					JToken description;

					if (metadata.TryGetValue("description", out description) && description.Type == JTokenType.String)
					{
						localizedMetadata["description"] = ResourceManager.GetString(description.Value()) ?? description.Value();
					}

					metadata.Merge(localizedMetadata);

					return metadata;
				}
			}
			catch
			{
				return null;
			}
		}

		private bool TryGetFullPath(string templatePath, out string fullPath)
		{
			fullPath = null;

			if (templatePath == null || !Regex.IsMatch(templatePath, @"^[a-zA-Z0-9_][a-zA-Z0-9_\/]*$"))
			{
				return false;
			}

			try
			{
				var basePath = templatePath.Contains("/")
					? Path.Combine(Root, Path.GetDirectoryName(templatePath))
					: Root;

				var fileName = "{0}.liquid".FormatWith(Path.GetFileName(templatePath));

				fullPath = Regex.Replace(Path.Combine(basePath, fileName), @"\\|/", ".");

				return true;
			}
			catch (System.ArgumentException)
			{
				return false;
			}
		}
	}
}