Exemple #1
0
 /// <summary>
 /// Initializes a new instance based on the specified HTTP <paramref name="context"/> and <paramref name="redirect"/>.
 /// </summary>
 /// <param name="context">The HTTP context of the request.</param>
 /// <param name="redirect">The redirect indicating where the user should be redirected to.</param>
 /// <param name="redirectType">The redirect type.</param>
 /// <param name="destinationUrl">The destination URL.</param>
 public RedirectPostLookupNotification(HttpContext context, IRedirect redirect, RedirectType redirectType, string destinationUrl)
 {
     HttpContext    = context;
     Redirect       = redirect;
     RedirectType   = redirectType;
     DestinationUrl = destinationUrl;
 }
Exemple #2
0
        public ActionResult AddRedirect([FromBody] JObject m)
        {
            AddRedirectOptions model = m.ToObject <AddRedirectOptions>();

            try {
                // Some input validation
                if (model == null)
                {
                    throw new RedirectsException("Failed parsing request body.");
                }
                if (string.IsNullOrWhiteSpace(model.OriginalUrl))
                {
                    throw new RedirectsException(_backOffice.Localize("errorNoUrl"));
                }
                if (string.IsNullOrWhiteSpace(model.Destination?.Url))
                {
                    throw new RedirectsException(_backOffice.Localize("errorNoDestination"));
                }

                // Add the redirect
                IRedirect redirect = _redirects.AddRedirect(model);

                // Map the result for the API
                return(new JsonResult(_backOffice.Map(redirect)));
            } catch (RedirectsException ex) {
                if (!ex.Is404)
                {
                    _logger.LogError(ex, ex.Message);
                }

                // Generate the error response
                return(Error(ex));
            }
        }
 /// <summary>
 /// Deletes the specified redirect.
 /// </summary>
 /// <param name="redirectDataContext">The redirect data context.</param>
 /// <param name="redirect">The redirect.</param>
 protected override void DeleteRedirect(object redirectDataContext, IRedirect redirect)
 {
     this._redirects.Remove(
         (from r in this._redirects
          where r.Id == redirect.Id
          select r).Single());
 }
Exemple #4
0
        /// <summary>
        /// Deletes the specified <paramref name="redirect"/>.
        /// </summary>
        /// <param name="redirect">The redirect to be deleted.</param>
        public void DeleteRedirect(IRedirect redirect)
        {
            // Some input validation
            if (redirect == null)
            {
                throw new ArgumentNullException(nameof(redirect));
            }

            // This implementation only supports the "Redirect class"
            if (redirect is not Redirect r)
            {
                throw new ArgumentException($"Redirect type is not supported: {redirect.GetType()}", nameof(redirect));
            }

            // Create a new scope
            using IScope scope = _scopeProvider.CreateScope();

            // Remove the redirect from the database
            try {
                scope.Database.Delete(r.Dto);
            } catch (Exception ex) {
                throw new RedirectsException("Unable to delete redirect from database.", ex);
            }

            // Complete the scope
            scope.Complete();
        }
        /// <summary>
        /// Updates the specified redirect.
        /// </summary>
        /// <param name="redirect">The redirect.</param>
        /// <returns>The redirect.</returns>
        public IRedirect UpdateRedirect(IRedirect redirect)
        {
            this._readerWriterLockSlim.EnterWriteLock();

            try
            {
                // Get the redirect data context.
                TRedirectDataContext redirectDataContext = this.GetRedirectDataContext();

                // Try to load the redirect to ensure that it exists.
                this.ReadRedirect(redirectDataContext, redirect.Id);

                // Update the redirect.
                var updatedRedirect = this.UpdateRedirect(redirectDataContext, redirect);

                // Save the redirect data context.
                this.SaveRedirectDataContext(redirectDataContext);

                // Dispose the redirect data context.
                this.DisposeRedirectDataContext(redirectDataContext);

                // Return the updated redirect to the caller.
                return(updatedRedirect);
            }
            finally
            {
                this._readerWriterLockSlim.ExitWriteLock();
            }
        }
        public IParsedRedirect ParseRedirect(
            IRedirect redirect)
        {
            var oldUrlParsed = _urlParser.Parse(
                redirect.OldUrl,
                _configuration.DefaultUrl,
                true);
            var newUrlParsed = _urlParser.Parse(
                redirect.NewUrl,
                _configuration.DefaultUrl,
                false);

            return(new ParsedRedirect
            {
                OldUrl = new Url
                {
                    Raw = redirect.OldUrl,
                    Parsed = oldUrlParsed,
                    Formatted = _urlFormatter.Format(
                        oldUrlParsed)
                },
                NewUrl = new Url
                {
                    Raw = redirect.NewUrl,
                    Parsed = newUrlParsed,
                    Formatted = _urlFormatter.Format(
                        newUrlParsed)
                },
                RedirectType = redirect.RedirectType
            });
        }
        public override void Process(HttpRequestArgs args)
        {
            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();
            if (Redirector.Provider == null)
            {
                return;
            }
            if (Context.Site == null || Context.Database == null)
            {
                return;
            }
            if (Config.IgnoredSites.Contains(Context.Site.Name, StringComparer.OrdinalIgnoreCase))
            {
                return;
            }
            if (Redirector.IsIgnoredPageMode())
            {
                return;
            }
            if (Context.Item != null)
            {
                return;
            }
            IRedirect redirect = Redirector.Provider.LookupUrl(args.Context.Request.Path);

            if (redirect == null)
            {
                return;
            }
            if (!redirect.Enabled)
            {
                return;
            }
            if (Config.SiteContextChecking && redirect.Sites != null && !redirect.Sites.Contains(Context.Site.Name, StringComparer.OrdinalIgnoreCase))
            {
                return;
            }
            string targetUrl           = redirect.GetTargetUrl(Context.Site.Name);
            string redirectQueryString = redirect.QueryString;

            if (!string.IsNullOrEmpty(targetUrl))
            {
                if (Config.LogProcessorStopwatch)
                {
                    stopwatch.Stop();
                    Log.Info(string.Format("Redirect Manager: httprequest processor total time is : {0}ms ({1} ticks)", ((double)stopwatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000.0).ToString("F"), stopwatch.ElapsedTicks), this);
                }

                if (string.IsNullOrEmpty(redirectQueryString))
                {
                    Redirector.Respond(args, redirect.ResponseStatusCode, redirect.ResponseStatusDescription, targetUrl);
                }
                else
                {
                    Redirector.Respond(args, redirect.ResponseStatusCode, redirect.ResponseStatusDescription, targetUrl, redirectQueryString);
                }
            }
        }
Exemple #8
0
        public ActionResult DeleteRedirect(Guid redirectId)
        {
            try {
                // Get a reference to the redirect
                IRedirect redirect = _redirects.GetRedirectByKey(redirectId);
                if (redirect == null)
                {
                    throw new RedirectNotFoundException();
                }

                // Delete the redirect
                _redirects.DeleteRedirect(redirect);

                // Map the result for the API
                return(new JsonResult(_backOffice.Map(redirect)));
            } catch (RedirectsException ex) {
                if (!ex.Is404)
                {
                    _logger.LogError(ex, ex.Message);
                }

                // Generate the error response
                return(Error(ex));
            }
        }
        /// <summary>
        /// Reads the redirect with the specified name.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="name">The name of the redirect</param>
        /// <returns>The redirect.</returns>
        public IRedirect ReadRedirectByName(IUser user, string name)
        {
            // Read the redirect.
            IRedirect redirect = this._redirectProvider.ReadRedirectByName(name);

            // Return the redirect to the caller.
            return(redirect);
        }
        /// <summary>
        /// Maps the specified <paramref name="redirect"/> to a corresponding <see cref="RedirectModel"/> to be returned in the API.
        /// </summary>
        /// <param name="redirect">The redirect to be mapped.</param>
        /// <returns>An instance of <see cref="RedirectModel"/>.</returns>
        public virtual RedirectModel Map(IRedirect redirect)
        {
            Dictionary <Guid, RedirectRootNodeModel> rootNodeLookup = new();
            Dictionary <Guid, IContent> contentLookup = new();
            Dictionary <Guid, IMedia>   mediaLookup   = new();

            return(Map(redirect, rootNodeLookup, contentLookup, mediaLookup));
        }
        /// <summary>
        /// Reads the redirect with the specified id.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="id">The id of the redirect</param>
        /// <returns>The redirect.</returns>
        public IRedirect ReadRedirect(IUser user, Guid id)
        {
            // Read the redirect.
            IRedirect redirect = this._redirectProvider.ReadRedirect(id);

            // Return the redirect to the caller.
            return(redirect);
        }
 public RedirectRootNodeModel(IRedirect redirect, IContent content, string[] domains)
 {
     Id      = content?.Id ?? 0;
     Key     = content?.Key ?? redirect.RootKey;
     Name    = content?.Name;
     Icon    = content?.ContentType.Icon;
     Domains = domains ?? Array.Empty <string>();
 }
        private RedirectModel Map(IRedirect redirect, Dictionary <Guid, RedirectRootNodeModel> rootNodeLookup,
                                  Dictionary <Guid, IContent> contentLookup, Dictionary <Guid, IMedia> mediaLookup)
        {
            RedirectRootNodeModel rootNode = null;

            if (redirect.RootKey != Guid.Empty)
            {
                if (!rootNodeLookup.TryGetValue(redirect.RootKey, out rootNode))
                {
                    if (!contentLookup.TryGetValue(redirect.RootKey, out IContent content))
                    {
                        content = Dependencies.ContentService.GetById(redirect.RootKey);
                        if (content != null)
                        {
                            contentLookup.Add(content.Key, content);
                        }
                    }
                    var domains = content == null ? null : Dependencies.DomainService.GetAssignedDomains(content.Id, false).Select(x => x.DomainName).ToArray();
                    rootNode = new RedirectRootNodeModel(redirect, content, domains);

                    rootNodeLookup.Add(rootNode.Key, rootNode);
                }
            }

            RedirectDestinationModel destination;

            if (redirect.Destination.Type == RedirectDestinationType.Content)
            {
                if (!contentLookup.TryGetValue(redirect.Destination.Key, out IContent content))
                {
                    content = Dependencies.ContentService.GetById(redirect.Destination.Key);
                    if (content != null)
                    {
                        contentLookup.Add(content.Key, content);
                    }
                }
                destination = new RedirectDestinationModel(redirect, content);
            }
            else if (redirect.Destination.Type == RedirectDestinationType.Media)
            {
                if (!mediaLookup.TryGetValue(redirect.Destination.Key, out IMedia media))
                {
                    media = Dependencies.MediaService.GetById(redirect.Destination.Key);
                    if (media != null)
                    {
                        mediaLookup.Add(media.Key, media);
                    }
                }
                destination = new RedirectDestinationModel(redirect, media);
            }
            else
            {
                destination = new RedirectDestinationModel(redirect);
            }

            return(new RedirectModel(redirect, rootNode, destination));
        }
Exemple #14
0
        /// <summary>
        /// Gets a value indicating whether this account may view a redirect.
        /// </summary>
        /// <param name="redirect">The redirect to determine authorization to see.</param>
        /// <returns>True if the user may view a redirect, otherwise false.</returns>
        public bool MayView(IRedirect redirect)
        {
            if (Access.HasFlag(AccessType.Admin))
            {
                return(true);
            }

            return(redirect?.AccountId == AccountId);
        }
        public RedirectBuilder WithContentRedirectRule(out RedirectRule redirectRule, int?contentReferenceId = null)
        {
            _redirectRule.ContentId = contentReferenceId ?? new Random().Next(1, 1000);

            redirectRule = _redirectRule;

            _redirect = new ExactMatchRedirect(_redirectRule);
            return(this);
        }
 public RedirectDestinationModel(IRedirect redirect, IContent content)
 {
     _destination  = redirect.Destination;
     Name          = content?.Name ?? redirect.Destination.Name;
     Icon          = content?.ContentType.Icon ?? "icon-article";
     IsNull        = content == null;
     IsTrashed     = content?.Trashed ?? false;
     IsPublished   = content?.Published ?? false;
     BackOfficeUrl = $"/umbraco/#/content/content/edit/{redirect.Destination.Id}";
 }
        public RedirectBuilder WithExactMatchRedirectRule(out RedirectRule redirectRule, string newPattern)
        {
            _redirectRule.RedirectRuleType = RedirectRuleType.ExactMatch;
            _redirectRule.NewPattern       = newPattern;

            redirectRule = _redirectRule;

            _redirect = new ExactMatchRedirect(_redirectRule);
            return(this);
        }
 public RedirectDestinationModel(IRedirect redirect, IMedia media)
 {
     _destination  = redirect.Destination;
     Name          = media?.Name ?? redirect.Destination.Name;
     Icon          = media?.ContentType.Icon ?? "icon-picture";
     IsNull        = media == null;
     IsTrashed     = media?.Trashed ?? false;
     IsPublished   = !IsNull;
     BackOfficeUrl = $"/umbraco/#/media/media/edit/{redirect.Destination.Id}";
 }
        /// <summary>
        /// Deletes the specified redirect.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="redirect">The redirect.</param>
        public void DeleteRedirect(IUser user, IRedirect redirect)
        {
            using (TransactionScope transactionScope = new TransactionScope())
            {
                // Delete the redirect.
                this._redirectProvider.DeleteRedirect(redirect);

                // Commit the transaction.
                transactionScope.Complete();
            }
        }
        /// <summary>
        /// Updates the specified redirect.
        /// </summary>
        /// <param name="redirectDataContext">The redirect data context.</param>
        /// <param name="redirect">The redirect.</param>
        /// <returns>The redirect.</returns>
        protected override IRedirect UpdateRedirect(object redirectDataContext, IRedirect redirect)
        {
            IRedirect selectedRedirect = this.ReadRedirect(redirect.Id);

            selectedRedirect.Name                 = redirect.Name;
            selectedRedirect.RedirectMode         = redirect.RedirectMode;
            selectedRedirect.SourceAuthentication = redirect.SourceAuthentication;
            selectedRedirect.Uri = redirect.Uri;

            return(selectedRedirect);
        }
        public RedirectBuilder WithWildcardRedirectRule(out RedirectRule redirectRule, string oldPattern, string newPattern)
        {
            _redirectRule.RedirectRuleType = RedirectRuleType.Wildcard;
            _redirectRule.OldPattern       = oldPattern;
            _redirectRule.NewPattern       = newPattern;

            redirectRule = _redirectRule;

            _redirect = new WildcardRedirect(_redirectRule);
            return(this);
        }
        /// <summary>
        /// Deletes the specified redirect.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="redirect">The redirect.</param>
        public void DeleteRedirect(IUser user, IRedirect redirect)
        {
            using (TransactionScope transactionScope = new TransactionScope())
            {
                // Delete the redirect.
                this._redirectProvider.DeleteRedirect(redirect);

                // Commit the transaction.
                transactionScope.Complete();
            }
        }
Exemple #23
0
        public ActionResult EditRedirect(Guid redirectId, [FromBody] EditRedirectOptions model)
        {
            try {
                // Get a reference to the redirect
                IRedirect redirect = _redirects.GetRedirectByKey(redirectId);
                if (redirect == null)
                {
                    throw new RedirectNotFoundException();
                }

                // Some input validation
                if (model == null)
                {
                    throw new RedirectsException("Failed parsing request body.");
                }
                if (string.IsNullOrWhiteSpace(model.OriginalUrl))
                {
                    throw new RedirectsException(_backOffice.Localize("errorNoUrl"));
                }
                if (string.IsNullOrWhiteSpace(model.Destination?.Url))
                {
                    throw new RedirectsException(_backOffice.Localize("errorNoDestination"));
                }

                // Split the URL and query string
                string[] urlParts = model.OriginalUrl.Split('?');
                string   url      = urlParts[0].TrimEnd('/');
                string   query    = urlParts.Length == 2 ? urlParts[1] : string.Empty;

                redirect.RootKey            = model.RootNodeKey;
                redirect.Url                = url;
                redirect.QueryString        = query;
                redirect.Destination        = model.Destination;
                redirect.IsPermanent        = model.IsPermanent;
                redirect.ForwardQueryString = model.ForwardQueryString;

                // Save/update the redirect
                _redirects.SaveRedirect(redirect);

                // Map the result for the API
                return(new JsonResult(_backOffice.Map(redirect)));
            } catch (RedirectsException ex) {
                if (!ex.Is404)
                {
                    _logger.LogError(ex, ex.Message);
                }

                // Generate the error response
                return(Error(ex));
            }
        }
        /// <summary>
        /// Creates the specified redirect.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="redirect">The redirect.</param>
        /// <returns>The redirect.</returns>
        public IRedirect CreateRedirect(IUser user, IRedirect redirect)
        {
            using (TransactionScope transactionScope = new TransactionScope())
            {
                // Create the redirect.
                IRedirect returnRedirect = this._redirectProvider.CreateRedirect(redirect);

                // Commit the transaction.
                transactionScope.Complete();

                // Return the redirect to the caller.
                return returnRedirect;
            }
        }
        /// <summary>
        /// Creates the specified redirect.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="redirect">The redirect.</param>
        /// <returns>The redirect.</returns>
        public IRedirect CreateRedirect(IUser user, IRedirect redirect)
        {
            using (TransactionScope transactionScope = new TransactionScope())
            {
                // Create the redirect.
                IRedirect returnRedirect = this._redirectProvider.CreateRedirect(redirect);

                // Commit the transaction.
                transactionScope.Complete();

                // Return the redirect to the caller.
                return(returnRedirect);
            }
        }
Exemple #26
0
 private void VerifyRedirect(
     string oldUrl,
     string newUrl,
     bool oldUrlHasHost,
     bool newUrlHasHost,
     string parsedOldUrl,
     string parsedNewUrl,
     string originalOldUrl,
     string originalNewUrl,
     bool originalOldUrlHasHost,
     bool originalNewUrlHasHost,
     RedirectType redirectType,
     IRedirect redirect)
 {
     Assert.AreEqual(
         oldUrl,
         redirect.OldUrl);
     Assert.AreEqual(
         newUrl,
         redirect.NewUrl);
     Assert.AreEqual(
         oldUrlHasHost,
         redirect.OldUrlHasHost);
     Assert.AreEqual(
         newUrlHasHost,
         redirect.NewUrlHasHost);
     Assert.AreEqual(
         parsedOldUrl,
         redirect.ParsedOldUrl);
     Assert.AreEqual(
         parsedNewUrl,
         redirect.ParsedNewUrl);
     Assert.AreEqual(
         originalOldUrl,
         redirect.OriginalOldUrl);
     Assert.AreEqual(
         originalNewUrl,
         redirect.OriginalNewUrl);
     Assert.AreEqual(
         originalOldUrlHasHost,
         redirect.OriginalOldUrlHasHost);
     Assert.AreEqual(
         originalNewUrlHasHost,
         redirect.OriginalNewUrlHasHost);
     Assert.AreEqual(
         redirectType,
         redirect.RedirectType);
 }
        /// <summary>
        /// Creates the specified redirect.
        /// </summary>
        /// <param name="redirect">The redirect.</param>
        /// <returns>The redirect.</returns>
        public IRedirect CreateRedirect(IRedirect redirect)
        {
            this._readerWriterLockSlim.EnterWriteLock();

            try
            {
                // Get the redirect data context.
                TRedirectDataContext redirectDataContext = this.GetRedirectDataContext();

                try
                {
                    // Try to load the redirect. If this fails, the redirect can be created.
                    this.ReadRedirect(redirectDataContext, redirect.Id);
                }
                catch (Exception)
                {
                    // Create the redirect.
                    var createdRedirect = this.CreateRedirect(redirectDataContext, redirect);

                    // Save the redirect data context.
                    this.SaveRedirectDataContext(redirectDataContext);

                    // Return the created redirect to the caller.
                    return(createdRedirect);
                }
                finally
                {
                    // Dispose the redirect data context.
                    this.DisposeRedirectDataContext(redirectDataContext);
                }

                throw new UniqueConstraintViolationException(String.Format(CultureInfo.CurrentUICulture,
                                                                           "The redirect '{0}' already exists.", redirect.Name));
            }
            finally
            {
                this._readerWriterLockSlim.ExitWriteLock();
            }
        }
Exemple #28
0
        /// <summary>
        /// Saves the specified <paramref name="redirect"/>.
        /// </summary>
        /// <param name="redirect">The redirected to be saved.</param>
        /// <returns>The saved <paramref name="redirect"/>.</returns>
        public IRedirect SaveRedirect(IRedirect redirect)
        {
            // Some input validation
            if (redirect == null)
            {
                throw new ArgumentNullException(nameof(redirect));
            }

            // This implementation only supports the "Redirect class"
            if (redirect is not Redirect r)
            {
                throw new ArgumentException($"Redirect type is not supported: {redirect.GetType()}", nameof(redirect));
            }

            // Check whether another redirect matches the new URL and query string
            IRedirect existing = GetRedirectByPathAndQuery(redirect.RootKey, redirect.Url, redirect.QueryString);

            if (existing != null && existing.Id != redirect.Id)
            {
                throw new RedirectsException("A redirect with the same URL and query string already exists.");
            }

            // Update the timestamp for when the redirect was modified
            redirect.UpdateDate = DateTime.UtcNow;

            // Update the redirect in the database
            using (var scope = _scopeProvider.CreateScope()) {
                try {
                    scope.Database.Update(r.Dto);
                } catch (Exception ex) {
                    _logger.LogError(ex, "Unable to update redirect into the database.");
                    throw new RedirectsException("Unable to update redirect into the database.", ex);
                }
                scope.Complete();
            }

            return(redirect);
        }
        /// <summary>
        /// Deletes the specified redirect.
        /// </summary>
        /// <param name="redirect">The redirect.</param>
        public void DeleteRedirect(IRedirect redirect)
        {
            this._readerWriterLockSlim.EnterWriteLock();

            try
            {
                // Get the redirect data context.
                TRedirectDataContext redirectDataContext = this.GetRedirectDataContext();

                // Delete the redirect.
                this.DeleteRedirect(redirectDataContext, redirect);

                // Save the redirect data context.
                this.SaveRedirectDataContext(redirectDataContext);

                // Dispose the redirect data context.
                this.DisposeRedirectDataContext(redirectDataContext);
            }
            finally
            {
                this._readerWriterLockSlim.ExitWriteLock();
            }
        }
Exemple #30
0
        /// <summary>
        /// Returns the first redirect matching the specified <paramref name="uri"/>, or <c>null</c> if the URI does not match any redirects.
        /// </summary>
        /// <param name="uri">The URI of the request.</param>
        /// <returns>An instance of <see cref="IRedirect"/>, or <c>null</c> if no matching redirects were found.</returns>
        public IRedirect GetRedirectByUri(Uri uri)
        {
            // Get the decoded path
            string path = HttpUtility.UrlDecode(uri.AbsolutePath);

            // Get the query string
            string query = uri.PathAndQuery.Split('?').Skip(1).FirstOrDefault();

            // Get the current Umbraco context
            _umbracoContextAccessor.TryGetUmbracoContext(out IUmbracoContext umbracoContext);

            // Determine the root node via domain of the request
            Guid rootKey = Guid.Empty;

            if (TryGetDomain(uri, out Domain domain))
            {
                IPublishedContent root = umbracoContext?.Content.GetById(domain.ContentId);
                if (root != null)
                {
                    rootKey = root.Key;
                }
            }

            // Look for a site specific redirect
            if (rootKey != Guid.Empty)
            {
                IRedirect redirect = GetRedirectByPathAndQuery(rootKey, path, query);
                if (redirect != null)
                {
                    return(redirect);
                }
            }

            // Look for a global redirect
            return(GetRedirectByPathAndQuery(Guid.Empty, path, query));
        }
Exemple #31
0
        public ActionResult EditRedirect(Guid rootNodeKey, Guid redirectId, string url,
                                         string linkMode, int linkId, Guid linkKey, string linkUrl,
                                         bool permanent = true, bool forward = false)
        {
            try {
                // Get a reference to the redirect
                IRedirect redirect = _redirects.GetRedirectByKey(redirectId);
                if (redirect == null)
                {
                    throw new RedirectNotFoundException();
                }

                // Some input validation
                if (string.IsNullOrWhiteSpace(url))
                {
                    throw new RedirectsException(_backOffice.Localize("errorNoUrl"));
                }
                if (string.IsNullOrWhiteSpace(linkUrl))
                {
                    throw new RedirectsException(_backOffice.Localize("errorNoDestination"));
                }
                if (string.IsNullOrWhiteSpace(linkMode))
                {
                    throw new RedirectsException(_backOffice.Localize("errorNoDestination"));
                }

                // Parse the destination type
                RedirectDestinationType type;
                switch (linkMode)
                {
                case "content": type = RedirectDestinationType.Content; break;

                case "media": type = RedirectDestinationType.Media; break;

                case "url": type = RedirectDestinationType.Url; break;

                default: throw new RedirectsException(_backOffice.Localize("errorUnknownLinkType"));
                }

                // Initialize a new destination instance
                RedirectDestination destination = new RedirectDestination {
                    Id   = linkId,
                    Key  = linkKey,
                    Type = type,
                    Name = redirect.Destination?.Name
                };

                // Split the URL and query string
                string[] urlParts = url.Split('?');
                url = urlParts[0].TrimEnd('/');
                string query = urlParts.Length == 2 ? urlParts[1] : string.Empty;

                // Update the properties of the redirect
                redirect.RootKey     = rootNodeKey;
                redirect.Url         = url;
                redirect.QueryString = query;
                redirect.SetDestination(destination);
                redirect.IsPermanent        = permanent;
                redirect.ForwardQueryString = forward;

                // Save/update the redirect
                _redirects.SaveRedirect(redirect);

                // Map the result for the API
                return(new JsonResult(_backOffice.Map(redirect)));
            } catch (RedirectsException ex) {
                if (!ex.Is404)
                {
                    _logger.LogError(ex, ex.Message);
                }

                // Generate the error response
                return(Error(ex));
            }
        }
 /// <summary>
 /// Creates the specified redirect.
 /// </summary>
 /// <param name="redirectDataContext">The redirect data context.</param>
 /// <param name="redirect">The redirect.</param>
 /// <returns>The redirect.</returns>
 protected override IRedirect CreateRedirect(object redirectDataContext, IRedirect redirect)
 {
     this._redirects.Add(redirect);
     return(redirect);
 }