< Summary - Jellyfin

Information
Class: Jellyfin.Server.Migrations.Routines.MigrateAuthenticationDb
Assembly: jellyfin
File(s): /srv/git/jellyfin/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 58
Coverable lines: 58
Total lines: 143
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 16
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
Perform()0%272160%

File(s)

/srv/git/jellyfin/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.IO;
 4using Emby.Server.Implementations.Data;
 5using Jellyfin.Database.Implementations;
 6using Jellyfin.Database.Implementations.Entities.Security;
 7using MediaBrowser.Controller;
 8using MediaBrowser.Controller.Library;
 9using Microsoft.Data.Sqlite;
 10using Microsoft.EntityFrameworkCore;
 11using Microsoft.Extensions.Logging;
 12
 13namespace Jellyfin.Server.Migrations.Routines
 14{
 15    /// <summary>
 16    /// A migration that moves data from the authentication database into the new schema.
 17    /// </summary>
 18#pragma warning disable CS0618 // Type or member is obsolete
 19    [JellyfinMigration("2025-04-20T14:00:00", nameof(MigrateAuthenticationDb), "5BD72F41-E6F3-4F60-90AA-09869ABE0E22")]
 20    public class MigrateAuthenticationDb : IMigrationRoutine
 21#pragma warning restore CS0618 // Type or member is obsolete
 22    {
 23        private const string DbFilename = "authentication.db";
 24
 25        private readonly ILogger<MigrateAuthenticationDb> _logger;
 26        private readonly IDbContextFactory<JellyfinDbContext> _dbProvider;
 27        private readonly IServerApplicationPaths _appPaths;
 28        private readonly IUserManager _userManager;
 29
 30        /// <summary>
 31        /// Initializes a new instance of the <see cref="MigrateAuthenticationDb"/> class.
 32        /// </summary>
 33        /// <param name="logger">The logger.</param>
 34        /// <param name="dbProvider">The database provider.</param>
 35        /// <param name="appPaths">The server application paths.</param>
 36        /// <param name="userManager">The user manager.</param>
 37        public MigrateAuthenticationDb(
 38            ILogger<MigrateAuthenticationDb> logger,
 39            IDbContextFactory<JellyfinDbContext> dbProvider,
 40            IServerApplicationPaths appPaths,
 41            IUserManager userManager)
 42        {
 043            _logger = logger;
 044            _dbProvider = dbProvider;
 045            _appPaths = appPaths;
 046            _userManager = userManager;
 047        }
 48
 49        /// <inheritdoc />
 50        public void Perform()
 51        {
 052            var dataPath = _appPaths.DataPath;
 053            using (var connection = new SqliteConnection($"Filename={Path.Combine(dataPath, DbFilename)}"))
 54            {
 055                connection.Open();
 056                using var dbContext = _dbProvider.CreateDbContext();
 57
 058                var authenticatedDevices = connection.Query("SELECT * FROM Tokens");
 59
 060                foreach (var row in authenticatedDevices)
 61                {
 062                    var dateCreatedStr = row.GetString(9);
 063                    _ = DateTime.TryParse(dateCreatedStr, out var dateCreated);
 064                    var dateLastActivityStr = row.GetString(10);
 065                    _ = DateTime.TryParse(dateLastActivityStr, out var dateLastActivity);
 66
 067                    if (row.IsDBNull(6))
 68                    {
 069                        dbContext.ApiKeys.Add(new ApiKey(row.GetString(3))
 070                        {
 071                            AccessToken = row.GetString(1),
 072                            DateCreated = dateCreated,
 073                            DateLastActivity = dateLastActivity
 074                        });
 75                    }
 76                    else
 77                    {
 078                        var userId = row.GetGuid(6);
 079                        var user = _userManager.GetUserById(userId);
 080                        if (user is null)
 81                        {
 82                            // User doesn't exist, don't bring over the device.
 83                            continue;
 84                        }
 85
 086                        dbContext.Devices.Add(new Device(
 087                            userId,
 088                            row.GetString(3),
 089                            row.GetString(4),
 090                            row.GetString(5),
 091                            row.GetString(2))
 092                        {
 093                            AccessToken = row.GetString(1),
 094                            IsActive = row.GetBoolean(8),
 095                            DateCreated = dateCreated,
 096                            DateLastActivity = dateLastActivity
 097                        });
 98                    }
 99                }
 100
 0101                var deviceOptions = connection.Query("SELECT * FROM Devices");
 0102                var deviceIds = new HashSet<string>();
 0103                foreach (var row in deviceOptions)
 104                {
 0105                    if (row.IsDBNull(2))
 106                    {
 107                        continue;
 108                    }
 109
 0110                    var deviceId = row.GetString(2);
 0111                    if (deviceIds.Contains(deviceId))
 112                    {
 113                        continue;
 114                    }
 115
 0116                    deviceIds.Add(deviceId);
 117
 0118                    dbContext.DeviceOptions.Add(new DeviceOptions(deviceId)
 0119                    {
 0120                        CustomName = row.IsDBNull(1) ? null : row.GetString(1)
 0121                    });
 122                }
 123
 0124                dbContext.SaveChanges();
 125            }
 126
 127            try
 128            {
 0129                File.Move(Path.Combine(dataPath, DbFilename), Path.Combine(dataPath, DbFilename + ".old"));
 130
 0131                var journalPath = Path.Combine(dataPath, DbFilename + "-journal");
 0132                if (File.Exists(journalPath))
 133                {
 0134                    File.Move(journalPath, Path.Combine(dataPath, DbFilename + ".old-journal"));
 135                }
 0136            }
 0137            catch (IOException e)
 138            {
 0139                _logger.LogError(e, "Error renaming legacy activity log database to 'authentication.db.old'");
 0140            }
 0141        }
 142    }
 143}