< Summary - Jellyfin

Information
Class: Jellyfin.Api.Controllers.StartupController
Assembly: Jellyfin.Api
File(s): /srv/git/jellyfin/Jellyfin.Api/Controllers/StartupController.cs
Line coverage
89%
Covered lines: 17
Uncovered lines: 2
Coverable lines: 19
Total lines: 162
Line coverage: 89.4%
Branch coverage
75%
Covered branches: 6
Total branches: 8
Branch coverage: 75%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 2/13/2026 - 12:11:21 AM Line coverage: 83.3% (20/24) Branch coverage: 50% (4/8) Total lines: 1544/19/2026 - 12:14:27 AM Line coverage: 87.8% (36/41) Branch coverage: 64.2% (9/14) Total lines: 1545/7/2026 - 12:15:44 AM Line coverage: 86% (37/43) Branch coverage: 61.1% (11/18) Total lines: 1595/13/2026 - 12:15:27 AM Line coverage: 89.4% (17/19) Branch coverage: 75% (6/8) Total lines: 162 2/13/2026 - 12:11:21 AM Line coverage: 83.3% (20/24) Branch coverage: 50% (4/8) Total lines: 1544/19/2026 - 12:14:27 AM Line coverage: 87.8% (36/41) Branch coverage: 64.2% (9/14) Total lines: 1545/7/2026 - 12:15:44 AM Line coverage: 86% (37/43) Branch coverage: 61.1% (11/18) Total lines: 1595/13/2026 - 12:15:27 AM Line coverage: 89.4% (17/19) Branch coverage: 75% (6/8) Total lines: 162

Coverage delta

Coverage delta 15 -15

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
CompleteWizard()100%11100%
UpdateStartupUser()75%8883.33%

File(s)

/srv/git/jellyfin/Jellyfin.Api/Controllers/StartupController.cs

#LineLine coverage
 1using System;
 2using System.ComponentModel.DataAnnotations;
 3using System.Threading.Tasks;
 4using Jellyfin.Api.Models.StartupDtos;
 5using MediaBrowser.Common.Api;
 6using MediaBrowser.Common.Net;
 7using MediaBrowser.Controller.Configuration;
 8using MediaBrowser.Controller.Library;
 9using Microsoft.AspNetCore.Authorization;
 10using Microsoft.AspNetCore.Http;
 11using Microsoft.AspNetCore.Mvc;
 12
 13namespace Jellyfin.Api.Controllers;
 14
 15/// <summary>
 16/// The startup wizard controller.
 17/// </summary>
 18[Authorize(Policy = Policies.FirstTimeSetupOrElevated)]
 19public class StartupController : BaseJellyfinApiController
 20{
 21    private readonly IServerConfigurationManager _config;
 22    private readonly IUserManager _userManager;
 23
 24    /// <summary>
 25    /// Initializes a new instance of the <see cref="StartupController" /> class.
 26    /// </summary>
 27    /// <param name="config">The server configuration manager.</param>
 28    /// <param name="userManager">The user manager.</param>
 3629    public StartupController(IServerConfigurationManager config, IUserManager userManager)
 30    {
 3631        _config = config;
 3632        _userManager = userManager;
 3633    }
 34
 35    /// <summary>
 36    /// Completes the startup wizard.
 37    /// </summary>
 38    /// <response code="204">Startup wizard completed.</response>
 39    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 40    [HttpPost("Complete")]
 41    [ProducesResponseType(StatusCodes.Status204NoContent)]
 42    public ActionResult CompleteWizard()
 43    {
 1644        _config.Configuration.IsStartupWizardCompleted = true;
 1645        _config.SaveConfiguration();
 1646        return NoContent();
 47    }
 48
 49    /// <summary>
 50    /// Gets the initial startup wizard configuration.
 51    /// </summary>
 52    /// <response code="200">Initial startup wizard configuration retrieved.</response>
 53    /// <returns>An <see cref="OkResult"/> containing the initial startup wizard configuration.</returns>
 54    [HttpGet("Configuration")]
 55    [ProducesResponseType(StatusCodes.Status200OK)]
 56    [Obsolete("Use configuration endpoints")]
 57    public ActionResult<StartupConfigurationDto> GetStartupConfiguration()
 58    {
 59        return new StartupConfigurationDto
 60        {
 61            ServerName = _config.Configuration.ServerName,
 62            UICulture = _config.Configuration.UICulture,
 63            MetadataCountryCode = _config.Configuration.MetadataCountryCode,
 64            PreferredMetadataLanguage = _config.Configuration.PreferredMetadataLanguage
 65        };
 66    }
 67
 68    /// <summary>
 69    /// Sets the initial startup wizard configuration.
 70    /// </summary>
 71    /// <param name="startupConfiguration">The updated startup configuration.</param>
 72    /// <response code="204">Configuration saved.</response>
 73    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 74    [HttpPost("Configuration")]
 75    [ProducesResponseType(StatusCodes.Status204NoContent)]
 76    [Obsolete("Use configuration endpoints")]
 77    public ActionResult UpdateInitialConfiguration([FromBody, Required] StartupConfigurationDto startupConfiguration)
 78    {
 79        _config.Configuration.ServerName = startupConfiguration.ServerName ?? string.Empty;
 80        _config.Configuration.UICulture = startupConfiguration.UICulture ?? string.Empty;
 81        _config.Configuration.MetadataCountryCode = startupConfiguration.MetadataCountryCode ?? string.Empty;
 82        _config.Configuration.PreferredMetadataLanguage = startupConfiguration.PreferredMetadataLanguage ?? string.Empty
 83        _config.SaveConfiguration();
 84        return NoContent();
 85    }
 86
 87    /// <summary>
 88    /// Sets remote access and UPnP.
 89    /// </summary>
 90    /// <param name="startupRemoteAccessDto">The startup remote access dto.</param>
 91    /// <response code="204">Configuration saved.</response>
 92    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 93    [HttpPost("RemoteAccess")]
 94    [ProducesResponseType(StatusCodes.Status204NoContent)]
 95    [Obsolete("Use configuration endpoints")]
 96    public ActionResult SetRemoteAccess([FromBody, Required] StartupRemoteAccessDto startupRemoteAccessDto)
 97    {
 98        NetworkConfiguration settings = _config.GetNetworkConfiguration();
 99        settings.EnableRemoteAccess = startupRemoteAccessDto.EnableRemoteAccess;
 100        _config.SaveConfiguration(NetworkConfigurationStore.StoreKey, settings);
 101        return NoContent();
 102    }
 103
 104    /// <summary>
 105    /// Gets the first user.
 106    /// </summary>
 107    /// <response code="200">Initial user retrieved.</response>
 108    /// <returns>The first user.</returns>
 109    [HttpGet("User")]
 110    [HttpGet("FirstUser", Name = "GetFirstUser_2")]
 111    [ProducesResponseType(StatusCodes.Status200OK)]
 112    [Obsolete("Use authentication endpoints")]
 113    public async Task<StartupUserDto> GetFirstUser()
 114    {
 115        // TODO: Remove this method when startup wizard no longer requires an existing user.
 116        await _userManager.InitializeAsync().ConfigureAwait(false);
 117        var user = _userManager.GetFirstUser() ?? throw new InvalidOperationException("No user exists after initializati
 118        return new StartupUserDto
 119        {
 120            Name = user.Username
 121        };
 122    }
 123
 124    /// <summary>
 125    /// Sets the user name and password.
 126    /// </summary>
 127    /// <param name="startupUserDto">The DTO containing username and password.</param>
 128    /// <response code="204">Updated user name and password.</response>
 129    /// <returns>
 130    /// A <see cref="Task" /> that represents the asynchronous update operation.
 131    /// The task result contains a <see cref="NoContentResult"/> indicating success.
 132    /// </returns>
 133    [HttpPost("User")]
 134    [ProducesResponseType(StatusCodes.Status204NoContent)]
 135    public async Task<ActionResult> UpdateStartupUser([FromBody] StartupUserDto startupUserDto)
 136    {
 1137        var user = _userManager.GetFirstUser();
 1138        if (user is null)
 139        {
 0140            return NotFound();
 141        }
 142
 1143        if (string.IsNullOrWhiteSpace(startupUserDto.Password))
 144        {
 0145            return BadRequest("Password must not be empty");
 146        }
 147
 1148        if (startupUserDto.Name is not null)
 149        {
 1150            user.Username = startupUserDto.Name;
 151        }
 152
 1153        await _userManager.UpdateUserAsync(user).ConfigureAwait(false);
 154
 1155        if (!string.IsNullOrEmpty(startupUserDto.Password))
 156        {
 1157            await _userManager.ChangePassword(user.Id, startupUserDto.Password).ConfigureAwait(false);
 158        }
 159
 1160        return NoContent();
 1161    }
 162}