diff --git a/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/Dnn.PersonaBar.UI.csproj b/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/Dnn.PersonaBar.UI.csproj index 6a53dbddb3c..31e0e352dd4 100644 --- a/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/Dnn.PersonaBar.UI.csproj +++ b/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/Dnn.PersonaBar.UI.csproj @@ -119,6 +119,7 @@ Code + diff --git a/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/Services/Dto/FrameworkQueryDTO.cs b/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/Services/Dto/FrameworkQueryDTO.cs new file mode 100644 index 00000000000..12b5a2d51cf --- /dev/null +++ b/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/Services/Dto/FrameworkQueryDTO.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + +namespace Dnn.PersonaBar.UI.Services.DTO +{ + using System; + using System.Runtime.Serialization; + + [DataContract] + public class FrameworkQueryDTO + { + [DataMember(Name = "UpToDate")] + public bool UpToDate { get; set; } = true; + + [DataMember(Name = "Version")] + public string Version { get; set; } = string.Empty; + + [DataMember(Name = "Url")] + public string Url { get; set; } = string.Empty; + + [DataMember(Name = "Critical")] + public bool IsCritical { get; set; } = false; + + [DataMember(Name = "Published")] + public DateTime Published { get; set; } + } +} diff --git a/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/Services/ServerSummaryController.cs b/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/Services/ServerSummaryController.cs index d93ed627a7c..564d51e507d 100644 --- a/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/Services/ServerSummaryController.cs +++ b/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/Services/ServerSummaryController.cs @@ -4,18 +4,21 @@ namespace Dnn.PersonaBar.UI.Services { - using System; + using System; + using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Http; using System.Security.Cryptography; - using System.Text; + using System.Text; + using System.Text.RegularExpressions; using System.Web; using System.Web.Caching; using System.Web.Http; using Dnn.PersonaBar.Library; - using Dnn.PersonaBar.Library.Attributes; + using Dnn.PersonaBar.Library.Attributes; + using Dnn.PersonaBar.UI.Services.DTO; using DotNetNuke.Application; using DotNetNuke.Common; using DotNetNuke.Common.Utilities; @@ -29,9 +32,6 @@ namespace Dnn.PersonaBar.UI.Services [MenuPermission(Scope = ServiceScope.Regular)] public class ServerSummaryController : PersonaBarApiController { - private const string CriticalUpdateHash = "e67b666fb40c4f304a41d1706d455c09017b7bcf4ec1e411450ebfcd2c8f12d0"; - private const string NormalUpdateHash = "df29e1cda367bb8fa8534b5fb2415406100252dec057138b8d63cbadb44fb8e7"; - private enum UpdateType { None = 0, @@ -56,7 +56,8 @@ public HttpResponseMessage GetServerInfo() FrameworkVersion = isHost ? Globals.NETFrameworkVersion.ToString(2) : string.Empty, ServerName = isHost ? Globals.ServerName : string.Empty, LicenseVisible = isHost && this.GetVisibleSetting("LicenseVisible"), - DocCenterVisible = this.GetVisibleSetting("DocCenterVisible"), + DocCenterVisible = this.GetVisibleSetting("DocCenterVisible"), + Update = this.UpdateInfo(), }; return this.Request.CreateResponse(HttpStatusCode.OK, response); @@ -68,87 +69,85 @@ public HttpResponseMessage GetServerInfo() } } + /// + /// Returns update information about current framework version. + /// + /// A serialized FrameworkQueryDTO object. [HttpGet] - public HttpResponseMessage GetUpdateLink() - { - UpdateType updateType; - var url = this.NeedUpdate(out updateType) ? Upgrade.UpgradeRedirect() : string.Empty; - - return this.Request.CreateResponse(HttpStatusCode.OK, new { Url = url, Type = updateType }); - } - + public HttpResponseMessage GetUpdateInfo() + { + return this.Request.CreateResponse(HttpStatusCode.OK, this.UpdateInfo()); + } + private bool GetVisibleSetting(string settingName) { var portalSettings = PortalController.Instance.GetPortalSettings(this.PortalId); return !portalSettings.ContainsKey(settingName) || string.IsNullOrEmpty(portalSettings[settingName]) || portalSettings[settingName] == "true"; - } - - private bool NeedUpdate(out UpdateType updateType) - { - updateType = UpdateType.None; - - if (HttpContext.Current == null || !Host.CheckUpgrade || !this.UserInfo.IsSuperUser) - { - return false; - } - - var version = DotNetNukeContext.Current.Application.Version; - var request = HttpContext.Current.Request; - - var imageUrl = Upgrade.UpgradeIndicator(version, request.IsLocal, request.IsSecureConnection); - imageUrl = Globals.AddHTTP(imageUrl.TrimStart('/')); - - try - { - string hash; - const string cacheKey = "UpdateServiceUrlCacheKey"; - var cachedData = DataCache.GetCache(cacheKey) as string; - if (cachedData != null) - { - hash = cachedData; - } - else - { - var webRequest = WebRequest.CreateHttp(imageUrl); - webRequest.Timeout = Host.WebRequestTimeout; - webRequest.UserAgent = request.UserAgent; - webRequest.Referer = request.RawUrl; - - using (var stream = ((HttpWebResponse)webRequest.GetResponse()).GetResponseStream()) - { - if (stream == null) - { - return false; - } - - using (var sha256 = SHA256.Create()) - { - hash = - BitConverter.ToString(sha256.ComputeHash(stream)).Replace("-", string.Empty).ToLowerInvariant(); - DataCache.SetCache(cacheKey, hash, (DNNCacheDependency)null, - Cache.NoAbsoluteExpiration, TimeSpan.FromDays(1), CacheItemPriority.Normal, null); - } - } - } - - switch (hash) - { - case NormalUpdateHash: - updateType = UpdateType.Normal; - return true; - case CriticalUpdateHash: - updateType = UpdateType.Critical; - return true; - default: - return false; - } - } - catch (Exception) - { - return false; - } - } + } + + private FrameworkQueryDTO UpdateInfo() + { + if (HttpContext.Current == null || !Host.CheckUpgrade || !this.UserInfo.IsSuperUser) + { + return new FrameworkQueryDTO(); + } + + return CBO.GetCachedObject(new CacheItemArgs("DnnUpdateUrl"), this.RetrieveUpdateUrl); + } + + private FrameworkQueryDTO RetrieveUpdateUrl(CacheItemArgs args) + { + try + { + var url = $"{DotNetNukeContext.Current.Application.UpgradeUrl}/Update/FrameworkStatus"; + url += "?core=" + Globals.FormatVersion(DotNetNukeContext.Current.Application.Version, "00", 3, string.Empty); + url += "&type=" + DotNetNukeContext.Current.Application.Type; + url += "&name=" + DotNetNukeContext.Current.Application.Name; + url += "&id=" + Host.GUID; + url += "&no=" + PortalController.Instance.GetPortals().Count; + url += "&os=" + Globals.FormatVersion(Globals.OperatingSystemVersion, "00", 2, string.Empty); + url += "&net=" + Globals.FormatVersion(Globals.NETFrameworkVersion, "00", 2, string.Empty); + url += "&db=" + Globals.FormatVersion(Globals.DatabaseEngineVersion, "00", 2, string.Empty); + var response = this.GetJsonObject(url); + if (response.Version.Length == 6) + { + response.Version = $"v. {response.Version.Substring(0, 2)}.{response.Version.Substring(2, 2)}.{response.Version.Substring(4, 2)}"; + } + + return response; + } + catch (Exception ex) + { + Exceptions.LogException(ex); + } + + return new FrameworkQueryDTO(); + } + + private T GetJsonObject(string url) + { + var request = Globals.GetExternalRequest(url); + using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) + { + if (response.StatusCode == HttpStatusCode.OK) + { + var dataStream = response.GetResponseStream(); + var reader = new StreamReader(dataStream); + var responseFromServer = reader.ReadToEnd(); + return Newtonsoft.Json.JsonConvert.DeserializeObject(responseFromServer); + } + } + + return default(T); + } + + private string UpdateUrl() + { + var url = DotNetNukeContext.Current.Application.UpgradeUrl; + + return url; + } } } diff --git a/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/admin/personaBar/App_LocalResources/PersonaBar.resx b/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/admin/personaBar/App_LocalResources/PersonaBar.resx index 5251f50e654..a17f0da1f84 100644 --- a/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/admin/personaBar/App_LocalResources/PersonaBar.resx +++ b/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/admin/personaBar/App_LocalResources/PersonaBar.resx @@ -297,8 +297,8 @@ OK - - [ Critical Update ] + + Critical [ New Update ] @@ -321,4 +321,10 @@ Click to unlock Edit Mode. + + Update + + + Latest Version + \ No newline at end of file diff --git a/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/admin/personaBar/css/main.css b/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/admin/personaBar/css/main.css index dd78ff01b3f..80bf7751d58 100644 --- a/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/admin/personaBar/css/main.css +++ b/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/admin/personaBar/css/main.css @@ -1,4 +1,4 @@ -@font-face { +@font-face { font-family: 'pb_regular'; src: url('open-sans.semibold.ttf') format('truetype'); font-weight: normal; @@ -732,27 +732,42 @@ transform: rotate(180deg); background-size: 32px auto; position: relative; border-bottom: 1px solid var(--dnn-color-pb-menu-divider); + text-align: center; } + .personabar .personabarLogo.updateLogo { + background-position: center 14px; + } .personabar .personabarLogo:hover { background-color: var(--dnn-color-pb-menu-background-hover); } .personabar .personabarLogo a.update { text-decoration: none; text-transform: uppercase; - font-size: 7px; + font-size: 10px; font-family: pb_semibold; display: none; position: absolute; bottom: 8px; - width: 100%; + width: 64px; text-align: center; + background-color: #21a3da; + border-radius: 3px; + color: #fff; + display: block; + padding: 2px; + margin-left: 5px; } + + .personabar .personabarLogo a.update.critical { + background-color: #D63333; + } + .personabar .personabarLogo a.update.normal-update { color: #21A3DA; display: block; } .personabar .personabarLogo a.update.critical-update { - color: #D9577A; + color: #D63333; display: block; } @@ -1943,7 +1958,13 @@ div.ui-dialog-titlebar > .ui-dialog-titlebar-close:hover { color: #fff; margin-top: 18px; cursor: default; + padding-bottom: 6px; } + + .hoverSummaryMenu ul li.border { + border-bottom: 1px solid #868484; + } + .hoverSummaryMenu ul li span, .hoverSummaryMenu ul li label { display: block; line-height: 13px; @@ -1956,8 +1977,7 @@ div.ui-dialog-titlebar > .ui-dialog-titlebar-close:hover { .hoverSummaryMenu ul li label { font-size: 12px; color: var(--dnn-color-pb-menu-text-highlight); - padding: 11px 0 18px 0; - border-bottom: 1px solid var(--dnn-color-pb-menu-divider); + padding: 2px 0 5px 0; text-transform: uppercase; -moz-word-break: break-all; -o-word-break: break-all; @@ -1994,6 +2014,8 @@ div.ui-dialog-titlebar > .ui-dialog-titlebar-close:hover { text-decoration: none; cursor: pointer; } + + .server-summary li.update a:hover, .server-summary li.doc-center a:hover, .server-summary li.logout:hover { color: #FFF; @@ -2002,6 +2024,32 @@ div.ui-dialog-titlebar > .ui-dialog-titlebar-close:hover { margin-top: 12px; } +.server-summary li.new-version-info.border { + border-color: #21a3da; +} + +.server-summary li.new-version-info label { + color: #21a3da; +} + +.server-summary li.new-version-info.border.critical { + border-color: #D63333; +} + +.server-summary li.new-version-info.critical label { + color: #D63333; +} + +.server-summary li.new-version-info span.update-critical { + font-size: 10px; + background-color: #D63333; + color: white; + text-transform: uppercase; + border-radius: 4px; + padding: 2px 4px; + float: right; +} + /* Popup Style END */ /* Dropdown Style */ diff --git a/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/admin/personaBar/index.html b/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/admin/personaBar/index.html index f3049db8b6a..d1fe93f3280 100644 --- a/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/admin/personaBar/index.html +++ b/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/admin/personaBar/index.html @@ -26,8 +26,8 @@
-