using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence.Repositories; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Strings; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Services.Implement { /// /// Represents the File Service, which is an easy access to operations involving objects like Scripts, Stylesheets and Templates /// public class FileService : RepositoryService, IFileService { private readonly IStylesheetRepository _stylesheetRepository; private readonly IScriptRepository _scriptRepository; private readonly ITemplateRepository _templateRepository; private readonly IPartialViewRepository _partialViewRepository; private readonly IPartialViewMacroRepository _partialViewMacroRepository; private readonly IAuditRepository _auditRepository; private readonly IShortStringHelper _shortStringHelper; private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; private const string PartialViewHeader = "@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage"; private const string PartialViewMacroHeader = "@inherits Umbraco.Cms.Web.Common.Macros.PartialViewMacroPage"; public FileService(IScopeProvider uowProvider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IStylesheetRepository stylesheetRepository, IScriptRepository scriptRepository, ITemplateRepository templateRepository, IPartialViewRepository partialViewRepository, IPartialViewMacroRepository partialViewMacroRepository, IAuditRepository auditRepository, IShortStringHelper shortStringHelper, IOptions globalSettings, IHostingEnvironment hostingEnvironment) : base(uowProvider, loggerFactory, eventMessagesFactory) { _stylesheetRepository = stylesheetRepository; _scriptRepository = scriptRepository; _templateRepository = templateRepository; _partialViewRepository = partialViewRepository; _partialViewMacroRepository = partialViewMacroRepository; _auditRepository = auditRepository; _shortStringHelper = shortStringHelper; _globalSettings = globalSettings.Value; _hostingEnvironment = hostingEnvironment; } #region Stylesheets /// public IEnumerable GetStylesheets(params string[] names) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _stylesheetRepository.GetMany(names); } } /// public IStylesheet GetStylesheetByName(string name) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _stylesheetRepository.Get(name); } } /// public void SaveStylesheet(IStylesheet stylesheet, int userId = Cms.Core.Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { var saveEventArgs = new SaveEventArgs(stylesheet); if (scope.Events.DispatchCancelable(SavingStylesheet, this, saveEventArgs)) { scope.Complete(); return; } _stylesheetRepository.Save(stylesheet); saveEventArgs.CanCancel = false; scope.Events.Dispatch(SavedStylesheet, this, saveEventArgs); Audit(AuditType.Save, userId, -1, "Stylesheet"); scope.Complete(); } } /// public void DeleteStylesheet(string path, int userId = Cms.Core.Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { var stylesheet = _stylesheetRepository.Get(path); if (stylesheet == null) { scope.Complete(); return; } var deleteEventArgs = new DeleteEventArgs(stylesheet); if (scope.Events.DispatchCancelable(DeletingStylesheet, this, deleteEventArgs)) { scope.Complete(); return; // causes rollback // causes rollback } _stylesheetRepository.Delete(stylesheet); deleteEventArgs.CanCancel = false; scope.Events.Dispatch(DeletedStylesheet, this, deleteEventArgs); Audit(AuditType.Delete, userId, -1, "Stylesheet"); scope.Complete(); } } /// public bool ValidateStylesheet(IStylesheet stylesheet) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _stylesheetRepository.ValidateStylesheet(stylesheet); } } public void CreateStyleSheetFolder(string folderPath) { using (var scope = ScopeProvider.CreateScope()) { _stylesheetRepository.AddFolder(folderPath); scope.Complete(); } } public void DeleteStyleSheetFolder(string folderPath) { using (var scope = ScopeProvider.CreateScope()) { _stylesheetRepository.DeleteFolder(folderPath); scope.Complete(); } } public Stream GetStylesheetFileContentStream(string filepath) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _stylesheetRepository.GetFileContentStream(filepath); } } public void SetStylesheetFileContent(string filepath, Stream content) { using (var scope = ScopeProvider.CreateScope()) { _stylesheetRepository.SetFileContent(filepath, content); scope.Complete(); } } public long GetStylesheetFileSize(string filepath) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _stylesheetRepository.GetFileSize(filepath); } } #endregion #region Scripts /// public IEnumerable GetScripts(params string[] names) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _scriptRepository.GetMany(names); } } /// public IScript GetScriptByName(string name) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _scriptRepository.Get(name); } } /// public void SaveScript(IScript script, int userId = Cms.Core.Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { var saveEventArgs = new SaveEventArgs(script); if (scope.Events.DispatchCancelable(SavingScript, this, saveEventArgs)) { scope.Complete(); return; } _scriptRepository.Save(script); saveEventArgs.CanCancel = false; scope.Events.Dispatch(SavedScript, this, saveEventArgs); Audit(AuditType.Save, userId, -1, "Script"); scope.Complete(); } } /// public void DeleteScript(string path, int userId = Cms.Core.Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { var script = _scriptRepository.Get(path); if (script == null) { scope.Complete(); return; } var deleteEventArgs = new DeleteEventArgs(script); if (scope.Events.DispatchCancelable(DeletingScript, this, deleteEventArgs)) { scope.Complete(); return; } _scriptRepository.Delete(script); deleteEventArgs.CanCancel = false; scope.Events.Dispatch(DeletedScript, this, deleteEventArgs); Audit(AuditType.Delete, userId, -1, "Script"); scope.Complete(); } } /// public bool ValidateScript(IScript script) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _scriptRepository.ValidateScript(script); } } public void CreateScriptFolder(string folderPath) { using (var scope = ScopeProvider.CreateScope()) { _scriptRepository.AddFolder(folderPath); scope.Complete(); } } public void DeleteScriptFolder(string folderPath) { using (var scope = ScopeProvider.CreateScope()) { _scriptRepository.DeleteFolder(folderPath); scope.Complete(); } } public Stream GetScriptFileContentStream(string filepath) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _scriptRepository.GetFileContentStream(filepath); } } public void SetScriptFileContent(string filepath, Stream content) { using (var scope = ScopeProvider.CreateScope()) { _scriptRepository.SetFileContent(filepath, content); scope.Complete(); } } public long GetScriptFileSize(string filepath) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _scriptRepository.GetFileSize(filepath); } } #endregion #region Templates /// /// Creates a template for a content type /// /// /// /// /// /// The template created /// public Attempt> CreateTemplateForContentType(string contentTypeAlias, string contentTypeName, int userId = Cms.Core.Constants.Security.SuperUserId) { var template = new Template(_shortStringHelper, contentTypeName, //NOTE: We are NOT passing in the content type alias here, we want to use it's name since we don't // want to save template file names as camelCase, the Template ctor will clean the alias as // `alias.ToCleanString(CleanStringType.UnderscoreAlias)` which has been the default. // This fixes: http://issues.umbraco.org/issue/U4-7953 contentTypeName); var evtMsgs = EventMessagesFactory.Get(); // TODO: This isn't pretty because we we're required to maintain backwards compatibility so we could not change // the event args here. The other option is to create a different event with different event // args specifically for this method... which also isn't pretty. So fix this in v8! var additionalData = new Dictionary { { "CreateTemplateForContentType", true }, { "ContentTypeAlias", contentTypeAlias }, }; if (contentTypeAlias != null && contentTypeAlias.Length > 255) { throw new InvalidOperationException("Name cannot be more than 255 characters in length."); } // check that the template hasn't been created on disk before creating the content type // if it exists, set the new template content to the existing file content string content = GetViewContent(contentTypeAlias); if (content != null) { template.Content = content; } using (var scope = ScopeProvider.CreateScope()) { var saveEventArgs = new SaveEventArgs(template, true, evtMsgs, additionalData); if (scope.Events.DispatchCancelable(SavingTemplate, this, saveEventArgs)) { scope.Complete(); return OperationResult.Attempt.Fail(OperationResultType.FailedCancelledByEvent, evtMsgs, template); } _templateRepository.Save(template); saveEventArgs.CanCancel = false; scope.Events.Dispatch(SavedTemplate, this, saveEventArgs); Audit(AuditType.Save, userId, template.Id, ObjectTypes.GetName(UmbracoObjectTypes.Template)); scope.Complete(); } return OperationResult.Attempt.Succeed(OperationResultType.Success, evtMsgs, template); } /// /// Create a new template, setting the content if a view exists in the filesystem /// /// /// /// /// /// /// public ITemplate CreateTemplateWithIdentity(string name, string alias, string content, ITemplate masterTemplate = null, int userId = Cms.Core.Constants.Security.SuperUserId) { if (name == null) { throw new ArgumentNullException(nameof(name)); } if (string.IsNullOrWhiteSpace(name)) { throw new ArgumentException("Name cannot be empty or contain only white-space characters", nameof(name)); } if (name.Length > 255) { throw new ArgumentOutOfRangeException(nameof(name), "Name cannot be more than 255 characters in length."); } // file might already be on disk, if so grab the content to avoid overwriting var template = new Template(_shortStringHelper, name, alias) { Content = GetViewContent(alias) ?? content }; if (masterTemplate != null) { template.SetMasterTemplate(masterTemplate); } SaveTemplate(template, userId); return template; } /// /// Gets a list of all objects /// /// An enumerable list of objects public IEnumerable GetTemplates(params string[] aliases) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _templateRepository.GetAll(aliases).OrderBy(x => x.Name); } } /// /// Gets a list of all objects /// /// An enumerable list of objects public IEnumerable GetTemplates(int masterTemplateId) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _templateRepository.GetChildren(masterTemplateId).OrderBy(x => x.Name); } } /// /// Gets a object by its alias. /// /// The alias of the template. /// The object matching the alias, or null. public ITemplate GetTemplate(string alias) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _templateRepository.Get(alias); } } /// /// Gets a object by its identifier. /// /// The identifier of the template. /// The object matching the identifier, or null. public ITemplate GetTemplate(int id) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _templateRepository.Get(id); } } /// /// Gets a object by its guid identifier. /// /// The guid identifier of the template. /// The object matching the identifier, or null. public ITemplate GetTemplate(Guid id) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var query = Query().Where(x => x.Key == id); return _templateRepository.Get(query).SingleOrDefault(); } } public IEnumerable GetTemplateDescendants(string alias) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _templateRepository.GetDescendants(alias); } } /// /// Gets the template descendants /// /// /// public IEnumerable GetTemplateDescendants(int masterTemplateId) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _templateRepository.GetDescendants(masterTemplateId); } } /// /// Gets the template children /// /// /// public IEnumerable GetTemplateChildren(string alias) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _templateRepository.GetChildren(alias); } } /// /// Gets the template children /// /// /// public IEnumerable GetTemplateChildren(int masterTemplateId) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _templateRepository.GetChildren(masterTemplateId); } } /// /// Saves a /// /// to save /// public void SaveTemplate(ITemplate template, int userId = Cms.Core.Constants.Security.SuperUserId) { if (template == null) { throw new ArgumentNullException(nameof(template)); } if (string.IsNullOrWhiteSpace(template.Name) || template.Name.Length > 255) { throw new InvalidOperationException("Name cannot be null, empty, contain only white-space characters or be more than 255 characters in length."); } using (var scope = ScopeProvider.CreateScope()) { if (scope.Events.DispatchCancelable(SavingTemplate, this, new SaveEventArgs(template))) { scope.Complete(); return; } _templateRepository.Save(template); scope.Events.Dispatch(SavedTemplate, this, new SaveEventArgs(template, false)); Audit(AuditType.Save, userId, template.Id, UmbracoObjectTypes.Template.GetName()); scope.Complete(); } } /// /// Saves a collection of objects /// /// List of to save /// Optional id of the user public void SaveTemplate(IEnumerable templates, int userId = Cms.Core.Constants.Security.SuperUserId) { var templatesA = templates.ToArray(); using (var scope = ScopeProvider.CreateScope()) { if (scope.Events.DispatchCancelable(SavingTemplate, this, new SaveEventArgs(templatesA))) { scope.Complete(); return; } foreach (var template in templatesA) _templateRepository.Save(template); scope.Events.Dispatch(SavedTemplate, this, new SaveEventArgs(templatesA, false)); Audit(AuditType.Save, userId, -1, UmbracoObjectTypes.Template.GetName()); scope.Complete(); } } /// /// Deletes a template by its alias /// /// Alias of the to delete /// public void DeleteTemplate(string alias, int userId = Cms.Core.Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { var template = _templateRepository.Get(alias); if (template == null) { scope.Complete(); return; } var args = new DeleteEventArgs(template); if (scope.Events.DispatchCancelable(DeletingTemplate, this, args)) { scope.Complete(); return; } _templateRepository.Delete(template); args.CanCancel = false; scope.Events.Dispatch(DeletedTemplate, this, args); Audit(AuditType.Delete, userId, template.Id, ObjectTypes.GetName(UmbracoObjectTypes.Template)); scope.Complete(); } } /// /// Validates a /// /// to validate /// True if Script is valid, otherwise false public bool ValidateTemplate(ITemplate template) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _templateRepository.ValidateTemplate(template); } } public Stream GetTemplateFileContentStream(string filepath) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _templateRepository.GetFileContentStream(filepath); } } public void SetTemplateFileContent(string filepath, Stream content) { using (var scope = ScopeProvider.CreateScope()) { _templateRepository.SetFileContent(filepath, content); scope.Complete(); } } public long GetTemplateFileSize(string filepath) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _templateRepository.GetFileSize(filepath); } } private string GetViewContent(string fileName) { if (fileName.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(fileName)); if (!fileName.EndsWith(".cshtml")) fileName = $"{fileName}.cshtml"; var fs = _templateRepository.GetFileContentStream(fileName); if (fs == null) return null; using (var view = new StreamReader(fs)) { return view.ReadToEnd().Trim(); } } #endregion #region Partial Views public IEnumerable GetPartialViewSnippetNames(params string[] filterNames) { var snippetPath = _hostingEnvironment.MapPathContentRoot($"{_globalSettings.UmbracoPath}/PartialViewMacros/Templates/"); var files = Directory.GetFiles(snippetPath, "*.cshtml") .Select(Path.GetFileNameWithoutExtension) .Except(filterNames, StringComparer.InvariantCultureIgnoreCase) .ToArray(); //Ensure the ones that are called 'Empty' are at the top var empty = files.Where(x => Path.GetFileName(x).InvariantStartsWith("Empty")) .OrderBy(x => x.Length) .ToArray(); return empty.Union(files.Except(empty)); } public void DeletePartialViewFolder(string folderPath) { using (var scope = ScopeProvider.CreateScope()) { _partialViewRepository.DeleteFolder(folderPath); scope.Complete(); } } public void DeletePartialViewMacroFolder(string folderPath) { using (var scope = ScopeProvider.CreateScope()) { _partialViewMacroRepository.DeleteFolder(folderPath); scope.Complete(); } } public IPartialView GetPartialView(string path) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _partialViewRepository.Get(path); } } public IPartialView GetPartialViewMacro(string path) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _partialViewMacroRepository.Get(path); } } public IEnumerable GetPartialViewMacros(params string[] names) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _partialViewMacroRepository.GetMany(names).OrderBy(x => x.Name); } } public Attempt CreatePartialView(IPartialView partialView, string snippetName = null, int userId = Cms.Core.Constants.Security.SuperUserId) { return CreatePartialViewMacro(partialView, PartialViewType.PartialView, snippetName, userId); } public Attempt CreatePartialViewMacro(IPartialView partialView, string snippetName = null, int userId = Cms.Core.Constants.Security.SuperUserId) { return CreatePartialViewMacro(partialView, PartialViewType.PartialViewMacro, snippetName, userId); } private Attempt CreatePartialViewMacro(IPartialView partialView, PartialViewType partialViewType, string snippetName = null, int userId = Cms.Core.Constants.Security.SuperUserId) { string partialViewHeader; switch (partialViewType) { case PartialViewType.PartialView: partialViewHeader = PartialViewHeader; break; case PartialViewType.PartialViewMacro: partialViewHeader = PartialViewMacroHeader; break; default: throw new ArgumentOutOfRangeException(nameof(partialViewType)); } string partialViewContent = null; if (snippetName.IsNullOrWhiteSpace() == false) { //create the file var snippetPathAttempt = TryGetSnippetPath(snippetName); if (snippetPathAttempt.Success == false) { throw new InvalidOperationException("Could not load snippet with name " + snippetName); } using (var snippetFile = new StreamReader(System.IO.File.OpenRead(snippetPathAttempt.Result))) { var snippetContent = snippetFile.ReadToEnd().Trim(); //strip the @inherits if it's there snippetContent = StripPartialViewHeader(snippetContent); //Update Model.Content. to be Model. when used as PartialView if(partialViewType == PartialViewType.PartialView) { snippetContent = snippetContent.Replace("Model.Content.", "Model."); } partialViewContent = $"{partialViewHeader}{Environment.NewLine}{snippetContent}"; } } using (var scope = ScopeProvider.CreateScope()) { var newEventArgs = new NewEventArgs(partialView, true, partialView.Alias, -1); if (scope.Events.DispatchCancelable(CreatingPartialView, this, newEventArgs)) { scope.Complete(); return Attempt.Fail(); } var repository = GetPartialViewRepository(partialViewType); if (partialViewContent != null) partialView.Content = partialViewContent; repository.Save(partialView); newEventArgs.CanCancel = false; scope.Events.Dispatch(CreatedPartialView, this, newEventArgs); Audit(AuditType.Save, userId, -1, partialViewType.ToString()); scope.Complete(); } return Attempt.Succeed(partialView); } public bool DeletePartialView(string path, int userId = Cms.Core.Constants.Security.SuperUserId) { return DeletePartialViewMacro(path, PartialViewType.PartialView, userId); } public bool DeletePartialViewMacro(string path, int userId = Cms.Core.Constants.Security.SuperUserId) { return DeletePartialViewMacro(path, PartialViewType.PartialViewMacro, userId); } private bool DeletePartialViewMacro(string path, PartialViewType partialViewType, int userId = Cms.Core.Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { var repository = GetPartialViewRepository(partialViewType); var partialView = repository.Get(path); if (partialView == null) { scope.Complete(); return true; } var deleteEventArgs = new DeleteEventArgs(partialView); if (scope.Events.DispatchCancelable(DeletingPartialView, this, deleteEventArgs)) { scope.Complete(); return false; } repository.Delete(partialView); deleteEventArgs.CanCancel = false; scope.Events.Dispatch(DeletedPartialView, this, deleteEventArgs); Audit(AuditType.Delete, userId, -1, partialViewType.ToString()); scope.Complete(); } return true; } public Attempt SavePartialView(IPartialView partialView, int userId = Cms.Core.Constants.Security.SuperUserId) { return SavePartialView(partialView, PartialViewType.PartialView, userId); } public Attempt SavePartialViewMacro(IPartialView partialView, int userId = Cms.Core.Constants.Security.SuperUserId) { return SavePartialView(partialView, PartialViewType.PartialViewMacro, userId); } private Attempt SavePartialView(IPartialView partialView, PartialViewType partialViewType, int userId = Cms.Core.Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { var saveEventArgs = new SaveEventArgs(partialView); if (scope.Events.DispatchCancelable(SavingPartialView, this, saveEventArgs)) { scope.Complete(); return Attempt.Fail(); } var repository = GetPartialViewRepository(partialViewType); repository.Save(partialView); saveEventArgs.CanCancel = false; Audit(AuditType.Save, userId, -1, partialViewType.ToString()); scope.Events.Dispatch(SavedPartialView, this, saveEventArgs); scope.Complete(); } return Attempt.Succeed(partialView); } public bool ValidatePartialView(IPartialView partialView) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _partialViewRepository.ValidatePartialView(partialView); } } public bool ValidatePartialViewMacro(IPartialView partialView) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _partialViewMacroRepository.ValidatePartialView(partialView); } } internal string StripPartialViewHeader(string contents) { var headerMatch = new Regex("^@inherits\\s+?.*$", RegexOptions.Multiline); return headerMatch.Replace(contents, string.Empty); } internal Attempt TryGetSnippetPath(string fileName) { if (fileName.EndsWith(".cshtml") == false) { fileName += ".cshtml"; } var snippetPath = _hostingEnvironment.MapPathContentRoot($"{_globalSettings.UmbracoPath}/PartialViewMacros/Templates/{fileName}"); return System.IO.File.Exists(snippetPath) ? Attempt.Succeed(snippetPath) : Attempt.Fail(); } public Stream GetPartialViewMacroFileContentStream(string filepath) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _partialViewMacroRepository.GetFileContentStream(filepath); } } public void SetPartialViewMacroFileContent(string filepath, Stream content) { using (var scope = ScopeProvider.CreateScope()) { _partialViewMacroRepository.SetFileContent(filepath, content); scope.Complete(); } } public Stream GetPartialViewFileContentStream(string filepath) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _partialViewRepository.GetFileContentStream(filepath); } } public void SetPartialViewFileContent(string filepath, Stream content) { using (var scope = ScopeProvider.CreateScope()) { _partialViewRepository.SetFileContent(filepath, content); scope.Complete(); } } public void CreatePartialViewFolder(string folderPath) { using (var scope = ScopeProvider.CreateScope()) { _partialViewRepository.AddFolder(folderPath); scope.Complete(); } } public void CreatePartialViewMacroFolder(string folderPath) { using (var scope = ScopeProvider.CreateScope()) { _partialViewMacroRepository.AddFolder(folderPath); scope.Complete(); } } public long GetPartialViewMacroFileSize(string filepath) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _partialViewMacroRepository.GetFileSize(filepath); } } public long GetPartialViewFileSize(string filepath) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _partialViewRepository.GetFileSize(filepath); } } private IPartialViewRepository GetPartialViewRepository(PartialViewType partialViewType) { switch (partialViewType) { case PartialViewType.PartialView: return _partialViewRepository; case PartialViewType.PartialViewMacro: return _partialViewMacroRepository; default: throw new ArgumentOutOfRangeException(nameof(partialViewType)); } } #endregion #region Snippets public string GetPartialViewSnippetContent(string snippetName) { return GetPartialViewMacroSnippetContent(snippetName, PartialViewType.PartialView); } public string GetPartialViewMacroSnippetContent(string snippetName) { return GetPartialViewMacroSnippetContent(snippetName, PartialViewType.PartialViewMacro); } private string GetPartialViewMacroSnippetContent(string snippetName, PartialViewType partialViewType) { if (snippetName.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(snippetName)); string partialViewHeader; switch (partialViewType) { case PartialViewType.PartialView: partialViewHeader = PartialViewHeader; break; case PartialViewType.PartialViewMacro: partialViewHeader = PartialViewMacroHeader; break; default: throw new ArgumentOutOfRangeException(nameof(partialViewType)); } // Try and get the snippet path var snippetPathAttempt = TryGetSnippetPath(snippetName); if (snippetPathAttempt.Success == false) { throw new InvalidOperationException("Could not load snippet with name " + snippetName); } using (var snippetFile = new StreamReader(System.IO.File.OpenRead(snippetPathAttempt.Result))) { var snippetContent = snippetFile.ReadToEnd().Trim(); //strip the @inherits if it's there snippetContent = StripPartialViewHeader(snippetContent); //Update Model.Content to be Model when used as PartialView if (partialViewType == PartialViewType.PartialView) { snippetContent = snippetContent .Replace("Model.Content.", "Model.") .Replace("(Model.Content)", "(Model)"); } var content = $"{partialViewHeader}{Environment.NewLine}{snippetContent}"; return content; } } #endregion private void Audit(AuditType type, int userId, int objectId, string entityType) { _auditRepository.Save(new AuditItem(objectId, type, userId, entityType)); } // TODO: Method to change name and/or alias of view template #region Event Handlers /// /// Occurs before Delete /// public static event TypedEventHandler> DeletingTemplate; /// /// Occurs after Delete /// public static event TypedEventHandler> DeletedTemplate; /// /// Occurs before Delete /// public static event TypedEventHandler> DeletingScript; /// /// Occurs after Delete /// public static event TypedEventHandler> DeletedScript; /// /// Occurs before Delete /// public static event TypedEventHandler> DeletingStylesheet; /// /// Occurs after Delete /// public static event TypedEventHandler> DeletedStylesheet; /// /// Occurs before Save /// public static event TypedEventHandler> SavingTemplate; /// /// Occurs after Save /// public static event TypedEventHandler> SavedTemplate; /// /// Occurs before Save /// public static event TypedEventHandler> SavingScript; /// /// Occurs after Save /// public static event TypedEventHandler> SavedScript; /// /// Occurs before Save /// public static event TypedEventHandler> SavingStylesheet; /// /// Occurs after Save /// public static event TypedEventHandler> SavedStylesheet; /// /// Occurs before Save /// public static event TypedEventHandler> SavingPartialView; /// /// Occurs after Save /// public static event TypedEventHandler> SavedPartialView; /// /// Occurs before Create /// public static event TypedEventHandler> CreatingPartialView; /// /// Occurs after Create /// public static event TypedEventHandler> CreatedPartialView; /// /// Occurs before Delete /// public static event TypedEventHandler> DeletingPartialView; /// /// Occurs after Delete /// public static event TypedEventHandler> DeletedPartialView; #endregion } }