public override async Task SendAsync(HealthCheckResults results) { if (ShouldSend(results) == false) { return; } if (string.IsNullOrEmpty(RecipientEmail)) { return; } var message = _textService?.Localize("healthcheck", "scheduledHealthCheckEmailBody", new[] { DateTime.Now.ToShortDateString(), DateTime.Now.ToShortTimeString(), _markdownToHtmlConverter?.ToHtml(results, Verbosity) }); // Include the umbraco Application URL host in the message subject so that // you can identify the site that these results are for. var host = _hostingEnvironment?.ApplicationMainUrl?.ToString(); var subject = _textService?.Localize("healthcheck", "scheduledHealthCheckEmailSubject", new[] { host }); var mailMessage = CreateMailMessage(subject, message); Task?task = _emailSender?.SendAsync(mailMessage, Constants.Web.EmailTypes.HealthCheck); if (task is not null) { await task; } }
public CopyResponse Copy(int id, int destinationId = -1) { if (id == destinationId) { return new CopyResponse { Message = _textService?.Localize("mediaCopy/cannotCopyToSelf") } } ; IMedia media = _mediaService.GetById(id); if (media == null) { return new CopyResponse { Message = _textService?.Localize("mediaCopy/mediaItemCouldntBeFound") } } ; IMedia destination = _mediaService.GetById(destinationId); if (destination == null && destinationId != -1) { return new CopyResponse { Message = _textService?.Localize("mediaCopy/destinationCouldntBeFound") } } ; if ((destinationId == -1 && !media.ContentType.AllowedAsRoot) || (destinationId != -1 && !destination.ContentType.IsAllowedUnderMediaType(media.ContentType))) { return(new CopyResponse { Message = _textService?.Localize( "mediaCopy/youreNotAllowedToCopyUnder", new Dictionary <string, string> { { "mediaName", media.Name }, { "destination", destinationId == -1 ? _textService?.Localize("mediaCopy/media") : destination.Name } }) }); } if (!CopyMedia(media, destinationId)) { return new CopyResponse { Message = _textService?.Localize("mediaCopy/weEncountedAProblem") } } ; else { return new CopyResponse { Success = true, Path = _nodePath } }; }
public CopyResponse PostCopy(int id, int destinationId = -1) { try { return(_mediaCopyService.Copy(id, destinationId)); } catch (Exception ex) { LogHelper.Error <MediaCopyService>("CopyMedia", ex); return(new CopyResponse { Message = _textService?.Localize("mediaCopy/weEncountedAProblem") }); } }
/// <inheritdoc cref="IValueRequiredValidator.ValidateRequired"/> public IEnumerable <ValidationResult> ValidateRequired(object value, string valueType) { if (value == null) { yield return(new ValidationResult(_textService?.Localize("validation", "invalidNull") ?? ValueCannotBeNull, new[] { "value" })); yield break; } if (valueType.InvariantEquals(ValueTypes.Json)) { if (value.ToString().DetectIsEmptyJson()) { yield return(new ValidationResult(_textService?.Localize("validation", "invalidEmpty") ?? ValueCannotBeEmpty, new[] { "value" })); } yield break; } if (value.ToString().IsNullOrWhiteSpace()) { yield return(new ValidationResult(_textService?.Localize("validation", "invalidEmpty") ?? ValueCannotBeEmpty, new[] { "value" })); } }
/// <summary> /// Maps the generic tab with custom properties for content /// </summary> /// <param name="content"></param> /// <param name="display"></param> /// <param name="dataTypeService"></param> /// <param name="localizedText"></param> /// <param name="contentTypeService"></param> private static void AfterMap(IContent content, ContentItemDisplay display, IDataTypeService dataTypeService, ILocalizedTextService localizedText, IContentTypeService contentTypeService) { //map the IsChildOfListView (this is actually if it is a descendant of a list view!) //TODO: Fix this shorthand .Ancestors() lookup, at least have an overload to use the current if (content.HasIdentity) { var ancesctorListView = content.Ancestors().FirstOrDefault(x => x.ContentType.IsContainer); display.IsChildOfListView = ancesctorListView != null; } else { //it's new so it doesn't have a path, so we need to look this up by it's parent + ancestors var parent = content.Parent(); if (parent == null) { display.IsChildOfListView = false; } else if (parent.ContentType.IsContainer) { display.IsChildOfListView = true; } else { var ancesctorListView = parent.Ancestors().FirstOrDefault(x => x.ContentType.IsContainer); display.IsChildOfListView = ancesctorListView != null; } } //map the tree node url if (HttpContext.Current != null) { var urlHelper = new UrlHelper(new RequestContext(new HttpContextWrapper(HttpContext.Current), new RouteData())); var url = urlHelper.GetUmbracoApiService <ContentTreeController>(controller => controller.GetTreeNode(display.Id.ToString(), null)); display.TreeNodeUrl = url; } //fill in the template config to be passed to the template drop down. var templateItemConfig = new Dictionary <string, string> { { "", "Choose..." } }; foreach (var t in content.ContentType.AllowedTemplates .Where(t => t.Alias.IsNullOrWhiteSpace() == false && t.Name.IsNullOrWhiteSpace() == false)) { templateItemConfig.Add(t.Alias, t.Name); } if (content.ContentType.IsContainer) { TabsAndPropertiesResolver.AddListView(display, "content", dataTypeService); } var properties = new List <ContentPropertyDisplay> { new ContentPropertyDisplay { Alias = string.Format("{0}releasedate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), Label = localizedText.Localize("content/releaseDate"), Value = display.ReleaseDate.HasValue ? display.ReleaseDate.Value.ToIsoString() : null, View = "datepicker" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor }, new ContentPropertyDisplay { Alias = string.Format("{0}expiredate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), Label = localizedText.Localize("content/unpublishDate"), Value = display.ExpireDate.HasValue ? display.ExpireDate.Value.ToIsoString() : null, View = "datepicker" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor }, new ContentPropertyDisplay { Alias = string.Format("{0}template", Constants.PropertyEditors.InternalGenericPropertiesPrefix), Label = "Template", //TODO: localize this? Value = display.TemplateAlias, View = "dropdown", //TODO: Hard coding until we make a real dropdown property editor to lookup Config = new Dictionary <string, object> { { "items", templateItemConfig } } }, new ContentPropertyDisplay { Alias = string.Format("{0}urls", Constants.PropertyEditors.InternalGenericPropertiesPrefix), Label = localizedText.Localize("content/urls"), Value = string.Join(",", display.Urls), View = "urllist" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor } }; TabsAndPropertiesResolver.MapGenericProperties(content, display, properties.ToArray(), genericProperties => { //TODO: This would be much nicer with the IUmbracoContextAccessor so we don't use singletons //If this is a web request and there's a user signed in and the // user has access to the settings section, we will if (HttpContext.Current != null && UmbracoContext.Current != null && UmbracoContext.Current.Security.CurrentUser != null && UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings))) { var currentDocumentType = contentTypeService.GetContentType(display.ContentTypeAlias); var currentDocumentTypeName = currentDocumentType == null ? string.Empty : currentDocumentType.Name; var currentDocumentTypeId = currentDocumentType == null ? string.Empty : currentDocumentType.Id.ToString(CultureInfo.InvariantCulture); //TODO: Hard coding this is not good var docTypeLink = string.Format("#/settings/framed/settings%252FeditNodeTypeNew.aspx%253Fid%253D{0}", currentDocumentTypeId); //Replace the doc type property var docTypeProp = genericProperties.First(x => x.Alias == string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix)); docTypeProp.Value = new List <object> { new { linkText = currentDocumentTypeName, url = docTypeLink, target = "_self", icon = "icon-item-arrangement" } }; //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor docTypeProp.View = "urllist"; } }); }
private static async Task <Attempt <UrlInfo> > DetectCollisionAsync(ILogger logger, IContent content, string url, string culture, IUmbracoContext umbracoContext, IPublishedRouter publishedRouter, ILocalizedTextService textService, IVariationContextAccessor variationContextAccessor, UriUtility uriUtility) { // test for collisions on the 'main' URL var uri = new Uri(url.TrimEnd(Constants.CharArrays.ForwardSlash), UriKind.RelativeOrAbsolute); if (uri.IsAbsoluteUri == false) { uri = uri.MakeAbsolute(umbracoContext.CleanedUmbracoUrl); } uri = uriUtility.UriToUmbraco(uri); IPublishedRequestBuilder builder = await publishedRouter.CreateRequestAsync(uri); IPublishedRequest pcr = await publishedRouter.RouteRequestAsync(builder, new RouteRequestOptions(RouteDirection.Outbound)); if (!pcr.HasPublishedContent()) { var logMsg = nameof(DetectCollisionAsync) + " did not resolve a content item for original url: {Url}, translated to {TranslatedUrl} and culture: {Culture}"; if (pcr.IgnorePublishedContentCollisions) { logger.LogDebug(logMsg, url, uri, culture); } else { logger.LogDebug(logMsg, url, uri, culture); } var urlInfo = UrlInfo.Message(textService.Localize("content", "routeErrorCannotRoute"), culture); return(Attempt.Succeed(urlInfo)); } if (pcr.IgnorePublishedContentCollisions) { return(Attempt <UrlInfo> .Fail()); } if (pcr.PublishedContent.Id != content.Id) { IPublishedContent o = pcr.PublishedContent; var l = new List <string>(); while (o != null) { l.Add(o.Name(variationContextAccessor)); o = o.Parent; } l.Reverse(); var s = "/" + string.Join("/", l) + " (id=" + pcr.PublishedContent.Id + ")"; var urlInfo = UrlInfo.Message(textService.Localize("content", "routeError", new[] { s }), culture); return(Attempt.Succeed(urlInfo)); } // no collision return(Attempt <UrlInfo> .Fail()); }
public static string Localize(this ILocalizedTextService manager, string?area, string?alias) => manager.Localize(area, alias, Thread.CurrentThread.CurrentUICulture);
public async Task PostSave_Validates_All_Cultures_Has_Domains() { ILocalizationService localizationService = GetRequiredService <ILocalizationService>(); localizationService.Save(new LanguageBuilder() .WithCultureInfo(DkIso) .WithIsDefault(false) .Build()); IContentTypeService contentTypeService = GetRequiredService <IContentTypeService>(); IContentType contentType = new ContentTypeBuilder().WithContentVariation(ContentVariation.Culture).Build(); contentTypeService.Save(contentType); Content content = new ContentBuilder() .WithoutIdentity() .WithContentType(contentType) .WithCultureName(UsIso, "Root") .WithCultureName(DkIso, "Rod") .Build(); IContentService contentService = GetRequiredService <IContentService>(); contentService.Save(content); ContentItemSave model = new ContentItemSaveBuilder() .WithContent(content) .WithAction(ContentSaveAction.Publish) .Build(); ILanguage dkLanguage = localizationService.GetLanguageByIsoCode(DkIso); IDomainService domainService = GetRequiredService <IDomainService>(); var dkDomain = new UmbracoDomain("/") { RootContentId = content.Id, LanguageId = dkLanguage.Id }; domainService.Save(dkDomain); var url = PrepareApiControllerUrl <ContentController>(x => x.PostSave(null)); HttpResponseMessage response = await Client.PostAsync(url, new MultipartFormDataContent { { new StringContent(JsonConvert.SerializeObject(model)), "contentItem" } }); var body = await response.Content.ReadAsStringAsync(); body = body.TrimStart(AngularJsonMediaTypeFormatter.XsrfPrefix); ContentItemDisplay display = JsonConvert.DeserializeObject <ContentItemDisplay>(body); ILocalizedTextService localizedTextService = GetRequiredService <ILocalizedTextService>(); var expectedMessage = localizedTextService.Localize("speechBubbles", "publishWithMissingDomain", new [] { UsIso }); Assert.Multiple(() => { Assert.NotNull(display); Assert.AreEqual(1, display.Notifications.Count(x => x.NotificationType == NotificationStyle.Warning)); Assert.AreEqual(expectedMessage, display.Notifications.FirstOrDefault(x => x.NotificationType == NotificationStyle.Warning)?.Message); }); }
/// <summary> /// Localize a key without any variables /// </summary> /// <param name="manager"></param> /// <param name="key"></param> /// <param name="culture"></param> /// <param name="tokens"></param> /// <returns></returns> public static string Localize(this ILocalizedTextService manager, string key, CultureInfo culture, string[] tokens) { return(manager.Localize(key, culture, ConvertToDictionaryVars(tokens))); }
/// <summary> /// Localize using the current thread culture /// </summary> /// <param name="manager"></param> /// <param name="key"></param> /// <param name="tokens"></param> /// <returns></returns> public static string Localize(this ILocalizedTextService manager, string key, string[] tokens) { return(manager.Localize(key, Thread.CurrentThread.CurrentUICulture, tokens)); }
/// <summary> /// Returns a localized month name from a month number. /// </summary> /// <param name="textService"> /// The text service. /// </param> /// <param name="culture"> /// The culture. /// </param> /// <param name="month"> /// The month. /// </param> /// <returns> /// The <see cref="string"/>. /// </returns> public static string GetLocalizedMonthName(this ILocalizedTextService textService, CultureInfo culture, int month) { string shortName; switch (month) { case 1: shortName = "jan"; break; case 2: shortName = "feb"; break; case 3: shortName = "mar"; break; case 4: shortName = "apr"; break; case 5: shortName = "may"; break; case 6: shortName = "jun"; break; case 7: shortName = "jul"; break; case 8: shortName = "aug"; break; case 9: shortName = "sep"; break; case 10: shortName = "oct"; break; case 11: shortName = "nov"; break; case 12: shortName = "dec"; break; default: shortName = "jan"; break; } return(textService.Localize(string.Format("merchelloGeneral/{0}", shortName), culture)); }
/// <summary> /// Returns the tree nodes for an application /// </summary> /// <param name="application">The application to load tree for</param> /// <param name="tree">An optional single tree alias, if specified will only load the single tree for the request app</param> /// <param name="queryStrings">The query strings</param> /// <param name="use">Tree use.</param> public async Task <ActionResult <TreeRootNode> > GetApplicationTrees(string?application, string?tree, [ModelBinder(typeof(HttpQueryStringModelBinder))] FormCollection?queryStrings, TreeUse use = TreeUse.Main) { application = application?.CleanForXss(); if (string.IsNullOrEmpty(application)) { return(NotFound()); } var section = _sectionService.GetByAlias(application); if (section == null) { return(NotFound()); } // find all tree definitions that have the current application alias var groupedTrees = _treeService.GetBySectionGrouped(application, use); var allTrees = groupedTrees.Values.SelectMany(x => x).ToList(); if (allTrees.Count == 0) { // if there are no trees defined for this section but the section is defined then we can have a simple // full screen section without trees var name = _localizedTextService.Localize("sections", application); return(TreeRootNode.CreateSingleTreeRoot(Constants.System.RootString, null, null, name, TreeNodeCollection.Empty, true)); } // handle request for a specific tree / or when there is only one tree if (!tree.IsNullOrWhiteSpace() || allTrees.Count == 1) { var t = tree.IsNullOrWhiteSpace() ? allTrees[0] : allTrees.FirstOrDefault(x => x.TreeAlias == tree); if (t == null) { return(NotFound()); } var treeRootNode = await GetTreeRootNode(t, Constants.System.Root, queryStrings); if (treeRootNode != null) { return(treeRootNode); } return(NotFound()); } // handle requests for all trees // for only 1 group if (groupedTrees.Count == 1) { var nodes = new TreeNodeCollection(); foreach (var t in allTrees) { var nodeResult = await TryGetRootNode(t, queryStrings); if (!(nodeResult?.Result is null)) { return(nodeResult.Result); } var node = nodeResult?.Value; if (node != null) { nodes.Add(node); } } var name = _localizedTextService.Localize("sections", application); if (nodes.Count > 0) { var treeRootNode = TreeRootNode.CreateMultiTreeRoot(nodes); treeRootNode.Name = name; return(treeRootNode); } // otherwise it's a section with all empty trees, aka a fullscreen section // todo is this true? what if we just failed to TryGetRootNode on all of them? SD: Yes it's true but we should check the result of TryGetRootNode and throw? return(TreeRootNode.CreateSingleTreeRoot(Constants.System.RootString, null, null, name, TreeNodeCollection.Empty, true)); } // for many groups var treeRootNodes = new List <TreeRootNode>(); foreach (var(groupName, trees) in groupedTrees) { var nodes = new TreeNodeCollection(); foreach (var t in trees) { var nodeResult = await TryGetRootNode(t, queryStrings); if (nodeResult != null && nodeResult.Result is not null) { return(nodeResult.Result); } var node = nodeResult?.Value; if (node != null) { nodes.Add(node); } } if (nodes.Count == 0) { continue; } // no name => third party // use localization key treeHeaders/thirdPartyGroup // todo this is an odd convention var name = groupName.IsNullOrWhiteSpace() ? "thirdPartyGroup" : groupName; var groupRootNode = TreeRootNode.CreateGroupNode(nodes, application); groupRootNode.Name = _localizedTextService.Localize("treeHeaders", name); treeRootNodes.Add(groupRootNode); } return(TreeRootNode.CreateGroupedMultiTreeRoot(new TreeNodeCollection(treeRootNodes.OrderBy(x => x.Name)))); }
public ActionResult <UserGroupDisplay?> PostSaveUserGroup(UserGroupSave userGroupSave) { if (userGroupSave == null) { throw new ArgumentNullException(nameof(userGroupSave)); } //authorize that the user has access to save this user group var authHelper = new UserGroupEditorAuthorizationHelper( _userService, _contentService, _mediaService, _entityService, _appCaches); Attempt <string?> isAuthorized = authHelper.AuthorizeGroupAccess(_backofficeSecurityAccessor.BackOfficeSecurity?.CurrentUser, userGroupSave.Alias); if (isAuthorized == false) { return(Unauthorized(isAuthorized.Result)); } //if sections were added we need to check that the current user has access to that section isAuthorized = authHelper.AuthorizeSectionChanges( _backofficeSecurityAccessor.BackOfficeSecurity?.CurrentUser, userGroupSave.PersistedUserGroup?.AllowedSections, userGroupSave.Sections); if (isAuthorized == false) { return(Unauthorized(isAuthorized.Result)); } //if start nodes were changed we need to check that the current user has access to them isAuthorized = authHelper.AuthorizeStartNodeChanges( _backofficeSecurityAccessor.BackOfficeSecurity?.CurrentUser, userGroupSave.PersistedUserGroup?.StartContentId, userGroupSave.StartContentId, userGroupSave.PersistedUserGroup?.StartMediaId, userGroupSave.StartMediaId); if (isAuthorized == false) { return(Unauthorized(isAuthorized.Result)); } //need to ensure current user is in a group if not an admin to avoid a 401 EnsureNonAdminUserIsInSavedUserGroup(userGroupSave); //map the model to the persisted instance _umbracoMapper.Map(userGroupSave, userGroupSave.PersistedUserGroup); if (userGroupSave.PersistedUserGroup is not null) { //save the group _userService.Save(userGroupSave.PersistedUserGroup, userGroupSave.Users?.ToArray()); } //deal with permissions //remove ones that have been removed var existing = _userService.GetPermissions(userGroupSave.PersistedUserGroup, true) .ToDictionary(x => x.EntityId, x => x); if (userGroupSave.AssignedPermissions is not null) { IEnumerable <int> toRemove = existing.Keys.Except(userGroupSave.AssignedPermissions.Select(x => x.Key)); foreach (var contentId in toRemove) { _userService.RemoveUserGroupPermissions(userGroupSave.PersistedUserGroup?.Id ?? default, contentId); } //update existing foreach (KeyValuePair <int, IEnumerable <string> > assignedPermission in userGroupSave.AssignedPermissions) { _userService.ReplaceUserGroupPermissions( userGroupSave.PersistedUserGroup?.Id ?? default, assignedPermission.Value.Select(x => x[0]), assignedPermission.Key); } } UserGroupDisplay?display = _umbracoMapper.Map <UserGroupDisplay>(userGroupSave.PersistedUserGroup); display?.AddSuccessNotification( _localizedTextService.Localize("speechBubbles", "operationSavedHeader"), _localizedTextService.Localize("speechBubbles", "editUserGroupSaved")); return(display); }
public ActionResult <MemberTypeDisplay?> PostSave(MemberTypeSave contentTypeSave) { //get the persisted member type var ctId = Convert.ToInt32(contentTypeSave.Id); IMemberType?ct = ctId > 0 ? _memberTypeService.Get(ctId) : null; if (_backofficeSecurityAccessor.BackOfficeSecurity?.CurrentUser?.HasAccessToSensitiveData() == false) { //We need to validate if any properties on the contentTypeSave have had their IsSensitiveValue changed, //and if so, we need to check if the current user has access to sensitive values. If not, we have to return an error IEnumerable <MemberPropertyTypeBasic> props = contentTypeSave.Groups.SelectMany(x => x.Properties); if (ct != null) { foreach (MemberPropertyTypeBasic prop in props) { // Id 0 means the property was just added, no need to look it up if (prop.Id == 0) { continue; } IPropertyType?foundOnContentType = ct.PropertyTypes.FirstOrDefault(x => x.Id == prop.Id); if (foundOnContentType == null) { return(NotFound(new { Message = "No property type with id " + prop.Id + " found on the content type" })); } if (ct.IsSensitiveProperty(foundOnContentType.Alias) && prop.IsSensitiveData == false) { //if these don't match, then we cannot continue, this user is not allowed to change this value return(Forbid()); } } } else { //if it is new, then we can just verify if any property has sensitive data turned on which is not allowed if (props.Any(prop => prop.IsSensitiveData)) { return(Forbid()); } } } ActionResult <IMemberType?> savedCt = PerformPostSave <MemberTypeDisplay, MemberTypeSave, MemberPropertyTypeBasic>( contentTypeSave, i => ct, type => _memberTypeService.Save(type)); if (!(savedCt.Result is null)) { return(savedCt.Result); } MemberTypeDisplay?display = _umbracoMapper.Map <MemberTypeDisplay>(savedCt.Value); display?.AddSuccessNotification( _localizedTextService.Localize("speechBubbles", "memberTypeSavedHeader"), string.Empty); return(display); }
public static string Localize(this ILocalizedTextService manager, string area, string key) { var fullKey = string.Join("/", area, key); return(manager.Localize(fullKey, Thread.CurrentThread.CurrentUICulture)); }
/// <summary> /// Localize a key without any variables /// </summary> /// <param name="manager"></param> /// <param name="area"></param> /// <param name="alias"></param> /// <param name="culture"></param> /// <param name="tokens"></param> /// <returns></returns> public static string Localize(this ILocalizedTextService manager, string area, string alias, CultureInfo culture, string?[] tokens) => manager.Localize(area, alias, culture, ConvertToDictionaryVars(tokens));
/// <summary> /// Localize using the current thread culture /// </summary> /// <param name="manager"></param> /// <param name="area"></param> /// <param name="alias"></param> /// <param name="tokens"></param> /// <returns></returns> public static string Localize(this ILocalizedTextService manager, string?area, string alias, string?[]?tokens) => manager.Localize(area, alias, Thread.CurrentThread.CurrentUICulture, ConvertToDictionaryVars(tokens));
public ActionResult <CodeFileDisplay> PostCreateContainer(string type, string parentId, string name) { if (string.IsNullOrWhiteSpace(type)) { throw new ArgumentException("Value cannot be null or whitespace.", "type"); } if (string.IsNullOrWhiteSpace(parentId)) { throw new ArgumentException("Value cannot be null or whitespace.", "parentId"); } if (string.IsNullOrWhiteSpace(name)) { throw new ArgumentException("Value cannot be null or whitespace.", "name"); } if (name.ContainsAny(Path.GetInvalidPathChars())) { return(ValidationProblem(_localizedTextService.Localize("codefile", "createFolderIllegalChars"))); } // if the parentId is root (-1) then we just need an empty string as we are // creating the path below and we don't want -1 in the path if (parentId == Constants.System.RootString) { parentId = string.Empty; } name = HttpUtility.UrlDecode(name); if (parentId.IsNullOrWhiteSpace() == false) { parentId = HttpUtility.UrlDecode(parentId); name = parentId.EnsureEndsWith("/") + name; } var virtualPath = string.Empty; switch (type) { case Constants.Trees.PartialViews: virtualPath = NormalizeVirtualPath(name, Constants.SystemDirectories.PartialViews); _fileService.CreatePartialViewFolder(virtualPath); break; case Constants.Trees.PartialViewMacros: virtualPath = NormalizeVirtualPath(name, Constants.SystemDirectories.MacroPartials); _fileService.CreatePartialViewMacroFolder(virtualPath); break; case Constants.Trees.Scripts: virtualPath = NormalizeVirtualPath(name, _globalSettings.UmbracoScriptsPath); _fileService.CreateScriptFolder(virtualPath); break; case Constants.Trees.Stylesheets: virtualPath = NormalizeVirtualPath(name, _globalSettings.UmbracoCssPath); _fileService.CreateStyleSheetFolder(virtualPath); break; } return(new CodeFileDisplay { VirtualPath = virtualPath, Path = Url.GetTreePathFromFilePath(virtualPath) }); }
private async Task <HealthCheckStatus> CheckForValidCertificate() { string message; StatusResultType result; // Attempt to access the site over HTTPS to see if it HTTPS is supported and a valid certificate has been configured var urlBuilder = new UriBuilder(_hostingEnvironment.ApplicationMainUrl) { Scheme = Uri.UriSchemeHttps }; Uri url = urlBuilder.Uri; var request = new HttpRequestMessage(HttpMethod.Head, url); try { using HttpResponseMessage response = await _httpClientEnsureInitialized.SendAsync(request); if (response.StatusCode == HttpStatusCode.OK) { // Got a valid response, check now if the certificate is expiring within the specified amount of days int?daysToExpiry = 0; if (request.Properties.TryGetValue( HttpPropertyKeyCertificateDaysToExpiry, out var certificateDaysToExpiry)) { daysToExpiry = (int?)certificateDaysToExpiry; } if (daysToExpiry <= 0) { result = StatusResultType.Error; message = _textService.Localize("healthcheck", "httpsCheckExpiredCertificate"); } else if (daysToExpiry < NumberOfDaysForExpiryWarning) { result = StatusResultType.Warning; message = _textService.Localize("healthcheck", "httpsCheckExpiringCertificate", new[] { daysToExpiry.ToString() }); } else { result = StatusResultType.Success; message = _textService.Localize("healthcheck", "httpsCheckValidCertificate"); } } else { result = StatusResultType.Error; message = _textService.Localize("healthcheck", "healthCheckInvalidUrl", new[] { url.AbsoluteUri, response.ReasonPhrase }); } } catch (Exception ex) { if (ex is WebException exception) { message = exception.Status == WebExceptionStatus.TrustFailure ? _textService.Localize("healthcheck", "httpsCheckInvalidCertificate", new[] { exception.Message }) : _textService.Localize("healthcheck", "healthCheckInvalidUrl", new[] { url.AbsoluteUri, exception.Message }); } else { message = _textService.Localize("healthcheck", "healthCheckInvalidUrl", new[] { url.AbsoluteUri, ex.Message }); } result = StatusResultType.Error; } return(new HealthCheckStatus(message) { ResultType = result, ReadMoreLink = result == StatusResultType.Success ? null : Constants.HealthChecks.DocumentationLinks.Security.HttpsCheck.CheckIfCurrentSchemeIsHttps, }); }
public async Task <ActionResult <MemberDisplay?> > PostSave([ModelBinder(typeof(MemberBinder))] MemberSave contentItem) { if (contentItem == null) { throw new ArgumentNullException("The member content item was null"); } // If we've reached here it means: // * Our model has been bound // * and validated // * any file attachments have been saved to their temporary location for us to use // * we have a reference to the DTO object and the persisted object // * Permissions are valid // map the properties to the persisted entity MapPropertyValues(contentItem); await ValidateMemberDataAsync(contentItem); // Unlike content/media - if there are errors for a member, we do NOT proceed to save them, we cannot so return the errors if (ModelState.IsValid == false) { MemberDisplay?forDisplay = _umbracoMapper.Map <MemberDisplay>(contentItem.PersistedContent); return(ValidationProblem(forDisplay, ModelState)); } // Create a scope here which will wrap all child data operations in a single transaction. // We'll complete this at the end of this method if everything succeeeds, else // all data operations will roll back. using ICoreScope scope = _scopeProvider.CreateCoreScope(); // Depending on the action we need to first do a create or update using the membership manager // this ensures that passwords are formatted correctly and also performs the validation on the provider itself. switch (contentItem.Action) { case ContentSaveAction.Save: ActionResult <bool> updateSuccessful = await UpdateMemberAsync(contentItem); if (!(updateSuccessful.Result is null)) { return(updateSuccessful.Result); } break; case ContentSaveAction.SaveNew: ActionResult <bool> createSuccessful = await CreateMemberAsync(contentItem); if (!(createSuccessful.Result is null)) { return(createSuccessful.Result); } break; default: // we don't support anything else for members return(NotFound()); } // return the updated model MemberDisplay?display = _umbracoMapper.Map <MemberDisplay>(contentItem.PersistedContent); // lastly, if it is not valid, add the model state to the outgoing object and throw a 403 if (!ModelState.IsValid) { return(ValidationProblem(display, ModelState, StatusCodes.Status403Forbidden)); } // put the correct messages in switch (contentItem.Action) { case ContentSaveAction.Save: case ContentSaveAction.SaveNew: display?.AddSuccessNotification( _localizedTextService.Localize("speechBubbles", "editMemberSaved"), _localizedTextService.Localize("speechBubbles", "editMemberSaved")); break; } // Mark transaction to commit all changes scope.Complete(); return(display); }
/// <summary> /// Localize using the current thread culture /// </summary> /// <param name="manager"></param> /// <param name="key"></param> /// <param name="tokens"></param> /// <returns></returns> public static string Localize(this ILocalizedTextService manager, string key, IDictionary <string, string> tokens = null) { return(manager.Localize(key, Thread.CurrentThread.CurrentUICulture, tokens)); }
/// <summary> /// Gets the URLs of the content item. /// </summary> /// <remarks> /// <para>Use when displaying URLs. If errors occur when generating the URLs, they will show in the list.</para> /// <para>Contains all the URLs that we can figure out (based upon domains, etc).</para> /// </remarks> public static async Task <IEnumerable <UrlInfo> > GetContentUrlsAsync( this IContent content, IPublishedRouter publishedRouter, IUmbracoContext umbracoContext, ILocalizationService localizationService, ILocalizedTextService textService, IContentService contentService, IVariationContextAccessor variationContextAccessor, ILogger <IContent> logger, UriUtility uriUtility, IPublishedUrlProvider publishedUrlProvider) { ArgumentNullException.ThrowIfNull(content); ArgumentNullException.ThrowIfNull(publishedRouter); ArgumentNullException.ThrowIfNull(umbracoContext); ArgumentNullException.ThrowIfNull(localizationService); ArgumentNullException.ThrowIfNull(textService); ArgumentNullException.ThrowIfNull(contentService); ArgumentNullException.ThrowIfNull(variationContextAccessor); ArgumentNullException.ThrowIfNull(logger); ArgumentNullException.ThrowIfNull(uriUtility); ArgumentNullException.ThrowIfNull(publishedUrlProvider); var result = new List <UrlInfo>(); if (content.Published == false) { result.Add(UrlInfo.Message(textService.Localize("content", "itemNotPublished"))); return(result); } // build a list of URLs, for the back-office // which will contain // - the 'main' URLs, which is what .Url would return, for each culture // - the 'other' URLs we know (based upon domains, etc) // // need to work through each installed culture: // on invariant nodes, each culture returns the same URL segment but, // we don't know if the branch to this content is invariant, so we need to ask // for URLs for all cultures. // and, not only for those assigned to domains in the branch, because we want // to show what GetUrl() would return, for every culture. var urls = new HashSet <UrlInfo>(); var cultures = localizationService.GetAllLanguages().Select(x => x.IsoCode).ToList(); // get all URLs for all cultures // in a HashSet, so de-duplicates too foreach (UrlInfo cultureUrl in await GetContentUrlsByCultureAsync(content, cultures, publishedRouter, umbracoContext, contentService, textService, variationContextAccessor, logger, uriUtility, publishedUrlProvider)) { urls.Add(cultureUrl); } // return the real URLs first, then the messages foreach (IGrouping <bool, UrlInfo> urlGroup in urls.GroupBy(x => x.IsUrl).OrderByDescending(x => x.Key)) { // in some cases there will be the same URL for multiple cultures: // * The entire branch is invariant // * If there are less domain/cultures assigned to the branch than the number of cultures/languages installed if (urlGroup.Key) { result.AddRange(urlGroup.DistinctBy(x => x.Text, StringComparer.OrdinalIgnoreCase).OrderBy(x => x.Text) .ThenBy(x => x.Culture)); } else { result.AddRange(urlGroup); } } // get the 'other' URLs - ie not what you'd get with GetUrl() but URLs that would route to the document, nevertheless. // for these 'other' URLs, we don't check whether they are routable, collide, anything - we just report them. foreach (UrlInfo otherUrl in publishedUrlProvider.GetOtherUrls(content.Id).OrderBy(x => x.Text) .ThenBy(x => x.Culture)) { // avoid duplicates if (urls.Add(otherUrl)) { result.Add(otherUrl); } } return(result); }
/// <summary> /// Gets the URLs of the content item. /// </summary> /// <remarks> /// <para>Use when displaying URLs. If errors occur when generating the URLs, they will show in the list.</para> /// <para>Contains all the URLs that we can figure out (based upon domains, etc).</para> /// </remarks> public static IEnumerable <UrlInfo> GetContentUrls(this IContent content, IPublishedRouter publishedRouter, UmbracoContext umbracoContext, ILocalizationService localizationService, ILocalizedTextService textService, IContentService contentService, ILogger logger) { if (content == null) { throw new ArgumentNullException(nameof(content)); } if (publishedRouter == null) { throw new ArgumentNullException(nameof(publishedRouter)); } if (umbracoContext == null) { throw new ArgumentNullException(nameof(umbracoContext)); } if (localizationService == null) { throw new ArgumentNullException(nameof(localizationService)); } if (textService == null) { throw new ArgumentNullException(nameof(textService)); } if (contentService == null) { throw new ArgumentNullException(nameof(contentService)); } if (logger == null) { throw new ArgumentNullException(nameof(logger)); } if (content.Published == false) { yield return(UrlInfo.Message(textService.Localize("content/itemNotPublished"))); yield break; } // build a list of URLs, for the back-office // which will contain // - the 'main' URLs, which is what .Url would return, for each culture // - the 'other' URLs we know (based upon domains, etc) // // need to work through each installed culture: // on invariant nodes, each culture returns the same URL segment but, // we don't know if the branch to this content is invariant, so we need to ask // for URLs for all cultures. // and, not only for those assigned to domains in the branch, because we want // to show what GetUrl() would return, for every culture. var urls = new HashSet <UrlInfo>(); var cultures = localizationService.GetAllLanguages().Select(x => x.IsoCode).ToList(); //get all URLs for all cultures //in a HashSet, so de-duplicates too foreach (var cultureUrl in GetContentUrlsByCulture(content, cultures, publishedRouter, umbracoContext, contentService, textService, logger)) { urls.Add(cultureUrl); } //return the real URLs first, then the messages foreach (var urlGroup in urls.GroupBy(x => x.IsUrl).OrderByDescending(x => x.Key)) { //in some cases there will be the same URL for multiple cultures: // * The entire branch is invariant // * If there are less domain/cultures assigned to the branch than the number of cultures/languages installed foreach (var dUrl in urlGroup.DistinctBy(x => x.Text.ToUpperInvariant()).OrderBy(x => x.Text).ThenBy(x => x.Culture)) { yield return(dUrl); } } // get the 'other' URLs - ie not what you'd get with GetUrl() but URLs that would route to the document, nevertheless. // for these 'other' URLs, we don't check whether they are routable, collide, anything - we just report them. foreach (var otherUrl in umbracoContext.UrlProvider.GetOtherUrls(content.Id).OrderBy(x => x.Text).ThenBy(x => x.Culture)) { if (urls.Add(otherUrl)) //avoid duplicates { yield return(otherUrl); } } }
private HealthCheckStatus CheckForValidCertificate() { var message = string.Empty; StatusResultType result; // Attempt to access the site over HTTPS to see if it HTTPS is supported // and a valid certificate has been configured var url = _runtime.ApplicationUrl.ToString().Replace("http:", "https:"); var request = (HttpWebRequest)WebRequest.Create(url); request.AllowAutoRedirect = false; try { var response = (HttpWebResponse)request.GetResponse(); // Check for 301/302 as a external login provider such as UmbracoID might be in use if (response.StatusCode == HttpStatusCode.Moved || response.StatusCode == HttpStatusCode.Redirect) { // Reset request to use the static login background image var absoluteLoginBackgroundImage = $"{url}/{_contentSection.LoginBackgroundImage}"; request = (HttpWebRequest)WebRequest.Create(absoluteLoginBackgroundImage); response = (HttpWebResponse)request.GetResponse(); } if (response.StatusCode == HttpStatusCode.OK) { // Got a valid response, check now for if certificate expiring within 14 days // Hat-tip: https://stackoverflow.com/a/15343898/489433 const int NumberOfDaysForExpiryWarning = 14; var cert = request.ServicePoint.Certificate; using (var cert2 = new X509Certificate2(cert)) { var expirationDate = cert2.NotAfter; var daysToExpiry = (int)Math.Floor((cert2.NotAfter - DateTime.Now).TotalDays); if (daysToExpiry <= 0) { result = StatusResultType.Error; message = _textService.Localize("healthcheck", "httpsCheckExpiredCertificate"); } else if (daysToExpiry < NumberOfDaysForExpiryWarning) { result = StatusResultType.Warning; message = _textService.Localize("healthcheck", "httpsCheckExpiringCertificate", new[] { daysToExpiry.ToString() }); } else { result = StatusResultType.Success; message = _textService.Localize("healthcheck", "httpsCheckValidCertificate"); } } } else { result = StatusResultType.Error; message = _textService.Localize("healthcheck", "healthCheckInvalidUrl", new[] { url, response.StatusDescription }); } } catch (Exception ex) { var exception = ex as WebException; if (exception != null) { message = exception.Status == WebExceptionStatus.TrustFailure ? _textService.Localize("healthcheck", "httpsCheckInvalidCertificate", new [] { exception.Message }) : _textService.Localize("healthcheck", "healthCheckInvalidUrl", new [] { url, exception.Message }); } else { message = _textService.Localize("healthcheck", "healthCheckInvalidUrl", new[] { url, ex.Message }); } result = StatusResultType.Error; } var actions = new List <HealthCheckAction>(); return (new HealthCheckStatus(message) { ResultType = result, Actions = actions }); }
/// <summary> /// Tries to return a <see cref="UrlInfo" /> for each culture for the content while detecting collisions/errors /// </summary> private static async Task <IEnumerable <UrlInfo> > GetContentUrlsByCultureAsync( IContent content, IEnumerable <string> cultures, IPublishedRouter publishedRouter, IUmbracoContext umbracoContext, IContentService contentService, ILocalizedTextService textService, IVariationContextAccessor variationContextAccessor, ILogger logger, UriUtility uriUtility, IPublishedUrlProvider publishedUrlProvider) { var result = new List <UrlInfo>(); foreach (var culture in cultures) { // if content is variant, and culture is not published, skip if (content.ContentType.VariesByCulture() && !content.IsCulturePublished(culture)) { continue; } // if it's variant and culture is published, or if it's invariant, proceed string url; try { url = publishedUrlProvider.GetUrl(content.Id, culture: culture); } catch (Exception ex) { logger.LogError(ex, "GetUrl exception."); url = "#ex"; } switch (url) { // deal with 'could not get the URL' case "#": result.Add(HandleCouldNotGetUrl(content, culture, contentService, textService)); break; // deal with exceptions case "#ex": result.Add(UrlInfo.Message(textService.Localize("content", "getUrlException"), culture)); break; // got a URL, deal with collisions, add URL default: // detect collisions, etc Attempt <UrlInfo?> hasCollision = await DetectCollisionAsync(logger, content, url, culture, umbracoContext, publishedRouter, textService, variationContextAccessor, uriUtility); if (hasCollision.Success && hasCollision.Result is not null) { result.Add(hasCollision.Result); } else { result.Add(UrlInfo.Url(url, culture)); } break; } } return(result); }
public static string Localize <T>(this ILocalizedTextService manager, string area, T key) where T : System.Enum => manager.Localize(area, key.ToString(), Thread.CurrentThread.CurrentUICulture);
private HealthCheckStatus CheckForValidCertificate() { var message = string.Empty; StatusResultType result; // Attempt to access the site over HTTPS to see if it HTTPS is supported // and a valid certificate has been configured var url = HealthCheckContext.SiteUrl.Replace("http:", "https:"); var request = (HttpWebRequest)WebRequest.Create(url); request.Method = "HEAD"; try { var response = (HttpWebResponse)request.GetResponse(); if (response.StatusCode == HttpStatusCode.OK) { // Got a valid response, check now for if certificate expiring within 14 days // Hat-tip: https://stackoverflow.com/a/15343898/489433 const int NumberOfDaysForExpiryWarning = 14; var cert = request.ServicePoint.Certificate; var cert2 = new X509Certificate2(cert); var expirationDate = cert2.NotAfter; var daysToExpiry = (int)Math.Floor((cert2.NotAfter - DateTime.Now).TotalDays); if (daysToExpiry <= 0) { result = StatusResultType.Error; message = _textService.Localize("healthcheck/httpsCheckExpiredCertificate"); } else if (daysToExpiry < NumberOfDaysForExpiryWarning) { result = StatusResultType.Warning; message = _textService.Localize("healthcheck/httpsCheckExpiringCertificate", new[] { daysToExpiry.ToString() }); } else { result = StatusResultType.Success; message = _textService.Localize("healthcheck/httpsCheckValidCertificate"); } } else { result = StatusResultType.Error; message = _textService.Localize("healthcheck/httpsCheckInvalidUrl", new[] { url, response.StatusDescription }); } } catch (Exception ex) { var exception = ex as WebException; if (exception != null) { message = exception.Status == WebExceptionStatus.TrustFailure ? _textService.Localize("healthcheck/httpsCheckInvalidCertificate", new [] { exception.Message }) : _textService.Localize("healthcheck/httpsCheckInvalidUrl", new [] { url, exception.Message }); } else { message = _textService.Localize("healthcheck/httpsCheckInvalidUrl", new[] { url, ex.Message }); } result = StatusResultType.Error; } var actions = new List <HealthCheckAction>(); return (new HealthCheckStatus(message) { ResultType = result, Actions = actions }); }
/// <summary> /// Returns an item to be used to display the recycle bin for media /// </summary> /// <returns></returns> public MediaItemDisplay GetRecycleBin() { var apps = new List <ContentApp>(); apps.Add(ListViewContentAppFactory.CreateContentApp(_dataTypeService, _propertyEditors, "recycleBin", "media", Constants.DataTypes.DefaultMediaListView)); apps[0].Active = true; var display = new MediaItemDisplay { Id = Constants.System.RecycleBinMedia, Alias = "recycleBin", ParentId = -1, Name = _localizedTextService.Localize("general", "recycleBin"), ContentTypeAlias = "recycleBin", CreateDate = DateTime.Now, IsContainer = true, Path = "-1," + Constants.System.RecycleBinMedia, ContentApps = apps }; return(display); }
/// <summary> /// Overridden to deal with custom member properties and permissions /// </summary> /// <param name="umbracoContext"></param> /// <param name="content"></param> /// <returns></returns> protected override List <Tab <ContentPropertyDisplay> > ResolveCore(UmbracoContext umbracoContext, IMember content) { var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider(); IgnoreProperties = content.PropertyTypes .Where(x => x.HasIdentity == false) .Select(x => x.Alias) .ToArray(); var result = base.ResolveCore(umbracoContext, content); if (provider.IsUmbracoMembershipProvider() == false) { //it's a generic provider so update the locked out property based on our known constant alias var isLockedOutProperty = result.SelectMany(x => x.Properties).FirstOrDefault(x => x.Alias == Constants.Conventions.Member.IsLockedOut); if (isLockedOutProperty?.Value != null && isLockedOutProperty.Value.ToString() != "1") { isLockedOutProperty.View = "readonlyvalue"; isLockedOutProperty.Value = _localizedTextService.Localize("general/no"); } } else { var umbracoProvider = (IUmbracoMemberTypeMembershipProvider)provider; //This is kind of a hack because a developer is supposed to be allowed to set their property editor - would have been much easier // if we just had all of the membeship provider fields on the member table :( // TODO: But is there a way to map the IMember.IsLockedOut to the property ? i dunno. var isLockedOutProperty = result.SelectMany(x => x.Properties).FirstOrDefault(x => x.Alias == umbracoProvider.LockPropertyTypeAlias); if (isLockedOutProperty?.Value != null && isLockedOutProperty.Value.ToString() != "1") { isLockedOutProperty.View = "readonlyvalue"; isLockedOutProperty.Value = _localizedTextService.Localize("general/no"); } } if (umbracoContext != null && umbracoContext.Security.CurrentUser != null && umbracoContext.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings))) { var memberTypeLink = string.Format("#/member/memberTypes/edit/{0}", content.ContentTypeId); //Replace the doctype property var docTypeProperty = result.SelectMany(x => x.Properties) .First(x => x.Alias == string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix)); docTypeProperty.Value = new List <object> { new { linkText = content.ContentType.Name, url = memberTypeLink, target = "_self", icon = "icon-item-arrangement" } }; docTypeProperty.View = "urllist"; } //check if there's an approval field var legacyProvider = provider as global::umbraco.providers.members.UmbracoMembershipProvider; if (content.HasIdentity == false && legacyProvider != null) { var approvedField = legacyProvider.ApprovedPropertyTypeAlias; var prop = result.SelectMany(x => x.Properties).FirstOrDefault(x => x.Alias == approvedField); if (prop != null) { prop.Value = 1; } } return(result); }
private string GetMessage(KeyValuePair <FilePermissionTest, IEnumerable <string> > status) => _textService.Localize("permissions", status.Key);